From d0388d243b1fb8be89a3c0ef0f59ee6166046328 Mon Sep 17 00:00:00 2001 From: slyphax Date: Sun, 1 Nov 2026 19:31:33 +0100 Subject: [PATCH] =?UTF-8?q?Editor=20komplett=20in=20den=20Kern:=20Oberfl?= =?UTF-8?q?=C3=A4che,=20Werkzeuge,=20Ansicht,=20Theme,=20Vorschaubilder,?= =?UTF-8?q?=20Bau-Geometrie?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 --- README.md | 8 +- editor/bau_katalog.gd | 448 +++ editor/bau_katalog.gd.uid | 1 + editor/bau_ops.gd | 204 ++ editor/bau_ops.gd.uid | 1 + editor/build_snap.gd | 256 ++ editor/build_snap.gd.uid | 1 + editor/fly_math.gd | 71 + editor/fly_math.gd.uid | 1 + editor/interaction.gd | 1729 ++++++++++ editor/interaction.gd.uid | 1 + editor/library_browser.gd | 167 + editor/library_browser.gd.uid | 1 + editor/mouse_pointer.gd | 39 + editor/mouse_pointer.gd.uid | 1 + editor/playtest/playtest_avatar.gd | 461 +++ editor/playtest/playtest_avatar.gd.uid | 1 + editor/playtest/playtest_body.gd | 581 ++++ editor/playtest/playtest_body.gd.uid | 1 + editor/playtest/playtest_mode.gd | 536 +++ editor/playtest/playtest_mode.gd.uid | 1 + editor/playtest/playtest_settings.gd | 84 + editor/playtest/playtest_settings.gd.uid | 1 + editor/playtest/test_start.gd | 92 + editor/playtest/test_start.gd.uid | 1 + editor/playtest/test_start_store.gd | 64 + editor/playtest/test_start_store.gd.uid | 1 + editor/playtest/test_start_tool.gd | 253 ++ editor/playtest/test_start_tool.gd.uid | 1 + editor/pointer_router.gd | 13 + editor/pointer_router.gd.uid | 1 + editor/shortcut_keys.gd | 121 + editor/shortcut_keys.gd.uid | 1 + editor/shortcut_policy.gd | 48 + editor/shortcut_policy.gd.uid | 1 + editor/spawn_tool.gd | 713 ++++ editor/spawn_tool.gd.uid | 1 + editor/symmetry_ops.gd | 647 ++++ editor/symmetry_ops.gd.uid | 1 + editor/terrain_tool.gd | 765 +++++ editor/terrain_tool.gd.uid | 1 + editor/test_run.gd | 110 + editor/test_run.gd.uid | 1 + editor/updater.gd | 428 +++ editor/updater.gd.uid | 1 + library/svmap_wasser.gd | 2 +- scenes/main.tscn | 12 + server/admin_client.gd | 112 + server/admin_client.gd.uid | 1 + server/admin_texte.gd | 101 + server/admin_texte.gd.uid | 1 + server/map_push.gd | 40 + server/map_push.gd.uid | 1 + server/server_store.gd | 114 + server/server_store.gd.uid | 1 + shaders/selection_outline.gdshader | 40 + shaders/selection_outline.gdshader.uid | 1 + svmap/group_state.gd | 2 +- theme/editor_theme.tres | 281 ++ thumbs/acacia_003.png | Bin 0 -> 1891 bytes thumbs/acacia_003.png.import | 40 + thumbs/acacia_005.png | Bin 0 -> 2064 bytes thumbs/acacia_005.png.import | 40 + thumbs/acacia_006.png | Bin 0 -> 2585 bytes thumbs/acacia_006.png.import | 40 + thumbs/air_defense_001.png | Bin 0 -> 2967 bytes thumbs/air_defense_001.png.import | 40 + thumbs/air_defense_002.png | Bin 0 -> 2828 bytes thumbs/air_defense_002.png.import | 40 + thumbs/air_defense_platform_001.png | Bin 0 -> 1854 bytes thumbs/air_defense_platform_001.png.import | 40 + thumbs/air_defense_platform_002.png | Bin 0 -> 1816 bytes thumbs/air_defense_platform_002.png.import | 40 + thumbs/antenna_001.png | Bin 0 -> 1113 bytes thumbs/antenna_001.png.import | 40 + thumbs/apc_001.png | Bin 0 -> 2798 bytes thumbs/apc_001.png.import | 40 + thumbs/apc_002.png | Bin 0 -> 2756 bytes thumbs/apc_002.png.import | 40 + thumbs/apc_cap.png | Bin 0 -> 1534 bytes thumbs/apc_cap.png.import | 40 + thumbs/apc_cap_1.png | Bin 0 -> 1533 bytes thumbs/apc_cap_1.png.import | 40 + thumbs/apc_weapon.png | Bin 0 -> 1895 bytes thumbs/apc_weapon.png.import | 40 + thumbs/barracks_001.png | Bin 0 -> 2687 bytes thumbs/barracks_001.png.import | 40 + thumbs/barrel_001.png | Bin 0 -> 2140 bytes thumbs/barrel_001.png.import | 40 + thumbs/barrel_002.png | Bin 0 -> 2148 bytes thumbs/barrel_002.png.import | 40 + thumbs/barrel_003.png | Bin 0 -> 2097 bytes thumbs/barrel_003.png.import | 40 + thumbs/barrel_004.png | Bin 0 -> 2111 bytes thumbs/barrel_004.png.import | 40 + thumbs/barrel_005.png | Bin 0 -> 2078 bytes thumbs/barrel_005.png.import | 40 + thumbs/barrel_006.png | Bin 0 -> 2107 bytes thumbs/barrel_006.png.import | 40 + thumbs/barrel_007.png | Bin 0 -> 2087 bytes thumbs/barrel_007.png.import | 40 + thumbs/barrel_008.png | Bin 0 -> 2107 bytes thumbs/barrel_008.png.import | 40 + thumbs/barrel_009.png | Bin 0 -> 2106 bytes thumbs/barrel_009.png.import | 40 + thumbs/barrel_010.png | Bin 0 -> 2104 bytes thumbs/barrel_010.png.import | 40 + thumbs/barrel_011.png | Bin 0 -> 1718 bytes thumbs/barrel_011.png.import | 40 + thumbs/barrel_012.png | Bin 0 -> 2550 bytes thumbs/barrel_012.png.import | 40 + thumbs/barrel_013.png | Bin 0 -> 2687 bytes thumbs/barrel_013.png.import | 40 + thumbs/barrier_001.png | Bin 0 -> 1581 bytes thumbs/barrier_001.png.import | 40 + thumbs/barrier_002.png | Bin 0 -> 1263 bytes thumbs/barrier_002.png.import | 40 + thumbs/barrier_003.png | Bin 0 -> 885 bytes thumbs/barrier_003.png.import | 40 + thumbs/barrier_004.png | Bin 0 -> 2388 bytes thumbs/barrier_004.png.import | 40 + thumbs/barrier_005.png | Bin 0 -> 2404 bytes thumbs/barrier_005.png.import | 40 + thumbs/barrier_006.png | Bin 0 -> 3050 bytes thumbs/barrier_006.png.import | 40 + thumbs/barrier_007.png | Bin 0 -> 2419 bytes thumbs/barrier_007.png.import | 40 + thumbs/barrier_008.png | Bin 0 -> 2122 bytes thumbs/barrier_008.png.import | 40 + thumbs/barrier_009.png | Bin 0 -> 2102 bytes thumbs/barrier_009.png.import | 40 + thumbs/barrier_010.png | Bin 0 -> 3041 bytes thumbs/barrier_010.png.import | 40 + thumbs/barrier_011.png | Bin 0 -> 2168 bytes thumbs/barrier_011.png.import | 40 + thumbs/barrier_012.png | Bin 0 -> 2066 bytes thumbs/barrier_012.png.import | 40 + thumbs/barrier_013.png | Bin 0 -> 2459 bytes thumbs/barrier_013.png.import | 40 + thumbs/barrier_014.png | Bin 0 -> 2540 bytes thumbs/barrier_014.png.import | 40 + thumbs/barrier_015.png | Bin 0 -> 2446 bytes thumbs/barrier_015.png.import | 40 + thumbs/barrier_016.png | Bin 0 -> 2743 bytes thumbs/barrier_016.png.import | 40 + thumbs/barrier_017.png | Bin 0 -> 2696 bytes thumbs/barrier_017.png.import | 40 + thumbs/bau_boden.png | Bin 0 -> 1200 bytes thumbs/bau_boden.png.import | 40 + thumbs/bau_bruestung.png | Bin 0 -> 1134 bytes thumbs/bau_bruestung.png.import | 40 + thumbs/bau_dach_ecke_aussen.png | Bin 0 -> 1083 bytes thumbs/bau_dach_ecke_aussen.png.import | 40 + thumbs/bau_dach_ecke_innen.png | Bin 0 -> 1299 bytes thumbs/bau_dach_ecke_innen.png.import | 40 + thumbs/bau_dach_giebel.png | Bin 0 -> 1122 bytes thumbs/bau_dach_giebel.png.import | 40 + thumbs/bau_dach_giebel_4.png | Bin 0 -> 1122 bytes thumbs/bau_dach_giebel_4.png.import | 40 + thumbs/bau_dach_giebel_6.png | Bin 0 -> 1122 bytes thumbs/bau_dach_giebel_6.png.import | 40 + thumbs/bau_dach_giebel_ende.png | Bin 0 -> 867 bytes thumbs/bau_dach_giebel_ende.png.import | 40 + thumbs/bau_dach_plateau.png | Bin 0 -> 1439 bytes thumbs/bau_dach_plateau.png.import | 40 + thumbs/bau_dach_pyramide.png | Bin 0 -> 980 bytes thumbs/bau_dach_pyramide.png.import | 40 + thumbs/bau_dach_pyramide_4.png | Bin 0 -> 980 bytes thumbs/bau_dach_pyramide_4.png.import | 40 + thumbs/bau_dach_pyramide_6.png | Bin 0 -> 980 bytes thumbs/bau_dach_pyramide_6.png.import | 40 + thumbs/bau_dach_schraege.png | Bin 0 -> 1197 bytes thumbs/bau_dach_schraege.png.import | 40 + thumbs/bau_fundament.png | Bin 0 -> 1170 bytes thumbs/bau_fundament.png.import | 40 + thumbs/bau_giebelwand.png | Bin 0 -> 833 bytes thumbs/bau_giebelwand.png.import | 40 + thumbs/bau_giebelwand_4.png | Bin 0 -> 833 bytes thumbs/bau_giebelwand_4.png.import | 40 + thumbs/bau_giebelwand_6.png | Bin 0 -> 833 bytes thumbs/bau_giebelwand_6.png.import | 40 + thumbs/bau_pfeiler.png | Bin 0 -> 599 bytes thumbs/bau_pfeiler.png.import | 40 + thumbs/bau_treppe.png | Bin 0 -> 1395 bytes thumbs/bau_treppe.png.import | 40 + thumbs/bau_wand.png | Bin 0 -> 938 bytes thumbs/bau_wand.png.import | 40 + thumbs/bau_wand_fenster.png | Bin 0 -> 1063 bytes thumbs/bau_wand_fenster.png.import | 40 + thumbs/bau_wand_scharte.png | Bin 0 -> 1078 bytes thumbs/bau_wand_scharte.png.import | 40 + thumbs/bau_wand_tuer.png | Bin 0 -> 1028 bytes thumbs/bau_wand_tuer.png.import | 40 + thumbs/blade_001.png | Bin 0 -> 703 bytes thumbs/blade_001.png.import | 40 + thumbs/blade_002.png | Bin 0 -> 1006 bytes thumbs/blade_002.png.import | 40 + thumbs/box_001.png | Bin 0 -> 3132 bytes thumbs/box_001.png.import | 40 + thumbs/box_002.png | Bin 0 -> 3154 bytes thumbs/box_002.png.import | 40 + thumbs/box_003.png | Bin 0 -> 3100 bytes thumbs/box_003.png.import | 40 + thumbs/box_004.png | Bin 0 -> 2010 bytes thumbs/box_004.png.import | 40 + thumbs/box_005.png | Bin 0 -> 2122 bytes thumbs/box_005.png.import | 40 + thumbs/box_006.png | Bin 0 -> 1186 bytes thumbs/box_006.png.import | 40 + thumbs/box_007.png | Bin 0 -> 1276 bytes thumbs/box_007.png.import | 40 + thumbs/box_008.png | Bin 0 -> 1221 bytes thumbs/box_008.png.import | 40 + thumbs/box_009.png | Bin 0 -> 1164 bytes thumbs/box_009.png.import | 40 + thumbs/box_010.png | Bin 0 -> 1196 bytes thumbs/box_010.png.import | 40 + thumbs/box_011.png | Bin 0 -> 1179 bytes thumbs/box_011.png.import | 40 + thumbs/box_012.png | Bin 0 -> 1659 bytes thumbs/box_012.png.import | 40 + thumbs/box_013.png | Bin 0 -> 1672 bytes thumbs/box_013.png.import | 40 + thumbs/box_014.png | Bin 0 -> 1806 bytes thumbs/box_014.png.import | 40 + thumbs/box_015.png | Bin 0 -> 1875 bytes thumbs/box_015.png.import | 40 + thumbs/box_016.png | Bin 0 -> 1392 bytes thumbs/box_016.png.import | 40 + thumbs/box_017.png | Bin 0 -> 1571 bytes thumbs/box_017.png.import | 40 + thumbs/box_018.png | Bin 0 -> 1707 bytes thumbs/box_018.png.import | 40 + thumbs/box_019.png | Bin 0 -> 1584 bytes thumbs/box_019.png.import | 40 + thumbs/box_020.png | Bin 0 -> 2203 bytes thumbs/box_020.png.import | 40 + thumbs/box_021.png | Bin 0 -> 4154 bytes thumbs/box_021.png.import | 40 + thumbs/box_022.png | Bin 0 -> 4430 bytes thumbs/box_022.png.import | 40 + thumbs/box_023.png | Bin 0 -> 2263 bytes thumbs/box_023.png.import | 40 + thumbs/box_024.png | Bin 0 -> 2532 bytes thumbs/box_024.png.import | 40 + thumbs/box_025.png | Bin 0 -> 2670 bytes thumbs/box_025.png.import | 40 + thumbs/box_026.png | Bin 0 -> 3757 bytes thumbs/box_026.png.import | 40 + thumbs/box_027.png | Bin 0 -> 4463 bytes thumbs/box_027.png.import | 40 + thumbs/box_028.png | Bin 0 -> 3825 bytes thumbs/box_028.png.import | 40 + thumbs/box_029.png | Bin 0 -> 4608 bytes thumbs/box_029.png.import | 40 + thumbs/box_030.png | Bin 0 -> 2365 bytes thumbs/box_030.png.import | 40 + thumbs/box_031.png | Bin 0 -> 2147 bytes thumbs/box_031.png.import | 40 + thumbs/building_001.png | Bin 0 -> 2316 bytes thumbs/building_001.png.import | 40 + thumbs/bush_002.png | Bin 0 -> 2523 bytes thumbs/bush_002.png.import | 40 + thumbs/bush_006.png | Bin 0 -> 2402 bytes thumbs/bush_006.png.import | 40 + thumbs/bush_007.png | Bin 0 -> 2141 bytes thumbs/bush_007.png.import | 40 + thumbs/cactus_001.png | Bin 0 -> 1369 bytes thumbs/cactus_001.png.import | 40 + thumbs/cactus_002.png | Bin 0 -> 1391 bytes thumbs/cactus_002.png.import | 40 + thumbs/cactus_003.png | Bin 0 -> 1349 bytes thumbs/cactus_003.png.import | 40 + thumbs/cactus_004.png | Bin 0 -> 2089 bytes thumbs/cactus_004.png.import | 40 + thumbs/cactus_005.png | Bin 0 -> 2362 bytes thumbs/cactus_005.png.import | 40 + thumbs/cactus_006.png | Bin 0 -> 2450 bytes thumbs/cactus_006.png.import | 40 + thumbs/cactus_007.png | Bin 0 -> 1460 bytes thumbs/cactus_007.png.import | 40 + thumbs/cactus_008.png | Bin 0 -> 1883 bytes thumbs/cactus_008.png.import | 40 + thumbs/cactus_009.png | Bin 0 -> 1444 bytes thumbs/cactus_009.png.import | 40 + thumbs/cactus_010.png | Bin 0 -> 1819 bytes thumbs/cactus_010.png.import | 40 + thumbs/cactus_011.png | Bin 0 -> 1779 bytes thumbs/cactus_011.png.import | 40 + thumbs/cactus_012.png | Bin 0 -> 1663 bytes thumbs/cactus_012.png.import | 40 + thumbs/cactus_013.png | Bin 0 -> 1820 bytes thumbs/cactus_013.png.import | 40 + thumbs/cactus_014.png | Bin 0 -> 1715 bytes thumbs/cactus_014.png.import | 40 + thumbs/cactus_015.png | Bin 0 -> 2671 bytes thumbs/cactus_015.png.import | 40 + thumbs/cart_001.png | Bin 0 -> 1316 bytes thumbs/cart_001.png.import | 40 + thumbs/checkpoint_001.png | Bin 0 -> 2346 bytes thumbs/checkpoint_001.png.import | 40 + thumbs/cistern_001.png | Bin 0 -> 2286 bytes thumbs/cistern_001.png.import | 40 + thumbs/cistern_002.png | Bin 0 -> 2203 bytes thumbs/cistern_002.png.import | 40 + thumbs/cistern_003.png | Bin 0 -> 1829 bytes thumbs/cistern_003.png.import | 40 + thumbs/cistern_004.png | Bin 0 -> 2213 bytes thumbs/cistern_004.png.import | 40 + thumbs/coil_001.png | Bin 0 -> 2246 bytes thumbs/coil_001.png.import | 40 + thumbs/concrete_wall_001.png | Bin 0 -> 1366 bytes thumbs/concrete_wall_001.png.import | 40 + thumbs/concrete_wall_002.png | Bin 0 -> 1381 bytes thumbs/concrete_wall_002.png.import | 40 + thumbs/concrete_wall_destroyed_001.png | Bin 0 -> 1532 bytes thumbs/concrete_wall_destroyed_001.png.import | 40 + thumbs/concrete_wall_destroyed_002.png | Bin 0 -> 1830 bytes thumbs/concrete_wall_destroyed_002.png.import | 40 + thumbs/concrete_wall_destroyed_003.png | Bin 0 -> 1873 bytes thumbs/concrete_wall_destroyed_003.png.import | 40 + thumbs/concrete_wall_destroyed_004.png | Bin 0 -> 1979 bytes thumbs/concrete_wall_destroyed_004.png.import | 40 + thumbs/conditioner_001.png | Bin 0 -> 2860 bytes thumbs/conditioner_001.png.import | 40 + thumbs/conditioner_002.png | Bin 0 -> 2881 bytes thumbs/conditioner_002.png.import | 40 + thumbs/construction_001.png | Bin 0 -> 2621 bytes thumbs/construction_001.png.import | 40 + thumbs/construction_002.png | Bin 0 -> 3105 bytes thumbs/construction_002.png.import | 40 + thumbs/container_001.png | Bin 0 -> 3642 bytes thumbs/container_001.png.import | 40 + thumbs/container_001_offen1.png | Bin 0 -> 3014 bytes thumbs/container_001_offen1.png.import | 40 + thumbs/container_001_offen2.png | Bin 0 -> 3173 bytes thumbs/container_001_offen2.png.import | 40 + thumbs/container_001_ohne.png | Bin 0 -> 2961 bytes thumbs/container_001_ohne.png.import | 40 + thumbs/container_002.png | Bin 0 -> 3422 bytes thumbs/container_002.png.import | 40 + thumbs/container_002_offen1.png | Bin 0 -> 2930 bytes thumbs/container_002_offen1.png.import | 40 + thumbs/container_002_offen2.png | Bin 0 -> 3034 bytes thumbs/container_002_offen2.png.import | 40 + thumbs/container_002_ohne.png | Bin 0 -> 2806 bytes thumbs/container_002_ohne.png.import | 40 + thumbs/container_003.png | Bin 0 -> 3642 bytes thumbs/container_003.png.import | 40 + thumbs/container_003_offen1.png | Bin 0 -> 3065 bytes thumbs/container_003_offen1.png.import | 40 + thumbs/container_003_offen2.png | Bin 0 -> 3169 bytes thumbs/container_003_offen2.png.import | 40 + thumbs/container_003_ohne.png | Bin 0 -> 2978 bytes thumbs/container_003_ohne.png.import | 40 + thumbs/container_004.png | Bin 0 -> 3513 bytes thumbs/container_004.png.import | 40 + thumbs/container_004_offen1.png | Bin 0 -> 2975 bytes thumbs/container_004_offen1.png.import | 40 + thumbs/container_004_offen2.png | Bin 0 -> 3080 bytes thumbs/container_004_offen2.png.import | 40 + thumbs/container_004_ohne.png | Bin 0 -> 2876 bytes thumbs/container_004_ohne.png.import | 40 + thumbs/container_005.png | Bin 0 -> 3535 bytes thumbs/container_005.png.import | 40 + thumbs/container_005_offen1.png | Bin 0 -> 3019 bytes thumbs/container_005_offen1.png.import | 40 + thumbs/container_005_offen2.png | Bin 0 -> 3136 bytes thumbs/container_005_offen2.png.import | 40 + thumbs/container_005_ohne.png | Bin 0 -> 2887 bytes thumbs/container_005_ohne.png.import | 40 + thumbs/container_006.png | Bin 0 -> 3545 bytes thumbs/container_006.png.import | 40 + thumbs/container_006_offen1.png | Bin 0 -> 3039 bytes thumbs/container_006_offen1.png.import | 40 + thumbs/container_006_offen2.png | Bin 0 -> 3075 bytes thumbs/container_006_offen2.png.import | 40 + thumbs/container_006_ohne.png | Bin 0 -> 2907 bytes thumbs/container_006_ohne.png.import | 40 + thumbs/container_007.png | Bin 0 -> 3480 bytes thumbs/container_007.png.import | 40 + thumbs/container_007_offen1.png | Bin 0 -> 2903 bytes thumbs/container_007_offen1.png.import | 40 + thumbs/container_007_offen2.png | Bin 0 -> 2982 bytes thumbs/container_007_offen2.png.import | 40 + thumbs/container_007_ohne.png | Bin 0 -> 2872 bytes thumbs/container_007_ohne.png.import | 40 + thumbs/container_008.png | Bin 0 -> 3347 bytes thumbs/container_008.png.import | 40 + thumbs/container_008_offen1.png | Bin 0 -> 2793 bytes thumbs/container_008_offen1.png.import | 40 + thumbs/container_008_offen2.png | Bin 0 -> 2982 bytes thumbs/container_008_offen2.png.import | 40 + thumbs/container_008_ohne.png | Bin 0 -> 2653 bytes thumbs/container_008_ohne.png.import | 40 + thumbs/deadwood_001.png | Bin 0 -> 1797 bytes thumbs/deadwood_001.png.import | 40 + thumbs/deadwood_002.png | Bin 0 -> 1502 bytes thumbs/deadwood_002.png.import | 40 + thumbs/deadwood_003.png | Bin 0 -> 1480 bytes thumbs/deadwood_003.png.import | 40 + thumbs/deadwood_004.png | Bin 0 -> 1727 bytes thumbs/deadwood_004.png.import | 40 + thumbs/deadwood_005.png | Bin 0 -> 2221 bytes thumbs/deadwood_005.png.import | 40 + thumbs/deadwood_006.png | Bin 0 -> 2182 bytes thumbs/deadwood_006.png.import | 40 + thumbs/deadwood_007.png | Bin 0 -> 1966 bytes thumbs/deadwood_007.png.import | 40 + thumbs/deadwood_008.png | Bin 0 -> 2178 bytes thumbs/deadwood_008.png.import | 40 + thumbs/deadwood_009.png | Bin 0 -> 1993 bytes thumbs/deadwood_009.png.import | 40 + thumbs/deadwood_010.png | Bin 0 -> 2114 bytes thumbs/deadwood_010.png.import | 40 + thumbs/deadwood_011.png | Bin 0 -> 2131 bytes thumbs/deadwood_011.png.import | 40 + thumbs/deadwood_012.png | Bin 0 -> 1920 bytes thumbs/deadwood_012.png.import | 40 + thumbs/deadwood_013.png | Bin 0 -> 1792 bytes thumbs/deadwood_013.png.import | 40 + thumbs/deadwood_016.png | Bin 0 -> 1436 bytes thumbs/deadwood_016.png.import | 40 + thumbs/deadwood_023.png | Bin 0 -> 1432 bytes thumbs/deadwood_023.png.import | 40 + thumbs/decal_001.png | Bin 0 -> 868 bytes thumbs/decal_001.png.import | 40 + thumbs/decal_002.png | Bin 0 -> 1062 bytes thumbs/decal_002.png.import | 40 + thumbs/decal_003.png | Bin 0 -> 517 bytes thumbs/decal_003.png.import | 40 + thumbs/decal_004.png | Bin 0 -> 623 bytes thumbs/decal_004.png.import | 40 + thumbs/decal_005.png | Bin 0 -> 634 bytes thumbs/decal_005.png.import | 40 + thumbs/decal_006.png | Bin 0 -> 591 bytes thumbs/decal_006.png.import | 40 + thumbs/decal_007.png | Bin 0 -> 618 bytes thumbs/decal_007.png.import | 40 + thumbs/decal_008.png | Bin 0 -> 607 bytes thumbs/decal_008.png.import | 40 + thumbs/decal_009.png | Bin 0 -> 628 bytes thumbs/decal_009.png.import | 40 + thumbs/decal_010.png | Bin 0 -> 946 bytes thumbs/decal_010.png.import | 40 + thumbs/decal_011.png | Bin 0 -> 684 bytes thumbs/decal_011.png.import | 40 + thumbs/decal_012.png | Bin 0 -> 561 bytes thumbs/decal_012.png.import | 40 + thumbs/decal_013.png | Bin 0 -> 540 bytes thumbs/decal_013.png.import | 40 + thumbs/decal_014.png | Bin 0 -> 725 bytes thumbs/decal_014.png.import | 40 + thumbs/door_001.png | Bin 0 -> 1216 bytes thumbs/door_001.png.import | 40 + thumbs/door_002.png | Bin 0 -> 1217 bytes thumbs/door_002.png.import | 40 + thumbs/door_003.png | Bin 0 -> 1323 bytes thumbs/door_003.png.import | 40 + thumbs/dune_010.png | Bin 0 -> 2769 bytes thumbs/dune_010.png.import | 40 + thumbs/fence_001.png | Bin 0 -> 2361 bytes thumbs/fence_001.png.import | 40 + thumbs/fence_002.png | Bin 0 -> 2216 bytes thumbs/fence_002.png.import | 40 + thumbs/fighter_jet_001.png | Bin 0 -> 1369 bytes thumbs/fighter_jet_001.png.import | 40 + thumbs/fighter_jet_002.png | Bin 0 -> 1416 bytes thumbs/fighter_jet_002.png.import | 40 + thumbs/fighter_jet_003.png | Bin 0 -> 2362 bytes thumbs/fighter_jet_003.png.import | 40 + thumbs/fighter_jet_004.png | Bin 0 -> 1654 bytes thumbs/fighter_jet_004.png.import | 40 + thumbs/flashlight_001.png | Bin 0 -> 998 bytes thumbs/flashlight_001.png.import | 40 + thumbs/flashlight_002.png | Bin 0 -> 1258 bytes thumbs/flashlight_002.png.import | 40 + thumbs/generator_001.png | Bin 0 -> 1585 bytes thumbs/generator_001.png.import | 40 + thumbs/generator_002.png | Bin 0 -> 1474 bytes thumbs/generator_002.png.import | 40 + thumbs/generator_003.png | Bin 0 -> 1378 bytes thumbs/generator_003.png.import | 40 + thumbs/generator_004.png | Bin 0 -> 1533 bytes thumbs/generator_004.png.import | 40 + thumbs/grass_003.png | Bin 0 -> 1806 bytes thumbs/grass_003.png.import | 40 + thumbs/grass_004.png | Bin 0 -> 1761 bytes thumbs/grass_004.png.import | 40 + thumbs/grass_005.png | Bin 0 -> 1716 bytes thumbs/grass_005.png.import | 40 + thumbs/grass_006.png | Bin 0 -> 1664 bytes thumbs/grass_006.png.import | 40 + thumbs/grass_007.png | Bin 0 -> 1957 bytes thumbs/grass_007.png.import | 40 + thumbs/grass_008.png | Bin 0 -> 2273 bytes thumbs/grass_008.png.import | 40 + thumbs/ground_001.png | Bin 0 -> 787 bytes thumbs/ground_001.png.import | 40 + thumbs/ground_002.png | Bin 0 -> 1246 bytes thumbs/ground_002.png.import | 40 + thumbs/ground_003.png | Bin 0 -> 1536 bytes thumbs/ground_003.png.import | 40 + thumbs/ground_004.png | Bin 0 -> 1998 bytes thumbs/ground_004.png.import | 40 + thumbs/ground_005.png | Bin 0 -> 2257 bytes thumbs/ground_005.png.import | 40 + thumbs/ground_006.png | Bin 0 -> 1088 bytes thumbs/ground_006.png.import | 40 + thumbs/ground_007.png | Bin 0 -> 1247 bytes thumbs/ground_007.png.import | 40 + thumbs/ground_008.png | Bin 0 -> 1402 bytes thumbs/ground_008.png.import | 40 + thumbs/ground_009.png | Bin 0 -> 1734 bytes thumbs/ground_009.png.import | 40 + thumbs/gsm_001.png | Bin 0 -> 2113 bytes thumbs/gsm_001.png.import | 40 + thumbs/hangar_001.png | Bin 0 -> 2261 bytes thumbs/hangar_001.png.import | 40 + thumbs/hangar_002.png | Bin 0 -> 3436 bytes thumbs/hangar_002.png.import | 40 + thumbs/hangar_003.png | Bin 0 -> 2698 bytes thumbs/hangar_003.png.import | 40 + thumbs/hangar_004.png | Bin 0 -> 2263 bytes thumbs/hangar_004.png.import | 40 + thumbs/hangar_005.png | Bin 0 -> 2218 bytes thumbs/hangar_005.png.import | 40 + thumbs/hangar_006.png | Bin 0 -> 1621 bytes thumbs/hangar_006.png.import | 40 + thumbs/hangar_007.png | Bin 0 -> 2078 bytes thumbs/hangar_007.png.import | 40 + thumbs/hangar_008.png | Bin 0 -> 2097 bytes thumbs/hangar_008.png.import | 40 + thumbs/hangar_door_001.png | Bin 0 -> 1360 bytes thumbs/hangar_door_001.png.import | 40 + thumbs/hangar_door_002.png | Bin 0 -> 1294 bytes thumbs/hangar_door_002.png.import | 40 + thumbs/hangar_door_003.png | Bin 0 -> 2084 bytes thumbs/hangar_door_003.png.import | 40 + thumbs/hedgehog_001.png | Bin 0 -> 1506 bytes thumbs/hedgehog_001.png.import | 40 + thumbs/helicopter_001.png | Bin 0 -> 1953 bytes thumbs/helicopter_001.png.import | 40 + thumbs/helicopter_platform_001.png | Bin 0 -> 1515 bytes thumbs/helicopter_platform_001.png.import | 40 + thumbs/hummer_001.png | Bin 0 -> 2986 bytes thumbs/hummer_001.png.import | 40 + thumbs/hummer_002.png | Bin 0 -> 4143 bytes thumbs/hummer_002.png.import | 40 + thumbs/hummer_003.png | Bin 0 -> 2915 bytes thumbs/hummer_003.png.import | 40 + thumbs/hummer_004.png | Bin 0 -> 3952 bytes thumbs/hummer_004.png.import | 40 + thumbs/ladder_001.png | Bin 0 -> 2934 bytes thumbs/ladder_001.png.import | 40 + thumbs/ladder_002.png | Bin 0 -> 2985 bytes thumbs/ladder_002.png.import | 40 + thumbs/ladder_003.png | Bin 0 -> 2959 bytes thumbs/ladder_003.png.import | 40 + thumbs/lamp_001.png | Bin 0 -> 1335 bytes thumbs/lamp_001.png.import | 40 + thumbs/log_001.png | Bin 0 -> 3325 bytes thumbs/log_001.png.import | 40 + thumbs/machine_gun_001.png | Bin 0 -> 2181 bytes thumbs/machine_gun_001.png.import | 40 + thumbs/machine_gun_002.png | Bin 0 -> 1219 bytes thumbs/machine_gun_002.png.import | 40 + thumbs/machine_gun_003.png | Bin 0 -> 2013 bytes thumbs/machine_gun_003.png.import | 40 + thumbs/machine_gun_003_schild.png | Bin 0 -> 2013 bytes thumbs/machine_gun_003_schild.png.import | 40 + thumbs/machine_gun_004.png | Bin 0 -> 1853 bytes thumbs/machine_gun_004.png.import | 40 + thumbs/machine_gun_005.png | Bin 0 -> 1246 bytes thumbs/machine_gun_005.png.import | 40 + thumbs/military_transport_aircraft_001.png | Bin 0 -> 1845 bytes ...military_transport_aircraft_001.png.import | 40 + thumbs/mortar_001.png | Bin 0 -> 2162 bytes thumbs/mortar_001.png.import | 40 + thumbs/observation_tower_001.png | Bin 0 -> 2252 bytes thumbs/observation_tower_001.png.import | 40 + thumbs/observation_tower_002.png | Bin 0 -> 2152 bytes thumbs/observation_tower_002.png.import | 40 + thumbs/obstacle_001.png | Bin 0 -> 1234 bytes thumbs/obstacle_001.png.import | 40 + thumbs/obstacle_002.png | Bin 0 -> 1583 bytes thumbs/obstacle_002.png.import | 40 + thumbs/obstacle_003.png | Bin 0 -> 1891 bytes thumbs/obstacle_003.png.import | 40 + thumbs/obstacle_004.png | Bin 0 -> 1879 bytes thumbs/obstacle_004.png.import | 40 + thumbs/obstacle_005.png | Bin 0 -> 1525 bytes thumbs/obstacle_005.png.import | 40 + thumbs/obstacle_006.png | Bin 0 -> 1179 bytes thumbs/obstacle_006.png.import | 40 + thumbs/obstacle_007.png | Bin 0 -> 1688 bytes thumbs/obstacle_007.png.import | 40 + thumbs/obstacle_008.png | Bin 0 -> 1254 bytes thumbs/obstacle_008.png.import | 40 + thumbs/obstacle_009.png | Bin 0 -> 1151 bytes thumbs/obstacle_009.png.import | 40 + thumbs/obstacle_010.png | Bin 0 -> 1137 bytes thumbs/obstacle_010.png.import | 40 + thumbs/pallet_001.png | Bin 0 -> 1481 bytes thumbs/pallet_001.png.import | 40 + thumbs/pallet_002.png | Bin 0 -> 1537 bytes thumbs/pallet_002.png.import | 40 + thumbs/pillar_001.png | Bin 0 -> 869 bytes thumbs/pillar_001.png.import | 40 + thumbs/pillar_002.png | Bin 0 -> 1009 bytes thumbs/pillar_002.png.import | 40 + thumbs/pillar_003.png | Bin 0 -> 730 bytes thumbs/pillar_003.png.import | 40 + thumbs/pillar_004.png | Bin 0 -> 1073 bytes thumbs/pillar_004.png.import | 40 + thumbs/pipe_001.png | Bin 0 -> 3274 bytes thumbs/pipe_001.png.import | 40 + thumbs/protection_001.png | Bin 0 -> 1648 bytes thumbs/protection_001.png.import | 40 + thumbs/protection_002.png | Bin 0 -> 1543 bytes thumbs/protection_002.png.import | 40 + thumbs/protective_wall_001.png | Bin 0 -> 848 bytes thumbs/protective_wall_001.png.import | 40 + thumbs/protective_wall_002.png | Bin 0 -> 840 bytes thumbs/protective_wall_002.png.import | 40 + thumbs/protective_wall_003.png | Bin 0 -> 946 bytes thumbs/protective_wall_003.png.import | 40 + thumbs/protective_wall_004.png | Bin 0 -> 929 bytes thumbs/protective_wall_004.png.import | 40 + thumbs/radiolocator_001.png | Bin 0 -> 2387 bytes thumbs/radiolocator_001.png.import | 40 + thumbs/radiolocator_002.png | Bin 0 -> 2404 bytes thumbs/radiolocator_002.png.import | 40 + thumbs/radiolocator_platform_001.png | Bin 0 -> 2812 bytes thumbs/radiolocator_platform_001.png.import | 40 + thumbs/radiolocator_platform_002.png | Bin 0 -> 2889 bytes thumbs/radiolocator_platform_002.png.import | 40 + thumbs/radiostation_001.png | Bin 0 -> 2109 bytes thumbs/radiostation_001.png.import | 40 + thumbs/radiostation_002.png | Bin 0 -> 2157 bytes thumbs/radiostation_002.png.import | 40 + thumbs/road_006.png | Bin 0 -> 1997 bytes thumbs/road_006.png.import | 40 + thumbs/road_007.png | Bin 0 -> 1907 bytes thumbs/road_007.png.import | 40 + thumbs/road_008.png | Bin 0 -> 1719 bytes thumbs/road_008.png.import | 40 + thumbs/road_009.png | Bin 0 -> 1831 bytes thumbs/road_009.png.import | 40 + thumbs/rock_003.png | Bin 0 -> 2155 bytes thumbs/rock_003.png.import | 40 + thumbs/rock_004.png | Bin 0 -> 2226 bytes thumbs/rock_004.png.import | 40 + thumbs/rock_005.png | Bin 0 -> 2677 bytes thumbs/rock_005.png.import | 40 + thumbs/rock_006.png | Bin 0 -> 2006 bytes thumbs/rock_006.png.import | 40 + thumbs/rock_007.png | Bin 0 -> 2294 bytes thumbs/rock_007.png.import | 40 + thumbs/rock_008.png | Bin 0 -> 1728 bytes thumbs/rock_008.png.import | 40 + thumbs/rock_009.png | Bin 0 -> 2611 bytes thumbs/rock_009.png.import | 40 + thumbs/rock_010.png | Bin 0 -> 2264 bytes thumbs/rock_010.png.import | 40 + thumbs/rock_011.png | Bin 0 -> 2304 bytes thumbs/rock_011.png.import | 40 + thumbs/rock_012.png | Bin 0 -> 2529 bytes thumbs/rock_012.png.import | 40 + thumbs/rock_013.png | Bin 0 -> 2548 bytes thumbs/rock_013.png.import | 40 + thumbs/rock_014.png | Bin 0 -> 2416 bytes thumbs/rock_014.png.import | 40 + thumbs/rock_015.png | Bin 0 -> 1776 bytes thumbs/rock_015.png.import | 40 + thumbs/rock_016.png | Bin 0 -> 2621 bytes thumbs/rock_016.png.import | 40 + thumbs/rock_017.png | Bin 0 -> 2156 bytes thumbs/rock_017.png.import | 40 + thumbs/rock_018.png | Bin 0 -> 2347 bytes thumbs/rock_018.png.import | 40 + thumbs/rock_019.png | Bin 0 -> 2427 bytes thumbs/rock_019.png.import | 40 + thumbs/rock_020.png | Bin 0 -> 2164 bytes thumbs/rock_020.png.import | 40 + thumbs/rock_021.png | Bin 0 -> 2376 bytes thumbs/rock_021.png.import | 40 + thumbs/rock_022.png | Bin 0 -> 2193 bytes thumbs/rock_022.png.import | 40 + thumbs/rock_023.png | Bin 0 -> 3020 bytes thumbs/rock_023.png.import | 40 + thumbs/rock_024.png | Bin 0 -> 2916 bytes thumbs/rock_024.png.import | 40 + thumbs/rock_038.png | Bin 0 -> 4110 bytes thumbs/rock_038.png.import | 40 + thumbs/sand_001.png | Bin 0 -> 1593 bytes thumbs/sand_001.png.import | 40 + thumbs/shell_001.png | Bin 0 -> 1743 bytes thumbs/shell_001.png.import | 40 + thumbs/shell_002.png | Bin 0 -> 1248 bytes thumbs/shell_002.png.import | 40 + thumbs/shell_003.png | Bin 0 -> 1057 bytes thumbs/shell_003.png.import | 40 + thumbs/shell_004.png | Bin 0 -> 1136 bytes thumbs/shell_004.png.import | 40 + thumbs/shell_005.png | Bin 0 -> 1188 bytes thumbs/shell_005.png.import | 40 + thumbs/shell_006.png | Bin 0 -> 1423 bytes thumbs/shell_006.png.import | 40 + thumbs/shell_007.png | Bin 0 -> 1960 bytes thumbs/shell_007.png.import | 40 + thumbs/shell_008.png | Bin 0 -> 2058 bytes thumbs/shell_008.png.import | 40 + thumbs/solar_battery_001.png | Bin 0 -> 2019 bytes thumbs/solar_battery_001.png.import | 40 + thumbs/stone_015.png | Bin 0 -> 1729 bytes thumbs/stone_015.png.import | 40 + thumbs/stone_016.png | Bin 0 -> 1703 bytes thumbs/stone_016.png.import | 40 + thumbs/stone_017.png | Bin 0 -> 1176 bytes thumbs/stone_017.png.import | 40 + thumbs/stone_018.png | Bin 0 -> 1338 bytes thumbs/stone_018.png.import | 40 + thumbs/stone_019.png | Bin 0 -> 1551 bytes thumbs/stone_019.png.import | 40 + thumbs/stone_020.png | Bin 0 -> 1735 bytes thumbs/stone_020.png.import | 40 + thumbs/stone_021.png | Bin 0 -> 1727 bytes thumbs/stone_021.png.import | 40 + thumbs/stone_022.png | Bin 0 -> 1155 bytes thumbs/stone_022.png.import | 40 + thumbs/stone_023.png | Bin 0 -> 1356 bytes thumbs/stone_023.png.import | 40 + thumbs/stone_024.png | Bin 0 -> 1559 bytes thumbs/stone_024.png.import | 40 + thumbs/stone_025.png | Bin 0 -> 1470 bytes thumbs/stone_025.png.import | 40 + thumbs/stone_026.png | Bin 0 -> 1451 bytes thumbs/stone_026.png.import | 40 + thumbs/table_001.png | Bin 0 -> 1335 bytes thumbs/table_001.png.import | 40 + thumbs/table_002.png | Bin 0 -> 1689 bytes thumbs/table_002.png.import | 40 + thumbs/tank_001.png | Bin 0 -> 2653 bytes thumbs/tank_001.png.import | 40 + thumbs/tank_002.png | Bin 0 -> 4322 bytes thumbs/tank_002.png.import | 40 + thumbs/tank_003.png | Bin 0 -> 2674 bytes thumbs/tank_003.png.import | 40 + thumbs/tank_004.png | Bin 0 -> 4405 bytes thumbs/tank_004.png.import | 40 + thumbs/tank_005.png | Bin 0 -> 2366 bytes thumbs/tank_005.png.import | 40 + thumbs/tank_006.png | Bin 0 -> 3493 bytes thumbs/tank_006.png.import | 40 + thumbs/tank_car_001.png | Bin 0 -> 2867 bytes thumbs/tank_car_001.png.import | 40 + thumbs/tank_car_002.png | Bin 0 -> 2828 bytes thumbs/tank_car_002.png.import | 40 + thumbs/tank_gun_001.png | Bin 0 -> 1472 bytes thumbs/tank_gun_001.png.import | 40 + thumbs/tank_gun_002.png | Bin 0 -> 1472 bytes thumbs/tank_gun_002.png.import | 40 + thumbs/tank_gun_003.png | Bin 0 -> 1442 bytes thumbs/tank_gun_003.png.import | 40 + thumbs/tank_gun_004.png | Bin 0 -> 1442 bytes thumbs/tank_gun_004.png.import | 40 + thumbs/tank_gun_005.png | Bin 0 -> 1569 bytes thumbs/tank_gun_005.png.import | 40 + thumbs/tank_gun_006.png | Bin 0 -> 1569 bytes thumbs/tank_gun_006.png.import | 40 + thumbs/tank_tower_001.png | Bin 0 -> 2157 bytes thumbs/tank_tower_001.png.import | 40 + thumbs/tank_tower_002.png | Bin 0 -> 2550 bytes thumbs/tank_tower_002.png.import | 40 + thumbs/tank_tower_003.png | Bin 0 -> 2105 bytes thumbs/tank_tower_003.png.import | 40 + thumbs/tank_tower_004.png | Bin 0 -> 2601 bytes thumbs/tank_tower_004.png.import | 40 + thumbs/tank_tower_005.png | Bin 0 -> 2360 bytes thumbs/tank_tower_005.png.import | 40 + thumbs/tank_tower_006.png | Bin 0 -> 3494 bytes thumbs/tank_tower_006.png.import | 40 + thumbs/target_001.png | Bin 0 -> 1612 bytes thumbs/target_001.png.import | 40 + thumbs/target_002.png | Bin 0 -> 1258 bytes thumbs/target_002.png.import | 40 + thumbs/tent_001.png | Bin 0 -> 3060 bytes thumbs/tent_001.png.import | 40 + thumbs/tent_002.png | Bin 0 -> 2951 bytes thumbs/tent_002.png.import | 40 + thumbs/tent_003.png | Bin 0 -> 3078 bytes thumbs/tent_003.png.import | 40 + thumbs/tent_004.png | Bin 0 -> 2849 bytes thumbs/tent_004.png.import | 40 + thumbs/tent_005.png | Bin 0 -> 3202 bytes thumbs/tent_005.png.import | 40 + thumbs/tent_006.png | Bin 0 -> 3005 bytes thumbs/tent_006.png.import | 40 + thumbs/tent_007.png | Bin 0 -> 3132 bytes thumbs/tent_007.png.import | 40 + thumbs/tent_008.png | Bin 0 -> 3001 bytes thumbs/tent_008.png.import | 40 + thumbs/tent_009.png | Bin 0 -> 2709 bytes thumbs/tent_009.png.import | 40 + thumbs/tent_010.png | Bin 0 -> 2301 bytes thumbs/tent_010.png.import | 40 + thumbs/tent_011.png | Bin 0 -> 2701 bytes thumbs/tent_011.png.import | 40 + thumbs/tent_012.png | Bin 0 -> 2310 bytes thumbs/tent_012.png.import | 40 + thumbs/tent_013.png | Bin 0 -> 1876 bytes thumbs/tent_013.png.import | 40 + thumbs/tent_014.png | Bin 0 -> 1922 bytes thumbs/tent_014.png.import | 40 + thumbs/tire_001.png | Bin 0 -> 1578 bytes thumbs/tire_001.png.import | 40 + thumbs/tires_001.png | Bin 0 -> 2694 bytes thumbs/tires_001.png.import | 40 + thumbs/toilet_001.png | Bin 0 -> 1729 bytes thumbs/toilet_001.png.import | 40 + thumbs/toilet_002.png | Bin 0 -> 1785 bytes thumbs/toilet_002.png.import | 40 + thumbs/tower_001.png | Bin 0 -> 1709 bytes thumbs/tower_001.png.import | 40 + thumbs/tower_002.png | Bin 0 -> 2551 bytes thumbs/tower_002.png.import | 40 + thumbs/tower_003.png | Bin 0 -> 2707 bytes thumbs/tower_003.png.import | 40 + thumbs/tower_004.png | Bin 0 -> 2665 bytes thumbs/tower_004.png.import | 40 + thumbs/tower_005.png | Bin 0 -> 2434 bytes thumbs/tower_005.png.import | 40 + thumbs/training_item_001.png | Bin 0 -> 2400 bytes thumbs/training_item_001.png.import | 40 + thumbs/training_item_002.png | Bin 0 -> 2322 bytes thumbs/training_item_002.png.import | 40 + thumbs/training_item_003.png | Bin 0 -> 3223 bytes thumbs/training_item_003.png.import | 40 + thumbs/training_item_004.png | Bin 0 -> 2161 bytes thumbs/training_item_004.png.import | 40 + thumbs/training_item_005.png | Bin 0 -> 1627 bytes thumbs/training_item_005.png.import | 40 + thumbs/training_item_006.png | Bin 0 -> 1617 bytes thumbs/training_item_006.png.import | 40 + thumbs/training_item_007.png | Bin 0 -> 2165 bytes thumbs/training_item_007.png.import | 40 + thumbs/truck_001.png | Bin 0 -> 2438 bytes thumbs/truck_001.png.import | 40 + thumbs/truck_002.png | Bin 0 -> 2467 bytes thumbs/truck_002.png.import | 40 + thumbs/truck_002_aufbau.png | Bin 0 -> 2467 bytes thumbs/truck_002_aufbau.png.import | 40 + thumbs/truck_002_tank.png | Bin 0 -> 2467 bytes thumbs/truck_002_tank.png.import | 40 + thumbs/truck_003.png | Bin 0 -> 2684 bytes thumbs/truck_003.png.import | 40 + thumbs/truck_004.png | Bin 0 -> 2671 bytes thumbs/truck_004.png.import | 40 + thumbs/truck_004_aufbau.png | Bin 0 -> 2671 bytes thumbs/truck_004_aufbau.png.import | 40 + thumbs/truck_004_plane.png | Bin 0 -> 2671 bytes thumbs/truck_004_plane.png.import | 40 + thumbs/truck_body_001.png | Bin 0 -> 1842 bytes thumbs/truck_body_001.png.import | 40 + thumbs/truck_body_002.png | Bin 0 -> 1883 bytes thumbs/truck_body_002.png.import | 40 + thumbs/truck_body_003.png | Bin 0 -> 2104 bytes thumbs/truck_body_003.png.import | 40 + thumbs/truck_body_004.png | Bin 0 -> 2085 bytes thumbs/truck_body_004.png.import | 40 + thumbs/truck_body_005.png | Bin 0 -> 1760 bytes thumbs/truck_body_005.png.import | 40 + thumbs/truck_body_006.png | Bin 0 -> 1826 bytes thumbs/truck_body_006.png.import | 40 + thumbs/wall_001.png | Bin 0 -> 822 bytes thumbs/wall_001.png.import | 40 + thumbs/wall_002.png | Bin 0 -> 773 bytes thumbs/wall_002.png.import | 40 + thumbs/wall_003.png | Bin 0 -> 732 bytes thumbs/wall_003.png.import | 40 + thumbs/wall_004.png | Bin 0 -> 726 bytes thumbs/wall_004.png.import | 40 + thumbs/wall_005.png | Bin 0 -> 818 bytes thumbs/wall_005.png.import | 40 + thumbs/wall_006.png | Bin 0 -> 761 bytes thumbs/wall_006.png.import | 40 + thumbs/wall_007.png | Bin 0 -> 684 bytes thumbs/wall_007.png.import | 40 + thumbs/wall_008.png | Bin 0 -> 832 bytes thumbs/wall_008.png.import | 40 + thumbs/wall_009.png | Bin 0 -> 698 bytes thumbs/wall_009.png.import | 40 + thumbs/wall_010.png | Bin 0 -> 710 bytes thumbs/wall_010.png.import | 40 + thumbs/wall_011.png | Bin 0 -> 857 bytes thumbs/wall_011.png.import | 40 + thumbs/wall_012.png | Bin 0 -> 932 bytes thumbs/wall_012.png.import | 40 + thumbs/wall_013.png | Bin 0 -> 800 bytes thumbs/wall_013.png.import | 40 + thumbs/wall_014.png | Bin 0 -> 785 bytes thumbs/wall_014.png.import | 40 + thumbs/wall_015.png | Bin 0 -> 831 bytes thumbs/wall_015.png.import | 40 + thumbs/wall_016.png | Bin 0 -> 886 bytes thumbs/wall_016.png.import | 40 + thumbs/wall_017.png | Bin 0 -> 781 bytes thumbs/wall_017.png.import | 40 + thumbs/wall_018.png | Bin 0 -> 880 bytes thumbs/wall_018.png.import | 40 + thumbs/wall_019.png | Bin 0 -> 895 bytes thumbs/wall_019.png.import | 40 + thumbs/wall_020.png | Bin 0 -> 771 bytes thumbs/wall_020.png.import | 40 + thumbs/wall_021.png | Bin 0 -> 979 bytes thumbs/wall_021.png.import | 40 + thumbs/wall_022.png | Bin 0 -> 825 bytes thumbs/wall_022.png.import | 40 + thumbs/wall_023.png | Bin 0 -> 887 bytes thumbs/wall_023.png.import | 40 + thumbs/wall_024.png | Bin 0 -> 786 bytes thumbs/wall_024.png.import | 40 + thumbs/wall_025.png | Bin 0 -> 724 bytes thumbs/wall_025.png.import | 40 + thumbs/wall_051.png | Bin 0 -> 858 bytes thumbs/wall_051.png.import | 40 + thumbs/wall_052.png | Bin 0 -> 779 bytes thumbs/wall_052.png.import | 40 + thumbs/wall_053.png | Bin 0 -> 813 bytes thumbs/wall_053.png.import | 40 + thumbs/wall_054.png | Bin 0 -> 775 bytes thumbs/wall_054.png.import | 40 + thumbs/wall_055.png | Bin 0 -> 844 bytes thumbs/wall_055.png.import | 40 + thumbs/wall_056.png | Bin 0 -> 760 bytes thumbs/wall_056.png.import | 40 + thumbs/wall_057.png | Bin 0 -> 842 bytes thumbs/wall_057.png.import | 40 + thumbs/wall_058.png | Bin 0 -> 668 bytes thumbs/wall_058.png.import | 40 + thumbs/wall_059.png | Bin 0 -> 697 bytes thumbs/wall_059.png.import | 40 + thumbs/wall_060.png | Bin 0 -> 833 bytes thumbs/wall_060.png.import | 40 + thumbs/wall_061.png | Bin 0 -> 789 bytes thumbs/wall_061.png.import | 40 + thumbs/wall_062.png | Bin 0 -> 752 bytes thumbs/wall_062.png.import | 40 + thumbs/wall_063.png | Bin 0 -> 740 bytes thumbs/wall_063.png.import | 40 + thumbs/wall_064.png | Bin 0 -> 777 bytes thumbs/wall_064.png.import | 40 + thumbs/wall_065.png | Bin 0 -> 905 bytes thumbs/wall_065.png.import | 40 + thumbs/wall_066.png | Bin 0 -> 832 bytes thumbs/wall_066.png.import | 40 + thumbs/wall_067.png | Bin 0 -> 866 bytes thumbs/wall_067.png.import | 40 + thumbs/wall_068.png | Bin 0 -> 945 bytes thumbs/wall_068.png.import | 40 + thumbs/wall_069.png | Bin 0 -> 934 bytes thumbs/wall_069.png.import | 40 + thumbs/wall_070.png | Bin 0 -> 862 bytes thumbs/wall_070.png.import | 40 + thumbs/wall_071.png | Bin 0 -> 712 bytes thumbs/wall_071.png.import | 40 + thumbs/wall_072.png | Bin 0 -> 835 bytes thumbs/wall_072.png.import | 40 + thumbs/wall_073.png | Bin 0 -> 797 bytes thumbs/wall_073.png.import | 40 + thumbs/wall_074.png | Bin 0 -> 876 bytes thumbs/wall_074.png.import | 40 + thumbs/wall_100.png | Bin 0 -> 749 bytes thumbs/wall_100.png.import | 40 + thumbs/water_tower_001.png | Bin 0 -> 2015 bytes thumbs/water_tower_001.png.import | 40 + thumbs/water_tower_002.png | Bin 0 -> 2282 bytes thumbs/water_tower_002.png.import | 40 + thumbs/water_tower_003.png | Bin 0 -> 2053 bytes thumbs/water_tower_003.png.import | 40 + thumbs/water_tower_004.png | Bin 0 -> 1602 bytes thumbs/water_tower_004.png.import | 40 + thumbs/wheel_001.png | Bin 0 -> 2018 bytes thumbs/wheel_001.png.import | 40 + thumbs/wheel_002.png | Bin 0 -> 2048 bytes thumbs/wheel_002.png.import | 40 + thumbs/wheel_003.png | Bin 0 -> 2691 bytes thumbs/wheel_003.png.import | 40 + thumbs/wheel_004.png | Bin 0 -> 2480 bytes thumbs/wheel_004.png.import | 40 + thumbs/wheel_005.png | Bin 0 -> 2428 bytes thumbs/wheel_005.png.import | 40 + thumbs/wire_001.png | Bin 0 -> 589 bytes thumbs/wire_001.png.import | 40 + thumbs/wire_002.png | Bin 0 -> 614 bytes thumbs/wire_002.png.import | 40 + thumbs/wire_003.png | Bin 0 -> 620 bytes thumbs/wire_003.png.import | 40 + ui/help_text.gd | 97 + ui/help_text.gd.uid | 1 + ui/inspector_panel.gd | 700 ++++ ui/inspector_panel.gd.uid | 1 + ui/main.gd | 2920 +++++++++++++++++ ui/main.gd.uid | 1 + ui/new_map_dialog.gd | 94 + ui/new_map_dialog.gd.uid | 1 + ui/panels/assets_panel.gd | 782 +++++ ui/panels/assets_panel.gd.uid | 1 + ui/panels/bauen_panel.gd | 118 + ui/panels/bauen_panel.gd.uid | 1 + ui/panels/check_panel.gd | 176 + ui/panels/check_panel.gd.uid | 1 + ui/panels/editor_panel.gd | 89 + ui/panels/editor_panel.gd.uid | 1 + ui/panels/loadout_panel.gd | 329 ++ ui/panels/loadout_panel.gd.uid | 1 + ui/panels/malen_panel.gd | 170 + ui/panels/malen_panel.gd.uid | 1 + ui/panels/map_panel.gd | 264 ++ ui/panels/map_panel.gd.uid | 1 + ui/panels/modus_panel.gd | 413 +++ ui/panels/modus_panel.gd.uid | 1 + ui/panels/registry.gd | 109 + ui/panels/registry.gd.uid | 1 + ui/panels/scene_tree_panel.gd | 590 ++++ ui/panels/scene_tree_panel.gd.uid | 1 + ui/panels/selection_panel.gd | 67 + ui/panels/selection_panel.gd.uid | 1 + ui/panels/server_panel.gd | 687 ++++ ui/panels/server_panel.gd.uid | 1 + ui/panels/settings_panel.gd | 160 + ui/panels/settings_panel.gd.uid | 1 + ui/panels/status_bar.gd | 81 + ui/panels/status_bar.gd.uid | 1 + ui/panels/symmetry_panel.gd | 237 ++ ui/panels/symmetry_panel.gd.uid | 1 + ui/panels/terrain_panel.gd | 282 ++ ui/panels/terrain_panel.gd.uid | 1 + ui/panels/test_start_panel.gd | 63 + ui/panels/test_start_panel.gd.uid | 1 + ui/panels/toolbar.gd | 156 + ui/panels/toolbar.gd.uid | 1 + ui/resize_map_dialog.gd | 275 ++ ui/resize_map_dialog.gd.uid | 1 + ui/ui_scale.gd | 136 + ui/ui_scale.gd.uid | 1 + ui/viewport_toolbar.gd | 78 + ui/viewport_toolbar.gd.uid | 1 + vendor/modular_builder/LICENSE | 125 + .../modular_building_detail.gd | 284 ++ .../modular_building_detail.gd.uid | 1 + .../modular_builder/modular_piece_geometry.gd | 748 +++++ .../modular_piece_geometry.gd.uid | 1 + viewport/gizmo.gd | 628 ++++ viewport/gizmo.gd.uid | 1 + viewport/glb_mesh_store.gd | 450 +++ viewport/glb_mesh_store.gd.uid | 1 + viewport/map_view_builder.gd | 883 +++++ viewport/map_view_builder.gd.uid | 1 + viewport/mesh_shapes.gd | 88 + viewport/mesh_shapes.gd.uid | 1 + viewport/orbit_camera.gd | 454 +++ viewport/orbit_camera.gd.uid | 1 + viewport/terrain_contour.gdshader | 237 ++ viewport/terrain_contour.gdshader.uid | 1 + viewport/terrain_mesh.gd | 446 +++ viewport/terrain_mesh.gd.uid | 1 + viewport/wasser.gdshader | 92 + viewport/wasser.gdshader.uid | 1 + 1070 files changed, 40907 insertions(+), 5 deletions(-) create mode 100644 editor/bau_katalog.gd create mode 100644 editor/bau_katalog.gd.uid create mode 100644 editor/bau_ops.gd create mode 100644 editor/bau_ops.gd.uid create mode 100644 editor/build_snap.gd create mode 100644 editor/build_snap.gd.uid create mode 100644 editor/fly_math.gd create mode 100644 editor/fly_math.gd.uid create mode 100644 editor/interaction.gd create mode 100644 editor/interaction.gd.uid create mode 100644 editor/library_browser.gd create mode 100644 editor/library_browser.gd.uid create mode 100644 editor/mouse_pointer.gd create mode 100644 editor/mouse_pointer.gd.uid create mode 100644 editor/playtest/playtest_avatar.gd create mode 100644 editor/playtest/playtest_avatar.gd.uid create mode 100644 editor/playtest/playtest_body.gd create mode 100644 editor/playtest/playtest_body.gd.uid create mode 100644 editor/playtest/playtest_mode.gd create mode 100644 editor/playtest/playtest_mode.gd.uid create mode 100644 editor/playtest/playtest_settings.gd create mode 100644 editor/playtest/playtest_settings.gd.uid create mode 100644 editor/playtest/test_start.gd create mode 100644 editor/playtest/test_start.gd.uid create mode 100644 editor/playtest/test_start_store.gd create mode 100644 editor/playtest/test_start_store.gd.uid create mode 100644 editor/playtest/test_start_tool.gd create mode 100644 editor/playtest/test_start_tool.gd.uid create mode 100644 editor/pointer_router.gd create mode 100644 editor/pointer_router.gd.uid create mode 100644 editor/shortcut_keys.gd create mode 100644 editor/shortcut_keys.gd.uid create mode 100644 editor/shortcut_policy.gd create mode 100644 editor/shortcut_policy.gd.uid create mode 100644 editor/spawn_tool.gd create mode 100644 editor/spawn_tool.gd.uid create mode 100644 editor/symmetry_ops.gd create mode 100644 editor/symmetry_ops.gd.uid create mode 100644 editor/terrain_tool.gd create mode 100644 editor/terrain_tool.gd.uid create mode 100644 editor/test_run.gd create mode 100644 editor/test_run.gd.uid create mode 100644 editor/updater.gd create mode 100644 editor/updater.gd.uid create mode 100644 scenes/main.tscn create mode 100644 server/admin_client.gd create mode 100644 server/admin_client.gd.uid create mode 100644 server/admin_texte.gd create mode 100644 server/admin_texte.gd.uid create mode 100644 server/map_push.gd create mode 100644 server/map_push.gd.uid create mode 100644 server/server_store.gd create mode 100644 server/server_store.gd.uid create mode 100644 shaders/selection_outline.gdshader create mode 100644 shaders/selection_outline.gdshader.uid create mode 100644 theme/editor_theme.tres create mode 100644 thumbs/acacia_003.png create mode 100644 thumbs/acacia_003.png.import create mode 100644 thumbs/acacia_005.png create mode 100644 thumbs/acacia_005.png.import create mode 100644 thumbs/acacia_006.png create mode 100644 thumbs/acacia_006.png.import create mode 100644 thumbs/air_defense_001.png create mode 100644 thumbs/air_defense_001.png.import create mode 100644 thumbs/air_defense_002.png create mode 100644 thumbs/air_defense_002.png.import create mode 100644 thumbs/air_defense_platform_001.png create mode 100644 thumbs/air_defense_platform_001.png.import create mode 100644 thumbs/air_defense_platform_002.png create mode 100644 thumbs/air_defense_platform_002.png.import create mode 100644 thumbs/antenna_001.png create mode 100644 thumbs/antenna_001.png.import create mode 100644 thumbs/apc_001.png create mode 100644 thumbs/apc_001.png.import create mode 100644 thumbs/apc_002.png create mode 100644 thumbs/apc_002.png.import create mode 100644 thumbs/apc_cap.png create mode 100644 thumbs/apc_cap.png.import create mode 100644 thumbs/apc_cap_1.png create mode 100644 thumbs/apc_cap_1.png.import create mode 100644 thumbs/apc_weapon.png create mode 100644 thumbs/apc_weapon.png.import create mode 100644 thumbs/barracks_001.png create mode 100644 thumbs/barracks_001.png.import create mode 100644 thumbs/barrel_001.png create mode 100644 thumbs/barrel_001.png.import create mode 100644 thumbs/barrel_002.png create mode 100644 thumbs/barrel_002.png.import create mode 100644 thumbs/barrel_003.png create mode 100644 thumbs/barrel_003.png.import create mode 100644 thumbs/barrel_004.png create mode 100644 thumbs/barrel_004.png.import create mode 100644 thumbs/barrel_005.png create mode 100644 thumbs/barrel_005.png.import create mode 100644 thumbs/barrel_006.png create mode 100644 thumbs/barrel_006.png.import create mode 100644 thumbs/barrel_007.png create mode 100644 thumbs/barrel_007.png.import create mode 100644 thumbs/barrel_008.png create mode 100644 thumbs/barrel_008.png.import create mode 100644 thumbs/barrel_009.png create mode 100644 thumbs/barrel_009.png.import create mode 100644 thumbs/barrel_010.png create mode 100644 thumbs/barrel_010.png.import create mode 100644 thumbs/barrel_011.png create mode 100644 thumbs/barrel_011.png.import create mode 100644 thumbs/barrel_012.png create mode 100644 thumbs/barrel_012.png.import create mode 100644 thumbs/barrel_013.png create mode 100644 thumbs/barrel_013.png.import create mode 100644 thumbs/barrier_001.png create mode 100644 thumbs/barrier_001.png.import create mode 100644 thumbs/barrier_002.png create mode 100644 thumbs/barrier_002.png.import create mode 100644 thumbs/barrier_003.png create mode 100644 thumbs/barrier_003.png.import create mode 100644 thumbs/barrier_004.png create mode 100644 thumbs/barrier_004.png.import create mode 100644 thumbs/barrier_005.png create mode 100644 thumbs/barrier_005.png.import create mode 100644 thumbs/barrier_006.png create mode 100644 thumbs/barrier_006.png.import create mode 100644 thumbs/barrier_007.png create mode 100644 thumbs/barrier_007.png.import create mode 100644 thumbs/barrier_008.png create mode 100644 thumbs/barrier_008.png.import create mode 100644 thumbs/barrier_009.png create mode 100644 thumbs/barrier_009.png.import create mode 100644 thumbs/barrier_010.png create mode 100644 thumbs/barrier_010.png.import create mode 100644 thumbs/barrier_011.png create mode 100644 thumbs/barrier_011.png.import create mode 100644 thumbs/barrier_012.png create mode 100644 thumbs/barrier_012.png.import create mode 100644 thumbs/barrier_013.png create mode 100644 thumbs/barrier_013.png.import create mode 100644 thumbs/barrier_014.png create mode 100644 thumbs/barrier_014.png.import create mode 100644 thumbs/barrier_015.png create mode 100644 thumbs/barrier_015.png.import create mode 100644 thumbs/barrier_016.png create mode 100644 thumbs/barrier_016.png.import create mode 100644 thumbs/barrier_017.png create mode 100644 thumbs/barrier_017.png.import create mode 100644 thumbs/bau_boden.png create mode 100644 thumbs/bau_boden.png.import create mode 100644 thumbs/bau_bruestung.png create mode 100644 thumbs/bau_bruestung.png.import create mode 100644 thumbs/bau_dach_ecke_aussen.png create mode 100644 thumbs/bau_dach_ecke_aussen.png.import create mode 100644 thumbs/bau_dach_ecke_innen.png create mode 100644 thumbs/bau_dach_ecke_innen.png.import create mode 100644 thumbs/bau_dach_giebel.png create mode 100644 thumbs/bau_dach_giebel.png.import create mode 100644 thumbs/bau_dach_giebel_4.png create mode 100644 thumbs/bau_dach_giebel_4.png.import create mode 100644 thumbs/bau_dach_giebel_6.png create mode 100644 thumbs/bau_dach_giebel_6.png.import create mode 100644 thumbs/bau_dach_giebel_ende.png create mode 100644 thumbs/bau_dach_giebel_ende.png.import create mode 100644 thumbs/bau_dach_plateau.png create mode 100644 thumbs/bau_dach_plateau.png.import create mode 100644 thumbs/bau_dach_pyramide.png create mode 100644 thumbs/bau_dach_pyramide.png.import create mode 100644 thumbs/bau_dach_pyramide_4.png create mode 100644 thumbs/bau_dach_pyramide_4.png.import create mode 100644 thumbs/bau_dach_pyramide_6.png create mode 100644 thumbs/bau_dach_pyramide_6.png.import create mode 100644 thumbs/bau_dach_schraege.png create mode 100644 thumbs/bau_dach_schraege.png.import create mode 100644 thumbs/bau_fundament.png create mode 100644 thumbs/bau_fundament.png.import create mode 100644 thumbs/bau_giebelwand.png create mode 100644 thumbs/bau_giebelwand.png.import create mode 100644 thumbs/bau_giebelwand_4.png create mode 100644 thumbs/bau_giebelwand_4.png.import create mode 100644 thumbs/bau_giebelwand_6.png create mode 100644 thumbs/bau_giebelwand_6.png.import create mode 100644 thumbs/bau_pfeiler.png create mode 100644 thumbs/bau_pfeiler.png.import create mode 100644 thumbs/bau_treppe.png create mode 100644 thumbs/bau_treppe.png.import create mode 100644 thumbs/bau_wand.png create mode 100644 thumbs/bau_wand.png.import create mode 100644 thumbs/bau_wand_fenster.png create mode 100644 thumbs/bau_wand_fenster.png.import create mode 100644 thumbs/bau_wand_scharte.png create mode 100644 thumbs/bau_wand_scharte.png.import create mode 100644 thumbs/bau_wand_tuer.png create mode 100644 thumbs/bau_wand_tuer.png.import create mode 100644 thumbs/blade_001.png create mode 100644 thumbs/blade_001.png.import create mode 100644 thumbs/blade_002.png create mode 100644 thumbs/blade_002.png.import create mode 100644 thumbs/box_001.png create mode 100644 thumbs/box_001.png.import create mode 100644 thumbs/box_002.png create mode 100644 thumbs/box_002.png.import create mode 100644 thumbs/box_003.png create mode 100644 thumbs/box_003.png.import create mode 100644 thumbs/box_004.png create mode 100644 thumbs/box_004.png.import create mode 100644 thumbs/box_005.png create mode 100644 thumbs/box_005.png.import create mode 100644 thumbs/box_006.png create mode 100644 thumbs/box_006.png.import create mode 100644 thumbs/box_007.png create mode 100644 thumbs/box_007.png.import create mode 100644 thumbs/box_008.png create mode 100644 thumbs/box_008.png.import create mode 100644 thumbs/box_009.png create mode 100644 thumbs/box_009.png.import create mode 100644 thumbs/box_010.png create mode 100644 thumbs/box_010.png.import create mode 100644 thumbs/box_011.png create mode 100644 thumbs/box_011.png.import create mode 100644 thumbs/box_012.png create mode 100644 thumbs/box_012.png.import create mode 100644 thumbs/box_013.png create mode 100644 thumbs/box_013.png.import create mode 100644 thumbs/box_014.png create mode 100644 thumbs/box_014.png.import create mode 100644 thumbs/box_015.png create mode 100644 thumbs/box_015.png.import create mode 100644 thumbs/box_016.png create mode 100644 thumbs/box_016.png.import create mode 100644 thumbs/box_017.png create mode 100644 thumbs/box_017.png.import create mode 100644 thumbs/box_018.png create mode 100644 thumbs/box_018.png.import create mode 100644 thumbs/box_019.png create mode 100644 thumbs/box_019.png.import create mode 100644 thumbs/box_020.png create mode 100644 thumbs/box_020.png.import create mode 100644 thumbs/box_021.png create mode 100644 thumbs/box_021.png.import create mode 100644 thumbs/box_022.png create mode 100644 thumbs/box_022.png.import create mode 100644 thumbs/box_023.png create mode 100644 thumbs/box_023.png.import create mode 100644 thumbs/box_024.png create mode 100644 thumbs/box_024.png.import create mode 100644 thumbs/box_025.png create mode 100644 thumbs/box_025.png.import create mode 100644 thumbs/box_026.png create mode 100644 thumbs/box_026.png.import create mode 100644 thumbs/box_027.png create mode 100644 thumbs/box_027.png.import create mode 100644 thumbs/box_028.png create mode 100644 thumbs/box_028.png.import create mode 100644 thumbs/box_029.png create mode 100644 thumbs/box_029.png.import create mode 100644 thumbs/box_030.png create mode 100644 thumbs/box_030.png.import create mode 100644 thumbs/box_031.png create mode 100644 thumbs/box_031.png.import create mode 100644 thumbs/building_001.png create mode 100644 thumbs/building_001.png.import create mode 100644 thumbs/bush_002.png create mode 100644 thumbs/bush_002.png.import create mode 100644 thumbs/bush_006.png create mode 100644 thumbs/bush_006.png.import create mode 100644 thumbs/bush_007.png create mode 100644 thumbs/bush_007.png.import create mode 100644 thumbs/cactus_001.png create mode 100644 thumbs/cactus_001.png.import create mode 100644 thumbs/cactus_002.png create mode 100644 thumbs/cactus_002.png.import create mode 100644 thumbs/cactus_003.png create mode 100644 thumbs/cactus_003.png.import create mode 100644 thumbs/cactus_004.png create mode 100644 thumbs/cactus_004.png.import create mode 100644 thumbs/cactus_005.png create mode 100644 thumbs/cactus_005.png.import create mode 100644 thumbs/cactus_006.png create mode 100644 thumbs/cactus_006.png.import create mode 100644 thumbs/cactus_007.png create mode 100644 thumbs/cactus_007.png.import create mode 100644 thumbs/cactus_008.png create mode 100644 thumbs/cactus_008.png.import create mode 100644 thumbs/cactus_009.png create mode 100644 thumbs/cactus_009.png.import create mode 100644 thumbs/cactus_010.png create mode 100644 thumbs/cactus_010.png.import create mode 100644 thumbs/cactus_011.png create mode 100644 thumbs/cactus_011.png.import create mode 100644 thumbs/cactus_012.png create mode 100644 thumbs/cactus_012.png.import create mode 100644 thumbs/cactus_013.png create mode 100644 thumbs/cactus_013.png.import create mode 100644 thumbs/cactus_014.png create mode 100644 thumbs/cactus_014.png.import create mode 100644 thumbs/cactus_015.png create mode 100644 thumbs/cactus_015.png.import create mode 100644 thumbs/cart_001.png create mode 100644 thumbs/cart_001.png.import create mode 100644 thumbs/checkpoint_001.png create mode 100644 thumbs/checkpoint_001.png.import create mode 100644 thumbs/cistern_001.png create mode 100644 thumbs/cistern_001.png.import create mode 100644 thumbs/cistern_002.png create mode 100644 thumbs/cistern_002.png.import create mode 100644 thumbs/cistern_003.png create mode 100644 thumbs/cistern_003.png.import create mode 100644 thumbs/cistern_004.png create mode 100644 thumbs/cistern_004.png.import create mode 100644 thumbs/coil_001.png create mode 100644 thumbs/coil_001.png.import create mode 100644 thumbs/concrete_wall_001.png create mode 100644 thumbs/concrete_wall_001.png.import create mode 100644 thumbs/concrete_wall_002.png create mode 100644 thumbs/concrete_wall_002.png.import create mode 100644 thumbs/concrete_wall_destroyed_001.png create mode 100644 thumbs/concrete_wall_destroyed_001.png.import create mode 100644 thumbs/concrete_wall_destroyed_002.png create mode 100644 thumbs/concrete_wall_destroyed_002.png.import create mode 100644 thumbs/concrete_wall_destroyed_003.png create mode 100644 thumbs/concrete_wall_destroyed_003.png.import create mode 100644 thumbs/concrete_wall_destroyed_004.png create mode 100644 thumbs/concrete_wall_destroyed_004.png.import create mode 100644 thumbs/conditioner_001.png create mode 100644 thumbs/conditioner_001.png.import create mode 100644 thumbs/conditioner_002.png create mode 100644 thumbs/conditioner_002.png.import create mode 100644 thumbs/construction_001.png create mode 100644 thumbs/construction_001.png.import create mode 100644 thumbs/construction_002.png create mode 100644 thumbs/construction_002.png.import create mode 100644 thumbs/container_001.png create mode 100644 thumbs/container_001.png.import create mode 100644 thumbs/container_001_offen1.png create mode 100644 thumbs/container_001_offen1.png.import create mode 100644 thumbs/container_001_offen2.png create mode 100644 thumbs/container_001_offen2.png.import create mode 100644 thumbs/container_001_ohne.png create mode 100644 thumbs/container_001_ohne.png.import create mode 100644 thumbs/container_002.png create mode 100644 thumbs/container_002.png.import create mode 100644 thumbs/container_002_offen1.png create mode 100644 thumbs/container_002_offen1.png.import create mode 100644 thumbs/container_002_offen2.png create mode 100644 thumbs/container_002_offen2.png.import create mode 100644 thumbs/container_002_ohne.png create mode 100644 thumbs/container_002_ohne.png.import create mode 100644 thumbs/container_003.png create mode 100644 thumbs/container_003.png.import create mode 100644 thumbs/container_003_offen1.png create mode 100644 thumbs/container_003_offen1.png.import create mode 100644 thumbs/container_003_offen2.png create mode 100644 thumbs/container_003_offen2.png.import create mode 100644 thumbs/container_003_ohne.png create mode 100644 thumbs/container_003_ohne.png.import create mode 100644 thumbs/container_004.png create mode 100644 thumbs/container_004.png.import create mode 100644 thumbs/container_004_offen1.png create mode 100644 thumbs/container_004_offen1.png.import create mode 100644 thumbs/container_004_offen2.png create mode 100644 thumbs/container_004_offen2.png.import create mode 100644 thumbs/container_004_ohne.png create mode 100644 thumbs/container_004_ohne.png.import create mode 100644 thumbs/container_005.png create mode 100644 thumbs/container_005.png.import create mode 100644 thumbs/container_005_offen1.png create mode 100644 thumbs/container_005_offen1.png.import create mode 100644 thumbs/container_005_offen2.png create mode 100644 thumbs/container_005_offen2.png.import create mode 100644 thumbs/container_005_ohne.png create mode 100644 thumbs/container_005_ohne.png.import create mode 100644 thumbs/container_006.png create mode 100644 thumbs/container_006.png.import create mode 100644 thumbs/container_006_offen1.png create mode 100644 thumbs/container_006_offen1.png.import create mode 100644 thumbs/container_006_offen2.png create mode 100644 thumbs/container_006_offen2.png.import create mode 100644 thumbs/container_006_ohne.png create mode 100644 thumbs/container_006_ohne.png.import create mode 100644 thumbs/container_007.png create mode 100644 thumbs/container_007.png.import create mode 100644 thumbs/container_007_offen1.png create mode 100644 thumbs/container_007_offen1.png.import create mode 100644 thumbs/container_007_offen2.png create mode 100644 thumbs/container_007_offen2.png.import create mode 100644 thumbs/container_007_ohne.png create mode 100644 thumbs/container_007_ohne.png.import create mode 100644 thumbs/container_008.png create mode 100644 thumbs/container_008.png.import create mode 100644 thumbs/container_008_offen1.png create mode 100644 thumbs/container_008_offen1.png.import create mode 100644 thumbs/container_008_offen2.png create mode 100644 thumbs/container_008_offen2.png.import create mode 100644 thumbs/container_008_ohne.png create mode 100644 thumbs/container_008_ohne.png.import create mode 100644 thumbs/deadwood_001.png create mode 100644 thumbs/deadwood_001.png.import create mode 100644 thumbs/deadwood_002.png create mode 100644 thumbs/deadwood_002.png.import create mode 100644 thumbs/deadwood_003.png create mode 100644 thumbs/deadwood_003.png.import create mode 100644 thumbs/deadwood_004.png create mode 100644 thumbs/deadwood_004.png.import create mode 100644 thumbs/deadwood_005.png create mode 100644 thumbs/deadwood_005.png.import create mode 100644 thumbs/deadwood_006.png create mode 100644 thumbs/deadwood_006.png.import create mode 100644 thumbs/deadwood_007.png create mode 100644 thumbs/deadwood_007.png.import create mode 100644 thumbs/deadwood_008.png create mode 100644 thumbs/deadwood_008.png.import create mode 100644 thumbs/deadwood_009.png create mode 100644 thumbs/deadwood_009.png.import create mode 100644 thumbs/deadwood_010.png create mode 100644 thumbs/deadwood_010.png.import create mode 100644 thumbs/deadwood_011.png create mode 100644 thumbs/deadwood_011.png.import create mode 100644 thumbs/deadwood_012.png create mode 100644 thumbs/deadwood_012.png.import create mode 100644 thumbs/deadwood_013.png create mode 100644 thumbs/deadwood_013.png.import create mode 100644 thumbs/deadwood_016.png create mode 100644 thumbs/deadwood_016.png.import create mode 100644 thumbs/deadwood_023.png create mode 100644 thumbs/deadwood_023.png.import create mode 100644 thumbs/decal_001.png create mode 100644 thumbs/decal_001.png.import create mode 100644 thumbs/decal_002.png create mode 100644 thumbs/decal_002.png.import create mode 100644 thumbs/decal_003.png create mode 100644 thumbs/decal_003.png.import create mode 100644 thumbs/decal_004.png create mode 100644 thumbs/decal_004.png.import create mode 100644 thumbs/decal_005.png create mode 100644 thumbs/decal_005.png.import create mode 100644 thumbs/decal_006.png create mode 100644 thumbs/decal_006.png.import create mode 100644 thumbs/decal_007.png create mode 100644 thumbs/decal_007.png.import create mode 100644 thumbs/decal_008.png create mode 100644 thumbs/decal_008.png.import create mode 100644 thumbs/decal_009.png create mode 100644 thumbs/decal_009.png.import create mode 100644 thumbs/decal_010.png create mode 100644 thumbs/decal_010.png.import create mode 100644 thumbs/decal_011.png create mode 100644 thumbs/decal_011.png.import create mode 100644 thumbs/decal_012.png create mode 100644 thumbs/decal_012.png.import create mode 100644 thumbs/decal_013.png create mode 100644 thumbs/decal_013.png.import create mode 100644 thumbs/decal_014.png create mode 100644 thumbs/decal_014.png.import create mode 100644 thumbs/door_001.png create mode 100644 thumbs/door_001.png.import create mode 100644 thumbs/door_002.png create mode 100644 thumbs/door_002.png.import create mode 100644 thumbs/door_003.png create mode 100644 thumbs/door_003.png.import create mode 100644 thumbs/dune_010.png create mode 100644 thumbs/dune_010.png.import create mode 100644 thumbs/fence_001.png create mode 100644 thumbs/fence_001.png.import create mode 100644 thumbs/fence_002.png create mode 100644 thumbs/fence_002.png.import create mode 100644 thumbs/fighter_jet_001.png create mode 100644 thumbs/fighter_jet_001.png.import create mode 100644 thumbs/fighter_jet_002.png create mode 100644 thumbs/fighter_jet_002.png.import create mode 100644 thumbs/fighter_jet_003.png create mode 100644 thumbs/fighter_jet_003.png.import create mode 100644 thumbs/fighter_jet_004.png create mode 100644 thumbs/fighter_jet_004.png.import create mode 100644 thumbs/flashlight_001.png create mode 100644 thumbs/flashlight_001.png.import create mode 100644 thumbs/flashlight_002.png create mode 100644 thumbs/flashlight_002.png.import create mode 100644 thumbs/generator_001.png create mode 100644 thumbs/generator_001.png.import create mode 100644 thumbs/generator_002.png create mode 100644 thumbs/generator_002.png.import create mode 100644 thumbs/generator_003.png create mode 100644 thumbs/generator_003.png.import create mode 100644 thumbs/generator_004.png create mode 100644 thumbs/generator_004.png.import create mode 100644 thumbs/grass_003.png create mode 100644 thumbs/grass_003.png.import create mode 100644 thumbs/grass_004.png create mode 100644 thumbs/grass_004.png.import create mode 100644 thumbs/grass_005.png create mode 100644 thumbs/grass_005.png.import create mode 100644 thumbs/grass_006.png create mode 100644 thumbs/grass_006.png.import create mode 100644 thumbs/grass_007.png create mode 100644 thumbs/grass_007.png.import create mode 100644 thumbs/grass_008.png create mode 100644 thumbs/grass_008.png.import create mode 100644 thumbs/ground_001.png create mode 100644 thumbs/ground_001.png.import create mode 100644 thumbs/ground_002.png create mode 100644 thumbs/ground_002.png.import create mode 100644 thumbs/ground_003.png create mode 100644 thumbs/ground_003.png.import create mode 100644 thumbs/ground_004.png create mode 100644 thumbs/ground_004.png.import create mode 100644 thumbs/ground_005.png create mode 100644 thumbs/ground_005.png.import create mode 100644 thumbs/ground_006.png create mode 100644 thumbs/ground_006.png.import create mode 100644 thumbs/ground_007.png create mode 100644 thumbs/ground_007.png.import create mode 100644 thumbs/ground_008.png create mode 100644 thumbs/ground_008.png.import create mode 100644 thumbs/ground_009.png create mode 100644 thumbs/ground_009.png.import create mode 100644 thumbs/gsm_001.png create mode 100644 thumbs/gsm_001.png.import create mode 100644 thumbs/hangar_001.png create mode 100644 thumbs/hangar_001.png.import create mode 100644 thumbs/hangar_002.png create mode 100644 thumbs/hangar_002.png.import create mode 100644 thumbs/hangar_003.png create mode 100644 thumbs/hangar_003.png.import create mode 100644 thumbs/hangar_004.png create mode 100644 thumbs/hangar_004.png.import create mode 100644 thumbs/hangar_005.png create mode 100644 thumbs/hangar_005.png.import create mode 100644 thumbs/hangar_006.png create mode 100644 thumbs/hangar_006.png.import create mode 100644 thumbs/hangar_007.png create mode 100644 thumbs/hangar_007.png.import create mode 100644 thumbs/hangar_008.png create mode 100644 thumbs/hangar_008.png.import create mode 100644 thumbs/hangar_door_001.png create mode 100644 thumbs/hangar_door_001.png.import create mode 100644 thumbs/hangar_door_002.png create mode 100644 thumbs/hangar_door_002.png.import create mode 100644 thumbs/hangar_door_003.png create mode 100644 thumbs/hangar_door_003.png.import create mode 100644 thumbs/hedgehog_001.png create mode 100644 thumbs/hedgehog_001.png.import create mode 100644 thumbs/helicopter_001.png create mode 100644 thumbs/helicopter_001.png.import create mode 100644 thumbs/helicopter_platform_001.png create mode 100644 thumbs/helicopter_platform_001.png.import create mode 100644 thumbs/hummer_001.png create mode 100644 thumbs/hummer_001.png.import create mode 100644 thumbs/hummer_002.png create mode 100644 thumbs/hummer_002.png.import create mode 100644 thumbs/hummer_003.png create mode 100644 thumbs/hummer_003.png.import create mode 100644 thumbs/hummer_004.png create mode 100644 thumbs/hummer_004.png.import create mode 100644 thumbs/ladder_001.png create mode 100644 thumbs/ladder_001.png.import create mode 100644 thumbs/ladder_002.png create mode 100644 thumbs/ladder_002.png.import create mode 100644 thumbs/ladder_003.png create mode 100644 thumbs/ladder_003.png.import create mode 100644 thumbs/lamp_001.png create mode 100644 thumbs/lamp_001.png.import create mode 100644 thumbs/log_001.png create mode 100644 thumbs/log_001.png.import create mode 100644 thumbs/machine_gun_001.png create mode 100644 thumbs/machine_gun_001.png.import create mode 100644 thumbs/machine_gun_002.png create mode 100644 thumbs/machine_gun_002.png.import create mode 100644 thumbs/machine_gun_003.png create mode 100644 thumbs/machine_gun_003.png.import create mode 100644 thumbs/machine_gun_003_schild.png create mode 100644 thumbs/machine_gun_003_schild.png.import create mode 100644 thumbs/machine_gun_004.png create mode 100644 thumbs/machine_gun_004.png.import create mode 100644 thumbs/machine_gun_005.png create mode 100644 thumbs/machine_gun_005.png.import create mode 100644 thumbs/military_transport_aircraft_001.png create mode 100644 thumbs/military_transport_aircraft_001.png.import create mode 100644 thumbs/mortar_001.png create mode 100644 thumbs/mortar_001.png.import create mode 100644 thumbs/observation_tower_001.png create mode 100644 thumbs/observation_tower_001.png.import create mode 100644 thumbs/observation_tower_002.png create mode 100644 thumbs/observation_tower_002.png.import create mode 100644 thumbs/obstacle_001.png create mode 100644 thumbs/obstacle_001.png.import create mode 100644 thumbs/obstacle_002.png create mode 100644 thumbs/obstacle_002.png.import create mode 100644 thumbs/obstacle_003.png create mode 100644 thumbs/obstacle_003.png.import create mode 100644 thumbs/obstacle_004.png create mode 100644 thumbs/obstacle_004.png.import create mode 100644 thumbs/obstacle_005.png create mode 100644 thumbs/obstacle_005.png.import create mode 100644 thumbs/obstacle_006.png create mode 100644 thumbs/obstacle_006.png.import create mode 100644 thumbs/obstacle_007.png create mode 100644 thumbs/obstacle_007.png.import create mode 100644 thumbs/obstacle_008.png create mode 100644 thumbs/obstacle_008.png.import create mode 100644 thumbs/obstacle_009.png create mode 100644 thumbs/obstacle_009.png.import create mode 100644 thumbs/obstacle_010.png create mode 100644 thumbs/obstacle_010.png.import create mode 100644 thumbs/pallet_001.png create mode 100644 thumbs/pallet_001.png.import create mode 100644 thumbs/pallet_002.png create mode 100644 thumbs/pallet_002.png.import create mode 100644 thumbs/pillar_001.png create mode 100644 thumbs/pillar_001.png.import create mode 100644 thumbs/pillar_002.png create mode 100644 thumbs/pillar_002.png.import create mode 100644 thumbs/pillar_003.png create mode 100644 thumbs/pillar_003.png.import create mode 100644 thumbs/pillar_004.png create mode 100644 thumbs/pillar_004.png.import create mode 100644 thumbs/pipe_001.png create mode 100644 thumbs/pipe_001.png.import create mode 100644 thumbs/protection_001.png create mode 100644 thumbs/protection_001.png.import create mode 100644 thumbs/protection_002.png create mode 100644 thumbs/protection_002.png.import create mode 100644 thumbs/protective_wall_001.png create mode 100644 thumbs/protective_wall_001.png.import create mode 100644 thumbs/protective_wall_002.png create mode 100644 thumbs/protective_wall_002.png.import create mode 100644 thumbs/protective_wall_003.png create mode 100644 thumbs/protective_wall_003.png.import create mode 100644 thumbs/protective_wall_004.png create mode 100644 thumbs/protective_wall_004.png.import create mode 100644 thumbs/radiolocator_001.png create mode 100644 thumbs/radiolocator_001.png.import create mode 100644 thumbs/radiolocator_002.png create mode 100644 thumbs/radiolocator_002.png.import create mode 100644 thumbs/radiolocator_platform_001.png create mode 100644 thumbs/radiolocator_platform_001.png.import create mode 100644 thumbs/radiolocator_platform_002.png create mode 100644 thumbs/radiolocator_platform_002.png.import create mode 100644 thumbs/radiostation_001.png create mode 100644 thumbs/radiostation_001.png.import create mode 100644 thumbs/radiostation_002.png create mode 100644 thumbs/radiostation_002.png.import create mode 100644 thumbs/road_006.png create mode 100644 thumbs/road_006.png.import create mode 100644 thumbs/road_007.png create mode 100644 thumbs/road_007.png.import create mode 100644 thumbs/road_008.png create mode 100644 thumbs/road_008.png.import create mode 100644 thumbs/road_009.png create mode 100644 thumbs/road_009.png.import create mode 100644 thumbs/rock_003.png create mode 100644 thumbs/rock_003.png.import create mode 100644 thumbs/rock_004.png create mode 100644 thumbs/rock_004.png.import create mode 100644 thumbs/rock_005.png create mode 100644 thumbs/rock_005.png.import create mode 100644 thumbs/rock_006.png create mode 100644 thumbs/rock_006.png.import create mode 100644 thumbs/rock_007.png create mode 100644 thumbs/rock_007.png.import create mode 100644 thumbs/rock_008.png create mode 100644 thumbs/rock_008.png.import create mode 100644 thumbs/rock_009.png create mode 100644 thumbs/rock_009.png.import create mode 100644 thumbs/rock_010.png create mode 100644 thumbs/rock_010.png.import create mode 100644 thumbs/rock_011.png create mode 100644 thumbs/rock_011.png.import create mode 100644 thumbs/rock_012.png create mode 100644 thumbs/rock_012.png.import create mode 100644 thumbs/rock_013.png create mode 100644 thumbs/rock_013.png.import create mode 100644 thumbs/rock_014.png create mode 100644 thumbs/rock_014.png.import create mode 100644 thumbs/rock_015.png create mode 100644 thumbs/rock_015.png.import create mode 100644 thumbs/rock_016.png create mode 100644 thumbs/rock_016.png.import create mode 100644 thumbs/rock_017.png create mode 100644 thumbs/rock_017.png.import create mode 100644 thumbs/rock_018.png create mode 100644 thumbs/rock_018.png.import create mode 100644 thumbs/rock_019.png create mode 100644 thumbs/rock_019.png.import create mode 100644 thumbs/rock_020.png create mode 100644 thumbs/rock_020.png.import create mode 100644 thumbs/rock_021.png create mode 100644 thumbs/rock_021.png.import create mode 100644 thumbs/rock_022.png create mode 100644 thumbs/rock_022.png.import create mode 100644 thumbs/rock_023.png create mode 100644 thumbs/rock_023.png.import create mode 100644 thumbs/rock_024.png create mode 100644 thumbs/rock_024.png.import create mode 100644 thumbs/rock_038.png create mode 100644 thumbs/rock_038.png.import create mode 100644 thumbs/sand_001.png create mode 100644 thumbs/sand_001.png.import create mode 100644 thumbs/shell_001.png create mode 100644 thumbs/shell_001.png.import create mode 100644 thumbs/shell_002.png create mode 100644 thumbs/shell_002.png.import create mode 100644 thumbs/shell_003.png create mode 100644 thumbs/shell_003.png.import create mode 100644 thumbs/shell_004.png create mode 100644 thumbs/shell_004.png.import create mode 100644 thumbs/shell_005.png create mode 100644 thumbs/shell_005.png.import create mode 100644 thumbs/shell_006.png create mode 100644 thumbs/shell_006.png.import create mode 100644 thumbs/shell_007.png create mode 100644 thumbs/shell_007.png.import create mode 100644 thumbs/shell_008.png create mode 100644 thumbs/shell_008.png.import create mode 100644 thumbs/solar_battery_001.png create mode 100644 thumbs/solar_battery_001.png.import create mode 100644 thumbs/stone_015.png create mode 100644 thumbs/stone_015.png.import create mode 100644 thumbs/stone_016.png create mode 100644 thumbs/stone_016.png.import create mode 100644 thumbs/stone_017.png create mode 100644 thumbs/stone_017.png.import create mode 100644 thumbs/stone_018.png create mode 100644 thumbs/stone_018.png.import create mode 100644 thumbs/stone_019.png create mode 100644 thumbs/stone_019.png.import create mode 100644 thumbs/stone_020.png create mode 100644 thumbs/stone_020.png.import create mode 100644 thumbs/stone_021.png create mode 100644 thumbs/stone_021.png.import create mode 100644 thumbs/stone_022.png create mode 100644 thumbs/stone_022.png.import create mode 100644 thumbs/stone_023.png create mode 100644 thumbs/stone_023.png.import create mode 100644 thumbs/stone_024.png create mode 100644 thumbs/stone_024.png.import create mode 100644 thumbs/stone_025.png create mode 100644 thumbs/stone_025.png.import create mode 100644 thumbs/stone_026.png create mode 100644 thumbs/stone_026.png.import create mode 100644 thumbs/table_001.png create mode 100644 thumbs/table_001.png.import create mode 100644 thumbs/table_002.png create mode 100644 thumbs/table_002.png.import create mode 100644 thumbs/tank_001.png create mode 100644 thumbs/tank_001.png.import create mode 100644 thumbs/tank_002.png create mode 100644 thumbs/tank_002.png.import create mode 100644 thumbs/tank_003.png create mode 100644 thumbs/tank_003.png.import create mode 100644 thumbs/tank_004.png create mode 100644 thumbs/tank_004.png.import create mode 100644 thumbs/tank_005.png create mode 100644 thumbs/tank_005.png.import create mode 100644 thumbs/tank_006.png create mode 100644 thumbs/tank_006.png.import create mode 100644 thumbs/tank_car_001.png create mode 100644 thumbs/tank_car_001.png.import create mode 100644 thumbs/tank_car_002.png create mode 100644 thumbs/tank_car_002.png.import create mode 100644 thumbs/tank_gun_001.png create mode 100644 thumbs/tank_gun_001.png.import create mode 100644 thumbs/tank_gun_002.png create mode 100644 thumbs/tank_gun_002.png.import create mode 100644 thumbs/tank_gun_003.png create mode 100644 thumbs/tank_gun_003.png.import create mode 100644 thumbs/tank_gun_004.png create mode 100644 thumbs/tank_gun_004.png.import create mode 100644 thumbs/tank_gun_005.png create mode 100644 thumbs/tank_gun_005.png.import create mode 100644 thumbs/tank_gun_006.png create mode 100644 thumbs/tank_gun_006.png.import create mode 100644 thumbs/tank_tower_001.png create mode 100644 thumbs/tank_tower_001.png.import create mode 100644 thumbs/tank_tower_002.png create mode 100644 thumbs/tank_tower_002.png.import create mode 100644 thumbs/tank_tower_003.png create mode 100644 thumbs/tank_tower_003.png.import create mode 100644 thumbs/tank_tower_004.png create mode 100644 thumbs/tank_tower_004.png.import create mode 100644 thumbs/tank_tower_005.png create mode 100644 thumbs/tank_tower_005.png.import create mode 100644 thumbs/tank_tower_006.png create mode 100644 thumbs/tank_tower_006.png.import create mode 100644 thumbs/target_001.png create mode 100644 thumbs/target_001.png.import create mode 100644 thumbs/target_002.png create mode 100644 thumbs/target_002.png.import create mode 100644 thumbs/tent_001.png create mode 100644 thumbs/tent_001.png.import create mode 100644 thumbs/tent_002.png create mode 100644 thumbs/tent_002.png.import create mode 100644 thumbs/tent_003.png create mode 100644 thumbs/tent_003.png.import create mode 100644 thumbs/tent_004.png create mode 100644 thumbs/tent_004.png.import create mode 100644 thumbs/tent_005.png create mode 100644 thumbs/tent_005.png.import create mode 100644 thumbs/tent_006.png create mode 100644 thumbs/tent_006.png.import create mode 100644 thumbs/tent_007.png create mode 100644 thumbs/tent_007.png.import create mode 100644 thumbs/tent_008.png create mode 100644 thumbs/tent_008.png.import create mode 100644 thumbs/tent_009.png create mode 100644 thumbs/tent_009.png.import create mode 100644 thumbs/tent_010.png create mode 100644 thumbs/tent_010.png.import create mode 100644 thumbs/tent_011.png create mode 100644 thumbs/tent_011.png.import create mode 100644 thumbs/tent_012.png create mode 100644 thumbs/tent_012.png.import create mode 100644 thumbs/tent_013.png create mode 100644 thumbs/tent_013.png.import create mode 100644 thumbs/tent_014.png create mode 100644 thumbs/tent_014.png.import create mode 100644 thumbs/tire_001.png create mode 100644 thumbs/tire_001.png.import create mode 100644 thumbs/tires_001.png create mode 100644 thumbs/tires_001.png.import create mode 100644 thumbs/toilet_001.png create mode 100644 thumbs/toilet_001.png.import create mode 100644 thumbs/toilet_002.png create mode 100644 thumbs/toilet_002.png.import create mode 100644 thumbs/tower_001.png create mode 100644 thumbs/tower_001.png.import create mode 100644 thumbs/tower_002.png create mode 100644 thumbs/tower_002.png.import create mode 100644 thumbs/tower_003.png create mode 100644 thumbs/tower_003.png.import create mode 100644 thumbs/tower_004.png create mode 100644 thumbs/tower_004.png.import create mode 100644 thumbs/tower_005.png create mode 100644 thumbs/tower_005.png.import create mode 100644 thumbs/training_item_001.png create mode 100644 thumbs/training_item_001.png.import create mode 100644 thumbs/training_item_002.png create mode 100644 thumbs/training_item_002.png.import create mode 100644 thumbs/training_item_003.png create mode 100644 thumbs/training_item_003.png.import create mode 100644 thumbs/training_item_004.png create mode 100644 thumbs/training_item_004.png.import create mode 100644 thumbs/training_item_005.png create mode 100644 thumbs/training_item_005.png.import create mode 100644 thumbs/training_item_006.png create mode 100644 thumbs/training_item_006.png.import create mode 100644 thumbs/training_item_007.png create mode 100644 thumbs/training_item_007.png.import create mode 100644 thumbs/truck_001.png create mode 100644 thumbs/truck_001.png.import create mode 100644 thumbs/truck_002.png create mode 100644 thumbs/truck_002.png.import create mode 100644 thumbs/truck_002_aufbau.png create mode 100644 thumbs/truck_002_aufbau.png.import create mode 100644 thumbs/truck_002_tank.png create mode 100644 thumbs/truck_002_tank.png.import create mode 100644 thumbs/truck_003.png create mode 100644 thumbs/truck_003.png.import create mode 100644 thumbs/truck_004.png create mode 100644 thumbs/truck_004.png.import create mode 100644 thumbs/truck_004_aufbau.png create mode 100644 thumbs/truck_004_aufbau.png.import create mode 100644 thumbs/truck_004_plane.png create mode 100644 thumbs/truck_004_plane.png.import create mode 100644 thumbs/truck_body_001.png create mode 100644 thumbs/truck_body_001.png.import create mode 100644 thumbs/truck_body_002.png create mode 100644 thumbs/truck_body_002.png.import create mode 100644 thumbs/truck_body_003.png create mode 100644 thumbs/truck_body_003.png.import create mode 100644 thumbs/truck_body_004.png create mode 100644 thumbs/truck_body_004.png.import create mode 100644 thumbs/truck_body_005.png create mode 100644 thumbs/truck_body_005.png.import create mode 100644 thumbs/truck_body_006.png create mode 100644 thumbs/truck_body_006.png.import create mode 100644 thumbs/wall_001.png create mode 100644 thumbs/wall_001.png.import create mode 100644 thumbs/wall_002.png create mode 100644 thumbs/wall_002.png.import create mode 100644 thumbs/wall_003.png create mode 100644 thumbs/wall_003.png.import create mode 100644 thumbs/wall_004.png create mode 100644 thumbs/wall_004.png.import create mode 100644 thumbs/wall_005.png create mode 100644 thumbs/wall_005.png.import create mode 100644 thumbs/wall_006.png create mode 100644 thumbs/wall_006.png.import create mode 100644 thumbs/wall_007.png create mode 100644 thumbs/wall_007.png.import create mode 100644 thumbs/wall_008.png create mode 100644 thumbs/wall_008.png.import create mode 100644 thumbs/wall_009.png create mode 100644 thumbs/wall_009.png.import create mode 100644 thumbs/wall_010.png create mode 100644 thumbs/wall_010.png.import create mode 100644 thumbs/wall_011.png create mode 100644 thumbs/wall_011.png.import create mode 100644 thumbs/wall_012.png create mode 100644 thumbs/wall_012.png.import create mode 100644 thumbs/wall_013.png create mode 100644 thumbs/wall_013.png.import create mode 100644 thumbs/wall_014.png create mode 100644 thumbs/wall_014.png.import create mode 100644 thumbs/wall_015.png create mode 100644 thumbs/wall_015.png.import create mode 100644 thumbs/wall_016.png create mode 100644 thumbs/wall_016.png.import create mode 100644 thumbs/wall_017.png create mode 100644 thumbs/wall_017.png.import create mode 100644 thumbs/wall_018.png create mode 100644 thumbs/wall_018.png.import create mode 100644 thumbs/wall_019.png create mode 100644 thumbs/wall_019.png.import create mode 100644 thumbs/wall_020.png create mode 100644 thumbs/wall_020.png.import create mode 100644 thumbs/wall_021.png create mode 100644 thumbs/wall_021.png.import create mode 100644 thumbs/wall_022.png create mode 100644 thumbs/wall_022.png.import create mode 100644 thumbs/wall_023.png create mode 100644 thumbs/wall_023.png.import create mode 100644 thumbs/wall_024.png create mode 100644 thumbs/wall_024.png.import create mode 100644 thumbs/wall_025.png create mode 100644 thumbs/wall_025.png.import create mode 100644 thumbs/wall_051.png create mode 100644 thumbs/wall_051.png.import create mode 100644 thumbs/wall_052.png create mode 100644 thumbs/wall_052.png.import create mode 100644 thumbs/wall_053.png create mode 100644 thumbs/wall_053.png.import create mode 100644 thumbs/wall_054.png create mode 100644 thumbs/wall_054.png.import create mode 100644 thumbs/wall_055.png create mode 100644 thumbs/wall_055.png.import create mode 100644 thumbs/wall_056.png create mode 100644 thumbs/wall_056.png.import create mode 100644 thumbs/wall_057.png create mode 100644 thumbs/wall_057.png.import create mode 100644 thumbs/wall_058.png create mode 100644 thumbs/wall_058.png.import create mode 100644 thumbs/wall_059.png create mode 100644 thumbs/wall_059.png.import create mode 100644 thumbs/wall_060.png create mode 100644 thumbs/wall_060.png.import create mode 100644 thumbs/wall_061.png create mode 100644 thumbs/wall_061.png.import create mode 100644 thumbs/wall_062.png create mode 100644 thumbs/wall_062.png.import create mode 100644 thumbs/wall_063.png create mode 100644 thumbs/wall_063.png.import create mode 100644 thumbs/wall_064.png create mode 100644 thumbs/wall_064.png.import create mode 100644 thumbs/wall_065.png create mode 100644 thumbs/wall_065.png.import create mode 100644 thumbs/wall_066.png create mode 100644 thumbs/wall_066.png.import create mode 100644 thumbs/wall_067.png create mode 100644 thumbs/wall_067.png.import create mode 100644 thumbs/wall_068.png create mode 100644 thumbs/wall_068.png.import create mode 100644 thumbs/wall_069.png create mode 100644 thumbs/wall_069.png.import create mode 100644 thumbs/wall_070.png create mode 100644 thumbs/wall_070.png.import create mode 100644 thumbs/wall_071.png create mode 100644 thumbs/wall_071.png.import create mode 100644 thumbs/wall_072.png create mode 100644 thumbs/wall_072.png.import create mode 100644 thumbs/wall_073.png create mode 100644 thumbs/wall_073.png.import create mode 100644 thumbs/wall_074.png create mode 100644 thumbs/wall_074.png.import create mode 100644 thumbs/wall_100.png create mode 100644 thumbs/wall_100.png.import create mode 100644 thumbs/water_tower_001.png create mode 100644 thumbs/water_tower_001.png.import create mode 100644 thumbs/water_tower_002.png create mode 100644 thumbs/water_tower_002.png.import create mode 100644 thumbs/water_tower_003.png create mode 100644 thumbs/water_tower_003.png.import create mode 100644 thumbs/water_tower_004.png create mode 100644 thumbs/water_tower_004.png.import create mode 100644 thumbs/wheel_001.png create mode 100644 thumbs/wheel_001.png.import create mode 100644 thumbs/wheel_002.png create mode 100644 thumbs/wheel_002.png.import create mode 100644 thumbs/wheel_003.png create mode 100644 thumbs/wheel_003.png.import create mode 100644 thumbs/wheel_004.png create mode 100644 thumbs/wheel_004.png.import create mode 100644 thumbs/wheel_005.png create mode 100644 thumbs/wheel_005.png.import create mode 100644 thumbs/wire_001.png create mode 100644 thumbs/wire_001.png.import create mode 100644 thumbs/wire_002.png create mode 100644 thumbs/wire_002.png.import create mode 100644 thumbs/wire_003.png create mode 100644 thumbs/wire_003.png.import create mode 100644 ui/help_text.gd create mode 100644 ui/help_text.gd.uid create mode 100644 ui/inspector_panel.gd create mode 100644 ui/inspector_panel.gd.uid create mode 100644 ui/main.gd create mode 100644 ui/main.gd.uid create mode 100644 ui/new_map_dialog.gd create mode 100644 ui/new_map_dialog.gd.uid create mode 100644 ui/panels/assets_panel.gd create mode 100644 ui/panels/assets_panel.gd.uid create mode 100644 ui/panels/bauen_panel.gd create mode 100644 ui/panels/bauen_panel.gd.uid create mode 100644 ui/panels/check_panel.gd create mode 100644 ui/panels/check_panel.gd.uid create mode 100644 ui/panels/editor_panel.gd create mode 100644 ui/panels/editor_panel.gd.uid create mode 100644 ui/panels/loadout_panel.gd create mode 100644 ui/panels/loadout_panel.gd.uid create mode 100644 ui/panels/malen_panel.gd create mode 100644 ui/panels/malen_panel.gd.uid create mode 100644 ui/panels/map_panel.gd create mode 100644 ui/panels/map_panel.gd.uid create mode 100644 ui/panels/modus_panel.gd create mode 100644 ui/panels/modus_panel.gd.uid create mode 100644 ui/panels/registry.gd create mode 100644 ui/panels/registry.gd.uid create mode 100644 ui/panels/scene_tree_panel.gd create mode 100644 ui/panels/scene_tree_panel.gd.uid create mode 100644 ui/panels/selection_panel.gd create mode 100644 ui/panels/selection_panel.gd.uid create mode 100644 ui/panels/server_panel.gd create mode 100644 ui/panels/server_panel.gd.uid create mode 100644 ui/panels/settings_panel.gd create mode 100644 ui/panels/settings_panel.gd.uid create mode 100644 ui/panels/status_bar.gd create mode 100644 ui/panels/status_bar.gd.uid create mode 100644 ui/panels/symmetry_panel.gd create mode 100644 ui/panels/symmetry_panel.gd.uid create mode 100644 ui/panels/terrain_panel.gd create mode 100644 ui/panels/terrain_panel.gd.uid create mode 100644 ui/panels/test_start_panel.gd create mode 100644 ui/panels/test_start_panel.gd.uid create mode 100644 ui/panels/toolbar.gd create mode 100644 ui/panels/toolbar.gd.uid create mode 100644 ui/resize_map_dialog.gd create mode 100644 ui/resize_map_dialog.gd.uid create mode 100644 ui/ui_scale.gd create mode 100644 ui/ui_scale.gd.uid create mode 100644 ui/viewport_toolbar.gd create mode 100644 ui/viewport_toolbar.gd.uid create mode 100644 vendor/modular_builder/LICENSE create mode 100644 vendor/modular_builder/modular_building_detail.gd create mode 100644 vendor/modular_builder/modular_building_detail.gd.uid create mode 100644 vendor/modular_builder/modular_piece_geometry.gd create mode 100644 vendor/modular_builder/modular_piece_geometry.gd.uid create mode 100644 viewport/gizmo.gd create mode 100644 viewport/gizmo.gd.uid create mode 100644 viewport/glb_mesh_store.gd create mode 100644 viewport/glb_mesh_store.gd.uid create mode 100644 viewport/map_view_builder.gd create mode 100644 viewport/map_view_builder.gd.uid create mode 100644 viewport/mesh_shapes.gd create mode 100644 viewport/mesh_shapes.gd.uid create mode 100644 viewport/orbit_camera.gd create mode 100644 viewport/orbit_camera.gd.uid create mode 100644 viewport/terrain_contour.gdshader create mode 100644 viewport/terrain_contour.gdshader.uid create mode 100644 viewport/terrain_mesh.gd create mode 100644 viewport/terrain_mesh.gd.uid create mode 100644 viewport/wasser.gdshader create mode 100644 viewport/wasser.gdshader.uid diff --git a/README.md b/README.md index e594b2a..6d4b957 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,13 @@ # ScopedVR Map-Kern -Gemeinsamer Code für den PC-Map-Editor und die Quest-App: .svmap lesen und -schreiben, Terrain-Daten, Objekte, Spawns, Zonen, Blickrichtung, Loadout, Undo. +Der Map-Editor selbst, als gemeinsamer Code für die PC-App und die Quest-App: +Oberfläche, Werkzeuge, Ansicht, .svmap, Undo. Beide Apps haben so dieselben Funktionen. Eingebunden als Git-Submodul unter `res://core/`. Regeln: -- Kein Code für Maus, Tastatur, Fenster oder Panels. Das gehört in die App. +- Eingaben kommen als PointerEvent an die Werkzeuge. Maus (mouse_pointer.gd) und + VR-Controller (Client) sind nur Übersetzer. +- Was nur am PC geht, steht hinter `main.vr_host`. - Keine App-spezifischen Pfade. Daten wie `res://library/objects.json` liefert die App. - Maps gehören nicht in dieses Repo. diff --git a/editor/bau_katalog.gd b/editor/bau_katalog.gd new file mode 100644 index 0000000..fe3fc92 --- /dev/null +++ b/editor/bau_katalog.gd @@ -0,0 +1,448 @@ +extends RefCounted +class_name BauKatalog +## Bauteil-Katalog des Bauen-Modus (Karte "Bauen sauber integrieren", 25.10.). +## +## Ein Bauteil ist ein GANZ NORMALES Bibliotheks-Objekt (`bau_*`, Kategorie +## "bauteile"): gesetzte Teile stehen in doc["objects"], tragen ein +## Gruppen-Feld (= ein Gebäude) und laufen damit durch dieselbe Kette wie jedes +## Objekt — Undo, Kopieren, Löschen, Symmetrie, Speichern, Server-Registry, +## Client-Loader, Trimesh-Kollision. Es gibt keinen Sonderblock "gebaeude" mehr. +## +## Geometrie: die CC0-Runtime des Modular Builder (addons/modular_builder, +## Michel Savadim, v0.2.0 — Lizenz siehe ADDON_LIZENZ.txt). Hier wird sie nur +## PARAMETRIERT (Wandhöhe 3 m, 2-m-Raster) und auf die Fußpunkt-Konvention der +## Bibliothek normalisiert: Unterkante y = 0, XZ um die Mitte zentriert +## (docs/objekt_fragmente.md). Die Farbe ist die Material-Grundfarbe (glTF +## baseColorFactor) — keine Texturen, keine Lizenzfragen, 1 Draw-Call je Teil; +## Editor, Client und Thumbnails laden sie dadurch identisch. +## +## Meshes entstehen aus diesem Katalog (tools/gen_bauteile.gd schreibt GLB + +## Trimesh-JSON + Registry-Fragment), der Editor zeigt die GLBs wie jedes andere +## Objekt. mesh() ist die Quelle für Generator UND Tests. + +const GEO_SCRIPT := "res://core/vendor/modular_builder/modular_piece_geometry.gd" +const DETAIL_SCRIPT := "res://core/vendor/modular_builder/modular_building_detail.gd" +const KATEGORIE := "bauteile" +const PREFIX := "bau_" + +const RASTER_M := 2.0 # Zellgröße (XZ) +const WAND_H := 3.0 # Wandhöhe eines Geschosses +const DICKE_M := 0.2 # Wand-/Plattendicke + +# Geometrie-Typen der Addon-Runtime (PieceType-Enum, Kopie der Werte) +const T_FUNDAMENT := 0 +const T_BODEN := 2 +const T_WAND := 3 +const T_GIEBEL := 5 +const T_DACH_GIEBEL := 6 +const T_DACH_PYRAMIDE := 9 +const T_TREPPE := 10 +const D_FENSTER := 0 +const D_TUER := 1 + +## Snap-Arten (build_snap.gd): +## "zelle" Mitte einer 2×2-Zelle (Fundament, Boden, Dächer) +## "kante" Mitte einer Zellkante (Wände) — Drehung ergibt sich aus der Kante +## "ecke" Zell-Ecke (Pfeiler) +## "treppe" 4×2-m-Fläche über zwei Zellen +const GRUPPEN := [ + {"key": "grund", "label": "Fundament & Boden", "oids": ["bau_fundament", "bau_boden"]}, + {"key": "waende", "label": "Wände", "oids": ["bau_wand", "bau_wand_tuer", "bau_wand_fenster", + "bau_wand_scharte", "bau_bruestung", "bau_pfeiler"]}, + {"key": "dach", "label": "Dach & Giebel (klein 2 m)", "oids": ["bau_giebelwand", "bau_dach_giebel", "bau_dach_pyramide"]}, + {"key": "dach_mittel", "label": "Dach & Giebel (mittel 4 m)", "oids": ["bau_giebelwand_4", "bau_dach_giebel_4", "bau_dach_pyramide_4"]}, + {"key": "dach_gross", "label": "Dach & Giebel (groß 6 m)", "oids": ["bau_giebelwand_6", "bau_dach_giebel_6", "bau_dach_pyramide_6"]}, + {"key": "dach_teile", "label": "Dach aus Einzelteilen (45°)", "oids": ["bau_dach_schraege", "bau_dach_ecke_aussen", + "bau_dach_ecke_innen", "bau_dach_plateau", "bau_dach_giebel_ende"]}, + {"key": "treppe", "label": "Treppe", "oids": ["bau_treppe"]}, +] + +const QUADRAT := [[-1.0, 0.0, -1.0], [1.0, 0.0, -1.0], [1.0, 0.0, 1.0], [-1.0, 0.0, 1.0]] +const QUADRAT_4 := [[-2.0, 0.0, -2.0], [2.0, 0.0, -2.0], [2.0, 0.0, 2.0], [-2.0, 0.0, 2.0]] +const QUADRAT_6 := [[-3.0, 0.0, -3.0], [3.0, 0.0, -3.0], [3.0, 0.0, 3.0], [-3.0, 0.0, 3.0]] + +## Reihenfolge = Anzeige-Reihenfolge (GRUPPEN nutzt dieselben IDs). +## "traeger": darauf darf gestapelt werden (Oberkante zählt als Ebene). +const KINDS := { + "bau_fundament": { + "label": "Fundament", "info": "2×2 m, 20 cm dick — Basis für Wände", "snap": "zelle", "traeger": true, + "typ": T_FUNDAMENT, "punkte": QUADRAT, "farbe": Color(0.42, 0.42, 0.40), + }, + "bau_boden": { + "label": "Boden / Decke", "info": "2×2 m Platte — Fußboden oder Decke fürs nächste Geschoss", + "snap": "zelle", "traeger": true, + "typ": T_BODEN, "punkte": QUADRAT, "farbe": Color(0.50, 0.46, 0.40), + }, + "bau_wand": { + "label": "Wand", "info": "2 m breit, 3 m hoch", "snap": "kante", "traeger": true, + "typ": T_WAND, "punkte": [[0.0, 0.0, 0.0], [2.0, 0.0, 0.0]], "farbe": Color(0.62, 0.53, 0.38), + }, + "bau_wand_tuer": { + "label": "Wand mit Tür", "info": "Türöffnung 1,2 × 2,2 m — man läuft hindurch", "snap": "kante", "traeger": true, + "typ": T_WAND, "punkte": [[0.0, 0.0, 0.0], [2.0, 0.0, 0.0]], "farbe": Color(0.62, 0.53, 0.38), + "details": [{"typ": D_TUER, "pos": [1.0, 1.1, 0.0], "w": 1.2, "h": 2.2}], + }, + "bau_wand_fenster": { + "label": "Wand mit Fenster", "info": "Fensteröffnung 1,2 × 1,2 m, Brüstung 1,1 m", "snap": "kante", "traeger": true, + "typ": T_WAND, "punkte": [[0.0, 0.0, 0.0], [2.0, 0.0, 0.0]], "farbe": Color(0.62, 0.53, 0.38), + "details": [{"typ": D_FENSTER, "pos": [1.0, 1.7, 0.0], "w": 1.2, "h": 1.2}], + }, + "bau_wand_scharte": { + "label": "Wand mit Schießscharte", "info": "Schlitz 1,0 × 0,4 m auf Schulterhöhe", "snap": "kante", "traeger": true, + "typ": T_WAND, "punkte": [[0.0, 0.0, 0.0], [2.0, 0.0, 0.0]], "farbe": Color(0.62, 0.53, 0.38), + "details": [{"typ": D_FENSTER, "pos": [1.0, 1.5, 0.0], "w": 1.0, "h": 0.4}], + }, + "bau_bruestung": { + "label": "Brüstung", "info": "2 m breit, 1,1 m hoch — Deckung, Dachrand", "snap": "kante", "traeger": true, + "typ": T_WAND, "punkte": [[0.0, 0.0, 0.0], [2.0, 0.0, 0.0]], "farbe": Color(0.56, 0.48, 0.35), "hoehe": 1.1, + }, + "bau_pfeiler": { + "label": "Eckpfeiler", "info": "Schließt die Ecke, wo zwei Wände zusammenstoßen", "snap": "ecke", "traeger": true, + "box": Vector3(0.3, 3.0, 0.3), "farbe": Color(0.42, 0.42, 0.40), + }, + "bau_giebelwand": { + "label": "Giebelwand", "info": "Dreieck-Abschluss unter dem Satteldach (2 m breit, 1 m Spitze)", + "snap": "kante", "traeger": false, + "typ": T_GIEBEL, "punkte": [[0.0, 0.0, 0.0], [2.0, 0.0, 0.0]], "rise": 1.0, "farbe": Color(0.62, 0.53, 0.38), + }, + "bau_dach_giebel": { + "label": "Satteldach", "info": "2×2 m, First in Richtung der Vorschau (R dreht)", "snap": "zelle", "traeger": false, + "typ": T_DACH_GIEBEL, "punkte": QUADRAT, "rise": 1.0, "farbe": Color(0.40, 0.25, 0.18), + }, + "bau_dach_pyramide": { + "label": "Pyramidendach", "info": "2×2 m, Spitze in der Mitte", "snap": "zelle", "traeger": false, + "typ": T_DACH_PYRAMIDE, "punkte": QUADRAT, "rise": 1.0, "farbe": Color(0.40, 0.25, 0.18), + }, + # Große Dächer (Test-Befund 25.10.: 2×2 m reichte nur für eine Zelle). Immer 45° + # (Spitze = halbe Breite); Giebelwand und Dach gleicher Größe passen zusammen. + "bau_giebelwand_4": { + "label": "Giebelwand 4 m", "info": "Dreieck-Abschluss, 4 m breit, 2 m Spitze — zum Satteldach 4 m", + "snap": "kante", "traeger": false, + "typ": T_GIEBEL, "punkte": [[0.0, 0.0, 0.0], [4.0, 0.0, 0.0]], "rise": 2.0, "farbe": Color(0.62, 0.53, 0.38), + }, + "bau_dach_giebel_4": { + "label": "Satteldach 4×4 m", "info": "4×4 m, First in Richtung der Vorschau (R dreht)", "snap": "zelle", "traeger": false, + "typ": T_DACH_GIEBEL, "punkte": QUADRAT_4, "rise": 2.0, "farbe": Color(0.40, 0.25, 0.18), + }, + "bau_dach_pyramide_4": { + "label": "Pyramidendach 4×4 m", "info": "4×4 m, Spitze in der Mitte", "snap": "zelle", "traeger": false, + "typ": T_DACH_PYRAMIDE, "punkte": QUADRAT_4, "rise": 2.0, "farbe": Color(0.40, 0.25, 0.18), + }, + "bau_giebelwand_6": { + "label": "Giebelwand 6 m", "info": "Dreieck-Abschluss, 6 m breit, 3 m Spitze — zum Satteldach 6 m", + "snap": "kante", "traeger": false, + "typ": T_GIEBEL, "punkte": [[0.0, 0.0, 0.0], [6.0, 0.0, 0.0]], "rise": 3.0, "farbe": Color(0.62, 0.53, 0.38), + }, + "bau_dach_giebel_6": { + "label": "Satteldach 6×6 m", "info": "6×6 m, First in Richtung der Vorschau (R dreht)", "snap": "zelle", "traeger": false, + "typ": T_DACH_GIEBEL, "punkte": QUADRAT_6, "rise": 3.0, "farbe": Color(0.40, 0.25, 0.18), + }, + "bau_dach_pyramide_6": { + "label": "Pyramidendach 6×6 m", "info": "6×6 m, Spitze in der Mitte", "snap": "zelle", "traeger": false, + "typ": T_DACH_PYRAMIDE, "punkte": QUADRAT_6, "rise": 3.0, "farbe": Color(0.40, 0.25, 0.18), + }, + # Dach aus Einzelteilen: alles 2×2-Zellen mit 45° (2 m Lauf = 2 m Höhe), massiv + # (rundum geschlossen, keine Lücke von innen). "profil" → _dach_mesh(). Tiefe + # Kante = -Z lokal (R dreht), Ecken: tiefer Punkt bei (-X,-Z). + "bau_dach_schraege": { + "label": "Dachschräge 45°", "info": "2×2 m, 2 m hoch — eine Seite des Dachs; die tiefe Kante zeigt in Richtung der Vorschau (R dreht)", + "snap": "zelle", "traeger": false, "profil": "schraege", "farbe": Color(0.40, 0.25, 0.18), + }, + "bau_dach_ecke_aussen": { + "label": "Dachecke außen", "info": "Walm-Ecke (Grat): zwei Schrägen treffen sich an einer Hausecke, die tiefe Ecke zeigt nach außen", + "snap": "zelle", "traeger": false, "profil": "ecke_aussen", "farbe": Color(0.40, 0.25, 0.18), + }, + "bau_dach_ecke_innen": { + "label": "Dachecke innen", "info": "Kehle: zwei Schrägen laufen in einer einspringenden Ecke (L-/T-Dach) zusammen", + "snap": "zelle", "traeger": false, "profil": "ecke_innen", "farbe": Color(0.40, 0.25, 0.18), + }, + "bau_dach_plateau": { + "label": "Dachplateau", "info": "2×2 m Block, 2 m hoch, oben flach — Mittelstück zwischen zwei Schrägen (breite Häuser), Schornstein-Sockel", + "snap": "zelle", "traeger": true, "profil": "plateau", "farbe": Color(0.40, 0.25, 0.18), + }, + "bau_dach_giebel_ende": { + "label": "Dachstirn 45°", "info": "Senkrechte Dreieck-Stirn (2 m breit, 2 m hoch) — Giebel-Abschluss unter einer Schräge, wenn das Dach an der Seite offen bleibt", + "snap": "kante", "traeger": false, "profil": "stirn", "farbe": Color(0.62, 0.53, 0.38), + }, + "bau_treppe": { + "label": "Treppe", "info": "4 m lang, 2 m breit, 3 m hoch — führt in ein Geschoss darüber", + "snap": "treppe", "traeger": false, + "typ": T_TREPPE, "punkte": [[0.0, 0.0, 0.0], [4.0, 3.0, 0.0]], "stufen": 15, "breite": 2.0, + "farbe": Color(0.46, 0.45, 0.42), + }, +} + +static var _mesh_cache: Dictionary = {} + + +static func ist_bau(oid: String) -> bool: + return KINDS.has(oid) + + +static func oids() -> Array: + return KINDS.keys() + + +static func label(oid: String) -> String: + return str((KINDS.get(oid, {}) as Dictionary).get("label", oid)) + + +static func snap_art(oid: String) -> String: + return str((KINDS.get(oid, {}) as Dictionary).get("snap", "zelle")) + + +## Platte = flaches Zell-Teil, auf dem man steht (Fundament, Boden/Decke). +static func ist_platte(oid: String) -> bool: + return snap_art(oid) == "zelle" and ist_traeger(oid) + + +static func ist_traeger(oid: String) -> bool: + return bool((KINDS.get(oid, {}) as Dictionary).get("traeger", false)) + + +## Ausmaße (m) des normalisierten Meshes: x = Länge/Breite, y = Höhe, z = Tiefe. +static func groesse(oid: String) -> Vector3: + var m := mesh(oid) + return m.get_aabb().size if m != null else Vector3.ZERO + + +# ------------------------------------------------------------------- Mesh --- + +## Normalisiertes Mesh (Fußpunkt unten-Mitte, Vertex-Farben) oder null. +static func mesh(oid: String) -> ArrayMesh: + if _mesh_cache.has(oid): + return _mesh_cache[oid] + var kind: Dictionary = KINDS.get(oid, {}) + if kind.is_empty(): + return null + var roh: ArrayMesh + if kind.has("box"): + roh = _box_mesh(kind["box"]) + elif kind.has("profil"): + roh = _dach_mesh(str(kind["profil"])) + else: + roh = _addon_mesh(kind) + var fertig := _normalisieren(roh, kind["farbe"] as Color) + _mesh_cache[oid] = fertig + return fertig + + +static func _box_mesh(size: Vector3) -> ArrayMesh: + var bm := BoxMesh.new() + bm.size = size + var out := ArrayMesh.new() + out.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, bm.get_mesh_arrays()) + return out + + +## Massive Dach-Teile aus Dreiecken (Zelle 2×2 m, lokal x,z ∈ [-1,1], 45°). +## Oberfläche h(x,z): Schräge = z+1, Ecke außen = min(x,z)+1, Ecke innen = max(x,z)+1, +## Plateau = 2. Dach-Stirn: dünnes Dreieck-Prisma. +static func _dach_mesh(profil: String) -> ArrayMesh: + var tris: Array = [] # je Dreieck [a, b, c] als Vector3 + var V := func(x: float, y: float, z: float) -> Vector3: return Vector3(x, y, z) + var quad := func(a: Vector3, b: Vector3, c: Vector3, d: Vector3) -> void: + tris.append([a, b, c]) + tris.append([a, c, d]) + var tri := func(a: Vector3, b: Vector3, c: Vector3) -> void: + tris.append([a, b, c]) + var mitte := Vector3(0.0, 0.7, 0.0) + match profil: + "schraege": + quad.call(V.call(-1, 0, -1), V.call(1, 0, -1), V.call(1, 2, 1), V.call(-1, 2, 1)) # Hang + quad.call(V.call(-1, 0, 1), V.call(1, 0, 1), V.call(1, 2, 1), V.call(-1, 2, 1)) # Rückwand + tri.call(V.call(-1, 0, -1), V.call(-1, 0, 1), V.call(-1, 2, 1)) # Stirn links + tri.call(V.call(1, 0, -1), V.call(1, 0, 1), V.call(1, 2, 1)) # Stirn rechts + quad.call(V.call(-1, 0, -1), V.call(1, 0, -1), V.call(1, 0, 1), V.call(-1, 0, 1)) # Boden + "ecke_aussen": + tri.call(V.call(-1, 0, -1), V.call(1, 0, -1), V.call(1, 2, 1)) + tri.call(V.call(-1, 0, -1), V.call(1, 2, 1), V.call(-1, 0, 1)) + tri.call(V.call(1, 0, -1), V.call(1, 0, 1), V.call(1, 2, 1)) + tri.call(V.call(-1, 0, 1), V.call(1, 0, 1), V.call(1, 2, 1)) + quad.call(V.call(-1, 0, -1), V.call(1, 0, -1), V.call(1, 0, 1), V.call(-1, 0, 1)) + "ecke_innen": + tri.call(V.call(-1, 0, -1), V.call(1, 2, -1), V.call(1, 2, 1)) + tri.call(V.call(-1, 0, -1), V.call(1, 2, 1), V.call(-1, 2, 1)) + tri.call(V.call(-1, 0, -1), V.call(1, 0, -1), V.call(1, 2, -1)) + tri.call(V.call(-1, 0, -1), V.call(-1, 2, 1), V.call(-1, 0, 1)) + quad.call(V.call(1, 0, -1), V.call(1, 0, 1), V.call(1, 2, 1), V.call(1, 2, -1)) + quad.call(V.call(-1, 0, 1), V.call(1, 0, 1), V.call(1, 2, 1), V.call(-1, 2, 1)) + quad.call(V.call(-1, 0, -1), V.call(1, 0, -1), V.call(1, 0, 1), V.call(-1, 0, 1)) + "plateau": + var bm := BoxMesh.new() + bm.size = Vector3(2.0, 2.0, 2.0) + var arr := bm.get_mesh_arrays() + var out := ArrayMesh.new() + out.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, arr) + return out + "stirn": + # Dünnes Dreieck-Prisma (Kante entlang X, 2 m breit, 2 m hoch, 0,2 m dick) + var d := 0.1 + tri.call(V.call(-1, 0, -d), V.call(1, 0, -d), V.call(-1, 2, -d)) + tri.call(V.call(-1, 0, d), V.call(-1, 2, d), V.call(1, 0, d)) + quad.call(V.call(-1, 0, -d), V.call(-1, 0, d), V.call(1, 0, d), V.call(1, 0, -d)) + quad.call(V.call(-1, 0, -d), V.call(-1, 2, -d), V.call(-1, 2, d), V.call(-1, 0, d)) + quad.call(V.call(1, 0, -d), V.call(1, 0, d), V.call(-1, 2, d), V.call(-1, 2, -d)) + mitte = Vector3(-0.33, 0.67, 0.0) + var pos := PackedVector3Array() + var nrm := PackedVector3Array() + for t in tris: + var a: Vector3 = t[0] + var b: Vector3 = t[1] + var c: Vector3 = t[2] + var n := (b - a).cross(c - a).normalized() + # nach außen drehen: Fläche muss vom Körper-Mittelpunkt wegzeigen + if n.dot((a + b + c) / 3.0 - mitte) < 0.0: + var tmp := b + b = c + c = tmp + n = -n + pos.append_array(PackedVector3Array([a, b, c])) + nrm.append_array(PackedVector3Array([n, n, n])) + var arrays := [] + arrays.resize(Mesh.ARRAY_MAX) + arrays[Mesh.ARRAY_VERTEX] = pos + arrays[Mesh.ARRAY_NORMAL] = nrm + var m := ArrayMesh.new() + m.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, arrays) + return m + + +static func _addon_mesh(kind: Dictionary) -> ArrayMesh: + var geo := Node3D.new() + geo.set_script(load(GEO_SCRIPT)) + geo.set("piece_type", int(kind["typ"])) + geo.set("unit_size", float(kind.get("hoehe", WAND_H))) + geo.set("thickness", DICKE_M) + if kind.has("rise"): + geo.set("rise", float(kind["rise"])) + if kind.has("stufen"): + geo.set("stair_count", int(kind["stufen"])) + geo.set("stair_width", float(kind["breite"])) + var pts := PackedVector3Array() + for p in (kind["punkte"] as Array): + pts.append(Vector3(float(p[0]), float(p[1]), float(p[2]))) + geo.set("custom_points", pts) + for d in (kind.get("details", []) as Array): + var detail := Node3D.new() + detail.set_script(load(DETAIL_SCRIPT)) + detail.set("detail_type", int(d["typ"])) + detail.set("width", float(d["w"])) + detail.set("height", float(d["h"])) + detail.position = Vector3(float(d["pos"][0]), float(d["pos"][1]), float(d["pos"][2])) + geo.add_child(detail) + var m: ArrayMesh = geo.call("_make_mesh") + geo.free() + return m + + +## Alle Flächen zu EINER Fläche verschmelzen, Fußpunkt-normalisieren, Material- +## Farbe setzen. +static func _normalisieren(roh: ArrayMesh, farbe: Color) -> ArrayMesh: + var aabb := roh.get_aabb() + var versatz := Vector3(aabb.position.x + aabb.size.x * 0.5, aabb.position.y, + aabb.position.z + aabb.size.z * 0.5) + var pos := PackedVector3Array() + var nrm := PackedVector3Array() + for s in roh.get_surface_count(): + var arr := roh.surface_get_arrays(s) + var v: PackedVector3Array = arr[Mesh.ARRAY_VERTEX] + var n: Variant = arr[Mesh.ARRAY_NORMAL] + var idx: Variant = arr[Mesh.ARRAY_INDEX] + var order: Array = [] + if idx is PackedInt32Array and not (idx as PackedInt32Array).is_empty(): + for i in (idx as PackedInt32Array): + order.append(i) + else: + for i in v.size(): + order.append(i) + for i in order: + pos.append(v[i] - versatz) + nrm.append((n as PackedVector3Array)[i] if n is PackedVector3Array else Vector3.UP) + # Die Addon-Geometrie hat Dreiecke gegen die Normalenrichtung gewickelt (sie + # rendert ohne Backface-Culling). Godot culled Rückseiten → Wicklung an die + # Normale anpassen, sonst sieht man Innenseiten und Dächer werden schwarz. + for t in range(0, pos.size() - 2, 3): + var gn := (pos[t + 2] - pos[t]).cross(pos[t + 1] - pos[t]) + if gn.dot(nrm[t]) < 0.0: + var tmp := pos[t + 1] + pos[t + 1] = pos[t + 2] + pos[t + 2] = tmp + var tn := nrm[t + 1] + nrm[t + 1] = nrm[t + 2] + nrm[t + 2] = tn + var arrays := [] + arrays.resize(Mesh.ARRAY_MAX) + arrays[Mesh.ARRAY_VERTEX] = pos + arrays[Mesh.ARRAY_NORMAL] = nrm + var out := ArrayMesh.new() + out.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, arrays) + var mat := StandardMaterial3D.new() + mat.albedo_color = farbe + mat.roughness = 0.9 + out.surface_set_material(0, mat) + return out + + +static func dreiecke(oid: String) -> int: + var m := mesh(oid) + return int(m.get_faces().size() / 3) if m != null else 0 + + +# ------------------------------------------------- Kollision / Registry ------ + +## Trimesh-Datei (library/kollisions/.json) — gleiche Felder wie die +## Pack-Dateien: Dreiecks-Suppe in Fußpunkt-Koordinaten. Türen, Fenster und +## Scharten sind echte Löcher (die Öffnung hat keine Dreiecke). +static func kollisions_json(oid: String) -> Dictionary: + var m := mesh(oid) + if m == null: + return {} + var verts: Array = [] + for v in m.get_faces(): + verts.append([snappedf(v.x, 0.0001), snappedf(v.y, 0.0001), snappedf(v.z, 0.0001)]) + var aabb := m.get_aabb() + return { + "oid": oid, + "quelle_glb": "res://assets/objekte/military_desert/%s/%s.glb" % [KATEGORIE, oid], + "dreiecke": int(verts.size() / 3), + "aabb_min": [snappedf(aabb.position.x, 0.001), snappedf(aabb.position.y, 0.001), snappedf(aabb.position.z, 0.001)], + "aabb_max": [snappedf(aabb.end.x, 0.001), snappedf(aabb.end.y, 0.001), snappedf(aabb.end.z, 0.001)], + "vertices": verts, + } + + +## Registry-Eintrag (Fragment library/objects.d/bauteile.json). +static func registry_eintrag(oid: String) -> Dictionary: + var g := groesse(oid) + return { + "poly": dreiecke(oid), + "collision": { + "quelle": "kollisions/%s.json" % oid, + "shape": "trimesh", + "size": [snappedf(g.x, 0.001), snappedf(g.y, 0.001), snappedf(g.z, 0.001)], + }, + "glb": "res://assets/objekte/military_desert/%s/%s.glb" % [KATEGORIE, oid], + "kategorie": KATEGORIE, + "name_de": label(oid), + } + + +## GLB schreiben (eigenes Mesh mit Vertex-Farben). Rückgabe: Godot-Fehlercode. +static func glb_schreiben(oid: String, pfad: String) -> int: + var m := mesh(oid) + if m == null: + return ERR_DOES_NOT_EXIST + var root := Node3D.new() + root.name = oid + var mi := MeshInstance3D.new() + mi.name = oid + mi.mesh = m + root.add_child(mi) + var gdoc := GLTFDocument.new() + var gstate := GLTFState.new() + var err := gdoc.append_from_scene(root, gstate) + if err == OK: + err = gdoc.write_to_filesystem(gstate, pfad) + root.free() + return err diff --git a/editor/bau_katalog.gd.uid b/editor/bau_katalog.gd.uid new file mode 100644 index 0000000..3ab1224 --- /dev/null +++ b/editor/bau_katalog.gd.uid @@ -0,0 +1 @@ +uid://defuinyvy5j8i diff --git a/editor/bau_ops.gd b/editor/bau_ops.gd new file mode 100644 index 0000000..3a86fe8 --- /dev/null +++ b/editor/bau_ops.gd @@ -0,0 +1,204 @@ +extends RefCounted +class_name BauOps +## Dokument-Operationen des Bauen-Modus (pure Funktionen, headless testbar). +## +## Ein Gebäude = eine Gruppe (GroupOps, Feld "group" + group_names) aus `bau_*`- +## Objekten. Alles Weitere — Verschieben, Drehen, Kopieren, Löschen, Symmetrie, +## Speichern — läuft über die normalen Objekt-Funktionen. Dieser Teil kennt nur, +## was speziell am Bauen ist: Teil setzen/ersetzen, Gebäude-Gruppen, Migration +## der alten "gebaeude"-Sektion (Karte t_97ea59c5 → Umbau 25.10.). + + +static func teile_zahl(doc: Dictionary) -> int: + var n := 0 + for o in (doc.get("objects", []) as Array): + if o is Dictionary and BauKatalog.ist_bau(str((o as Dictionary).get("id", ""))): + n += 1 + return n + + +## Dreiecke aller Bauteile (grobe Poly-Übersicht für die Statuszeile). +static func dreiecke_gesamt(doc: Dictionary) -> int: + var n := 0 + for o in (doc.get("objects", []) as Array): + if o is Dictionary: + n += BauKatalog.dreiecke(str((o as Dictionary).get("id", ""))) + return n + + +## Neue Gebäude-Gruppe anlegen und benennen. Rückgabe: Gruppen-ID. +static func gruppe_neu(doc: Dictionary) -> int: + var gid := GroupOps.next_group_id(doc) + GroupState.set_group_name(doc, gid, "Gebäude %d" % (gebaeude_zahl(doc) + 1)) + return gid + + +## Anzahl Gebäude-Gruppen (Gruppen, deren erstes Mitglied ein Bauteil ist). +static func gebaeude_zahl(doc: Dictionary) -> int: + return gebaeude_gruppen(doc).size() + + +## [{gid, name, indizes, dreiecke}] für alle Gebäude-Gruppen. +static func gebaeude_gruppen(doc: Dictionary) -> Array: + var out: Array = [] + var objects: Array = doc.get("objects", []) + for gid in GroupOps.active_group_ids(doc): + var members := GroupOps.members_of(doc, int(gid)) + if members.is_empty(): + continue + var bau := false + var tris := 0 + for i in members: + var oid := str((objects[i] as Dictionary).get("id", "")) + if BauKatalog.ist_bau(oid): + bau = true + tris += BauKatalog.dreiecke(oid) + if bau: + out.append({"gid": int(gid), "name": GroupState.display_name(doc, int(gid)), + "indizes": members, "dreiecke": tris}) + return out + + +## Teil setzen oder ersetzen (snap = BuildSnap.berechne-Ergebnis, ok=true). +## Mutiert doc["objects"]; der Aufrufer macht snapshot/commit. +## gid: Zielgruppe (Gebäude); bei Symmetrie bekommt der Zwilling ein eigenes +## Spiegel-Gebäude (spiegel_gid, vom Aufrufer gemerkt: 1 Original-Gebäude ↔ 1 Spiegel). +## Rückgabe: {index, twin, ersetzt}. +static func setze_teil(doc: Dictionary, oid: String, snap: Dictionary, gid: int, + sym_mode: int, spiegel_gid := -1) -> Dictionary: + var objects: Array = doc["objects"] + var pos: Vector3 = snap["pos"] + var rot := float(snap["rot"]) + var ersetze := int(snap.get("ersetze", -1)) + if ersetze >= 0 and ersetze < objects.size(): + var o: Dictionary = objects[ersetze] + o["id"] = oid + o["pos"] = [pos.x, pos.y, pos.z] + SvmapIO.rot_setzen(o, Vector3(0.0, rot, 0.0)) + # Symmetrie: der Zwilling bekommt dasselbe Teil an seiner (gespiegelten) Stelle. + var key := SymmetryCore.sym_of(o) + if sym_mode != SymmetryCore.Mode.OFF and not key.is_empty(): + var partner := SymmetryCore.find_partner_index(objects, key, ersetze) + if partner >= 0 and objects[partner] is Dictionary: + (objects[partner] as Dictionary)["id"] = oid + return {"index": ersetze, "twin": -1, "ersetzt": true} + var neu := {"id": oid, "pos": [pos.x, pos.y, pos.z], "scale": 1.0, "rot_y_deg": rot, "group": gid} + objects.append(neu) + var index := objects.size() - 1 + var twin := -1 + if sym_mode != SymmetryCore.Mode.OFF: + var res: Dictionary = ObjectOps.symmetry_place_twin(doc, index, sym_mode) + twin = int(res.get("twin", -1)) + if twin >= 0 and spiegel_gid >= 0: + (objects[twin] as Dictionary)["group"] = spiegel_gid + return {"index": index, "twin": twin, "ersetzt": false} + + +## Eine ganze Gebäude-Gruppe als Indizes (für „Ganzes Gebäude wählen“). +static func gebaeude_von(doc: Dictionary, index: int) -> Array: + var objects: Array = doc.get("objects", []) + if index < 0 or index >= objects.size(): + return [] + var gid := GroupOps.group_id(objects[index]) + if gid == GroupOps.UNGROUPED: + return [index] + return GroupOps.members_of(doc, gid) + + +# ----------------------------------------------------------- Demo / Test ---- + +## Kleines Haus über die echte Klick-Logik setzen (Fundament, Wände, Tür, Fenster, +## Giebel, Dach, Treppe) — für Demo und Tests. Jeder Schritt = BuildSnap-Treffer +## wie im Editor. Rückgabe: Gruppen-ID. history kann null sein. +static func haus_demo(doc: Dictionary, history: Variant, mitte: Vector3) -> int: + var gid := gruppe_neu(doc) + var terrain := func(_x: float, _z: float) -> float: return mitte.y + var before: Dictionary = history.snapshot(["objects", "group_names"]) if history != null else {} + # 2×2 Zellen (4×4 m): Zellmitten bei (±1, ±1) relativ zur Mitte. + var ox := floorf(mitte.x / 2.0) * 2.0 + var oz := floorf(mitte.z / 2.0) * 2.0 + var schritte := [ + ["bau_fundament", Vector3(ox - 1, mitte.y, oz - 1), 0.0], + ["bau_fundament", Vector3(ox + 1, mitte.y, oz - 1), 0.0], + ["bau_fundament", Vector3(ox - 1, mitte.y, oz + 1), 0.0], + ["bau_fundament", Vector3(ox + 1, mitte.y, oz + 1), 0.0], + # Wände liegen GANZ in der Zelle, in der die Maus ist (Außenseite bündig mit + # der Kante) — deshalb zielen die Klicks 10 cm ins Hausinnere. + ["bau_wand", Vector3(ox - 1, mitte.y, oz - 1.9), 0.0], + ["bau_wand_fenster", Vector3(ox + 1, mitte.y, oz - 1.9), 0.0], + ["bau_wand_tuer", Vector3(ox - 1, mitte.y, oz + 1.9), 0.0], + ["bau_wand", Vector3(ox + 1, mitte.y, oz + 1.9), 0.0], + ["bau_wand", Vector3(ox - 1.9, mitte.y, oz - 1), 90.0], + ["bau_wand_scharte", Vector3(ox - 1.9, mitte.y, oz + 1), 90.0], + ["bau_wand", Vector3(ox + 1.9, mitte.y, oz - 1), 90.0], + ["bau_wand", Vector3(ox + 1.9, mitte.y, oz + 1), 90.0], + ] + for st in schritte: + _demo_setzen(doc, str(st[0]), st[1] as Vector3, float(st[2]), gid, terrain) + # Ein großes Satteldach (4×4 m) auf die Wandoberkante. + var oben := mitte.y + BauKatalog.WAND_H + _demo_setzen(doc, "bau_dach_giebel_4", Vector3(ox, oben, oz), 0.0, gid, terrain) + if history != null: + history.commit("Haus gebaut (Demo)", before, history.snapshot(["objects", "group_names"])) + return gid + + +static func _demo_setzen(doc: Dictionary, oid: String, hit: Vector3, dreh: float, gid: int, + gelaende: Callable) -> void: + var teile := BuildSnap.sammle_teile(doc) + var snap := BuildSnap.berechne(oid, hit, dreh, teile, gelaende) + if bool(snap["ok"]): + setze_teil(doc, oid, snap, gid, SymmetryCore.Mode.OFF) + + +# --------------------------------------------------------------- Migration -- + +## Alte Sektion doc["gebaeude"] (Karte t_97ea59c5, 10 prozedurale Teile ohne +## Registry) → bau_*-Objekte in EINER Gruppe, dann Sektion entfernen. Beste +## Näherung: Teil-Ursprünge der alten Teile lagen an Wandanfang/Zellmitte, die +## neuen Bauteile an der Mitte der Grundfläche; Höhen (2 m → 3 m) ändern sich. +## Rückgabe: Anzahl übernommener Teile. +const _ALT := { + "fundament": "bau_fundament", "boden": "bau_boden", "wand": "bau_wand", + "tuer": "bau_wand_tuer", "fenster": "bau_wand_fenster", + "giebelwand": "bau_giebelwand", "giebelwand_rechts": "bau_giebelwand", + "dach_giebel": "bau_dach_giebel", "dach_pyramide": "bau_dach_pyramide", + "treppe": "bau_treppe", +} + +static func migriere_gebaeude(doc: Dictionary) -> int: + if not doc.has("gebaeude"): + return 0 + var alt: Variant = doc["gebaeude"] + doc.erase("gebaeude") + if not (alt is Array) or (alt as Array).is_empty(): + return 0 + if not doc.has("objects") or not (doc["objects"] is Array): + doc["objects"] = [] + var objects: Array = doc["objects"] + var gid := gruppe_neu(doc) + var n := 0 + for teil in alt: + if not (teil is Dictionary): + continue + var oid: String = _ALT.get(str((teil as Dictionary).get("id", "")), "") + if oid.is_empty(): + continue + var p: Array = (teil as Dictionary).get("pos", [0.0, 0.0, 0.0]) + var rot := float((teil as Dictionary).get("rot", 0.0)) + var pos := Vector3(float(p[0]), float(p[1]), float(p[2])) + var local := Vector3.ZERO + match str((teil as Dictionary).get("id", "")): + "wand", "tuer", "fenster", "giebelwand", "giebelwand_rechts": + local = Vector3(1.0, 0.0, 0.0) # alt: Ursprung am Wandanfang + "treppe": + local = Vector3(2.0, 0.0, 0.0) # alt: 2 m lang ab Ursprung + "boden": + pos.y -= BauKatalog.DICKE_M # alt: Oberkante am Ursprung + pos += Basis(Vector3.UP, deg_to_rad(rot)) * local + objects.append({"id": oid, "pos": [pos.x, pos.y, pos.z], "scale": 1.0, + "rot_y_deg": fposmod(rot, 360.0), "group": gid}) + n += 1 + if n == 0: + GroupState.set_group_name(doc, gid, "") + return n diff --git a/editor/bau_ops.gd.uid b/editor/bau_ops.gd.uid new file mode 100644 index 0000000..1bd8d65 --- /dev/null +++ b/editor/bau_ops.gd.uid @@ -0,0 +1 @@ +uid://bh4sybddgu3mt diff --git a/editor/build_snap.gd b/editor/build_snap.gd new file mode 100644 index 0000000..36997a3 --- /dev/null +++ b/editor/build_snap.gd @@ -0,0 +1,256 @@ +extends RefCounted +class_name BuildSnap +## Raster- und Ebenen-Logik des Bauen-Modus (pure Funktionen, headless testbar). +## +## Warum neu: die alte Logik rastete jedes Teil NUR auf eine Zellecke und nahm +## als Höhe die Klickhöhe — ein Klick auf die Seite einer Wand setzte das neue +## Teil mitten in die Luft, Wände ließen sich nur über Rotationsraten an die +## richtige Kante bringen. Jetzt: +## • XZ: Zellen-Teile rasten in die Zellmitte, Wände auf die NÄCHSTE Zellkante +## (Drehung ergibt sich aus der Kante), Pfeiler auf die nächste Ecke, +## Treppen auf eine 4×2-m-Fläche über zwei Zellen. +## • Y: nie die Klickhöhe, sondern eine EBENE: Gelände (höchster Punkt unter +## der Grundfläche) oder Oberkante eines tragenden Bauteils darunter. Gewählt +## wird die höchste Ebene, die nicht mehr als TOL_M über dem Klickpunkt liegt. +## • Ein gleichartiges Teil auf demselben Platz wird ERSETZT (Tür in eine +## vorhandene Wand einsetzen); Klick auf die Oberkante stapelt stattdessen. +## +## Position eines Teils = Fußpunkt (Unterkante, Mitte der Grundfläche) — wie +## jedes Bibliotheks-Objekt (BauKatalog.mesh ist so normalisiert). + +const TOL_M := 0.35 # so weit darf eine Ebene ÜBER dem Klickpunkt liegen +const SHRINK_M := 0.05 # Grundflächen-Schnitt: minimale Überlappung ignorieren +const SAME_M := 0.08 # Toleranz für "gleiche Stelle" +const UEBERSTAND_M := 0.01 # Wand-Außenseite steht 1 cm vor der Plattenkante: keine deckungsgleichen + # Flächen (Z-Fighting/Flackern an Boden↔Wand) + + +## Ergebnis-Wörterbuch: +## ok false = hier nicht setzbar (grund erklärt warum) +## pos Vector3 Fußpunkt +## rot Y-Drehung in Grad +## ersetze Index des Objekts, das ersetzt wird (-1 = neues Teil) +## ebene gewählte Höhe (= pos.y) +## grund Klartext (bei ok=false) bzw. Hinweis +## +## teile: Array von {"i": Index, "oid": String, "pos": Vector3, "rot": float} +## (nur Bauteile, siehe sammle_teile). +## gelaende: Callable(x: float, z: float) -> float +## dreh: Nutzerdrehung in Grad (wird auf 90° gerastet) +## kamera_dir: Blickrichtung des Klickstrahls (für Zell-Wahl an Wandkanten), optional +## ebene_fix: feste Geschosshöhe (Geschoss-Wahl im Bauen-Tab); NAN = automatisch. +## Dann hängt die Höhe NICHT mehr an Wänden/Böden darunter — Decken und Böden +## lassen sich auch mitten im großen Raum setzen. +static func berechne(oid: String, hit: Vector3, dreh: float, teile: Array, + gelaende: Callable, hit_ist_objekt := false, kamera_dir := Vector3.ZERO, + ebene_fix := NAN) -> Dictionary: + var art := BauKatalog.snap_art(oid) + var gr := BauKatalog.groesse(oid) + var q := int(roundf(dreh / 90.0)) + var viertel := ((q % 4) + 4) % 4 + var p := Vector2(hit.x, hit.z) + # Treffer auf einem Objekt: Wände liegen GANZ in einer Zelle — die Quer-Achse + # kommt dann von der Wand (Decke/Dach landet in der Zelle der Wand). Bei anderen + # Objekten die Zelle auf der Kameraseite wählen (Klick liegt auf einer Grenze). + var wand_getroffen := {} + if hit_ist_objekt: + wand_getroffen = _wand_unter_klick(teile, p, hit.y) + if hit_ist_objekt and art != "kante": + if not wand_getroffen.is_empty(): + var wp: Vector3 = wand_getroffen["pos"] + if absf(sin(deg_to_rad(float(wand_getroffen["rot"])))) > 0.5: + p.x = wp.x + else: + p.y = wp.z + elif kamera_dir != Vector3.ZERO: + var d2 := Vector2(kamera_dir.x, kamera_dir.z) + if d2.length() > 0.01: + p -= d2.normalized() * 0.2 + var mitte := Vector2.ZERO + var rot := 0.0 + var r := BauKatalog.RASTER_M + match art: + "zelle": + # Teile über mehrere Zellen (große Dächer): gerade Zellzahl → Mitte auf + # einer Zellecke, ungerade → Mitte einer Zelle. + mitte = Vector2(_raster_mitte(p.x, gr.x), _raster_mitte(p.y, gr.z)) + rot = viertel * 90.0 + "ecke": + mitte = Vector2(roundf(p.x / r) * r, roundf(p.y / r) * r) + "treppe": + rot = viertel * 90.0 + if viertel % 2 == 0: # Lauf entlang X: Mitte auf gerader X-, ungerader Z-Linie + mitte = Vector2(roundf(p.x / r) * r, floorf(p.y / r) * r + r * 0.5) + else: + mitte = Vector2(floorf(p.x / r) * r + r * 0.5, roundf(p.y / r) * r) + _: # "kante" + var vorhanden := wand_getroffen + if not vorhanden.is_empty(): + # Klick auf eine vorhandene Wand (Seite = ersetzen, Oberkante = stapeln): + # GENAU ihre Lage übernehmen, nicht neu aus der Klickstelle raten. + var tp: Vector3 = vorhanden["pos"] + mitte = Vector2(tp.x, tp.z) + rot = 90.0 if absf(sin(deg_to_rad(float(vorhanden["rot"])))) > 0.5 else 0.0 + else: + # Wand liegt GANZ IN der Zelle, in der der Mauszeiger ist: Außenseite + # bündig mit der Zellkante (Boden/Fundament), nicht halb in der Luft. + # Dadurch schließen sich auch Ecken ohne Lücke (Test-Befund 25.10.). + var laenge := gr.x + var halbe_dicke := gr.z * 0.5 + var fx := p.x / r + var fz := p.y / r + var h_mitte := Vector2(_raster_mitte(p.x, laenge), roundf(fz) * r) # Kante entlang X + var v_mitte := Vector2(roundf(fx) * r, _raster_mitte(p.y, laenge)) # Kante entlang Z + if p.distance_squared_to(h_mitte) <= p.distance_squared_to(v_mitte): + mitte = h_mitte + mitte.y += (halbe_dicke - UEBERSTAND_M) * (1.0 if p.y >= h_mitte.y else -1.0) + rot = 0.0 + else: + mitte = v_mitte + mitte.x += (halbe_dicke - UEBERSTAND_M) * (1.0 if p.x >= v_mitte.x else -1.0) + rot = 90.0 + rot += 180.0 * float(viertel % 2) # R dreht die Wand um (Blickseite der Teile) + rot = fposmod(rot, 360.0) + var quer := absf(sin(deg_to_rad(rot))) > 0.5 # 90°/270°: X- und Z-Ausdehnung getauscht + var half := Vector2(gr.z, gr.x) * 0.5 if quer else Vector2(gr.x, gr.z) * 0.5 + var rect := Rect2(mitte - half, half * 2.0) + + # Ebenen sammeln: Gelände + Oberkanten tragender Teile unter der Grundfläche. + var gel_max := -INF + for sx in [0.0, 0.5, 1.0]: + for sz in [0.0, 0.5, 1.0]: + gel_max = maxf(gel_max, float(gelaende.call(rect.position.x + rect.size.x * sx, + rect.position.y + rect.size.y * sz))) + var ebenen: Array = [gel_max] + var kern := rect.grow(-SHRINK_M) + for t in teile: + var troid := str(t["oid"]) + var tr := teil_rect(t) + if not tr.intersects(kern): + continue + var top: float = (t["pos"] as Vector3).y + BauKatalog.groesse(troid).y + if not BauKatalog.ist_traeger(troid): + continue + if (art == "kante" or art == "ecke") and BauKatalog.ist_platte(troid): + # Wände/Pfeiler zählen von der UNTERKANTE einer Platte (Boden/Decke/ + # Fundament): jedes Geschoss liegt dadurch auf Vielfachen der Wandhöhe — + # mit oder ohne Decke darunter sitzen obere Wände gleich hoch + # (Test-Befund 25.10.). Die Platte selbst liegt auf der Wandoberkante. + ebenen.append((t["pos"] as Vector3).y) + else: + ebenen.append(top) + var ebene := ebene_fix if not is_nan(ebene_fix) else _waehle_ebene(ebenen, hit.y) + + # Platz belegt? Gleiche Art + gleiche Stelle + gleiche Ebene → ersetzen/ablehnen. + var ersetze := -1 + for t in teile: + var troid := str(t["oid"]) + if BauKatalog.snap_art(troid) != art: + continue + var tp: Vector3 = t["pos"] + if absf(tp.y - ebene) > SAME_M: + continue + if Vector2(tp.x, tp.z).distance_to(mitte) > SAME_M: + continue + if art == "kante" and absf(fposmod(float(t["rot"]), 180.0) - fposmod(rot, 180.0)) > 1.0: + continue + if art == "treppe" and absf(fposmod(float(t["rot"]), 360.0) - rot) > 1.0: + continue + if troid == oid and absf(fposmod(float(t["rot"]) - rot, 360.0)) < 1.0: + return {"ok": false, "pos": Vector3(mitte.x, ebene, mitte.y), "rot": rot, "ersetze": -1, + "ebene": ebene, "grund": "Hier steht schon %s." % BauKatalog.label(oid)} + ersetze = int(t["i"]) + break + return {"ok": true, "pos": Vector3(mitte.x, ebene, mitte.y), "rot": rot, "ersetze": ersetze, + "ebene": ebene, "grund": ""} + + +## Mitte eines Teils der Länge `laenge` entlang einer Achse: gerade Zellzahl → +## auf der nächsten Zellgrenze, ungerade → Mitte der Zelle. +static func _raster_mitte(wert: float, laenge: float) -> float: + var r := BauKatalog.RASTER_M + var zellen := maxi(1, int(roundf(laenge / r))) + if zellen % 2 == 0: + return roundf(wert / r) * r + return floorf(wert / r) * r + r * 0.5 + + +## Vorhandene Wand, auf die der Klick trifft (Seite oder Oberkante): Rückgabe das +## Teil-Wörterbuch oder {}. `p` = Klickpunkt in XZ, `y` = Klickhöhe. +static func _wand_unter_klick(teile: Array, p: Vector2, y: float) -> Dictionary: + var bester := {} + var bester_d := INF + for t in teile: + var troid := str(t["oid"]) + if BauKatalog.snap_art(troid) != "kante": + continue + var tr := teil_rect(t).grow(0.06) + if not tr.has_point(p): + continue + var unten: float = (t["pos"] as Vector3).y + var oben := unten + BauKatalog.groesse(troid).y + if y < unten - 0.1 or y > oben + 0.1: + continue + var d := p.distance_squared_to(tr.get_center()) + if d < bester_d: + bester_d = d + bester = t + return bester + + +## Höchste Ebene ≤ hit_y + TOL; gibt es keine (Klick tief unter allen), die tiefste. +static func _waehle_ebene(ebenen: Array, hit_y: float) -> float: + var best := -INF + var tiefste := INF + for e in ebenen: + var ev := float(e) + tiefste = minf(tiefste, ev) + if ev <= hit_y + TOL_M and ev > best: + best = ev + return best if best > -INF else tiefste + + +## Grundfläche (XZ) eines gesetzten Bauteils in Weltkoordinaten. +static func teil_rect(t: Dictionary) -> Rect2: + var gr := BauKatalog.groesse(str(t["oid"])) + var rot := float(t["rot"]) + var quer := absf(sin(deg_to_rad(rot))) > 0.5 + var half := Vector2(gr.z, gr.x) * 0.5 if quer else Vector2(gr.x, gr.z) * 0.5 + var pos: Vector3 = t["pos"] + return Rect2(Vector2(pos.x, pos.z) - half, half * 2.0) + + +## Alle Bauteile aus doc["objects"] (Index, oid, pos, rot) — nur `bau_*`. +static func sammle_teile(doc: Dictionary) -> Array: + var out: Array = [] + var objects: Array = doc.get("objects", []) + for i in objects.size(): + var o: Variant = objects[i] + if not (o is Dictionary): + continue + var oid := str((o as Dictionary).get("id", "")) + if not BauKatalog.ist_bau(oid): + continue + var pos: Array = (o as Dictionary).get("pos", [0.0, 0.0, 0.0]) + if pos.size() != 3: + continue + out.append({ + "i": i, "oid": oid, + "pos": Vector3(float(pos[0]), float(pos[1]), float(pos[2])), + "rot": float(SvmapIO.objekt_rotation(o as Dictionary).y), + }) + return out + + +## Höhe des untersten Geschosses (= Fußpunkt der tiefsten Platte/Wand im Umkreis von +## `radius` um `p`), sonst das Gelände bei `p`. Geschoss k liegt bei Basis + k·WAND_H. +static func geschoss_basis(teile: Array, p: Vector2, gelaende: Callable, radius := 40.0) -> float: + var tiefste := INF + for t in teile: + var tp: Vector3 = t["pos"] + if Vector2(tp.x, tp.z).distance_to(p) > radius: + continue + var oid := str(t["oid"]) + if BauKatalog.ist_platte(oid) or BauKatalog.snap_art(oid) == "kante": + tiefste = minf(tiefste, tp.y) + return tiefste if tiefste < INF else float(gelaende.call(p.x, p.y)) diff --git a/editor/build_snap.gd.uid b/editor/build_snap.gd.uid new file mode 100644 index 0000000..1d8709e --- /dev/null +++ b/editor/build_snap.gd.uid @@ -0,0 +1 @@ +uid://irnbwhk0eijq diff --git a/editor/fly_math.gd b/editor/fly_math.gd new file mode 100644 index 0000000..22276b5 --- /dev/null +++ b/editor/fly_math.gd @@ -0,0 +1,71 @@ +extends RefCounted +class_name FlyMath +## Freelook-Flug-Mathe (Karte t_c46d31c2, Karte 1/3) — bewusst pure Funktionen +## (kein Knoten, keine Kamera): speed_for/wheel_speed/move_delta/forward- und +## Euler-Umrechnung. tests/test_shortcuts.gd prüft headless; orbit_camera.gd +## ist nur der dünne Anwender. +## +## Euler-Konvention identisch zur Orbit-Kamera (_apply in orbit_camera.gd): +## Blickrichtung forward(yaw, pitch) = +## (−sin(yaw)·cos(pitch), −sin(pitch), −cos(yaw)·cos(pitch)) +## pitch positiv = Kamera schaut von OBEN herab (Orbit-Pitch 5…85°), +## im Flug erlaubt: −85…+85° (auch von unten hochschauen). + +const BASE_SPEED_MPS := 30.0 # Grundgeschwindigkeit (Mausrad ändert sie dauerhaft) +const FAST_MULT := 3.0 # Strg halten = schneller (Shooter-Konvention) +const SLOW_MULT := 0.3 # Alt halten = langsamer +const WHEEL_MULT := 1.15 # Mausrad-Tick: +15 % / −13 % +const SPEED_MIN_MPS := 2.0 +const SPEED_MAX_MPS := 300.0 + +const PITCH_MAX_DEG := 85.0 # Flug-Blick grenzwertig (±) — kein Gimbal-Kippen + + +## Flug-Tempo: Strg dominiert, wenn (unüblicherweise) beide Modifier unten sind. +static func speed_for(base_mps: float, fast: bool, slow: bool) -> float: + if fast: + return base_mps * FAST_MULT + if slow: + return base_mps * SLOW_MULT + return base_mps + + +## Mausrad-Tick: Grundgeschwindigkeit DAUERHAFT ändern (nicht nur solange +## gedrückt) — up=true schneller, down=false langsamer, immer geklemmt. +static func wheel_speed(base_mps: float, up: bool) -> float: + var next := base_mps * WHEEL_MULT if up else base_mps / WHEEL_MULT + return clampf(next, SPEED_MIN_MPS, SPEED_MAX_MPS) + + +## Bewegungs-Delta für einen Frame. forward = BLICKRICHTUNG (3D, mit Pitch — +## W/S fliegen dorthin, wo man hinsieht), right = horizontal-rechts, und +## vertikal ist Welt-UP (Leertaste/Shift heben/senken unabhängig vom Blick — +## Shooter-Konvention, Sly-Wunsch 17.10.). +## Diagonal-Eingaben werden normalisiert (kein √2-Tempo). Rückgabe: Meter. +static func move_delta(forward: Vector3, right: Vector3, fwd_input: float, + side_input: float, vert_input: float, speed_mps: float, delta_s: float) -> Vector3: + var dir := forward * fwd_input + right * side_input + Vector3.UP * vert_input + if dir.length_squared() < 0.0000001: + return Vector3.ZERO + return dir.normalized() * speed_mps * delta_s + + +## Blickrichtung → (yaw_deg, pitch_deg) in der Orbit-Konvention (siehe oben). +static func euler_from_forward(forward: Vector3) -> Vector2: + var f := forward + if f.length_squared() < 0.0000001: + return Vector2(0.0, 0.0) + f = f.normalized() + var pitch := rad_to_deg(asin(clampf(-f.y, -1.0, 1.0))) + var yaw := rad_to_deg(atan2(-f.x, -f.z)) + return Vector2(yaw, pitch) + + +## (yaw_deg, pitch_deg) → Blickrichtung (Inverse von euler_from_forward). +static func forward_from_euler(yaw_deg: float, pitch_deg: float) -> Vector3: + var yaw := deg_to_rad(yaw_deg) + var pitch := deg_to_rad(clampf(pitch_deg, -PITCH_MAX_DEG, PITCH_MAX_DEG)) + return Vector3( + -sin(yaw) * cos(pitch), + -sin(pitch), + -cos(yaw) * cos(pitch)) \ No newline at end of file diff --git a/editor/fly_math.gd.uid b/editor/fly_math.gd.uid new file mode 100644 index 0000000..9885ab3 --- /dev/null +++ b/editor/fly_math.gd.uid @@ -0,0 +1 @@ +uid://btbsxedv3fvw diff --git a/editor/interaction.gd b/editor/interaction.gd new file mode 100644 index 0000000..266078f --- /dev/null +++ b/editor/interaction.gd @@ -0,0 +1,1729 @@ +extends Node3D +## Maus-Interaktion im Editor-Viewport (M2 UX-Fundament, Karte t_40d855d0; +## Auswahl-System Erweiterung: Karte t_f6f29d86): +## - Ghost-Preview: beim Platzieren schwebt eine transparente Vorschau am +## Cursor, Klick setzt das Objekt (kein "überraschtes" Ergebnis). +## - Auswahl: angeklickte Objekte färben sich orange, Ziehen verschiebt, +## R-Taste ODER Mausrad dreht (15°-Raster), Entf löscht. +## - Mehrfachauswahl (Karte t_f6f29d86, erweitert t_c46d31c2): Umschalt+Klick +## ODER Strg+Klick fügt hinzu/entfernt, Rahmen-Aufziehen über leeren Boden +## wählt alles im Rahmen. Löschen/Duplizieren wirken auf die GANZE Auswahl. +## - Gruppen: Objekte mit gleicher "group"-ID ziehen/drehen gemeinsam +## (GroupOps), Gruppieren/Lösen über main-Buttons (Strg+G / Strg+Umschalt+G). +## - Undo: Jede Aktion = EINE ActionHistory-Stufe (auch Gruppen-Ziehen). +## Alle Meldungen laufen über main._set_status — Klartext + nächsten Schritt +## vorschlagen (Chef-Grundsatz, map-editor-README). +## +## Lebt im selben SubViewport-Welt-Knoten wie Kamera + Viewport-Bauer; +## main.gd verdrahtet Referenzen per setup(). + +const ROT_STEP_DEG := 15.0 +const TILT_STEP_DEG := 15.0 # Kipp-Schritt (Karte t_e166e656: Strg+R / Alt+R) +const DRAG_THRESHOLD_PX := 4.0 +const GRID_M := 1.0 # Raster-Snap-Weite (Objekt-Werkzeuge links, Karte t_3a998ae4) + +# Höhe beim Ziehen merken (Karte t_7567a06f): das Objekt behält seinen +# Abstand zum Terrain — ein angehobenes Objekt bleibt beim Verschieben oben. + +var main # Hauptfenster (script-erweitert, Variant — Referenzen per setup()) +var camera: Camera3D +var view_builder # script-erweitert, Variant + +# Platzier-Modus +var placing := false +var place_oid := "" +var place_rot_deg := 0.0 +var place_tilt_x := 0.0 # Kippen X beim Platzieren (Karte t_e166e656, Strg+R) +var place_tilt_z := 0.0 # Kippen Z beim Platzieren (Karte t_e166e656, Alt+R) +# U5 (t_5e3e97c9): Shift beim Setz-Klick = Serienmodus — weiter setzen wie +# bisher (Ghost bleibt an, jeder Klick setzt). Ohne Shift wird EIN Objekt +# gesetzt und das Werkzeug beendet sich selbst; das neue Objekt ist ausgewählt. +var _place_series := false +var _ghost: Node3D # Ghost-ROOT: Position = Objekt-Fußpunkt — + # identisch zur platzierten Marker-Position + # (Karte t_4092e3a0: Ghost == Platzierung). +var _ghost_mi: MeshInstance3D # Kind-Mesh, gehoben um half_height — + # exakt wie der Viewport-Bauer (map_view_builder). +var _ghost_active := false # Ghost sichtbar weil Cursor über der Map ist + +# Bauen-Modus (Bauteile bau_*): der Ghost rastet über BuildSnap (Kante/Zelle/ +# Ebene), jeder Klick setzt ein Teil in das laufende Gebäude (= Gruppe). +var build_group_id := -1 # laufendes Gebäude; -1 = nächstes Teil beginnt ein neues +var _build_last: Dictionary = {} # letztes BuildSnap-Ergebnis (pos/rot/ersetze/ok/grund) +var _build_hit: Dictionary = {} # letzter Treffer {punkt, obj, dir} +var _build_hint := "" # letzte Statuszeile des Ghosts (kein Spam) +var build_geschoss := -1 # -1 = Höhe automatisch, sonst festes Geschoss (0 = Boden, 1 = erste Decke …) +const BAU_GESCHOSS_MAX := 8 + +# Terrain-Höhen-Cache (Karte t_4092e3a0): der Objekt-Cursor trifft das GELÄNDE +# (TerrainField.raycast, wie Terrain-/Bauen-/Spawn-Werkzeug), nicht mehr nur +# die flache Basis-Ebene. Dekodiert einmal pro Map-Änderung, nicht pro Mausbewegung. +var _heights := PackedFloat32Array() +var _res := 0 +var _sx := 0.0 +var _sz := 0.0 + +# Auswahl + Greifen +var selected_index := -1 # PRIMÄR-Objekt (letzter Klick) — Grab/Status-Anker +var selected_indices: Array = [] # komplette Auswahl in Klick-Reihenfolge (int-Indizes) +var _dragging := false +var _drag_moved := false +var _press_pos := Vector2.ZERO +var _grab_offset := Vector3.ZERO # Einzel-Greifen (Rückwärtskompatibilität) +var _drag_lift := 0.0 # Terrain-Abstand des Objekts beim Anfassen (Höhe hebt sich mit) + +# Gruppen-/Mehrfach-Ziehen (Karte t_f6f29d86) +var _drag_members: Array = [] # Indizes, die GEMEINSAM ziehen +var _grab_offsets: Dictionary = {} # index (int) → Vector3 (y = 0) +var _drag_lifts: Dictionary = {} # index (int) → float (Terrain-Abstand beim Anfassen, t_7567a06f) +var _drag_primary := -1 # Anker-Objekt (Raster-Snap & Delta-Herkunft) +var _drag_is_group := false # Zieh-Menge = komplette svmap-Gruppe + +# Rahmen-Ausziehen (Rubberband) über leeren Boden +var _rubber_pending := false # Press auf leerer Fläche, noch nicht geschwenkt +var _rubber_active := false # Rahmen wird gerade aufgezogen +var _rubber_start := Vector2.ZERO +var _rubber_shift := false # Umschalt: Rahmen zur Auswahl HINZUFÜGEN + +# Strg halten = temporärer Snap-Zwang (Karte t_55257792): egal was der +# Raster-Snap-Schalter sagt — solange Strg unten ist, rastet Bewegen/Platzieren. +# Aus JEDEM durchgelassenen Input-Event aktualisiert (Maus- UND Taste). +var _ctrl_held := false + +# Greifen (Karte t_55257792, G — Blender-Semantik): die Auswahl hängt an der +# Maus, Linksklick setzt die neue Position (EIN Undo-Schritt), Esc bricht ab +# und stellt die EXAKTEN alten Positionen wieder her. +var _grabbing := false +var _grab_members: Array = [] # Indizes der Greif-Menge (inkl. Gruppe) +var _grab_primary := -1 +var _grab_originals: Dictionary = {} # idx (int) → [x, y, z] exakt (Rückabwicklung) +var _grab_lifts: Dictionary = {} # idx (int) → Terrain-Abstand beim Anfassen +var _grab_before: Dictionary = {} # History-Snapshot VOR dem Greifen +# Symmetrie-Zwillinge beim Greifen (M3, t_34908425): Mitglied → Partner-Index; +# Originale der Partner, die NICHT selbst greifen (für die Esc-Rückabwicklung). +var _grab_twin_map: Dictionary = {} # idx (int) → partner index (int) +var _grab_twin_originals: Dictionary = {} # partner idx (int) → [x, y, z] exakt + + +func setup(p_main, p_camera: Camera3D, p_builder) -> void: + main = p_main + camera = p_camera + view_builder = p_builder + refresh_terrain_cache() # t_4092e3a0: Cursor trifft das Gelände ab der ersten Mausbewegung + + +## Symmetrie-Modus aus dem Hauptfenster lesen (M3, t_34908425). Fehlt das Feld +## (ältere Test-Doppel, Setup-Reihenfolgen), gilt Aus — nie ein harter Fehler. +func _sym_mode() -> int: + var v: Variant = main.get("sym_mode") if main != null else null + return int(v) if v is int else SymmetryCore.Mode.OFF + + +## Kamera fragt: dreht das Mausrad gerade ein Objekt/eine Vorschau +## (dann zoomt das Rad NICHT)? Im Freelook-Flug (t_c46d31c2) blockt das Rad +## zusätzlich ALLE Objekt-Reaktionen — dort ändert es die Grundgeschwindigkeit. +func wheel_blocked() -> bool: + if _camera_flying(): + return true + return placing or selected_index >= 0 + + +func _camera_flying() -> bool: + return camera != null and camera.has_method("fly_active") \ + and bool(camera.call("fly_active")) + + +## Höhen-Cache auffrischen (Karte t_4092e3a0): NACH Terrain-Edits, Undo/Redo, +## Laden/Neu — main ruft das in _after_structure_change. Ein Decode pro +## Änderung statt pro Mausbewegung (129×129-Quantisierung bleibt billig). +func refresh_terrain_cache() -> void: + var terrain: Dictionary = main.doc.get("terrain", {}) + _res = int(terrain.get("resolution", 0)) + _sx = float(terrain.get("size_x_m", 0.0)) + _sz = float(terrain.get("size_z_m", 0.0)) + if _res >= 2 and _sx > 0.0 and _sz > 0.0: + _heights = SvmapIO.decode_heights(terrain) + else: + _heights = PackedFloat32Array() + + +func _ground_point(viewport_pos: Vector2) -> Variant: + # Cursor-Strahl → erster Treffer AUF DEM GELÄNDE (Karte t_4092e3a0): die + # Höhenform zählt, nicht die flache Basis-Ebene — sonst landet ein Objekt + # auf einem Hügel versetzt hinter dem Cursor. Gleicher Pfad wie Terrain-, + # Bauen- und Spawn-Werkzeug (TerrainField.raycast). Rückgabe null = kein + # Treffer (Strahl ins Leere / außerhalb der Map). + var terrain: Dictionary = main.doc.get("terrain", {}) + if terrain.is_empty(): + return null + var origin := camera.project_ray_origin(viewport_pos) + var dir := camera.project_ray_normal(viewport_pos) + if _res >= 2 and _heights.size() >= _res * _res: + return TerrainField.raycast(_heights, _res, _sx, _sz, origin, dir) + # Fallback (Map ohne brauchbares Höhenfeld): Basis-Ebene wie bisher. + var plane_y := float(terrain.get("min_height_m", 0.0)) + if absf(dir.y) < 0.0001: + return null + var t := (plane_y - origin.y) / dir.y + if t <= 0.0: + return null + return origin + dir * t + + +func _terrain_half() -> Vector2: + var terrain: Dictionary = main.doc.get("terrain", {}) + return Vector2(float(terrain.get("size_x_m", 1024.0)), float(terrain.get("size_z_m", 1024.0))) * 0.5 + + +## Cursor-Strahl → getroffenes Objekt. Rückgabe: Index in doc.objects oder -1. +## Zwei Stufen (Mauer-Klick-Fix 24.10.): Die Kugel-Näherung der Marker ist nur +## noch Vorfilter — entschieden wird über den EXAKTEN Treffer auf den echten +## Mesh-Dreiecken (nächstes getroffenes Objekt gewinnt). Nur wenn der Strahl +## kein Mesh trifft, zählt wie bisher die nächste Kugel (kleine Objekte und +## Platzhalter bleiben leicht anklickbar). +func _pick_object(viewport_pos: Vector2) -> int: + var origin := camera.project_ray_origin(viewport_pos) + var dir := camera.project_ray_normal(viewport_pos) + var ground: Variant = _ground_point(viewport_pos) + var ground_t := INF + if ground != null: + ground_t = (ground as Vector3).distance_to(origin) + var exact := -1 + var exact_t := INF + var best := -1 + var best_t := INF + for marker in view_builder.object_markers: + if marker == null or not is_instance_valid(marker): + continue + var center: Vector3 = marker.global_position + Vector3.UP * float(marker.get_meta("half_height", 1.0)) + var to_center := center - origin + var tca := to_center.dot(dir) + if tca <= 0.0: + continue + var d2 := to_center.length_squared() - tca * tca + var radius := float(marker.get_meta("pick_radius", 1.0)) + if d2 > radius * radius: + continue + var t := tca - sqrt(radius * radius - d2) + if t < best_t and t < ground_t + 0.01: + best = int(marker.get_meta("obj_index", -1)) + best_t = t + var mi := SelectionMath.marker_mesh(marker) + if mi != null and mi.mesh != null: + var mt := SelectionMath.ray_mesh_distance(mi.global_transform, + SelectionMath.mesh_faces(mi.mesh), origin, dir) + if mt >= 0.0 and mt < exact_t and mt < ground_t + 0.01: + exact = int(marker.get_meta("obj_index", -1)) + exact_t = mt + return exact if exact >= 0 else best + + +# ------------------------------------------------------------ Platzieren ---- + +func start_placement(oid: String) -> void: + place_oid = oid + placing = true + place_rot_deg = 0.0 + place_tilt_x = 0.0 + place_tilt_z = 0.0 + _place_series = BauKatalog.ist_bau(oid) # U5: Einmal-Modus; Bauteile = Serie (Esc beendet) + _ghost_active = false + _build_last = {} + _build_hit = {} + _build_hint = "" + refresh_terrain_cache() # Cursor trifft das GELÄNDE — Cache muss frisch sein + _ensure_ghost() + _ensure_ghost_visible() + var label: String = main.object_label(oid) + if BauKatalog.ist_bau(oid): + main.call("_set_status", "%s: Maus über die Karte — die Vorschau rastet auf Zelle/Kante ein. Klick setzt, R dreht, Esc beendet. Klick auf die Wandseite ersetzt das Teil (z. B. Tür), Klick auf die Oberkante stapelt." % label) + main.call("_highlight_library", oid) + return + var hinweis := "" if not GlbMeshStore.fehlt(oid) \ + else " (Platzhalter — echte GLB fehlt für %s)" % oid + main.call("_set_status", "%s%s: führe die Maus über die Karte — Klick setzt es. Mausrad dreht vorher, ESC bricht ab (Rechte Maustaste = Flug)." % [label, hinweis]) + main.call("_highlight_library", oid) + + +func cancel_placement() -> void: + if _ghost != null and is_instance_valid(_ghost): + _ghost.visible = false + placing = false + place_oid = "" + _place_series = false + _ghost_active = false + _build_last = {} + _build_hit = {} + build_geschoss = -1 + main.call("_highlight_library", "") + main.call("_base_tool_status") + + +## U5 (t_5e3e97c9): Ein Setz-Klick beendet das Platzier-Werkzeug und wählt +## GENAU das neue Objekt aus (Baum-Markierung + Inspektor folgen über +## select_object). Ghost aus, Kachel-Hervorhebung im Assets-Panel aus +## (_highlight_library("")), das Objekt-Werkzeug bleibt das aktive Werkzeug. +## from_tree=true: der Baum wird bereits von _apply_selection_view markiert — +## kein zweites Auswahl-Ereignis (Auswahl-Stabilität, Karten-Test). +## Aufruf VOR der Klartext-Statusmeldung: die letzte Meldung gewinnt. +func finish_placement_and_select(new_index: int) -> void: + if _ghost != null and is_instance_valid(_ghost): + _ghost.visible = false + placing = false + place_oid = "" + _place_series = false + _ghost_active = false + main.call("_highlight_library", "") + select_object(new_index, true) + + +func _ensure_ghost() -> void: + if _ghost != null and is_instance_valid(_ghost): + return + # Struktur WIE der Viewport-Bauer (map_view_builder._build_objects): + # Root auf dem Fußpunkt, Kind-Mesh um half_height gehoben. So kann Ghost + # und platziertes Objekt nie auseinanderfallen (Karte t_4092e3a0). + _ghost = Node3D.new() + _ghost_mi = MeshInstance3D.new() + var mat := StandardMaterial3D.new() + mat.albedo_color = Color(0.6, 0.9, 1.0, 0.45) + mat.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA + mat.emission_enabled = true + mat.emission = Color(0.2, 0.5, 0.8) * 0.4 + _ghost_mi.material_override = mat + _ghost.add_child(_ghost_mi) + add_child(_ghost) + _ghost.visible = false + + +func _ghost_refresh_mesh() -> void: + var lib: Dictionary = main.manifest.get("objects", {}) + var entry: Dictionary = lib.get(place_oid, {}) + var col: Dictionary = entry.get("collision", {}) + # Echtes GLB vorziehen (Karte t_9b50b231) — die Vorschau zeigt das + # Modell, das landet, nicht nur die Kollisionsform. Ohne GLB: Platzhalter. + var mesh := GlbMeshStore.mesh_fuer(place_oid) + if mesh == null: + mesh = MeshShapes.make_placeholder(str(col.get("shape", "box")), col, 1.0) + _ghost_mi.mesh = mesh + # Gleicher Lift wie beim platzierten Objekt: Mesh-Unterseite = Fußpunkt. + _ghost_mi.position.y = MeshShapes.half_height(mesh) + + +func _ensure_ghost_visible() -> void: + _ghost_refresh_mesh() + _ghost_rotation_anwenden() + _ghost.visible = true + + +## Ghost-Rotation inkl. Kippen (Karte t_e166e656): Euler (X-Kippen, Y-Drehung, +## Z-Kippen) — derselbe Weg wie beim platzierten Objekt (rot_setzen schreibt +## genau diese drei Werte). +func _ghost_rotation_anwenden() -> void: + if _ghost == null or not is_instance_valid(_ghost): + return + if BauKatalog.ist_bau(place_oid): + _bau_ghost_neu() # Drehung ergibt sich aus Kante/Zelle + R + return + _ghost.rotation_degrees = Vector3(place_tilt_x, place_rot_deg, place_tilt_z) + + +## Raster-Snap (wenn in main angeschaltet ODER Strg gehalten wird — temporärer +## Snap-Zwang, Karte t_55257792): X/Z auf ganze Meter rasten — Objekte passen +## dann nebeneinander wie Bauklötze. Höhe bleibt Terrain. +func _apply_grid(pos: Vector3) -> Vector3: + if not (bool(main.get("grid_snap")) or _ctrl_held): + return pos + pos.x = ObjectOps.snap_coord(pos.x, true, GRID_M) + pos.z = ObjectOps.snap_coord(pos.z, true, GRID_M) + return pos + + +## Raster-Snap-Erzwingung fürs Platzieren: Schalter an ODER Strg gehalten. +func _placement_grid_enabled() -> bool: + return bool(main.get("grid_snap")) or _ctrl_held + + +func _ghost_update(viewport_pos: Vector2) -> void: + if BauKatalog.ist_bau(place_oid): + _bau_ghost_update(viewport_pos) + return + var p: Variant = _ground_point(viewport_pos) + if p == null: + _ghost_active = false + _ghost.visible = false + return + _ghost_active = true + # EIN Pfad für Ghost UND Platzierung (Karte t_4092e3a0): Fußpunkt = + # Terrain-Höhe am gerasteten Punkt. Der sichtbare Lift hängt am Kind-Mesh. + _ghost.position = ObjectOps.placement_foot( + main.doc, p as Vector3, _placement_grid_enabled(), _terrain_half(), true) + _ghost.visible = true + + +func _place_object(viewport_pos: Vector2, mb_shift_held := false) -> void: + if BauKatalog.ist_bau(place_oid): + _place_bau(viewport_pos) + return + var p: Variant = _ground_point(viewport_pos) + if p == null: + main.call("_set_status", "Da war kein Boden unter dem Mauszeiger — klicke IN die Karte (die grüne Fläche).", true) + return + var half := _terrain_half() + var foot: Vector3 = ObjectOps.placement_foot( + main.doc, p as Vector3, _placement_grid_enabled(), half, false) + if absf(foot.x) > half.x or absf(foot.z) > half.y: + main.call("_set_status", "Das wäre außerhalb der Map gelandet — klicke innerhalb der grünen Fläche.", true) + return + + # Poly-Budget prüfen, BEVOR etwas passiert (hilfreiche Meldung statt Fehler). + # Symmetrie-Modus (M3, t_34908425): der Zwilling kostet Dasselbe nochmal — + # außer das Objekt liegt auf der Mitte/Achse (wird nicht gedoppelt). + var sym_mode: int = _sym_mode() + var sym_center := SymmetryCore.map_center(main.doc) + var sym_factor := 1.0 + if sym_mode != SymmetryCore.Mode.OFF \ + and not SymmetryCore.maps_to_self(sym_mode, foot, sym_center): + sym_factor = 2.0 + var lib: Dictionary = main.manifest.get("objects", {}) + var entry: Dictionary = lib.get(place_oid, {}) + var poly := float(entry.get("poly", 0)) + var used := SvmapDocument.poly_usage(main.doc, main.manifest) + var budget := float(SvmapIO.MAX_TOTAL_POLY) + if used + poly * sym_factor > budget: + main.call("_set_status", + "Kein Platz mehr im Poly-Budget (%s von %s belegt) — lass ein Objekt weg oder drück Strg+Z, um etwas zurückzunehmen." + % [main._fmt_int(int(used)), main._fmt_int(int(budget))], true) + return + + var before: Dictionary = main.history.snapshot(["objects"]) + # EIN Pfad für Ghost UND Platzierung (Karte t_4092e3a0): derselbe Fußpunkt + # wie die Vorschau — Raster-Snap + Terrain-Höhe am gerasteten Punkt. + var pos_f := [foot.x, foot.y, foot.z] + var neues_obj := { + "id": place_oid, + "pos": pos_f, + "scale": 1.0, # Karte t_e166e656: Scale ist FIX — immer Originalgröße + "rot_y_deg": float(place_rot_deg), + } + # Karte t_e166e656: gekippt platziert → rot-Feld (Euler xyz) in die Datei. + if absf(place_tilt_x) > 0.0001 or absf(place_tilt_z) > 0.0001: + SvmapIO.rot_setzen(neues_obj, Vector3(place_tilt_x, float(place_rot_deg), place_tilt_z)) + (main.doc["objects"] as Array).append(neues_obj) + var new_index: int = (main.doc["objects"] as Array).size() - 1 + # Symmetrie (M3, t_34908425): der Zwilling wandert in denselben Undo-Schritt + # (ein Commit für Quelle + Zwilling) und bekommt dieselbe sym-Kennung. + var twin_index := -1 + var on_axis := false + if sym_mode != SymmetryCore.Mode.OFF: + var symres: Dictionary = ObjectOps.symmetry_place_twin(main.doc, new_index, sym_mode) + twin_index = int(symres.get("twin", -1)) + on_axis = bool(symres.get("on_axis", false)) + main.history.commit("%s platzieren" % main.object_label(place_oid), + before, main.history.snapshot(["objects"])) + main.call("_after_structure_change") + # U5 (t_5e3e97c9): Shift gehalten = Serienmodus (weiter setzen wie bisher, + # Ghost bleibt an) — sonst beendet das Werkzeug sich selbst und DAS NEUE + # Objekt ist ausgewählt (Baum markiert, Inspektor gefüllt). + if mb_shift_held: + _place_series = true + select_object(new_index, true) + if twin_index >= 0: + main.call("_set_status", "Serienmodus (Shift) — ESC beendet. %s platziert, Zwilling jeweils mitgesetzt; Strg+Z nimmt BEIDE je Schritt zurück. Weitere Klicks setzen erneut." % main.object_label(place_oid)) + else: + main.call("_set_status", "Serienmodus (Shift) — ESC beendet. Weitere Klicks setzen erneut; Strg+Z nimmt je Schritt zurück.") + else: + var placed_oid := place_oid # U5: finish leert place_oid — Label vorher sichern + finish_placement_and_select(new_index) + if twin_index >= 0: + main.call("_set_status", "%s gesetzt und ausgewählt — der Spiegel-Zwilling wurde mitgesetzt; Strg+Z nimmt BEIDE zurück. Ziehen verschiebt, R oder Mausrad dreht, Entf löscht." % main.object_label(placed_oid)) + elif on_axis: + main.call("_set_status", "%s gesetzt und ausgewählt — liegt auf der Symmetrie-Mitte und wird NICHT gedoppelt. Ziehen verschiebt, R oder Mausrad dreht, Entf löscht." % main.object_label(placed_oid)) + else: + main.call("_set_status", "%s gesetzt und ausgewählt. Ziehen verschiebt, R oder Mausrad dreht, Entf löscht, Strg+Z nimmt es zurück." % main.object_label(placed_oid)) + + +# ----------------------------------------------------- Bauen (bau_*) ----- + +## Strahl → Treffer auf Gelände ODER einem gesetzten Objekt (Bauteile müssen +## sich auf Wänden/Böden stapeln lassen). Rückgabe {punkt, obj (-1 = Gelände), dir} +## oder {} bei Leerlauf. +func _build_ray_hit(viewport_pos: Vector2) -> Dictionary: + var origin := camera.project_ray_origin(viewport_pos) + var dir := camera.project_ray_normal(viewport_pos) + var ground: Variant = _ground_point(viewport_pos) + if build_geschoss >= 0: + return _build_ray_geschoss(origin, dir, ground) + var best_t := INF + var out := {} + if ground != null: + best_t = (ground as Vector3).distance_to(origin) + out = {"punkt": ground, "obj": -1, "dir": dir} + for marker in view_builder.object_markers: + if marker == null or not is_instance_valid(marker): + continue + var center: Vector3 = marker.global_position + Vector3.UP * float(marker.get_meta("half_height", 1.0)) + var to_center := center - origin + var tca := to_center.dot(dir) + if tca <= 0.0: + continue + var radius := float(marker.get_meta("pick_radius", 1.0)) + if to_center.length_squared() - tca * tca > radius * radius: + continue + var mi := SelectionMath.marker_mesh(marker) + if mi == null or mi.mesh == null: + continue + var mt := SelectionMath.ray_mesh_distance(mi.global_transform, + SelectionMath.mesh_faces(mi.mesh), origin, dir) + if mt >= 0.0 and mt < best_t: + best_t = mt + out = {"punkt": origin + dir * mt, "obj": int(marker.get_meta("obj_index", -1)), "dir": dir} + return out + + +## Feste Geschosshöhe: der Strahl trifft die waagerechte Ebene dieses Geschosses, +## egal ob darunter Wand, Boden oder nur Gelände ist (Decke mitten im Raum). +func _build_ray_geschoss(origin: Vector3, dir: Vector3, ground: Variant) -> Dictionary: + var xz := Vector2(origin.x, origin.z) + if ground != null: + xz = Vector2((ground as Vector3).x, (ground as Vector3).z) + var y := _bau_geschoss_hoehe(xz) + if absf(dir.y) < 0.001: + return {} + var t := (y - origin.y) / dir.y + if t <= 0.0: + return {} + return {"punkt": origin + dir * t, "obj": -1, "dir": dir, "ebene": y} + + +func _bau_gelaende_fn() -> Callable: + return func(x: float, z: float) -> float: + if _res >= 2 and _heights.size() >= _res * _res: + return TerrainField.height_at(_heights, _res, _sx, _sz, x, z) + return float(main.doc.get("terrain", {}).get("min_height_m", 0.0)) + + +func _bau_geschoss_hoehe(xz: Vector2) -> float: + var basis := BuildSnap.geschoss_basis(BuildSnap.sammle_teile(main.doc), xz, _bau_gelaende_fn()) + return basis + float(build_geschoss) * BauKatalog.WAND_H + + +## Bild↑/Bild↓ bzw. Knöpfe im Bauen-Tab: Geschoss wechseln (0 → zurück auf Automatik). +func bau_geschoss_aendern(delta: int) -> void: + var neu := build_geschoss + if delta > 0: + neu = 1 if build_geschoss < 0 else mini(build_geschoss + 1, BAU_GESCHOSS_MAX) + elif build_geschoss >= 0: + neu = build_geschoss - 1 # 0 → -1 (Automatik) + build_geschoss = neu + _build_hint = "" + if placing and not _build_hit.is_empty(): + _bau_ghost_neu() + main.call("_set_status", bau_geschoss_text()) + main.call("_refresh_bau_info") + + +func bau_geschoss_text() -> String: + if build_geschoss < 0: + return "Höhe: automatisch (Gelände bzw. Oberkante des Teils darunter). Bild↑ wählt ein festes Geschoss — dann sitzen Böden/Decken überall im Raum." + return "Höhe: festes Geschoss %d (%s). Bild↑/Bild↓ wechselt, bis „automatisch“ erreicht ist." % [ + build_geschoss, "Erdgeschoss-Boden" if build_geschoss == 0 else "%d × %d m über dem Boden" % [build_geschoss, int(BauKatalog.WAND_H)]] + + +func _bau_ghost_update(viewport_pos: Vector2) -> void: + _build_hit = _build_ray_hit(viewport_pos) + if _build_hit.is_empty(): + _ghost_active = false + _ghost.visible = false + _build_last = {} + return + _bau_ghost_neu() + + +## Snap neu berechnen (Mausbewegung ODER R-Taste) und den Ghost setzen. +func _bau_snap() -> Dictionary: + if _build_hit.is_empty(): + return {} + return BuildSnap.berechne(place_oid, _build_hit["punkt"] as Vector3, place_rot_deg, + BuildSnap.sammle_teile(main.doc), _bau_gelaende_fn(), + int(_build_hit.get("obj", -1)) >= 0, _build_hit.get("dir", Vector3.ZERO) as Vector3, + float(_build_hit.get("ebene", NAN))) + + +func _bau_ghost_neu() -> void: + _build_last = _bau_snap() + if _build_last.is_empty(): + return + var pos: Vector3 = _build_last["pos"] + var half := _terrain_half() + var innerhalb := absf(pos.x) <= half.x and absf(pos.z) <= half.y + _ghost.position = pos + _ghost.rotation_degrees = Vector3(0.0, float(_build_last["rot"]), 0.0) + _ghost_active = true + _ghost.visible = true + var mat := _ghost_mi.material_override as StandardMaterial3D + var hinweis := "" + if not bool(_build_last["ok"]) or not innerhalb: + mat.albedo_color = Color(1.0, 0.25, 0.2, 0.5) + hinweis = str(_build_last["grund"]) if not bool(_build_last["ok"]) else "Außerhalb der Map." + elif int(_build_last["ersetze"]) >= 0: + mat.albedo_color = Color(1.0, 0.7, 0.2, 0.55) + hinweis = "Klick ersetzt das vorhandene Teil durch %s (Strg+Z holt es zurück)." % main.object_label(place_oid) + else: + mat.albedo_color = Color(0.6, 0.9, 1.0, 0.45) + if hinweis != _build_hint: + _build_hint = hinweis + if not hinweis.is_empty(): + main.call("_set_status", hinweis) + + +## Klick im Bauen-Modus: Teil setzen/ersetzen — ein Undo-Schritt, Teil landet im +## laufenden Gebäude (Gruppe), Serie bleibt aktiv (Esc beendet). +func _place_bau(viewport_pos: Vector2) -> void: + _build_hit = _build_ray_hit(viewport_pos) + if _build_hit.is_empty(): + main.call("_set_status", "Da war nichts unter dem Mauszeiger — klicke IN die Karte (die grüne Fläche).", true) + return + var snap := _bau_snap() + if snap.is_empty(): + return + var pos: Vector3 = snap["pos"] + var half := _terrain_half() + if absf(pos.x) > half.x or absf(pos.z) > half.y: + main.call("_set_status", "Das wäre außerhalb der Map gelandet — klicke innerhalb der grünen Fläche.", true) + return + if not bool(snap["ok"]): + main.call("_set_status", str(snap["grund"]), true) + return + var objects: Array = main.doc["objects"] + var ersetzt := int(snap["ersetze"]) >= 0 + var lib: Dictionary = main.manifest.get("objects", {}) + var poly := float((lib.get(place_oid, {}) as Dictionary).get("poly", 0)) + var sym_mode: int = _sym_mode() + var sym_factor := 1.0 + if sym_mode != SymmetryCore.Mode.OFF and not SymmetryCore.maps_to_self( + sym_mode, pos, SymmetryCore.map_center(main.doc)): + sym_factor = 2.0 + if not ersetzt and objects.size() + int(sym_factor) > SvmapIO.MAX_OBJECTS: + main.call("_set_status", "Limit erreicht: In eine Map passen maximal %d Objekte — das Löschen von Objekten macht wieder Platz." % SvmapIO.MAX_OBJECTS, true) + return + var used := SvmapDocument.poly_usage(main.doc, main.manifest) + var budget := float(SvmapIO.MAX_TOTAL_POLY) + if used + poly * sym_factor > budget: + main.call("_set_status", + "Kein Platz mehr im Poly-Budget (%s von %s belegt) — lass ein Teil weg oder drück Strg+Z." + % [main._fmt_int(int(used)), main._fmt_int(int(budget))], true) + return + var keys := ["objects", "group_names"] + var before: Dictionary = main.history.snapshot(keys) + if not before.has("group_names"): + before["group_names"] = null # Undo entfernt die neu angelegten Gebäude-Namen wieder + var label: String = main.object_label(place_oid) + var gid := _bau_gruppe() + var spiegel := -1 + if sym_mode != SymmetryCore.Mode.OFF and sym_factor > 1.0: + spiegel = _bau_spiegel_gruppe(gid) + BauOps.setze_teil(main.doc, place_oid, snap, gid, sym_mode, spiegel) + main.history.commit("%s bauen" % label if not ersetzt else "%s einsetzen" % label, + before, main.history.snapshot(keys)) + main.call("_after_structure_change") + _build_hit = _build_ray_hit(viewport_pos) + _bau_ghost_neu() + main.call("_set_status", "%s %s (%s, %d Teile). Weiter klicken — R dreht, Esc beendet, Strg+Z nimmt das letzte Teil zurück." % [ + label, "eingesetzt" if ersetzt else "gesetzt", GroupState.display_name(main.doc, gid), + GroupOps.members_of(main.doc, gid).size()]) + main.call("_refresh_bau_info") + + +## Laufendes Gebäude (Gruppe): bestehende Gruppe weiterführen oder neue anlegen +## und benennen. Rückgabe: Gruppen-ID. +func _bau_gruppe() -> int: + if build_group_id >= 0 and not GroupOps.members_of(main.doc, build_group_id).is_empty(): + return build_group_id + build_group_id = BauOps.gruppe_neu(main.doc) + return build_group_id + + +## Gruppe für den Spiegel-Zwilling des laufenden Gebäudes (1 Gebäude ↔ 1 Spiegel). +var _bau_spiegel: Dictionary = {} # laufende ID → Spiegel-ID + +func _bau_spiegel_gruppe(gid: int) -> int: + var sp := int(_bau_spiegel.get(gid, -1)) + if sp >= 0 and not GroupOps.members_of(main.doc, sp).is_empty(): + return sp + sp = maxi(GroupOps.next_group_id(main.doc), gid + 1) + GroupState.set_group_name(main.doc, sp, "%s (Spiegel)" % GroupState.display_name(main.doc, gid)) + _bau_spiegel[gid] = sp + return sp + + +## Nächstes Teil beginnt ein NEUES Gebäude (Button „Neues Gebäude“). +func neues_gebaeude() -> void: + build_group_id = -1 + _bau_spiegel.clear() + + +## Demo-Hook: Ghost an einem Punkt parken (Screenshots ohne Maus). +func demo_park_bau(punkt: Vector3) -> void: + _build_hit = {"punkt": punkt, "obj": -1, "dir": Vector3.ZERO} + _bau_ghost_neu() + + +# --------------------------------------------------------------- Auswahl ---- + +## Einzel-Auswahl (Klick ins Objekt / Klick im Baum): ersetzt die Auswahl. +func select_object(idx: int, from_tree := false) -> void: + selected_indices = [idx] if idx >= 0 else [] + selected_index = idx + _apply_selection_view() + if not from_tree: + main.call("_mark_tree_selection", idx) + main.call("_selection_status", idx) + + +## Mehrere auf einmal (Rahmen-Ausziehen, Demo) — Reihenfolge bleibt erhalten. +func select_many(indices: Array, silent := false) -> void: + var objects: Array = main.doc.get("objects", []) + selected_indices = [] + for i in indices: + if i is int and i >= 0 and i < objects.size(): + selected_indices.append(i) + selected_index = selected_indices.back() if not selected_indices.is_empty() else -1 + _apply_selection_view() + if not silent: + main.call("_selection_status", selected_index) + + +## Umschalt+Klick: Objekt zur Auswahl HINZUFÜGEN (oder wieder rausnehmen). +func select_toggle(idx: int) -> void: + var objects: Array = main.doc.get("objects", []) + if idx < 0 or idx >= objects.size(): + return + var label: String = main.object_label(str(objects[idx].get("id", ""))) + if selected_indices.has(idx): + selected_indices.erase(idx) + if selected_index == idx: + selected_index = selected_indices.back() if not selected_indices.is_empty() else -1 + main.call("_set_status", "%s aus der Auswahl genommen — noch %d Objekte markiert. Umschalt-/Strg+Klick fügt wieder hinzu." % [label, selected_indices.size()]) + else: + selected_indices.append(idx) + selected_index = idx + main.call("_set_status", "%s zur Auswahl dazugeholt — jetzt %d Objekte. Mehr umschalten (Umschalt-/Strg+Klick), Rahmen aufziehen oder Strg+G zum Gruppieren." % [label, selected_indices.size()]) + _apply_selection_view() + main.call("_sync_selection_panel") + + +func clear_selection(silent := false) -> void: + if selected_index != -1 or not selected_indices.is_empty(): + selected_indices = [] + selected_index = -1 + view_builder.call("set_selected_multi", []) + if not silent: + main.call("_set_status", "Auswahl aufgehoben.") + main.call("_sync_selection_panel") + + +## Auswahl-Anzeige (Viewport-Färbung + Baum + Panel) aus dem aktuellen Stand. +func _apply_selection_view() -> void: + view_builder.call("set_selected_multi", selected_indices) + # Baum GANZ synchron (Karte t_c46d31c2): auch Abwählen per Strg+Klick im + # Viewport entfernt die Baum-Markierung wieder. + main.call("_mark_tree_selection_multi", selected_indices) + if selected_index >= 0: + main.call("_mark_tree_selection", selected_index) + + +## Ausgewählte Objekte zu EINER Gruppe machen (main-Button/Strg+G). +func group_selection() -> void: + var objects: Array = main.doc.get("objects", []) + var valid: Array = [] + for i in selected_indices: + if i is int and i >= 0 and i < objects.size(): + valid.append(i) + if valid.size() < 2: + main.call("_set_status", "Eine Gruppe braucht mindestens 2 Objekte — markiere zuerst mehrere (Umschalt+Klick oder Rahmen aufziehen).", true) + return + var before: Dictionary = main.history.snapshot(["objects"]) + var gid := GroupOps.group(main.doc, valid) + main.history.commit("Auswahl gruppieren (%d Objekte → Gruppe %d)" % [valid.size(), gid + 1], + before, main.history.snapshot(["objects"])) + _mark_dirty() + main.call("_refresh_history_buttons") + _apply_selection_view() + main.call("_sync_selection_panel") + main.call("_set_status", "Gruppe %d gebaut: %d Objekte ziehen und drehen jetzt GEMEINSAM. „Gruppe lösen“ (Strg+Umschalt+G) macht es rückgängig — die Objekte bleiben, nur die Bindung löst sich." % [gid + 1, valid.size()]) + + +## Gruppe(n) der Auswahl komplett lösen (main-Button/Strg+Umschalt+G). +func ungroup_selection() -> void: + var groups: Array = GroupOps.groups_of(main.doc, selected_indices) + if groups.is_empty(): + main.call("_set_status", "In der Auswahl steckt keine Gruppe — markiere zuerst ein Objekt aus einer Gruppe.", true) + return + var before: Dictionary = main.history.snapshot(["objects"]) + var freed := GroupOps.ungroup(main.doc, selected_indices) + main.history.commit("Gruppe gelöst (%d Objekte)" % freed, + before, main.history.snapshot(["objects"])) + _mark_dirty() + main.call("_refresh_history_buttons") + _apply_selection_view() + main.call("_sync_selection_panel") + main.call("_set_status", "Gruppe gelöst: %d Objekte sind wieder einzeln verschiebbar — Strg+Z baut die Gruppe wieder zusammen." % freed) + + +# ---------------------------------------------------- Drehen / Löschen ------ + +## Auswahl drehen (R / Mausrad / Button): bei mehreren Objekten oder einer +## Gruppe rotiert ALLES gemeinsam um den Gruppen-Mittelpunkt. Mausrad-Ticks +## derselben Auswahl laufen zu EINEM Undo-Schritt zusammen (merge_tag). +func rotate_selected(delta_deg: float, merge_suffix: String = "") -> void: + if selected_index < 0 or selected_indices.is_empty(): + return + var objects: Array = main.doc.get("objects", []) + if selected_index >= objects.size(): + return + var members := selected_indices.duplicate() + # Einzelnes Objekt, das in einer Gruppe steckt → die GANZE Gruppe drehen + # (Sly-Erwartung: die Gruppe dreht gemeinsam) und sichtbar markieren. + if members.size() == 1: + var gid := GroupOps.group_id(objects[members[0]]) + if gid != GroupOps.UNGROUPED: + members = GroupOps.members_of(main.doc, gid) + select_many(members, true) + main.call("_sync_selection_panel") + var before: Dictionary = main.history.snapshot(["objects"]) + GroupOps.rotate_members(main.doc, members, delta_deg) + _sync_members_to_markers(members) + # Symmetrie (M3, t_34908425): Zwillinge der gedrehten Auswahl auf den exakten + # Spiegel setzen (Punkt: +180°-Basis, Achse: Vorzeichen) — IM SELBEN Commit. + var twins: Array = ObjectOps.symmetry_sync_pairs( + main.doc, members, _sym_mode(), selected_index) + _sync_members_to_markers(twins) + var tag := "rotmulti:%s%s" % [str(members), merge_suffix] + main.history.commit("Auswahl gedreht (%d Objekte)" % members.size(), + before, main.history.snapshot(["objects"]), tag) + _mark_dirty() + main.call("_refresh_history_buttons") + main.call("_refresh_stats") + main.call("_sync_selection_panel") + + +## Auswahl KIPPEN (Karte t_e166e656 — Sly: „nicht nur rotieren, sondern auch +## kippen in sämtliche Achsen“). axis_x = Kippen um die X-Achse (vor/zurück +## neigen), sonst um die Z-Achse (links/rechts neigen). Ein Einzelobjekt in +## einer Gruppe kippt die GANZE Gruppe (wie beim Drehen), Mehrfachauswahl +## kippt jedes Objekt um denselben Betrag, Symmetrie-Zwillinge laufen im +## SELBEN Commit mit. rot/rot_y_deg bleiben über SvmapIO.rot_setzen synchron. +func tilt_selected(axis_x: bool, delta_deg: float, merge_suffix: String = "") -> void: + if selected_index < 0 or selected_indices.is_empty(): + return + var objects: Array = main.doc.get("objects", []) + if selected_index >= objects.size(): + return + var members := selected_indices.duplicate() + if members.size() == 1: + var gid := GroupOps.group_id(objects[members[0]]) + if gid != GroupOps.UNGROUPED: + members = GroupOps.members_of(main.doc, gid) + select_many(members, true) + main.call("_sync_selection_panel") + var before: Dictionary = main.history.snapshot(["objects"]) + var axis := "X" if axis_x else "Z" + for i in members: + var obj: Dictionary = objects[i] + var euler := SvmapIO.objekt_rotation(obj) + var neu := Vector3(euler.x, euler.y, euler.z) + if axis_x: + neu.x = fposmod(euler.x + delta_deg + 3600.0, 360.0) + else: + neu.z = fposmod(euler.z + delta_deg + 3600.0, 360.0) + SvmapIO.rot_setzen(obj, neu) + _sync_members_to_markers(members) + var twins: Array = ObjectOps.symmetry_sync_pairs( + main.doc, members, _sym_mode(), selected_index) + _sync_members_to_markers(twins) + var tag := ("tilt:%d" % selected_index if members.size() == 1 \ + else "tiltmulti:%s" % str(members)) + merge_suffix + main.history.commit("Auswahl gekippt (%s, %d Objekte)" % [axis, members.size()], + before, main.history.snapshot(["objects"]), tag) + _mark_dirty() + main.call("_refresh_history_buttons") + main.call("_refresh_stats") + main.call("_sync_selection_panel") + main.call("_set_status", "Auswahl um %s%s gekippt — Inspektor zeigt die Werte; Strg+Z nimmt den Schritt zurück." % [ + ("+%.0f°" % delta_deg) if delta_deg > 0.0 else ("%.0f°" % delta_deg), axis]) + + +## Nach Doc-Änderung die betroffenen Marker positionieren/drehen (kein Rebuild). +func _sync_members_to_markers(members: Array) -> void: + var objects: Array = main.doc.get("objects", []) + for i in members: + if i >= view_builder.object_markers.size(): + continue + var marker: Node3D = view_builder.object_markers[i] + if marker == null or not is_instance_valid(marker): + continue + var pos: Array = (objects[i] as Dictionary).get("pos", [0.0, 0.0, 0.0]) + marker.position = Vector3(float(pos[0]), float(pos[1]), float(pos[2])) + # Karte t_e166e656: volle 3-Achsen-Rotation (rot-Feld oder Fallback rot_y_deg). + marker.rotation_degrees = SvmapIO.objekt_rotation(objects[i] as Dictionary) + + +func delete_selected() -> void: + if selected_indices.is_empty() or selected_index < 0: + main.call("_set_status", "Nichts ausgewählt — klicke zuerst ein Objekt an, das gelöscht werden soll.", true) + return + var objects: Array = main.doc.get("objects", []) + var doomed: Array = [] + for i in selected_indices: + if i is int and i >= 0 and i < objects.size(): + doomed.append(i) + if doomed.is_empty(): + clear_selection(true) + return + # Symmetrie (M3, t_34908425): die Partner der Auswahl löschen sich MIT — + # ein Paar lebt oder stirbt zusammen, IM SELBEN Undo-Schritt. + doomed = ObjectOps.symmetry_expand_delete(main.doc, doomed, _sym_mode()) + var before: Dictionary = main.history.snapshot(["objects", "group_names"]) + if not before.has("group_names"): + before["group_names"] = null + var label: String + if doomed.size() == 1: + label = "%s löschen" % main.object_label(str(objects[doomed[0]].get("id", ""))) + else: + label = "%d Objekte löschen" % doomed.size() + # Rückwärts löschen, damit die Indizes währenddessen stimmen. + doomed.sort() + doomed.reverse() + for i in doomed: + objects.remove_at(i) + GroupState.prune_orphans(main.doc) # Gebäude ohne Teile verlieren ihren Namen + main.history.commit(label, before, main.history.snapshot(["objects", "group_names"])) + clear_selection(true) + main.call("_after_structure_change") + main.call("_set_status", "%s ist erledigt — Strg+Z (Rückgängig) holt %s zurück." % [ + label, "alles" if doomed.size() > 1 else "es"]) + + +# ------------------------------------------ Duplizieren/Höhe/Spiegeln ------ +## (Karte t_7567a06f — alle drei auch bei Sly bedienbar: Button rechts + +## Tastenkürzel, alles über ActionHistory, Klartext-Status-Hilfe.) + +## Strg+D / Button "Duplizieren" (Karte t_c46d31c2): JEDE Kopie rastet +2 m in +## X versetzt ein (Füßpunkt-Höhe unverändert, mit Raster-Snap eingerastet, wenn +## an) — bei Mehrfachauswahl werden ALLE Objekte kopiert, EIN Undo-Schritt für +## alle Kopien, die Kopien sind direkt als neue Auswahl angewählt. Poly-Budget +## und Objekt-Limit werden VOR dem Kopieren gesammelt geprüft. +func duplicate_selected() -> void: + var objects: Array = main.doc.get("objects", []) + var sources: Array = [] + for i in selected_indices: + if i is int and i >= 0 and i < objects.size(): + sources.append(i) + if sources.is_empty(): + main.call("_set_status", "Nichts ausgewählt — klicke zuerst ein Objekt an, das du kopieren willst.", true) + return + if objects.size() + sources.size() > SvmapIO.MAX_OBJECTS \ + and _sym_mode() == SymmetryCore.Mode.OFF: + main.call("_set_status", "Limit erreicht: In eine Map passen maximal %d Objekte — das Löschen von Objekten macht wieder Platz." % SvmapIO.MAX_OBJECTS, true) + return + var lib: Dictionary = main.manifest.get("objects", {}) + var sym_mode: int = _sym_mode() + var sym_center := SymmetryCore.map_center(main.doc) + var twins_planned := 0 + var poly_sum := 0.0 + for i in sources: + var src_obj: Dictionary = objects[i] + var scl := float(src_obj.get("scale", 1.0)) + var entry: Dictionary = lib.get(str(src_obj.get("id", "")), {}) + poly_sum += float(entry.get("poly", 0)) * scl * scl + # Symmetrie (M3, t_34908425): JEDE Kopie bekommt einen Zwilling (außer + # auf der Mitte/Achse) — Budget und Objekt-Limit VORAB mitrechnen. + if sym_mode != SymmetryCore.Mode.OFF: + var spos: Array = src_obj.get("pos", [0.0, 0.0, 0.0]) + if (spos as Array).size() == 3 and not SymmetryCore.maps_to_self( + sym_mode, Vector3(float(spos[0]), float(spos[1]), float(spos[2])), sym_center): + twins_planned += 1 + poly_sum += float(entry.get("poly", 0)) * scl * scl + if twins_planned > 0 and objects.size() + sources.size() + twins_planned > SvmapIO.MAX_OBJECTS: + main.call("_set_status", "Limit erreicht: In eine Map passen maximal %d Objekte — mit Symmetrie-Zwilllingen bräuchte es %d. Das Löschen von Objekten macht wieder Platz." % [SvmapIO.MAX_OBJECTS, objects.size() + sources.size() + twins_planned], true) + return + var used := SvmapDocument.poly_usage(main.doc, main.manifest) + var budget := float(SvmapIO.MAX_TOTAL_POLY) + if used + poly_sum > budget: + main.call("_set_status", "Für %s fehlt das Poly-Budget (%s von %s belegt) — Strg+Z nimmt etwas zurück, oder lösche ein anderes Objekt." % [ + "die Kopien" if sources.size() > 1 else "eine Kopie", + main._fmt_int(int(used)), main._fmt_int(int(budget))], true) + return + var before: Dictionary = main.history.snapshot(["objects", "group_names"]) + if not before.has("group_names"): + before["group_names"] = null # Undo entfernt die Namen der Kopie-Gruppen wieder + # Gebäude (Bauteile): Kopie rückt um die Gebäudebreite weg statt 2 m — sonst + # läge sie halb im Original. + var offset_x := ObjectOps.DUPLICATE_OFFSET_M.x + var bau_min := INF + var bau_max := -INF + for i in sources: + var so: Dictionary = objects[i] + if BauKatalog.ist_bau(str(so.get("id", ""))): + var spx := float((so.get("pos", [0.0, 0.0, 0.0]) as Array)[0]) + bau_min = minf(bau_min, spx) + bau_max = maxf(bau_max, spx) + if bau_min < INF: + offset_x = maxf(offset_x, ceilf((bau_max - bau_min + 4.0) / 2.0) * 2.0) + var new_indices: Array = ObjectOps.duplicate_objects(main.doc, sources, bool(main.get("grid_snap")), offset_x) + if new_indices.is_empty(): + clear_selection(true) + return + # Symmetrie (M3, t_34908425): jede Kopie bekommt ihren Zwilling (exakter + # Spiegel der KOPIE, neue sym-Kennung) — im selben Commit wie die Kopien. + var sym_twins: Array = [] + if sym_mode != SymmetryCore.Mode.OFF: + for c in new_indices: + if c is int: + var sres: Dictionary = ObjectOps.symmetry_place_twin(main.doc, c, sym_mode) + if int(sres.get("twin", -1)) >= 0: + sym_twins.append(int(sres["twin"])) + var label: String + if new_indices.size() == 1: + label = "%s duplizieren" % main.object_label(str((objects[sources[0]] as Dictionary).get("id", ""))) + else: + label = "%d Objekte duplizieren" % new_indices.size() + main.history.commit(label, before, main.history.snapshot(["objects", "group_names"])) + main.call("_after_structure_change") + # Kopien direkt anwählen — Sly kann sie gleich weiterziehen. Die frischen + # Zwillinge wandern mit in die Auswahl (beide Seiten sichtbar markiert). + var selected_new: Array = new_indices.duplicate() + selected_new.append_array(sym_twins) + select_many(selected_new) + if sym_twins.is_empty(): + main.call("_set_status", "%s: die Kopie(n) liegen +2 m versetzt und sind direkt angewählt — Ziehen verschiebt, Entf löscht, Strg+Z nimmt ALLE Kopien auf einmal zurück." % label) + else: + main.call("_set_status", "%s: %d Kopie(n) + %d Zwilling(e) sind direkt angewählt — jede Kopie bildet mit ihrem Zwilling ein neues Paar. Strg+Z nimmt ALLE auf einmal zurück." % [label, new_indices.size(), sym_twins.size()]) + + +## ▲/▼ / Strg+Bild↑/↓: AUSWAHL in 0,25-m-Schritten anheben/absenken +## (Karte t_55257792: die GANZE Auswahl, wie Entf/Strg+D auch). +## Mehrere Klicks in Serie = EIN Undo-Schritt (Merge-Tag, wie beim Drehen). +## Absenken stoppt am Terrain (nichts wird begraben), Anheben an der +## Match-Grenze (bounds.max) — Regeln in ObjectOps.lift_object. +func lift_selected(delta_m: float) -> void: + if selected_index < 0: + main.call("_set_status", "Nichts ausgewählt — klicke zuerst ein Objekt an, das du anheben oder absenken willst.", true) + return + if placing: + return + var objects: Array = main.doc.get("objects", []) + if selected_index >= objects.size(): + clear_selection(true) + return + var members := _lift_members() + var before: Dictionary = main.history.snapshot(["objects"]) + var applied_sum := 0.0 + for i in members: + applied_sum += ObjectOps.lift_object(main.doc, i, delta_m) + if absf(applied_sum) < 0.0001: + # Nichts passiert (Snapshot verwerfen): hilfsbereit erklären, WO die Grenze ist. + var ground: String + if delta_m > 0.0: + ground = "Die Match-Höhe ist erreicht — höher passt der Server nicht mehr." + else: + ground = "Die untere Match-Grenze ist erreicht — tiefer passt der Server nicht mehr (Versenken im Boden ist erlaubt, Karte t_e166e656)." + main.call("_set_status", ground) + return + var after: Dictionary = main.history.snapshot(["objects"]) + var tag := "lift:%d" % selected_index if members.size() == 1 \ + else "liftmulti:%s" % str(members) + main.history.commit(_lift_label(members, delta_m, applied_sum), + before, after, tag) + for i in members: + if i >= view_builder.object_markers.size(): + continue + var marker: Node3D = view_builder.object_markers[i] + if marker != null and is_instance_valid(marker): + marker.position.y = float((objects[i]["pos"] as Array)[1]) + main.dirty = true + main.call("_refresh_file_label") + main.call("_refresh_stats") + main.call("_refresh_history_buttons") + main.call("_sync_selection_panel") + # Karte t_e166e656: Versenk-Tiefe sichtbar machen (Stein halb im Boden). + var sel_pos: Array = (objects[selected_index]["pos"] as Array) + var boden := SvmapDocument.terrain_height_at(main.doc, float(sel_pos[0]), float(sel_pos[2])) + var tiefe := boden - float(sel_pos[1]) + var versenk := "" + if tiefe > 0.01: + versenk = " (%.2f m versenkt)" % tiefe + main.call("_set_status", "%s auf %.2f m%s — mehrmals drücken stapelt weiter; Strg+Z nimmt alle Stufen auf einmal zurück." % [ + _lift_label(members, delta_m, applied_sum), float(sel_pos[1]), versenk]) + + +## Heben/Absenken wirkt auf die GANZE Auswahl (Karte t_55257792) — ein einzelnes +## Objekt, das in einer Gruppe steckt, zieht die ganze Gruppe mit (wie Drehen). +func _lift_members() -> Array: + var members := selected_indices.duplicate() + if members.size() == 1: + var objects: Array = main.doc.get("objects", []) + var gid := GroupOps.group_id(objects[members[0]]) + if gid != GroupOps.UNGROUPED: + members = GroupOps.members_of(main.doc, gid) + select_many(members, true) + main.call("_sync_selection_panel") + return members + + +func _lift_label(members: Array, delta_m: float, applied_sum: float) -> String: + var dir := "angehoben" if delta_m > 0.0 else "abgesenkt" + if members.size() == 1: + return "Objekt %s (%s)" % [dir, "%.2f m" % applied_sum] + return "%d Objekte %s (%.2f m)" % [members.size(), dir, applied_sum] + + +## Strg+Bild↑ (Karte t_55257792): die AUSWAHL direkt auf das Terrain/Boden +## absetzen (Godot "Snap Object to Floor"-Äquivalent fürs Fußpunkt-Modell). +## EIN Undo-Schritt; steht alles schon am Boden → Meldung statt leerem Commit. +func snap_selection_to_floor() -> void: + if selected_indices.is_empty() or selected_index < 0: + main.call("_set_status", "Nichts ausgewählt — Strg+Bild↑ setzt die Auswahl auf den Boden. Klicke zuerst ein Objekt an.", true) + return + if placing: + return + var members := _lift_members() + var before: Dictionary = main.history.snapshot(["objects"]) + var changed := ObjectOps.snap_selection_to_floor(main.doc, members) + if changed == 0: + main.call("_set_status", "Steht schon alles auf dem Boden — nichts zu setzen.") + return + main.history.commit("Auswahl auf Boden gesetzt (%d Objekte)" % changed, + before, main.history.snapshot(["objects"])) + for i in members: + if i >= view_builder.object_markers.size(): + continue + var marker: Node3D = view_builder.object_markers[i] + if marker != null and is_instance_valid(marker): + var pos: Array = ((main.doc.get("objects", []) as Array)[i] as Dictionary).get("pos", [0.0, 0.0, 0.0]) + marker.position = Vector3(float(pos[0]), float(pos[1]), float(pos[2])) + _mark_dirty() + main.call("_refresh_stats") + main.call("_refresh_history_buttons") + main.call("_sync_selection_panel") + main.call("_set_status", "%d Objekt(e) auf den Boden gesetzt — Strg+Z nimmt es zurück." % changed) + + +## Pfeiltasten (Karte t_55257792): Auswahl im 2-m-Raster verschieben — EINE +## Zelle pro Tastendruck, Richtung = Kamera-Ausrichtung nächste Weltachse +## (MoveMath). Fußpunkt bleibt am Raster, Höhe wandert mit (t_7567a06f). +## EIN Undo-Schritt pro Tastendruck. +func nudge_selection(delta: Vector3) -> void: + if selected_indices.is_empty() or selected_index < 0: + main.call("_set_status", "Nichts ausgewählt — Pfeiltasten verschieben die Auswahl im 2-m-Raster. Klicke zuerst ein Objekt an.") + return + if placing: + return + var members := selected_indices.duplicate() + var objects: Array = main.doc.get("objects", []) + if members.size() == 1: + var gid := GroupOps.group_id(objects[members[0]]) + if gid != GroupOps.UNGROUPED: + members = GroupOps.members_of(main.doc, gid) + var before: Dictionary = main.history.snapshot(["objects"]) + var changed := ObjectOps.nudge_objects(main.doc, members, delta) + if changed == 0: + return # am Map-Rand geklemmt — Snapshot verwerfen, kein Commit + _sync_members_to_markers(members) + # Symmetrie (M3, t_34908425): Zwillinge mitführen — exakter Spiegel der + # verschobenen Quelle, im selben Commit (Pfeiltasten = 1 Undo-Schritt). + var twins: Array = ObjectOps.symmetry_sync_pairs( + main.doc, members, _sym_mode()) + _sync_members_to_markers(twins) + var desc := "Objekt verschoben (Pfeiltaste)" if members.size() == 1 \ + else "%d Objekte verschoben (Pfeiltasten)" % members.size() + main.history.commit(desc, before, main.history.snapshot(["objects"])) + _mark_dirty() + main.call("_refresh_history_buttons") + main.call("_refresh_stats") + main.call("_sync_selection_panel") + main.call("_set_status", "%s — 2 m pro Tastendruck. Greifen (G) setzt frei, Strg+Bild↑ setzt auf den Boden." % desc) + + +# ------------------------------------------------------------ Greifen (G) ---- +## Blender-Semantik (Karte t_55257792): G hängt die Auswahl an die Maus, +## Linksklick setzt die neue Position (EIN Undo-Schritt, Raster-Snap wie +## eingestellt bzw. Strg-Zwang), Esc bricht ab und setzt die EXAKTEN alten +## Positionen zurück. Die Auswahl wandert GEMEINSAM (Gruppe/Mehrfachauswahl), +## relative Anordnung bleibt exakt erhalten, Terrain-Abstand je Objekt bleibt. + +## Greifen starten. false = nichts ausgewählt (Meldung steht dann). +func grab_begin() -> bool: + if _grabbing: + return true + if placing: + return false + var objects: Array = main.doc.get("objects", []) + var members := selected_indices.duplicate() + if members.size() == 1: + var gid := GroupOps.group_id(objects[members[0]]) + if gid != GroupOps.UNGROUPED: + members = GroupOps.members_of(main.doc, gid) + select_many(members, true) + main.call("_sync_selection_panel") + if members.is_empty() or selected_index < 0: + main.call("_set_status", "Nichts ausgewählt — G greift die Auswahl, damit du sie mit der Maus frei setzen kannst. Klicke zuerst ein Objekt an.") + return false + _grab_members = members + _grab_primary = selected_index + _grab_originals = {} + _grab_lifts = {} + for i in members: + var pos: Array = (objects[i] as Dictionary).get("pos", [0.0, 0.0, 0.0]) + _grab_originals[i] = [float(pos[0]), float(pos[1]), float(pos[2])] + _grab_lifts[i] = float(pos[1]) - SvmapDocument.terrain_height_at( + main.doc, float(pos[0]), float(pos[2])) + # Symmetrie (M3, t_34908425): Zwillinge der Greif-Menge merken — sie ziehen + # live mit (exakter Spiegel) und Esc setzt sie EXAKT zurück. + _grab_twin_map = {} + _grab_twin_originals = {} + if _sym_mode() != SymmetryCore.Mode.OFF: + for i in members: + if not (i is int) or i < 0 or i >= objects.size() or not (objects[i] is Dictionary): + continue + var sym_key := SymmetryCore.sym_of(objects[i] as Dictionary) + if sym_key.is_empty(): + continue + var t := SymmetryCore.find_partner_index(objects, sym_key, i) + if t < 0: + continue + _grab_twin_map[i] = t + if not members.has(t) and not _grab_twin_originals.has(t): + var tpos: Array = (objects[t] as Dictionary).get("pos", [0.0, 0.0, 0.0]) + if (tpos as Array).size() == 3: + _grab_twin_originals[t] = [float(tpos[0]), float(tpos[1]), float(tpos[2])] + _grabbing = true + _grab_before = main.history.snapshot(["objects"]) + main.call("_set_status", "GREIFEN an: die Auswahl hängt an der Maus — Linksklick setzt sie neu (mit Raster-Snap), Esc bricht ab und setzt zurück.") + return true + + +## Auswahl live zur Cursor-Bodenposition ziehen (Maus-Bewegung ODER Demo-Hook +## mit Weltpunkt). Der Primär-Anker geht EXAKT zum Punkt (rastet, wenn Snap +## an bzw. Strg), die Mitglieder wandern mit demselben Delta mit. +func grab_move(hit: Vector3) -> void: + if not _grabbing: + return + var target := _apply_grid(hit) + var half := _terrain_half() + var primary_pos: Array = _grab_originals[_grab_primary] + var delta := Vector3(target.x - float(primary_pos[0]), 0.0, + target.z - float(primary_pos[2])) + var objects: Array = main.doc.get("objects", []) + for i in _grab_members: + var orig: Array = _grab_originals[i] + var nx := clampf(float(orig[0]) + delta.x, -half.x, half.x) + var nz := clampf(float(orig[2]) + delta.z, -half.y, half.y) + var ny := SvmapDocument.terrain_height_at(main.doc, nx, nz) + float(_grab_lifts[i]) + (objects[i] as Dictionary)["pos"] = [nx, ny, nz] + if i < view_builder.object_markers.size(): + var marker: Node3D = view_builder.object_markers[i] + if marker != null and is_instance_valid(marker): + marker.position = Vector3(nx, ny, nz) + # Symmetrie (M3, t_34908425): Zwillinge live mitziehen — doc + Marker, + # exakter Spiegel der gegriffenen Quelle. + _sym_grab_twin_move() + + +## Linksklick im Greifen: Positionen festschreiben — EIN Undo-Schritt. +func grab_confirm() -> void: + if not _grabbing: + return + _grabbing = false + var desc := "Objekt verschoben (greifen)" if _grab_members.size() == 1 \ + else "%d Objekte verschoben (greifen)" % _grab_members.size() + main.history.commit(desc, _grab_before, main.history.snapshot(["objects"])) + _grab_members = [] + _grab_originals = {} + _grab_lifts = {} + _grab_before = {} + _grab_twin_map = {} + _grab_twin_originals = {} + _mark_dirty() + main.call("_refresh_history_buttons") + main.call("_refresh_stats") + main.call("_sync_selection_panel") + main.call("_set_status", "%s — Strg+Z nimmt den ganzen Zug zurück. G greift erneut, Esc hebt immer ab." % desc) + + +## Esc im Greifen: EXAKTE Rückabwicklung auf die Positionen von grab_begin — +## byte-identisch (keine Float-Re-Rechnung), KEIN History-Eintrag. +func grab_cancel() -> void: + if not _grabbing: + return + _grabbing = false + var objects: Array = main.doc.get("objects", []) + for i in _grab_members: + var orig: Array = _grab_originals[i] + (objects[i] as Dictionary)["pos"] = [float(orig[0]), float(orig[1]), float(orig[2])] + if i < view_builder.object_markers.size(): + var marker: Node3D = view_builder.object_markers[i] + if marker != null and is_instance_valid(marker): + marker.position = Vector3(float(orig[0]), float(orig[1]), float(orig[2])) + # Symmetrie (M3, t_34908425): die MITgezogenen Zwillinge exakt zurücksetzen. + for t in _grab_twin_originals: + var torig: Array = _grab_twin_originals[t] + (objects[t] as Dictionary)["pos"] = [float(torig[0]), float(torig[1]), float(torig[2])] + if t < view_builder.object_markers.size(): + var tmarker: Node3D = view_builder.object_markers[t] + if tmarker != null and is_instance_valid(tmarker): + tmarker.position = Vector3(float(torig[0]), float(torig[1]), float(torig[2])) + _grab_members = [] + _grab_originals = {} + _grab_lifts = {} + _grab_before = {} + _grab_twin_map = {} + _grab_twin_originals = {} + main.call("_set_status", "Greifen abgebrochen — alles ist wieder, wie es war.") + + +## Symmetrie (M3): Zwillinge beim GREIFEN live mitziehen — doc + Marker, +## exakter Spiegel der Quelle. Gehören BEIDE Seiten eines Paares zur Greif- +## Menge, ist die Quelle das Primär-Objekt (sonst der niedrigere Index). +func _sym_grab_twin_move() -> void: + var sym_mode: int = _sym_mode() + if sym_mode == SymmetryCore.Mode.OFF or _grab_twin_map.is_empty(): + return + var objects: Array = main.doc.get("objects", []) + var center := SymmetryCore.map_center(main.doc) + var handled: Dictionary = {} + for i in _grab_members: + if not _grab_twin_map.has(i): + continue + var t: int = int(_grab_twin_map[i]) + var pair_key := "%d|%d" % [mini(i, t), maxi(i, t)] + if handled.has(pair_key): + continue + handled[pair_key] = true + var src_i: int = i + if _grab_members.has(t): + if _grab_primary == t: + src_i = t + elif _grab_primary != i and t < i: + src_i = t + var twin_i: int = t if src_i == i else i + if src_i >= objects.size() or not (objects[src_i] is Dictionary): + continue + var spos: Array = (objects[src_i] as Dictionary).get("pos", [0.0, 0.0, 0.0]) + if (spos as Array).size() != 3: + continue + var mp := SymmetryCore.mirror_point(sym_mode, + Vector3(float(spos[0]), float(spos[1]), float(spos[2])), center) + (objects[twin_i] as Dictionary)["pos"] = [mp.x, mp.y, mp.z] + if twin_i < view_builder.object_markers.size(): + var tm: Node3D = view_builder.object_markers[twin_i] + if tm != null and is_instance_valid(tm): + tm.position = Vector3(mp.x, mp.y, mp.z) + + +## Symmetrie (M3): Zwillinge beim ZIEHEN live mitführen (nur Marker — das doc +## schreibt _commit_drag über symmetry_sync_pairs). Quelle = Primär-Objekt, +## wenn beide Seiten eines Paares in der Zieh-Menge sind, sonst niedrigerer Index. +func _sym_drag_sync_live() -> void: + var sym_mode: int = _sym_mode() + if sym_mode == SymmetryCore.Mode.OFF or view_builder == null: + return + var objects: Array = main.doc.get("objects", []) + var center := SymmetryCore.map_center(main.doc) + var handled: Dictionary = {} + for i in _drag_members: + if not (i is int) or i < 0 or i >= objects.size() or not (objects[i] is Dictionary): + continue + var key := SymmetryCore.sym_of(objects[i] as Dictionary) + if key.is_empty(): + continue + var t := SymmetryCore.find_partner_index(objects, key, i) + if t < 0: + continue + var pair_key := "%d|%d" % [mini(i, t), maxi(i, t)] + if handled.has(pair_key): + continue + handled[pair_key] = true + var src_i: int = i + if _drag_members.has(t): + if _drag_primary == t: + src_i = t + elif _drag_primary != i and t < i: + src_i = t + var twin_i: int = t if src_i == i else i + if src_i >= view_builder.object_markers.size() or twin_i >= view_builder.object_markers.size(): + continue + var sm: Node3D = view_builder.object_markers[src_i] + var tm: Node3D = view_builder.object_markers[twin_i] + if sm == null or tm == null or not is_instance_valid(sm) or not is_instance_valid(tm): + continue + tm.position = SymmetryCore.mirror_point(sym_mode, sm.position, center) + + + + +## ⇄ Spiegeln (X: links↔rechts, Z: vor↔zurück) an der Stelle des Objekts — +## die Blickrichtung wird gespiegelt (sicher selbstinvers: doppelt = zurück). +func mirror_selected(axis: String) -> void: + if selected_index < 0: + main.call("_set_status", "Nichts ausgewählt — klicke zuerst ein Objekt an, das du spiegeln willst.", true) + return + var objects: Array = main.doc.get("objects", []) + if selected_index >= objects.size(): + clear_selection(true) + return + var before: Dictionary = main.history.snapshot(["objects"]) + var obj: Dictionary = objects[selected_index] + var old_rot := float(obj.get("rot_y_deg", 0.0)) + ObjectOps.mirror_object(obj, axis) + var new_rot := float(obj.get("rot_y_deg", 0.0)) + var marker: Node3D = view_builder.object_markers[selected_index] if selected_index < view_builder.object_markers.size() else null + if marker != null and is_instance_valid(marker): + marker.rotation.y = deg_to_rad(new_rot) + # Symmetrie (M3, t_34908425): der Zwilling dreht MIT (exakter Spiegel der + # neuen Blickrichtung) — im selben Commit wie die Quelle. + var twins: Array = ObjectOps.symmetry_sync_pairs( + main.doc, [selected_index], _sym_mode(), selected_index) + _sync_members_to_markers(twins) + var desc := "Objekt gespiegelt (links↔rechts)" if axis == "x" else "Objekt gespiegelt (vor↔zurück)" + main.history.commit(desc, before, main.history.snapshot(["objects"])) + main.dirty = true + main.call("_refresh_file_label") + main.call("_refresh_history_buttons") + main.call("_sync_selection_panel") + main.call("_set_status", "%s — Blickrichtung %.0f° → %.0f°. Strg+Z stellt die alte Richtung wieder her." % [ + desc, old_rot, new_rot]) + + +# ------------------------------------------------------------ Eingaben ------ + +func _unhandled_input(event: InputEvent) -> void: + # Strg-Zwang (Karte t_55257792) aus JEDEM durchgelassenen Event verfolgen — + # Maus-Events tragen den Modifier, Tasten-Events ebenso (nicht konsumieren!). + if event is InputEventKey: + _ctrl_held = (event as InputEventKey).ctrl_pressed + var p := MousePointer.from_input(event) + if p != null and handle_pointer(p): + get_viewport().set_input_as_handled() + + +## Rechte Maustaste kommt hier nie an (Karte t_2470de89): sie gehört mit +## absolutem Vorrang dem Freelook-Flug (orbit_camera.gd). Beim Platzieren +## bleibt das Objekt IN der Hand, Abwurf nur über Esc. +func handle_pointer(p: PointerEvent) -> bool: + if p.kind != PointerEvent.Kind.CANCEL: + _ctrl_held = p.ctrl + var mode: String = main.get("tool_mode") + if mode == "terrain" or mode == "spawns": + return false # Terrain-Pinsel / Spawn-Zonen haben das Zepter (eigene Werkzeuge) + match p.kind: + PointerEvent.Kind.MOVE: + _on_pointer_move(p.position) + PointerEvent.Kind.PRESS: + if _grabbing: + grab_confirm() + return true + _on_left_press(p) + return true + PointerEvent.Kind.RELEASE: + _on_left_release(p) + PointerEvent.Kind.SCROLL: + if _camera_flying(): + return false # Mausrad = Flug-Tempo (orbit_camera), kein Objekt-Drehen + if placing: + place_rot_deg = fmod(place_rot_deg + p.scroll * (90.0 if BauKatalog.ist_bau(place_oid) else ROT_STEP_DEG) + 3600.0, 360.0) + _ghost_rotation_anwenden() + return true + if selected_index >= 0 and not _grabbing: + rotate_selected(p.scroll * ROT_STEP_DEG) + return true + return false + + +func _on_pointer_move(pos: Vector2) -> void: + if placing: + _ghost_update(pos) + if _grabbing: + var gh: Variant = _ground_point(pos) + if gh != null: + grab_move(gh as Vector3) + return + if _rubber_pending or _rubber_active: + var dist := Vector2(pos.x - _press_pos.x, pos.y - _press_pos.y).length() + if dist > DRAG_THRESHOLD_PX: + _rubber_active = true + _rubber_pending = false + if _rubber_active: + main.call("_rubberband_update", _rubber_start, pos) + return + if _dragging and not placing and not _drag_members.is_empty(): + _drag_members_move(pos) + elif _dragging and not placing and selected_index >= 0: + # Einzel-Greifen (alter Pfad, ohne Gruppe/Mehrfachauswahl) + var p: Variant = _ground_point(pos) + if p == null: + return + var new_pos: Vector3 = _apply_grid((p as Vector3) + _grab_offset) + var half := _terrain_half() + new_pos.x = clampf(new_pos.x, -half.x, half.x) + new_pos.z = clampf(new_pos.z, -half.y, half.y) + # Höhe: der Terrain-Abstand bleibt beim Ziehen erhalten (angehoben + # schwebt weiter oben) — kein harter Terrain-Clamp mehr, t_7567a06f. + new_pos.y = SvmapDocument.terrain_height_at(main.doc, new_pos.x, new_pos.z) + _drag_lift + var dist := Vector2(pos.x - _press_pos.x, pos.y - _press_pos.y).length() + if dist > DRAG_THRESHOLD_PX: + _drag_moved = true + if _drag_moved: + var marker: Node3D = view_builder.object_markers[selected_index] + if marker != null and is_instance_valid(marker): + marker.position = new_pos + + +func _on_left_press(p: PointerEvent) -> void: + if placing: + _place_object(p.position, p.shift) # U5: Shift = Serienmodus + return + _press_pos = p.position + var hit := _pick_object(p.position) + if hit >= 0: + if p.shift or p.command: + # Umschalt+Klick / Strg+Klick (Karte t_c46d31c2): zur Auswahl + # hinzufügen/entfernen — kein Ziehen. + select_toggle(hit) + return + if not selected_indices.has(hit): + select_object(hit) + _begin_drag(hit, p.position) + else: + # Leere Stelle: Rahmen-Ausziehen vorbereiten; loser Klick = Auswahl weg. + _rubber_pending = true + _rubber_active = false + _rubber_start = p.position + _rubber_shift = p.shift + + +## Zieh-Menge festlegen: Mehrfachauswahl oder komplette Gruppe ziehen GEMEINSAM. +## Vom Gizmo im Drehen-Modus gesetzt: ein Klick auf das gewählte Objekt zieht +## es NICHT mehr weg (nur die Ringe drehen). +var no_drag_move := false + + +func _begin_drag(hit: int, viewport_pos: Vector2) -> void: + if no_drag_move and hit == selected_index: + return + var objects: Array = main.doc.get("objects", []) + _drag_members = [] + _grab_offsets = {} + _drag_lifts = {} + _drag_is_group = false + if selected_indices.size() > 1: + _drag_members = selected_indices.duplicate() + else: + var gid := GroupOps.group_id(objects[hit]) + if gid != GroupOps.UNGROUPED: + var members := GroupOps.members_of(main.doc, gid) + if members.size() > 1: + _drag_members = members + _drag_is_group = true + select_many(members, true) # ganze Gruppe sichtbar markieren + if _drag_members.is_empty(): + _drag_members = [selected_index] + _drag_primary = selected_index if selected_index >= 0 else hit + _dragging = true + _drag_moved = false + var p: Variant = _ground_point(viewport_pos) + if p != null: + for i in _drag_members: + if i >= view_builder.object_markers.size(): + continue + var marker: Node3D = view_builder.object_markers[i] + if marker != null and is_instance_valid(marker): + var off: Vector3 = marker.position - (p as Vector3) + off.y = 0.0 + _grab_offsets[i] = off + # Terrain-Abstand einfrieren (t_7567a06f, für die GANZE Zieh- + # Menge): ein Objekt mit Höhe behält beim Ziehen diesen Abstand + # zum Boden — bodennah bleibt bodennah, angehoben schwebt weiter. + var lift := marker.position.y \ + - SvmapDocument.terrain_height_at(main.doc, marker.position.x, marker.position.z) + _drag_lifts[i] = lift + if i == _drag_primary: + _grab_offset = off + _drag_lift = lift + else: + for i in _drag_members: + _grab_offsets[i] = Vector3.ZERO + _drag_lifts[i] = 0.0 + _grab_offset = Vector3.ZERO + _drag_lift = 0.0 + + +## Gemeinsames Ziehen: Delta vom Primär-Objekt auf ALLE Mitglieder — relative +## Anordnung bleibt exakt erhalten, Raster-Snap rastet die GANZE Gruppe. +func _drag_members_move(viewport_pos: Vector2) -> void: + var p: Variant = _ground_point(viewport_pos) + if p == null or not _grab_offsets.has(_drag_primary): + return + var half := _terrain_half() + var new_primary: Vector3 = _apply_grid((p as Vector3) + (_grab_offsets[_drag_primary] as Vector3)) + new_primary.x = clampf(new_primary.x, -half.x, half.x) + new_primary.z = clampf(new_primary.z, -half.y, half.y) + new_primary.y = SvmapDocument.terrain_height_at(main.doc, new_primary.x, new_primary.z) + var dist := Vector2(viewport_pos.x - _press_pos.x, viewport_pos.y - _press_pos.y).length() + if dist > DRAG_THRESHOLD_PX: + _drag_moved = true + if not _drag_moved: + return + var primary_marker: Node3D = view_builder.object_markers[_drag_primary] + if primary_marker == null or not is_instance_valid(primary_marker): + return + var delta: Vector3 = new_primary - primary_marker.position + delta.y = 0.0 + if delta.length_squared() < 0.0000001: + return + for i in _drag_members: + if i >= view_builder.object_markers.size(): + continue + var marker: Node3D = view_builder.object_markers[i] + if marker == null or not is_instance_valid(marker): + continue + var np: Vector3 = marker.position + delta + np.x = clampf(np.x, -half.x, half.x) + np.z = clampf(np.z, -half.y, half.y) + # Höhe: Terrain-Abstand bleibt erhalten (t_7567a06f, pro Objekt — + # angehoben schwebt weiter, bodennah bleibt bodennah). + np.y = SvmapDocument.terrain_height_at(main.doc, np.x, np.z) \ + + float(_drag_lifts.get(i, 0.0)) + marker.position = np + # Symmetrie (M3, t_34908425): Zwillinge LIVE mitziehen (nur Marker — + # das doc schreibt _commit_drag), exakter Spiegel der gezogenen Quelle. + _sym_drag_sync_live() + + +func _on_left_release(p: PointerEvent) -> void: + if _rubber_pending or _rubber_active: + var was_active := _rubber_active + _rubber_pending = false + _rubber_active = false + main.call("_rubberband_clear") + if was_active: + _finish_rubberband(p.position) + elif not _rubber_shift: + # Loser Klick auf leere Fläche: Auswahl aufheben (Klick statt Auswendiglernen). + if not selected_indices.is_empty(): + clear_selection() + return + if _dragging: + _dragging = false + if _drag_moved and not _drag_members.is_empty(): + _commit_drag() + _drag_moved = false + _drag_members = [] + _grab_offsets = {} + _drag_is_group = false + + +## Rahmen-Ausziehen abgeschlossen: alle Marker im Rahmen auswählen. +func _finish_rubberband(end_pos: Vector2) -> void: + var rect := SelectionMath.rect_from(_rubber_start, end_pos) + var positions: Array = [] + for marker in view_builder.object_markers: + if marker != null and is_instance_valid(marker): + positions.append(marker.global_position) + else: + positions.append(Vector3(INF, INF, INF)) # kaputter Marker: nie im Rahmen + var picked := SelectionMath.pick_in_rect(camera, positions, rect) + if _rubber_shift and not picked.is_empty(): + for i in picked: + if not selected_indices.has(i): + selected_indices.append(i) + selected_index = picked[picked.size() - 1] + elif not _rubber_shift: + selected_indices = picked + selected_index = picked.back() if not picked.is_empty() else -1 + _apply_selection_view() + main.call("_sync_selection_panel") + if selected_indices.is_empty(): + main.call("_set_status", "Der Rahmen hat kein Objekt erwischt — zieh ihn über die Objekte, die du zusammen bearbeiten willst.") + else: + main.call("_set_status", "Rahmen-Auswahl: %d Objekte markiert. Strg+G gruppier sie, oder ziehe sie gemeinsam weiter." % selected_indices.size()) + + +## Bewegte Marker → Doc schreiben, EIN Undo-Schritt für den ganzen Zug. +func _commit_drag() -> void: + var objects: Array = main.doc.get("objects", []) + var moved: Array = [] + for i in _drag_members: + if i >= objects.size() or i >= view_builder.object_markers.size(): + continue + var marker: Node3D = view_builder.object_markers[i] + if marker == null or not is_instance_valid(marker): + continue + moved.append(i) + if moved.is_empty(): + return + var before: Dictionary = main.history.snapshot(["objects"]) + for i in moved: + var pos: Vector3 = (view_builder.object_markers[i] as Node3D).position + objects[i]["pos"] = [float(pos.x), float(pos.y), float(pos.z)] + # Symmetrie (M3, t_34908425): Zwillinge der gezogenen Auswahl auf den exakten + # Spiegel setzen — IM SELBEN Commit (ein Zug = EIN Undo-Schritt für beide). + var twins: Array = ObjectOps.symmetry_sync_pairs( + main.doc, moved, _sym_mode(), _drag_primary) + _sync_members_to_markers(twins) + var desc: String + if _drag_is_group: + desc = "Gruppe verschoben (%d Objekte)" % moved.size() + elif moved.size() > 1: + desc = "%d Objekte verschoben" % moved.size() + else: + desc = "Objekt verschoben" + main.history.commit(desc, before, main.history.snapshot(["objects"])) + _mark_dirty() + main.call("_refresh_history_buttons") + main.call("_refresh_stats") + + +## Dirty-Markierung ohne Full-Rebuild (Auswahl/Marker bleiben bestehen). +func _mark_dirty() -> void: + main.set("dirty", true) + main.call("_refresh_file_label") + + +# ---------------------------------------------------- Screenshot-Hilfe ------ + +## Demo-Hook (Desktop-Smoke): Ghost außerhalb echter Maus-Ereignisse parken, +## damit ein Screenshot die Vorschau zeigen kann. +func demo_park_ghost(world_pos: Vector3, oid: String) -> void: + start_placement(oid) + placing = true + place_oid = oid + _ghost_refresh_mesh() + _ghost.position = world_pos + _ghost_rotation_anwenden() + _ghost.visible = true + _ghost_active = true + main.call("_highlight_library", oid) + main.call("_set_status", "%s: führe die Maus über die Karte — Klick setzt es. Mausrad dreht vorher, ESC bricht ab (Rechte Maustaste = Flug)." % main.object_label(oid)) + + +## Demo-Hook (Gruppen-Smoke, Karte t_f6f29d86): die Auswahl EXAKT so ziehen +## wie ein echter Drag-Release (Marker bewegen + EIN Commit). +func demo_drag_selection(delta: Vector3) -> void: + if selected_indices.is_empty(): + return + _drag_members = selected_indices.duplicate() + _drag_is_group = false + _drag_primary = selected_index + _dragging = true + _drag_moved = true + for i in _drag_members: + if i < view_builder.object_markers.size(): + var marker: Node3D = view_builder.object_markers[i] + if marker != null and is_instance_valid(marker): + marker.position += delta + _commit_drag() + _dragging = false + _drag_members = [] + _drag_moved = false diff --git a/editor/interaction.gd.uid b/editor/interaction.gd.uid new file mode 100644 index 0000000..4d72a94 --- /dev/null +++ b/editor/interaction.gd.uid @@ -0,0 +1 @@ +uid://cdfcdpiga4j0s diff --git a/editor/library_browser.gd b/editor/library_browser.gd new file mode 100644 index 0000000..a7616c3 --- /dev/null +++ b/editor/library_browser.gd @@ -0,0 +1,167 @@ +extends RefCounted +class_name LibraryBrowser +## Objekt-Bibliothek des Editors (Karte t_3a998ae4): deutscher Name, Gruppen +## für den Bibliothek-Browser und Thumbnail-Laden (128-px-PNGs, einmalig per +## Headless-Render erzeugt — tools/gen_thumbs.gd). +## +## Bewusst OHNE UI: reine Daten/Funktionen, damit die Tests (tests/test_library.gd) +## headless alles prüfen können. Die IDs sind der Vertrag (Entscheidung 20) — +## Gruppen/Namen leben HIER im Editor (die objects.json bleibt 1:1 die Kopie +## der Server-Registry, damit ein Sync sie nicht verwüstet). + +## Deutsche Anzeige-Namen für Bibliotheks-IDs, die KEIN `name_de` im Manifest +## haben (IDs sind der Vertrag, Entscheidung 20). Seit der Military-Pack- +## Umstellung (25.10.2026) hat jedes Objekt ein `name_de` — die Liste bleibt +## leer und dient nur als Override-Möglichkeit. +const NAMES := {} + +## Fallback-Gruppe für Objekte ohne bekannte Kategorie. +const GROUP_ORDER := ["sonstiges"] +const GROUP_LABELS := { + "sonstiges": "Sonstiges", +} + +## Kategorien des Military-Desert-Packs (Manifest-Feld `kategorie`, siehe +## library/objects.json; Quelle der Slugs/Namen: scopedvr-match-server +## tools/pack_katalog.py). Reihenfolge = Anzeige-Reihenfolge. Unbekannte +## Kategorien (z. B. spätere Bauteil-Module) tauchen automatisch mit ihrem +## Slug als Gruppe auf, ganz vor "Sonstiges". +const KAT_ORDER := ["bauteile", "panzer", "radfahrzeuge", "luftfahrzeuge", "stellungen", "fahrzeugteile", "gebaeude", "zelte", "tuerme", "mauern", "sperren", "kisten", "technik", "ausruestung", "training", "baeume", "pflanzen", "felsen", "boden", "decals"] +const KAT_GROUPS := { + "bauteile": {"key": "bauteile", "label": "Bauteile (eigene Häuser)"}, + "panzer": {"key": "panzer", "label": "Panzer & Transportpanzer"}, + "radfahrzeuge": {"key": "radfahrzeuge", "label": "Radfahrzeuge"}, + "luftfahrzeuge": {"key": "luftfahrzeuge", "label": "Flugzeuge & Hubschrauber"}, + "stellungen": {"key": "stellungen", "label": "Geschütze & Stellungen"}, + "fahrzeugteile": {"key": "fahrzeugteile", "label": "Fahrzeugteile"}, + "gebaeude": {"key": "gebaeude", "label": "Gebäude & Hangars"}, + "zelte": {"key": "zelte", "label": "Zelte"}, + "tuerme": {"key": "tuerme", "label": "Türme & Masten"}, + "mauern": {"key": "mauern", "label": "Mauern & Wände"}, + "sperren": {"key": "sperren", "label": "Sperren & Zäune"}, + "kisten": {"key": "kisten", "label": "Kisten, Fässer & Container"}, + "technik": {"key": "technik", "label": "Technik & Funk"}, + "ausruestung": {"key": "ausruestung", "label": "Ausrüstung & Zubehör"}, + "training": {"key": "training", "label": "Training & Ziele"}, + "baeume": {"key": "baeume", "label": "Bäume & Totholz"}, + "pflanzen": {"key": "pflanzen", "label": "Pflanzen, Kakteen & Gras"}, + "felsen": {"key": "felsen", "label": "Felsen & Steine"}, + "boden": {"key": "boden", "label": "Boden, Straßen & Dünen"}, + "decals": {"key": "decals", "label": "Boden-Decals"}, +} + +## Anzeige-Größe der Vorschaubilder im Browser (Karte t_59fc0f21): vorher 40 px, +## jetzt Kacheln mit 128 px (25.10.: größer, deutlicher) (128-px-PNGs werden auf die Anzeige-Größe skaliert). +const THUMB_DISPLAY_PX := 128 + + +## Manifest-Cache (vom Editor beim Laden gesetzt): damit object_label() und +## group_of() auch ohne Manifest-Parameter den deutschen Namen / die Kategorie +## kennen (Statuszeile, Szenen-Baum, Inspector). +static var _manifest_cache: Dictionary = {} + + +static func setze_manifest(manifest: Dictionary) -> void: + _manifest_cache = (manifest.get("objects", {}) as Dictionary) if manifest.has("objects") else {} + + +static func object_label(oid: String) -> String: + if BauKatalog.ist_bau(oid): + return BauKatalog.label(oid) + if NAMES.has(oid): + return str(NAMES[oid]) + var entry: Dictionary = _manifest_cache.get(oid, {}) as Dictionary + var name_de := str(entry.get("name_de", "")) + if not name_de.is_empty(): + return name_de + return oid.capitalize() + + +## Gruppe einer ID (ohne Manifest-Eintrag → "sonstiges"). +static func group_of(oid: String) -> String: + if BauKatalog.ist_bau(oid): + return "bauteile" + var entry: Dictionary = _manifest_cache.get(oid, {}) as Dictionary + return group_of_entry(oid, entry) + + +## Gruppe eines Katalog-Eintrags: Manifest-Feld `kategorie` (KAT_GROUPS); +## unbekannte Kategorie → eigene Gruppe mit dem Slug als Schlüssel; kein +## Eintrag/keine Kategorie → "sonstiges". entry darf leer sein. +static func group_of_entry(_oid: String, entry: Dictionary) -> String: + var kat := str(entry.get("kategorie", "")) + if kat.is_empty(): + return "sonstiges" + if KAT_GROUPS.has(kat): + return str(KAT_GROUPS[kat]["key"]) + return kat + + +## Deutscher Anzeigename: Manifest-Feld `name_de`, sonst NAMES/fallback. +static func entry_label(oid: String, entry: Dictionary) -> String: + var name_de := str(entry.get("name_de", "")) + if not name_de.is_empty(): + return name_de + return object_label(oid) + + +## Gruppen für den Browser, geprüft gegen das Manifest: nur Gruppen mit +## Objekten erscheinen. Unbekannte Kategorien wandern als eigene Gruppe vor +## "Sonstiges" — neue Bibliotheks-Einträge brechen die UI nicht. +static func groups_in_order(manifest: Dictionary) -> Array: + var lib: Dictionary = manifest.get("objects", {}) + var by_group := {} + for oid in lib.keys(): + var entry: Dictionary = lib.get(oid, {}) as Dictionary + var key := group_of_entry(str(oid), entry) + if not by_group.has(key): + by_group[key] = [] + (by_group[key] as Array).append(str(oid)) + var reihenfolge: Array = KAT_ORDER.duplicate() + var fremde: Array = [] + for key in by_group.keys(): + if not reihenfolge.has(key) and not GROUP_ORDER.has(key): + fremde.append(key) + fremde.sort() + reihenfolge.append_array(fremde) + reihenfolge.append_array(GROUP_ORDER) + var out: Array = [] + for key in reihenfolge: + var ids: Array = (by_group.get(key, []) as Array) + ids.sort() + if ids.is_empty() and key != "sonstiges": + continue + out.append({"key": key, "label": _group_label(key), "ids": ids}) + return out + + +static func _group_label(key: String) -> String: + if GROUP_LABELS.has(key): + return str(GROUP_LABELS[key]) + for kat in KAT_GROUPS.values(): + if str(kat["key"]) == key: + return str(kat["label"]) + return key.capitalize() + + +## Thumbnail-Pfad (128-px-PNG, tools/gen_thumbs.gd erzeugt sie einmalig). +static func thumb_path(oid: String) -> String: + return "res://core/thumbs/%s.png" % oid + + +## Thumbnail als Textur laden — direkt über Image (kein Import-System nötig, +## geht damit auch frisch nach git pull ohne Import), auf Anzeige-Größe +## runtergerechnet. size_px steuert die Anzeige-Größe (Default = THUMB_DISPLAY_PX +## = 96, Karte t_59fc0f21; vorher fest 40). null = noch kein Thumbnail → +## Button fällt aufs Text-Layout zurück (Fehler sieht man nicht, man sieht +## einfach nur kein Bild). +static func load_thumb(oid: String, size_px := THUMB_DISPLAY_PX) -> Texture2D: + var path := thumb_path(oid) + if not FileAccess.file_exists(path): + return null + var img := Image.load_from_file(path) + if img == null: + return null + if img.get_width() != size_px or img.get_height() != size_px: + img.resize(size_px, size_px, Image.INTERPOLATE_LANCZOS) + return ImageTexture.create_from_image(img) diff --git a/editor/library_browser.gd.uid b/editor/library_browser.gd.uid new file mode 100644 index 0000000..d4c7d10 --- /dev/null +++ b/editor/library_browser.gd.uid @@ -0,0 +1 @@ +uid://o3jwxk87gtw diff --git a/editor/mouse_pointer.gd b/editor/mouse_pointer.gd new file mode 100644 index 0000000..cff83d9 --- /dev/null +++ b/editor/mouse_pointer.gd @@ -0,0 +1,39 @@ +class_name MousePointer +extends RefCounted +## Übersetzt Maus und Esc-Taste in PointerEvent. Die rechte Maustaste fehlt +## absichtlich: sie gehört dem Freelook-Flug (orbit_camera.gd). + + +static func from_input(event: InputEvent) -> PointerEvent: + if event is InputEventMouseMotion: + var mm := event as InputEventMouseMotion + var p := PointerEvent.make(PointerEvent.Kind.MOVE, mm.position) + p.shift = mm.shift_pressed + p.ctrl = mm.ctrl_pressed + p.command = mm.is_command_or_control_pressed() + p.pressure = mm.pressure + return p + if event is InputEventMouseButton: + var mb := event as InputEventMouseButton + var kind := PointerEvent.Kind.MOVE + var scroll := 0 + match mb.button_index: + MOUSE_BUTTON_LEFT: + kind = PointerEvent.Kind.PRESS if mb.pressed else PointerEvent.Kind.RELEASE + MOUSE_BUTTON_WHEEL_UP, MOUSE_BUTTON_WHEEL_DOWN: + if not mb.pressed: + return null + kind = PointerEvent.Kind.SCROLL + scroll = 1 if mb.button_index == MOUSE_BUTTON_WHEEL_UP else -1 + _: + return null + var p := PointerEvent.make(kind, mb.position) + p.shift = mb.shift_pressed + p.ctrl = mb.ctrl_pressed + p.command = mb.is_command_or_control_pressed() + p.scroll = scroll + return p + if event is InputEventKey and (event as InputEventKey).pressed \ + and (event as InputEventKey).keycode == KEY_ESCAPE: + return PointerEvent.make(PointerEvent.Kind.CANCEL) + return null diff --git a/editor/mouse_pointer.gd.uid b/editor/mouse_pointer.gd.uid new file mode 100644 index 0000000..3b06f99 --- /dev/null +++ b/editor/mouse_pointer.gd.uid @@ -0,0 +1 @@ +uid://1nyr0qwwdvnv diff --git a/editor/playtest/playtest_avatar.gd b/editor/playtest/playtest_avatar.gd new file mode 100644 index 0000000..8554ed2 --- /dev/null +++ b/editor/playtest/playtest_avatar.gd @@ -0,0 +1,461 @@ +class_name PlaytestAvatar +extends Node3D +## Playtest-Avatar (Karte t_17a35c59) — SPIEGEL des Bot-Avatars aus dem +## Quest-Client (scripts/match/bot_avatar.gd + MatchRemoteAvatar), Sly-Wunsch +## 20.10.: „das Player Model in den Map Editor … genau so wie im Spiel bei +## den Bots" + „direkt natürlich auch mit den Animationen bitte!". +## +## Quelle der Wahrheit: bot_avatar.gd. Dieses Modul übernimmt 1:1: +## - das GLB assets/avatars/quaternius_ual/ual1_standard.glb (Quaternius +## UAL, CC0) + das Rifle assets/weapons/m40_rifle.glb an hand_r — +## aufgelöst über den NACHBAR-KLON ../scopedvr-client (gleiche Auflösung +## wie GlbMeshStore/TestRun), NICHT dupliziert. Lädt mit GLTFDocument +## (die GLB liegt außerhalb res:// — kein Import-System). +## - die AnimationTree-Pipeline (A4/W14): BlendSpace1D Idle/Walk/Jog mit +## Blend-Punkten auf den Clip-Naturgeschwindigkeiten (0,0 / 0,979 / +## 2,620 m/s), sync = true, TimeScale-Subtrees für die Kadenz, darüber +## die StateMachine mit dem Motion-State. Crossfade ~0,2 s. +## - die Kadenz-Mathe (BOT2/vc23): Kadenz = m/s / Ziel-Schrittlänge +## (Walk 0,95 m / Jog 0,85 m), TimeScale = Kadenz × Zykluslänge / 2 +## Schritte pro Zyklus, Klammern CADENCE 1,0–4,5 und FOOT_SYNC 0,6–2,0. +## - die Gait-Schwellen (A2 §6.2): ≤ 0,3 m/s Idle, ≤ 2,6 m/s Walk, sonst +## Jog — im Editor aus der ECHTEN PlaytestBody-Geschwindigkeit gespeist. +## - die Frontachse (vc21-Fix): das UAL-GLB blickt nach +Z, der Body-Yaw +## richtet −Z aus → MODEL_YAW_OFFSET = π auf dem Modell-Kind. Blick- +## richtung == Bewegungsrichtung. +## - den Blend-Ruckel-Fix: Sollwerte werden in _process weich nachgezogen +## (BLEND_SMOOTH_S = 0,25 s), Parameter-Writes nur bei Änderung. +## +## NICHT gespiegelt (Match-only, kein Trigger im Editor-Testlauf): Engage/ +## Shoot/Hit/Death-One-Shots, Team-Tönung, Namensschild, Netzwerk-Interpo- +## lation, Ragdoll. Die StateMachine trägt deshalb nur den Motion-State — +## die Loop-Pipeline (die Sly sieht) ist identisch zum Spiel. +## +## Regel (wie KolliderBau/svmap_tint): Ändert der Client die Pipeline, wird +## dieser Spiegel MIT geändert. Bewusst KEINE Editor-eigenen Maße oder +## Anim-Parameter — Proportionen/Konstanten strikt aus der Client-Quelle. +## +## Fehlt der Client-Klon (oder die GLB): lade_avatar() gibt null zurück — +## PlaytestMode bleibt dann komplett in First Person (graceful, kein Crash). + +## ------------------------------------------------ Quelle (Client-Klon) ---- +## Relative Pfade IM Client-Repo (Nachbar-Klon, nicht dupliziert). +const MODEL_REL := "assets/avatars/quaternius_ual/ual1_standard.glb" +const RIFLE_REL := "assets/weapons/m40_rifle.glb" + +## ------------------------------------- Clips (MatchRemoteAvatar-Erbe) ----- +const CLIP_IDLE := "Idle" +const CLIP_WALK := "Walk" +const CLIP_JOG := "Jog_Fwd" + +## Server-/Inferenz-States (A1-Vertrag, bot_avatar.gd): 0=IDLE 1=WALK 2=JOG. +const STATE_IDLE := 0 +const STATE_WALK := 1 +const STATE_JOG := 2 + +## Gait-Schwellen (A2 §6.2, bot_avatar.gd): Velocity → State. +const IDLE_SPEED_MAX_MPS := 0.3 +const WALK_SPEED_MAX_MPS := 2.6 + +## Blend-Punkte = Clip-Naturgeschwindigkeiten (H1-Messung, bot_avatar.gd). +const WALK_NATURAL_MPS := 0.979 +const JOG_NATURAL_MPS := 2.620 +const BLEND_IDLE_MPS := 0.0 +const BLEND_MAX_MPS := 4.0 + +## Kadenz-Kalibrierung (BOT2/vc23, bot_avatar.gd): Ziel-Schrittlängen + Klammern. +const WALK_STEP_M := 0.95 +const JOG_STEP_M := 0.85 +const CADENCE_MIN := 1.0 +const CADENCE_MAX := 4.5 +const FOOT_SYNC_MIN := 0.6 +const FOOT_SYNC_MAX := 2.0 + +## Crossfade (A4) + Blend-Glättung (vc21-Ruckel-Fix, bot_avatar.gd). +const CROSSFADE_S := 0.2 +const BLEND_SMOOTH_S := 0.25 + +## Modell-Anker (bot_avatar.gd): Knoten = Kopf-Anker in Augenhöhe (1,65 m), +## GLB-Kind hängt mit negativem Y-Versatz (Füße am Boden, Modell 1,83 m). +const MODEL_EYE_HEIGHT := 1.65 +const MODEL_Y_OFFSET := -1.65 +## Frontachse (vc21-Messung): GLB blickt nach +Z → 180°-Korrektur auf dem +## Modell-Kind, damit die Front auf das lokale −Z (Body-Vorwärts) zeigt. +const MODEL_FORWARD_LOCAL := Vector3(0.0, 0.0, 1.0) +const MODEL_YAW_OFFSET := PI + +## Rifle-Mount (vc21-Messung, bot_avatar.gd): hand_r, Lauf → Hand-+Y, +## Rifle-oben → Hand-+Z = reine +90°-X-Drehung; Griff 0,067 m auf Hand-+Y. +const RIFLE_HAND_BONE := "hand_r" +const RIFLE_ROT_BASIS := Basis(Vector3(1.0, 0.0, 0.0), deg_to_rad(90.0)) +const RIFLE_POS := Vector3(0.0, 0.067, 0.0) + +## AnimationTree-Vertrag (bot_avatar.gd — Namen sind Teil des Vertrags). +const SM_MOTION := "Motion" +const P_BLEND := "parameters/Motion/Speed/blend_position" +const P_WALK_SCALE := "parameters/Motion/Speed/Walk/WalkTs/scale" +const P_JOG_SCALE := "parameters/Motion/Speed/Jog/JogTs/scale" +const P_PLAYBACK := "parameters/playback" + +## GLB-Instanz (Modell-Wurzel), AnimationPlayer (Clip-Lieferant), Tree. +var _model: Node3D = null +var _anim: AnimationPlayer = null +var _tree: AnimationTree = null +var _playback: AnimationNodeStateMachinePlayback = null +## Sichtbarer Zustand (Tests/Debug): Soll-Clip + Soll-Blend. +var _cur_clip := "" +var state := STATE_IDLE +var speed_mps := 0.0 +var _blend_cur := 0.0 +var _blend_target := 0.0 +var _walk_scale_cur := 1.0 +var _walk_scale_target := 1.0 +var _jog_scale_cur := 1.0 +var _jog_scale_target := 1.0 + + +## Client-Projektordner (Nachbar-Klon oder konfigurierter Pfad) — dieselbe +## Auflösung wie der alte Client-Start (test_run.gd). "" = keiner gefunden. +static func client_wurzel() -> String: + return TestRun.find_client(ProjectSettings.globalize_path("res://"), + TestRun.load_cfg()) + + +## Absoluter Modell-/Rifle-Pfad im Client-Klon ("" = kein Klon gefunden). +static func model_pfad() -> String: + var root := client_wurzel() + if root.is_empty(): + return "" + return root.path_join(MODEL_REL) + + +static func rifle_pfad() -> String: + var root := client_wurzel() + if root.is_empty(): + return "" + return root.path_join(RIFLE_REL) + + +## State aus der echten Geschwindigkeit (Spiegel von _track_velocity, +## bot_avatar.gd — dieselben Schwellen, ohne Netzwerk-Glättung). +static func zustand_fuer(speed: float) -> int: + if speed <= IDLE_SPEED_MAX_MPS: + return STATE_IDLE + if speed <= WALK_SPEED_MAX_MPS: + return STATE_WALK + return STATE_JOG + + +## Avatar aus dem Client-Klon laden (null = fehlt/nicht ladbar → graceful +## Fallback auf First Person beim Aufrufer). Baut Modell + AnimationTree +## + Rifle-Mount exakt wie bot_avatar._ready/_build_model/_build_anim_tree. +static func lade_avatar() -> PlaytestAvatar: + var glb_pfad := model_pfad() + if glb_pfad.is_empty() or not FileAccess.file_exists(glb_pfad): + push_warning("PLAYTEST_AVATAR: Modell fehlt (%s) — Third Person nicht verfügbar" % glb_pfad) + return null + var gltf := GLTFDocument.new() + var state := GLTFState.new() + if gltf.append_from_file(glb_pfad, state) != OK: + push_warning("PLAYTEST_AVATAR: GLB nicht ladbar: %s" % glb_pfad) + return null + var szene: Node = gltf.generate_scene(state) + if szene == null: + push_warning("PLAYTEST_AVATAR: GLB-Szene leer: %s" % glb_pfad) + return null + var avatar := PlaytestAvatar.new() + avatar.name = "Avatar" + avatar._model = szene as Node3D + if avatar._model == null: + push_warning("PLAYTEST_AVATAR: GLB-Wurzel kein Node3D: %s" % glb_pfad) + szene.free() + return null + avatar._model.name = "Body" + # Kopf-Anker-Konvention (bot_avatar._build_model): das GLB-Kind hängt mit + # MODEL_Y_OFFSET nach unten (GLB-Ursprung = Füße) — der Avatar-Node selbst + # sitzt bei PlaytestBody in Augenhöhe über dem Füßpunkt (set_avatar). + # vc21-Frontachse: GLB blickt nach +Z → 180° auf das Modell-Kind, damit + # die Modell-Front auf das Avatar-lokale −Z zeigt (= Body-Vorwärts). + avatar._model.position = Vector3(0.0, MODEL_Y_OFFSET, 0.0) + avatar._model.rotation.y = MODEL_YAW_OFFSET + avatar.add_child(avatar._model) + for child in avatar._model.find_children("*", "AnimationPlayer", true, false): + avatar._anim = child + if avatar._anim == null: + push_warning("PLAYTEST_AVATAR: kein AnimationPlayer im GLB — Avatar unbrauchbar") + avatar.free() + return null + # Importer-Semantik nachbilden: der Godot-Editor-Import (Client .import) + # streicht Animations-Namens-ENDUNGEN "-loop"/"_loop" und setzt dann + # Loop-Mode LOOP_LINEAR. GLTFDocument (Runtime-Ladung) liefert die rohen + # Namen ("Idle_Loop", "Walk_Loop", …) OHNE Loop-Mode — ohne diese + # Normalisierung hätten die Loops den falschen Namen (Bot-Vertrag: Idle/ + # Walk/Jog_Fwd) und würden nach einem Zyklus stehen bleiben. + avatar._normalisiere_clips() + if avatar._anim.get_animation_list().is_empty(): + push_warning("PLAYTEST_AVATAR: kein AnimationPlayer/Clips im GLB — Avatar unbrauchbar") + avatar.free() + return null + avatar._baue_anim_tree() + avatar._baue_rifle() + # Start-Anim: Idle (wie bot_avatar._ready — kein T-Pose-Blitz). + avatar.apply_state(STATE_IDLE, 0.0) + return avatar + + +## Importer-Semantik (siehe Aufrufkommentar): "_loop"/"-loop"-Endungen +## streichen, LOOP_LINEAR setzen — genau das, was der Client-.import mit +## derselben GLB macht (dort heißen die Clips Idle/Walk/Jog_Fwd, Loop-Mode +## im Asset korrekt, siehe bot_avatar.gd-Clip-Doku). +func _normalisiere_clips() -> void: + for lib_name in _anim.get_animation_library_list(): + var lib := _anim.get_animation_library(lib_name) + for clip_name in lib.get_animation_list(): + var animation: Animation = lib.get_animation(clip_name) + var lower := String(clip_name).to_lower() + if lower.ends_with("_loop") or lower.ends_with("-loop"): + var clean := String(clip_name).substr(0, String(clip_name).length() - 5) + lib.rename_animation(clip_name, clean) + animation.loop_mode = Animation.LOOP_LINEAR + + +## AnimationTree (A4-Pipeline, Motion-Zweig): BlendSpace1D Idle/Walk/Jog + +## TimeScale-Subtrees, darüber die StateMachine mit dem Motion-State. +## Verdrahtungs-Fallen (bot_avatar.gd A4-Sektion, Probe 18.10.): Clips als +## EIGENE Library auf die Tree kopieren (anim_player-Compatibility-Pfad +## überspringt die GLB-Default-Library), root_node = Modell-Wurzel +## (Track-Pfade "Armature/Skeleton3D:*"), Player bleibt reiner Clip-Lieferant. +func _baue_anim_tree() -> void: + _anim.stop() + var tree := AnimationTree.new() + tree.name = "AnimTree" + _model.add_child(tree) + var lib := AnimationLibrary.new() + for clip in _anim.get_animation_list(): + lib.add_animation(clip, _anim.get_animation(clip)) + tree.add_animation_library("", lib) + tree.root_node = tree.get_path_to(_model) + var motion := AnimationNodeBlendTree.new() + var blend := AnimationNodeBlendSpace1D.new() + var idle := AnimationNodeAnimation.new() + idle.animation = CLIP_IDLE + blend.add_blend_point(idle, BLEND_IDLE_MPS, 0, "Idle") + blend.add_blend_point(_speed_scaled_clip(CLIP_WALK, "WalkAnim", "WalkTs"), + WALK_NATURAL_MPS, 1, "Walk") + blend.add_blend_point(_speed_scaled_clip(CLIP_JOG, "JogAnim", "JogTs"), + JOG_NATURAL_MPS, 2, "Jog") + blend.min_space = 0.0 + blend.max_space = BLEND_MAX_MPS + blend.sync = true # vc21: gemeinsame Phase beim Blenden (kein Fuß-Pop) + motion.add_node("Speed", blend) + motion.connect_node("output", 0, "Speed") + var sm := AnimationNodeStateMachine.new() + sm.add_node(SM_MOTION, motion) + tree.tree_root = sm + tree.active = true + tree.process_callback = AnimationTree.ANIMATION_PROCESS_IDLE + _tree = tree + # _playback bewusst NICHT hier holen: der Baum hängt noch nicht im + # Szenenbaum — tree.get(P_PLAYBACK) liefert vorher null. Der Motion- + # Start passiert in apply_state() über _playback_holen() (nach dem + # Baum-Eintritt, wie _ensure_motion im Client). + + +## A4-Helfer (1:1 bot_avatar.gd): Clip-Subtree mit AnimationNodeTimeScale. +func _speed_scaled_clip(clip: String, anim_name: String, ts_name: String) -> AnimationNodeBlendTree: + var bt := AnimationNodeBlendTree.new() + var an := AnimationNodeAnimation.new() + an.animation = clip + var ts := AnimationNodeTimeScale.new() + bt.add_node(anim_name, an) + bt.add_node(ts_name, ts) + bt.connect_node(ts_name, 0, anim_name) + bt.connect_node("output", 0, ts_name) + return bt + + +## Rifle an hand_r (1:1 bot_avatar._build_rifle). Fehlt das Rifle-GLB oder +## der Knochen: warnen und ohne Waffe weiter (Avatar bleibt brauchbar). +func _baue_rifle() -> void: + var rifle_pfad_datei := rifle_pfad() + if rifle_pfad_datei.is_empty() or not FileAccess.file_exists(rifle_pfad_datei): + push_warning("PLAYTEST_AVATAR: Rifle fehlt (%s) — Avatar ohne Waffe" % rifle_pfad_datei) + return + var skeleton := _skeleton() + if skeleton == null: + push_warning("PLAYTEST_AVATAR: kein Skeleton3D — Rifle bleibt unattached") + return + if skeleton.find_bone(RIFLE_HAND_BONE) < 0: + push_warning("PLAYTEST_AVATAR: Hand-Knochen '%s' fehlt — Rifle bleibt unattached" % RIFLE_HAND_BONE) + return + var gltf := GLTFDocument.new() + var state := GLTFState.new() + if gltf.append_from_file(rifle_pfad_datei, state) != OK: + push_warning("PLAYTEST_AVATAR: Rifle-GLB nicht ladbar: %s" % rifle_pfad_datei) + return + var szene: Node = gltf.generate_scene(state) + if szene == null: + return + var attach := BoneAttachment3D.new() + attach.name = "RifleMount" + attach.bone_name = RIFLE_HAND_BONE + skeleton.add_child(attach) + var rifle := szene as Node3D + rifle.name = "Rifle" + rifle.basis = RIFLE_ROT_BASIS + rifle.position = RIFLE_POS + attach.add_child(rifle) + + +## Erstes Skeleton3D unter dem GLB (bot_avatar._build_model-Suche). +func _skeleton() -> Skeleton3D: + if _model == null: + return null + for child in _model.find_children("*", "Skeleton3D", true, false): + return child + return null + + +## ---------------------------------------------------------------- Anim ---- + +## Playtest-Movement-State anlegen (Kartenvorgabe: aus der ECHTEN Bewegung). +## mps < 0 = "nicht bekannt" → Kadenz unverändert lassen (wie bot_avatar). +func apply_state(new_state: int, new_speed_mps: float = -1.0) -> void: + if new_state != STATE_IDLE and new_state != STATE_WALK and new_state != STATE_JOG: + return # unbekannter State: nichts ändern (wie _clip_for_state ""). + state = new_state + if new_speed_mps >= 0.0: + speed_mps = new_speed_mps + var clip := _clip_for_state(state) + if clip.is_empty(): + return + _cur_clip = clip + if state == STATE_WALK: + _blend_target = WALK_NATURAL_MPS + _walk_scale_target = gait_scale_for(state, speed_mps) + _jog_scale_target = 1.0 + elif state == STATE_JOG: + _blend_target = JOG_NATURAL_MPS + _jog_scale_target = gait_scale_for(state, speed_mps) + _walk_scale_target = 1.0 + else: + _blend_target = BLEND_IDLE_MPS + _walk_scale_target = 1.0 + _jog_scale_target = 1.0 + if not is_processing(): + # Ohne _process-Treiber (Tests vor dem ersten Frame) sofort schreiben. + _blend_cur = _blend_target + _walk_scale_cur = _walk_scale_target + _jog_scale_cur = _jog_scale_target + _write_blend_params() + var playback := _playback_holen() + if playback != null: + # Wie bot_avatar._ensure_motion: Loop-State halten bzw. zurück. + # Der pre-tree start() der StateMachine kann beim Baum-Eintritt + # verworfen werden (leerer Knoten) → hier sauber (neu) starten. + var node := String(playback.get_current_node()) + if node.is_empty(): + playback.start(SM_MOTION) + elif node != SM_MOTION: + playback.travel(SM_MOTION) + + +## Bot2-Kadenz (1:1 bot_avatar.gd): Kadenz = m/s / Ziel-Schrittlänge, geklemmt. +func gait_cadence_for(s: int, mps: float) -> float: + var step := WALK_STEP_M if s == STATE_WALK else JOG_STEP_M + if s != STATE_WALK and s != STATE_JOG: + return 0.0 + return clampf(mps / maxf(step, 0.05), CADENCE_MIN, CADENCE_MAX) + + +## Bot2-TimeScale (1:1 bot_avatar.gd): Kadenz × Zykluslänge / 2 Schritte. +func gait_scale_for(s: int, mps: float) -> float: + var cadence := gait_cadence_for(s, mps) + if cadence <= 0.0: + return 1.0 + var cycle := _cycle_len_for(s) + if cycle <= 0.0: + return 1.0 + return clampf(cadence * cycle / 2.0, FOOT_SYNC_MIN, FOOT_SYNC_MAX) + + +func _cycle_len_for(s: int) -> float: + var clip := _clip_for_state(s) + if clip.is_empty() or _anim == null or not _anim.has_animation(clip): + return 0.0 + return _anim.get_animation(clip).length + + +## StateMachine-Playback faul holen: erst NACH dem Baum-Eintritt kann die +## Tree den "parameters/playback"-Parameter auflösen (vorher null). +func _playback_holen() -> AnimationNodeStateMachinePlayback: + if _playback == null and _tree != null: + _playback = _tree.get(P_PLAYBACK) as AnimationNodeStateMachinePlayback + return _playback + + +## Clip-Auflösung (1:1 bot_avatar._clip_for_state, ohne ENGAGE — Match-only). +func _clip_for_state(s: int) -> String: + match s: + STATE_IDLE: + return CLIP_IDLE + STATE_WALK: + return CLIP_WALK + STATE_JOG: + return CLIP_JOG + _: + return "" + + +## vc21: Welt-Richtung, in die das MESH blickt (Vertrag wie +## bot_avatar.model_forward: Front == Bewegungsrichtung). Hier wird die +## ECHTE Modell-Transform gemessen — der MODEL_YAW_OFFSET sitzt in diesem +## Spiegel auf dem Modell-Kind (nicht auf dem Node wie im Client), die +## Messung über _model.global_transform ist davon unabhängig korrekt. +func model_forward() -> Vector3: + if _model == null: + return Vector3(0.0, 0.0, -1.0) + var f: Vector3 = _model.global_transform.basis * MODEL_FORWARD_LOCAL + f.y = 0.0 + return f.normalized() + + +## Aktueller StateMachine-State ("" ohne Baum) — Tests/Debug. +func tree_state() -> String: + var playback := _playback_holen() + if playback == null: + return "" + return String(playback.get_current_node()) + + +## Soll-Clip des aktuellen States (wie bot_avatar.current_clip, ohne One-Shots). +func current_clip() -> String: + return _cur_clip + + +## AnimationTree aktiv? (Tests: "animiert überhaupt".) +func anim_running() -> bool: + return _tree != null and _tree.active + + +func _process(delta: float) -> void: + # vc21: Blend/Kadenz weich nachziehen (kein sichtbares Springen). + if _tree == null: + return + var k := clampf(delta / BLEND_SMOOTH_S, 0.0, 1.0) + _blend_cur = lerpf(_blend_cur, _blend_target, k) + _walk_scale_cur = lerpf(_walk_scale_cur, _walk_scale_target, k) + _jog_scale_cur = lerpf(_jog_scale_cur, _jog_scale_target, k) + _write_blend_params() + + +## vc21: geglätteten Stand in die Tree schreiben (nur bei Änderung). +func _write_blend_params() -> void: + if _tree == null: + return + if absf(float(_tree.get(P_BLEND)) - _blend_cur) > 0.0005: + _tree.set(P_BLEND, _blend_cur) + if absf(float(_tree.get(P_WALK_SCALE)) - _walk_scale_cur) > 0.0005: + _tree.set(P_WALK_SCALE, _walk_scale_cur) + if absf(float(_tree.get(P_JOG_SCALE)) - _jog_scale_cur) > 0.0005: + _tree.set(P_JOG_SCALE, _jog_scale_cur) diff --git a/editor/playtest/playtest_avatar.gd.uid b/editor/playtest/playtest_avatar.gd.uid new file mode 100644 index 0000000..4651d03 --- /dev/null +++ b/editor/playtest/playtest_avatar.gd.uid @@ -0,0 +1 @@ +uid://cvj6x35cenpbm diff --git a/editor/playtest/playtest_body.gd b/editor/playtest/playtest_body.gd new file mode 100644 index 0000000..b365446 --- /dev/null +++ b/editor/playtest/playtest_body.gd @@ -0,0 +1,581 @@ +extends CharacterBody3D +class_name PlaytestBody +## Lauf-Modus Spieler (Karte t_1cdc1a72, Physik-Neubau t_1da96275): +## erste Person, WASD + Maus, Shift = rennen, Space = springen, Gravitation. +## +## ECHTE PHYSIK — identisch zum Quest-3-Client (Sly-Forderung 20.10.: +## „Die Möglichkeiten des Map Editors sollen ABSOLUT identisch mit der +## Quest-3-Version sein“). Dieser Body ist ein CharacterBody3D mit EXAKT +## denselben Parametern wie client/scripts/world/testmap_player.gd +## (TestmapPlayer): Kapsel 0.35 × 1.8, WALK/SPRINT/JUMP/GRAVITY, +## Step-Up 0.45 m nach move_and_slide (RayCast-Kanten-Abtastung, 1:1 +## gespiegelt inkl. Decken-Guard). Die Kollider kommen von KolliderBau +## (Spiegel von svmap_world.gd) — dieselben Trimeshe wie im Spiel. +## +## Der alte AABB-Blocking-Code (vorgecachte Kisten, eigener step()-Solver +## ohne Physik-Server) ist ENTFERNT — es gibt genau EINEN Bewegungscode, +## denselben wie auf der Quest. +## +## Steuerung: _physics_process pollt die Tasten (oder die Autopilot-Haken +## auto_move_dir/auto_jump/auto_run für Suiten und spätere Automatisierung) +## und fährt dieselbe Logik wie der Client. ESC wird NICHT hier gefangen: +## main.gd behandelt Esc VOR der normalen Esc-Kette, solange der Lauf-Modus +## aktiv ist („Esc = zurück zum Editor“). +## +## Koordinaten-Konvention (wie Client): Body-Ursprung = KAPSEL-MITTE, +## Kamera sitzt EYE_HEIGHT über der Mitte (TestmapPlayer.EYE_HEIGHT). + +signal exit_requested + +# --- Parameter 1:1 aus client/scripts/world/testmap_player.gd --------------- +const WALK_SPEED := 6.0 +const SPRINT_SPEED := 14.0 +const JUMP_SPEED := 4.5 +const GRAVITY := 9.8 +const EYE_HEIGHT := 0.65 # Kamera über der Kapsel-Mitte (Kapsel 1.8 m) +const KILL_Y_DROP_M := -200.0 # Notfall: unter die Welt gefallen → Respawn +const KAPSEL_RADIUS := 0.35 +const KAPSEL_HEIGHT := 1.8 +const HALF_H := 0.9 # Kapsel-Halbhöhe (Kapsel 1.8 m) — Füße = y − 0.9 +const STEP_HEIGHT := 0.45 # = TestmapPlayer.STEP_HEIGHT (Karte t_f9adf97c) +const STEP_PROBE_DIST := 0.7 +const STEP_LIFT_EPS := 0.02 + +# --- Editor-seitige Konventionen (unverändert gegenüber dem alten Body) ----- +const DEFAULT_MOUSE_SENS := 0.25 # Grad pro Pixel Mausbewegung +const PITCH_LIMIT := 89.0 # Kopfüber/Nackenschmerz-Grenze +const TELEPORT_REICHWEITE := 4000.0 + +## Spielbare Parameter +var mouse_sens: float = DEFAULT_MOUSE_SENS + +## Map-Dokument (nur LESEND — Terrain-Raster für Spawn/HUD/Notfall) +var doc: Dictionary = {} +## Fliegen / God-Mode (Karte t_aaff5dcc, Taste G): KEINE Gravitation, Bewegung +## in Blickrichtung (inkl. Nickwinkel), Space = steigen, Noclip — der Tester +## kommt auch über Wände/Hügel schnell ans Ziel. +var fly_mode := false +## Autopilot-Haken (wie TestmapPlayer.auto_move_dir, Karte t_f9adf97c): +## nicht-leer = DIESER Welt-Vektor ist der Bewegungswunsch (Tastatur aus). +var auto_move_dir := Vector3.ZERO +## Autopilot-Ergänzung für Suiten: Sprung/Run erzwingen ohne Tastatur. +var auto_jump := false +var auto_run := false +## Suite-Hook: nicht-leer = komplettes Input-Dictionary überschreibt ALLES +## (gleiche Form wie der alte step()-Input: fwd/back/left/right/run/jump). +var auto_input: Dictionary = {} + +## Bewegungszustand (Kompatibilität zur alten Oberfläche) +var yaw_deg: float = 0.0 # Gierwinkel Blickrichtung (Grad) +var pitch_deg: float = 0.0 # Nickwinkel Blickrichtung (Grad) +var on_floor: bool = false + +## Kinder: die Spiel-Kamera (Augen) — PlaytestMode hängt sie an und macht current +var look_cam: Camera3D + +## Höhenfeld-Cache (Zeile: res*res Meter) — von PlaytestMode via set_terrain() +## gefüllt (Spawn/HUD/jump_to_spawn; die PHYSIK läuft über den Trimesh-Kollider). +var heights: PackedFloat32Array = PackedFloat32Array() +var res: int = 0 +var size_x: float = 0.0 +var size_z: float = 0.0 +var hmin: float = 0.0 +var hmax: float = 0.0 + +var _spawn_pos := Vector3.ZERO + + +func _ready() -> void: + _spawn_pos = global_position + var cs := CollisionShape3D.new() + var capsule := CapsuleShape3D.new() + capsule.radius = KAPSEL_RADIUS + capsule.height = KAPSEL_HEIGHT + cs.shape = capsule + add_child(cs) + look_cam = Camera3D.new() + look_cam.name = "Camera" + look_cam.position.y = EYE_HEIGHT + look_cam.far = 4000.0 + add_child(look_cam) + look_cam.current = true + _baue_dritte_kamera() + _apply_look() + + +## Third-Person-Kamera (Karte t_17a35c59): SpringArm3D = RayCast hinter dem +## Spieler — die Kamera wird an die Kollision zurückgezogen (kein Clipping +## durch Wände). Pivot auf Augenhöhe, Arm-Länge 3,5 m + 0,3 m Margin, der +## eigene Body ist ausgeschlossen (sonst trifft der Strahl die eigene Kapsel). +func _baue_dritte_kamera() -> void: + spring = SpringArm3D.new() + spring.name = "ThirdPersonArm" + spring.position = Vector3(0.0, EYE_HEIGHT, 0.0) + spring.spring_length = 3.5 + spring.margin = 0.3 + spring.collision_mask = 1 + tpp_cam = Camera3D.new() + tpp_cam.name = "ThirdPersonCamera" + tpp_cam.far = 4000.0 + spring.add_child(tpp_cam) + add_child(spring) + spring.add_excluded_object(get_rid()) + tpp_cam.current = false + + +## Kinder: die Third-Person-Kamera (SpringArm + Kamera) — Karte t_17a35c59. +var spring: SpringArm3D = null +var tpp_cam: Camera3D = null + +## Playtest-Avatar (Spiegel des Bot-Rigs, playtest_avatar.gd). null = kein +## Client-Klon/Modell → Third Person bleibt gesperrt (graceful Fallback). +var avatar: Node3D = null + +## Perspektive (Taste V, persistiert in PlaytestSettings): false = First +## Person (Standard), true = Third Person (Avatar sichtbar, Kamera hinten). +var perspektive_dritte := false + + +## Blickrichtung auf Körper + Kameras übertragen. +## Der BODY rotiert mit dem Blick-Yaw (wie TestmapPlayer.rotate_y) — das +## trägt die Avatar-Front (Kind des Körpers) und die Third-Person-Kamera. +## Die WASD-Bewegung selbst folgt dem Yaw über _fahren (parallel gefixt in +## 52919b3, dort aus yaw_deg gebaut — beide Wege ergeben dieselbe Richtung). +## Vor beiden Fixes blieb der Body ungedreht (Beweis-Probe +## tests/probe_move_dir.gd: yaw −90° + W → −Z statt +X = weltachsen-fixiert). +func _apply_look() -> void: + # 1:1 TestmapPlayer: der BODY trägt den Yaw (rotate_y), die Kamera nur + # den Pitch — sonst doppelt sich die Drehung (Kamera hängt am Körper). + rotation.y = deg_to_rad(yaw_deg) + if look_cam == null: + return + look_cam.rotation = Vector3(deg_to_rad(pitch_deg), 0.0, 0.0) + look_cam.position = Vector3(0.0, EYE_HEIGHT, 0.0) + # Third Person: die SpringArm-Kamera teilt dieselbe Blickachse (Yaw über + # den Körper, Pitch über den Arm) — Blickrichtung == Kamerarichtung. + if spring != null: + spring.rotation = Vector3(deg_to_rad(pitch_deg), 0.0, 0.0) + + +## Füß-Höhe über der Welt (Kapsel-Mitte minus Halbhöhe) — HUD/Tests. +func fuss_hoehe() -> float: + return global_position.y - HALF_H + + +## Volle 3D-Blickrichtung (Karte t_aaff5dcc): -Z um Pitch (X) und Yaw (Y) +## gedreht — genau die Blickachse der Kamera. Fliegen bewegt entlang DIESEM +## Vektor (Blick nach unten = abwärts fliegen), Gehen nur horizontal. +func view_direction() -> Vector3: + var yaw_rad := deg_to_rad(yaw_deg) + var pitch_rad := deg_to_rad(pitch_deg) + return Vector3(-sin(yaw_rad) * cos(pitch_rad), sin(pitch_rad), + -cos(yaw_rad) * cos(pitch_rad)) + + +## Echter Physics-Step: Input zusammenbauen (Tasten ODER Autopilot) → fahren. +func _physics_process(delta: float) -> void: + var input := {} + if not auto_input.is_empty(): + input = auto_input + else: + input = { + "fwd": Input.is_key_pressed(KEY_W), + "back": Input.is_key_pressed(KEY_S), + "left": Input.is_key_pressed(KEY_A), + "right": Input.is_key_pressed(KEY_D), + "run": Input.is_key_pressed(KEY_SHIFT) or auto_run, + "jump": Input.is_key_pressed(KEY_SPACE) or auto_jump, + } + if auto_move_dir.length_squared() > 0.0: + input["auto_dir"] = auto_move_dir + _fahren(delta, input) + + +## Ein Bewegungs-Schritt (physics frame) mit EXPLIZITEM Input ausführen. +## input = {fwd, back, left, right, run, jump: bool, auto_dir: Vector3}. +## DIESE Methode ist 1:1 die _physics_process des TestmapPlayers — +## identische Bewegungsmathe, identische Step-Up-Aufrufreihenfolge. +func _fahren(delta: float, input: Dictionary) -> void: + # --- Fliegen / God-Mode (Karte t_aaff5dcc, Taste G) ---------------------- + # Keine Gravitation, Bewegung in der VOLLEN Blickrichtung, Space = steigen, + # Noclip (direkt positionieren — kein move_and_slide, kein Kollider). + if fly_mode: + var fly_speed := WALK_SPEED if not bool(input.get("run", false)) else SPRINT_SPEED + var fly_yaw_rad := deg_to_rad(yaw_deg) + var fly_right := Vector3(cos(fly_yaw_rad), 0.0, -sin(fly_yaw_rad)) + var wish3: Vector3 + var ad: Variant = input.get("auto_dir", null) + if ad is Vector3 and (ad as Vector3).length_squared() > 0.0: + wish3 = (ad as Vector3).normalized() * fly_speed + else: + wish3 = view_direction() * (1.0 if bool(input.get("fwd", false)) else 0.0) \ + - view_direction() * (1.0 if bool(input.get("back", false)) else 0.0) \ + + fly_right * (1.0 if bool(input.get("right", false)) else 0.0) \ + - fly_right * (1.0 if bool(input.get("left", false)) else 0.0) + if bool(input.get("jump", false)): + wish3 += Vector3.UP + if wish3.length_squared() > 0.0: + wish3 = wish3.normalized() * fly_speed + velocity = wish3 + position += velocity * delta + on_floor = false + _apply_look() + return + + # Welt-Richtung aus dem Blickwinkel (y-only, wie Client). WICHTIG: aus + # yaw_deg bauen, NICHT aus transform.basis (Sly-Befund 20.10.: WASD lief + # sonst stur in eine Himmelsrichtung). Seit t_17a35c59 rotiert der + # Körperknoten ZUSÄTZLICH mit dem Yaw (_apply_look — Avatar-Front und + # Third-Person-Kamera hängen daran); die Bewegung bleibt bewusst an + # yaw_deg gekoppelt — beide Wege führen auf dieselbe Richtung, die + # Entkopplung hält die Bewegung unabhängig vom Avatar-Zustand. + # Identisch zu view_direction(). + var yaw_rad := deg_to_rad(yaw_deg) + var forward := Vector3(-sin(yaw_rad), 0.0, -cos(yaw_rad)) + var right := Vector3(cos(yaw_rad), 0.0, -sin(yaw_rad)) + var dir := Vector3.ZERO + var ad2: Variant = input.get("auto_dir", null) + if ad2 is Vector3 and (ad2 as Vector3).length_squared() > 0.0: + dir = ad2 as Vector3 + else: + if bool(input.get("fwd", false)): + dir += forward + if bool(input.get("back", false)): + dir -= forward + if bool(input.get("right", false)): + dir += right + if bool(input.get("left", false)): + dir -= right + var speed := SPRINT_SPEED if bool(input.get("run", false)) else WALK_SPEED + if dir.length_squared() > 0.0: + dir = dir.normalized() * speed + velocity.x = dir.x + velocity.z = dir.z + if is_on_floor() and bool(input.get("jump", false)): + velocity.y = JUMP_SPEED + if not is_on_floor(): + velocity.y -= GRAVITY * delta + var pre_pos := global_position + move_and_slide() + # Stufen-Hilfe (Karte t_f9adf97c, 1:1 aus TestmapPlayer): nach + # move_and_slide() prüfen, ob die horizontale Bewegung von einer Wand + # gestoppt wurde, während der Wunsch weiter in die Wand zeigt. + var wish_xz := Vector3(dir.x, 0.0, dir.z) + var blocked := false + if wish_xz.length_squared() > 0.0001: + if is_on_wall() and get_wall_normal().dot(wish_xz.normalized()) < -0.1: + blocked = true + else: + var got := global_position - pre_pos + got.y = 0.0 + var want := wish_xz * delta + if got.length() < want.length() * 0.4: + blocked = true + if blocked: + try_step_up(wish_xz) + if global_position.y < KILL_Y_DROP_M: + # Sicherheitsnetz (sollte mit Trimesh-Terrain nicht passieren). + global_position = _spawn_pos + velocity = Vector3.ZERO + on_floor = is_on_floor() + _apply_look() + + +## ------------------------------------------------------------------ +## Stufen-Hilfe — 1:1 aus client/scripts/world/testmap_player.gd +## (Karte t_f9adf97c): Stufen bis STEP_HEIGHT erklimmen. Nach +## move_and_slide(), wenn die horizontale Bewegung von einer Wand gestoppt +## wurde UND der Bewegungswunsch in die Wand zeigt: +## Ray 1 (Fußhöhe vorwärts) → Wand-/Kanten-Fläche finden, +## Ray 2 (Kopfhöhe vorwärts) → Wand überragt die Stufenhöhe? → blockt, +## Ray 3 (über der Kante abwärts) → neue Standfläche messen, +## Decken-Strahl → Platz für die Kapsel über der Stufe? +## ------------------------------------------------------------------ +func _capsule_half_height() -> float: + for child in get_children(): + var cs := child as CollisionShape3D + if cs != null and cs.shape is CapsuleShape3D: + return (cs.shape as CapsuleShape3D).height * 0.5 + return 0.9 + + +func try_step_up(wish: Vector3) -> bool: + var dir := Vector3(wish.x, 0.0, wish.z) + if not is_on_floor() or dir.length_squared() < 0.0001: + return false + dir = dir.normalized() + var space := get_world_3d().direct_space_state + if space == null: + return false + var half_h := _capsule_half_height() + var feet := global_position.y - half_h + var mask := collision_mask # nur die Welt tasten, nicht den eigenen Körper + var exclude: Array[RID] = [get_rid()] + + # Ray 1: vorwärts in Knöchelhöhe — gibt es überhaupt eine Stufe/Wand? + var ankle := global_position + Vector3(0.0, -half_h + 0.05, 0.0) + var q1 := PhysicsRayQueryParameters3D.create( + ankle + dir * 0.1, ankle + dir * STEP_PROBE_DIST, mask, exclude) + var hit1 := space.intersect_ray(q1) + if hit1.is_empty(): + return false + if (hit1["normal"] as Vector3).dot(dir) > -0.3: + return false # Fläche zeigt nicht gegen die Laufrichtung (Rampe/Kante) + + # Ray 2: vorwärts knapp ÜBER der maximalen Stufenhöhe — trifft er die + # Wand noch, ist sie höher als STEP_HEIGHT → kein Anheben. + var top_probe := global_position + Vector3(0.0, -half_h + STEP_HEIGHT + 0.01, 0.0) + var q2 := PhysicsRayQueryParameters3D.create( + top_probe + dir * 0.1, top_probe + dir * STEP_PROBE_DIST, mask, exclude) + if not space.intersect_ray(q2).is_empty(): + return false # Wand überragt die Stufenhöhe + + # Ray 3: über der Kante abwärts — neue Standfläche messen (Startpunkt + # liegt über Ray 2 frei, also außerhalb der Wand). + var edge := (hit1["position"] as Vector3) + dir * 0.1 + var q3 := PhysicsRayQueryParameters3D.create( + Vector3(edge.x, feet + STEP_HEIGHT + 0.05, edge.z), + Vector3(edge.x, feet - 0.05, edge.z), mask, exclude) + var hit3 := space.intersect_ray(q3) + if hit3.is_empty(): + return false + var new_feet := (hit3["position"] as Vector3).y + if new_feet < feet - 0.01: # Abgrund statt Fläche? Nichts anheben. + return false + var diff := new_feet - feet + if diff > STEP_HEIGHT + 0.005 or diff <= 0.0: + return false + if (hit3["normal"] as Vector3).y < 0.5: + return false # keine begehbare Fläche (Decke/Schräge von unten) + + # Decken-Check: Platz für die volle Kapselhöhe über der neuen Standfläche? + # An der Ziel-XZ prüfen (etwas vorwärts — dort landt die Kapsel nach dem + # Schritt), sonst entgeht die Terrassen-Decke über dem Stufenkopf. + var check := global_position + dir * 0.45 + var q4 := PhysicsRayQueryParameters3D.create( + Vector3(check.x, new_feet + 0.05, check.z), + Vector3(check.x, new_feet + half_h * 2.0 + 0.05, check.z), + mask, exclude) + if not space.intersect_ray(q4).is_empty(): + return false # Decke zu tief (z. B. Terrassen-Untersicht): unten bleiben + + # Sanftes Anheben: Positions-Snap auf die neue Standfläche … + global_position.y = new_feet + half_h + STEP_LIFT_EPS + # … und Bewegung fortführen: der zweite move_and_slide()-Schritt trägt + # die Kapsel VOR die Kante auf die neue Stufe (sonst steht sie nur + # tangential auf der Kante und fällt zurück). + move_and_slide() + return true + + +## Maus-Bewegung (nur der Spieler selbst fängt sie — die Editor-Werkzeuge +## sind im Lauf-Modus eingefroren). +func _unhandled_input(event: InputEvent) -> void: + if event is InputEventMouseMotion: + var mm := event as InputEventMouseMotion + yaw_deg = wrapf(yaw_deg - mm.relative.x * mouse_sens, -180.0, 180.0) + pitch_deg = clampf(pitch_deg - mm.relative.y * mouse_sens, + -PITCH_LIMIT, PITCH_LIMIT) + _apply_look() + get_viewport().set_input_as_handled() + + +## ESC-Request — wird von main.gd angerufen (die Esc-Priorität gehört dort +## hin, damit die normale Esc-Kette NICHT auch noch zieht). +func request_exit() -> void: + exit_requested.emit() + + +## Terrain-Raster EINMALIG aus dem Dokument dekodieren (R16/LE/Base64 → +## Meter-Array). Nutzt den Standard-Decoder SvmapIO.decode_heights (derselbe +## Code wie beim Editor-Rendering) — nichts neu rechnen. Die PHYSIK läuft +## über den Trimesh-Kollider (KolliderBau.terrain_form, identisch zum +## Client); dieses Raster dient Spawn/jump_to_spawn/HUD-Referenz. +func set_terrain(d: Dictionary) -> void: + doc = d + heights = PackedFloat32Array() + res = 0 + size_x = 0.0 + size_z = 0.0 + hmin = 0.0 + hmax = 0.0 + if d.is_empty(): + return + var terrain: Dictionary = d.get("terrain", {}) + res = int(terrain.get("resolution", 0)) + size_x = float(terrain.get("size_x_m", 0.0)) + size_z = float(terrain.get("size_z_m", 0.0)) + hmin = float(terrain.get("min_height_m", 0.0)) + hmax = float(terrain.get("max_height_m", 0.0)) + if res < 2 or size_x <= 0.0 or size_z <= 0.0: + return + var decoded: PackedFloat32Array = SvmapIO.decode_heights(terrain) + if decoded.size() < res * res: + return + heights = decoded + + +## Teleport zum Punkt unter dem Fadenkreuz (Karte t_96e3c4ee, Taste T im +## Testlauf): Strahl aus dem Auge gegen die ECHTE Physik-Welt (Trimesh- +## Terrain + Objekt-/Bauteil-Kollider — dieselben Flächen wie im Spiel). +## Gelandet wird auf dem Boden DARUNTER (Strahl senkrecht abwärts). Nie im +## Objekt landen: ist die Kapsel am Zielpunkt nicht frei, wird der Teleport +## abgelehnt (ok=false). Rückgabe: {ok, x, z, ground, msg}. +func teleport_to_ground(origin: Vector3, dir: Vector3) -> Dictionary: + var space := get_world_3d().direct_space_state + if space == null: + return {"ok": false, "x": 0.0, "z": 0.0, "ground": 0.0, + "msg": "Kein Boden unterm Fadenkreuz — hier kann der Test-Start nicht hin."} + var d := dir + if d.length_squared() > 0.000000001: + d = d.normalized() + var q := PhysicsRayQueryParameters3D.create(origin, origin + d * TELEPORT_REICHWEITE) + q.exclude = [get_rid()] + var hit := space.intersect_ray(q) + if hit.is_empty(): + return {"ok": false, "x": 0.0, "z": 0.0, "ground": 0.0, + "msg": "Kein Boden unterm Fadenkreuz — hier kann der Test-Start nicht hin."} + var ziel := hit["position"] as Vector3 + # Boden DARUNTER: senkrechter Strahl ab etwas über dem Treffer — trifft + # er nichts (Treffer war eine Wandfläche ohne Boden drunter), Terrain- + # Raster als Rückfallebene. + var ground := ziel.y + var q2 := PhysicsRayQueryParameters3D.create( + Vector3(ziel.x, ziel.y + 0.5, ziel.z), + Vector3(ziel.x, ziel.y - 50.0, ziel.z)) + q2.exclude = [get_rid()] + var hit2 := space.intersect_ray(q2) + if hit2.is_empty(): + ground = terrain_height(ziel.x, ziel.z) + else: + ground = (hit2["position"] as Vector3).y + var tx := ziel.x + var tz := ziel.z + # Landeplatz prüfen: passt die Kapsel dort frei? (Nie im Objekt landen.) + var probe := CapsuleShape3D.new() + probe.radius = KAPSEL_RADIUS + probe.height = KAPSEL_HEIGHT + var qp := PhysicsShapeQueryParameters3D.new() + qp.shape = probe + qp.transform = Transform3D(Basis.IDENTITY, + Vector3(tx, ground + HALF_H + 0.02, tz)) + qp.exclude = [get_rid()] + if not space.intersect_shape(qp, 1).is_empty(): + return {"ok": false, "x": tx, "z": tz, "ground": ground, + "msg": "Da steht etwas im Weg (%.1f, %.1f) — dort kannst du nicht landen." % [tx, tz]} + position = Vector3(tx, ground + HALF_H + 0.02, tz) + velocity = Vector3.ZERO + on_floor = true + _apply_look() + return {"ok": true, "x": tx, "z": tz, "ground": ground, "msg": ""} + + +## Terrain-Höhe an Welt-X/Z — aus dem DOCUMENT-Raster (nichts neu rechnen). +## Referenz für Spawn/jump_to_spawn/HUD; die Physik nutzt den Trimesh. +func terrain_height(x: float, z: float) -> float: + if res < 2 or size_x <= 0.0 or size_z <= 0.0: + return hmin + if heights.size() < res * res: + return hmin + var last := float(res - 1) + var fx := clampf((x / size_x + 0.5) * last, 0.0, last) + var fz := clampf((z / size_z + 0.5) * last, 0.0, last) + var xi := int(floor(fx)) + var zi := int(floor(fz)) + var tx := fx - float(xi) + var tz := fz - float(zi) + var xi1 := mini(xi + 1, res - 1) + var zi1 := mini(zi + 1, res - 1) + var h00 := _sample(xi, zi) + var h10 := _sample(xi1, zi) + var h01 := _sample(xi, zi1) + var h11 := _sample(xi1, zi1) + return lerpf(lerpf(h00, h10, tx), lerpf(h01, h11, tx), tz) + + +func _sample(xi: int, zi: int) -> float: + var idx := zi * res + xi + if idx < 0 or idx >= heights.size(): + return hmin + return heights[idx] + + +## Maus-Empfindlichkeit als Multiplikator setzen (Karte t_aaff5dcc, 0,1–5,0, +## Standard 1,0): die Body-Basis (DEFAULT_MOUSE_SENS Grad/Pixel) wird mit dem +## Multiplikator skaliert — jede PC/Maus-Kombination ist anders. +func set_sensitivity(mult: float) -> void: + var m := clampf(mult, PlaytestSettings.MIN_SENS, PlaytestSettings.MAX_SENS) + mouse_sens = DEFAULT_MOUSE_SENS * m + + +# ------------------------------------------ Avatar + Perspektive (V) ------- +# Karte t_17a35c59: derselbe Avatar wie die Bots im Spiel (Spiegel-Modul +# playtest_avatar.gd, GLB aus dem Nachbar-Klon), umschaltbar First/Third. + +## Avatar (aus PlaytestAvatar.lade_avatar) anhängen. Anker: Kopf-Anker- +## Konvention des Clients (bot_avatar.gd) — Avatar-Node in Augenhöhe +## (MODEL_EYE_HEIGHT 1,65 m) über dem Füßpunkt, GLB-Kind hängt mit +## MODEL_Y_OFFSET nach unten. null = kein Modell (Third bleibt gesperrt). +func set_avatar(node: Node3D) -> void: + if avatar != null and is_instance_valid(avatar): + avatar.queue_free() + avatar = node + if avatar == null: + perspektive_dritte = false + _apply_perspektive() + return + # add_child reparentet NICHT — ein Node mit altem Parent würde still + # abgelehnt (Probe 20.10.: Avatar blieb unter root). Erst lösen, dann + # als Kind anhängen. + if avatar.get_parent() != null: + avatar.get_parent().remove_child(avatar) + add_child(avatar) + avatar.position = Vector3(0.0, + PlaytestAvatar.MODEL_EYE_HEIGHT - HALF_H, 0.0) + # Start-Zustand sauber in den Baum schreiben (apply_state vor add_child + # könnte Tree-Parameter noch nicht flushen). + avatar.call("apply_state", PlaytestAvatar.STATE_IDLE, 0.0) + _apply_perspektive() + + +## Taste V: Perspektive umschalten. Rückgabe: neuer Zustand (true = Third). +## Ohne Avatar bleibt First Person aktiv (graceful Fallback — Meldung macht +## der Aufrufer/PlaytestMode). +func toggle_perspektive() -> bool: + var neu := not perspektive_dritte + if avatar == null: + neu = false + return set_perspektive(neu) + + +## Perspektive direkt setzen (Enter-Pfad liest PlaytestSettings). Rückgabe: +## der tatsächlich aktive Zustand (ohne Avatar nie Third). +func set_perspektive(dritte: bool) -> bool: + if avatar == null: + dritte = false + perspektive_dritte = dritte + _apply_perspektive() + return perspektive_dritte + + +## Sichtbarkeit + aktive Kamera je Perspektive: +## First Person — Avatar unsichtbar (Kapsel bleibt physisch aktiv, +## Kamera auf Augenhöhe wie Client-TestmapPlayer), +## Third Person — Avatar sichtbar, SpringArm-Kamera hinter/über dem +## Spieler mit Wand-Kollision (kein Clipping). +func _apply_perspektive() -> void: + if avatar != null and is_instance_valid(avatar): + avatar.visible = perspektive_dritte + if look_cam != null: + look_cam.current = not perspektive_dritte + if tpp_cam != null: + tpp_cam.current = perspektive_dritte + + +## Echte horizontale Geschwindigkeit (m/s) aus dem letzten Physik-Schritt — +## Quelle für die Avatar-Gait-Speisung (Stillstand/Walk/Jog aus der realen +## Bewegung, nicht aus dem Input-Wunsch). +func horizontale_geschwindigkeit() -> float: + var v := velocity + v.y = 0.0 + return v.length() diff --git a/editor/playtest/playtest_body.gd.uid b/editor/playtest/playtest_body.gd.uid new file mode 100644 index 0000000..035ed25 --- /dev/null +++ b/editor/playtest/playtest_body.gd.uid @@ -0,0 +1 @@ +uid://csv8o2g8wdtue diff --git a/editor/playtest/playtest_mode.gd b/editor/playtest/playtest_mode.gd new file mode 100644 index 0000000..c43c4bc --- /dev/null +++ b/editor/playtest/playtest_mode.gd @@ -0,0 +1,536 @@ +extends Node +## Lauf-Modus (Karte t_1cdc1a72): erste Person IM Map-Builder selbst — +## kein Client-Ordner, kein zweiter Prozess, kein VR/OpenXR, kein Server. +## +## Verantwortung dieses Zustands: +## - Beim Start: die map_view_builder-Ausgabe (Modelle + Pack-Texturen) +## 1:1 weiterverwenden (der Node3D-Baum bleibt stehen, nur Editor-UI/Input +## geht weg), Maus-Capture-Wunsch setzen, Panels ausblenden. +## - Kollider-Bau via KolliderBau (core/svmap/kollider_bau.gd — 1:1-Spiegel +## des Quest-Clients, Karte t_1da96275): Terrain-Trimesh + Objekt-Kollider +## (box/kugel/zylinder/verbund/trimesh inkl. library/kollisions-Quellen) +## + Bauteil-Trimeshe (bau_*-Objekte: Treppen/Türen/Wände begehbar +## wie echte Geometrie). +## - PlaytestBody (CharacterBody3D, IDENTISCHE Parameter wie der +## Testmap-Spieler inkl. Step-Up 0.45 m) anlegen, Terrain-Raster EINMAL +## dekodieren, Start = erster Spawnpunkt (Team Blau), sonst Kartenmitte. +## - ESC → exit_requested → main.gd stellt den Editor-Zustand 1:1 wieder her +## (Panels, Maus, Kamera, Auswahl, Dokument, Undo-Stapel unverändert). +## - HUD (Position, FPS, „ESC = zurück zum Editor") als CanvasLayer-Overlay. +## +## Bewusst KEIN _physics_process hier: alle Bewegung/Eingabe lebt im +## PlaytestBody; dieser Zustand managed nur Lifecycle + HUD. + +const BODY_SCRIPT := "res://core/editor/playtest/playtest_body.gd" +const KOLLIDER_SCRIPT := "res://core/svmap/kollider_bau.gd" +const AVATAR_SCRIPT := "res://core/editor/playtest/playtest_avatar.gd" + +## Der laufende Spieler (PlaytestBody, CharacterBody3D mit echter Physik) +var body: Node3D = null +## Welt-Kollider (Terrain + Objekte + Bauteile) — Kind dieses Modus, +## wird mit exit() abgeräumt. +var _kollider_root: Node3D = null + +## Editor-UI-Verweise (vom main.gd-Handler gesetzt): die Panels, die +## AUSGEBLENDET werden sollen (Variant statt Control-Typ — keine UI-Kopie). +var ui_panels: Array = [] # Array[Control] +var ui_status: Variant = null # Statuszeilen-Label (nur visible umschalten) +var help_label: Variant = null # Hilfe-Label (nur visible umschalten) + +## Maus-Capture-Wunsch (Suite testet diesen Zustand) +var _want_capture := false +## HUD-Elemente +var hud: CanvasLayer = null +var hud_pos: Label = null +var hud_fps: Label = null +var hud_hint: Label = null +var hud_msg: Label = null # Klartext-Nachricht (z. B. Test-Start via T) +var hud_dir: Label = null # Blickrichtung + Höhe (Karte t_aaff5dcc) +## Hilfe-Overlay (F1, Karte t_aaff5dcc): alle Tasten im Klartext. +var help_layer: CanvasLayer = null +## Kartenmitte/Achsen-Linien (Taste X, Karte t_aaff5dcc — praktisch beim +## gespiegelten Bauen, Karte M1): X-Rot/Z-Blau/Y-Grün durch die Kartenmitte. +var _axis_node: Node3D = null +## FPS-Smoothing (Anzeige, keine Physik) +var _fps_smooth := 0.0 +## Ist der Lauf-Modus gerade aktiv? (Reentrancy-Schutz für enter/exit) +var active := false +## Avatar-Modelle waren beim Start verfügbar? (Karte t_17a35c59 — ohne +## Client-Klon bleibt Third Person gesperrt, graceful Fallback.) +var _avatar_da := false + +signal exit_requested + + +## Starten: übernimmt die Sicht (Panels aus, Maus-Capture-Wunsch an) und +## legt den Spieler am Startpunkt an. Fallback-Reihenfolge (Karte t_96e3c4ee, +## je mit Klartext-Hinweis): gesetzter Test-Start (start_override) → erster +## Spawnpunkt (Team Blau) → Kartenmitte. start_override = Vector3 (nur x/z +## zählen, Höhe kommt automatisch vom Terrain) oder null (= altes Verhalten). +## view_builder = der map_view_builder-Node (Marker-Tree mit pick_radius/ +## half_height-Metas bleibt stehen und liefert die Hindernis-Blöcke). +func enter(doc: Dictionary, view_builder: Node3D, start_override: Variant = null) -> void: + if active: + return + active = true + _set_ui_visible(false) + _set_status_capture(true) + + body = load(BODY_SCRIPT).new() + body.call("set_terrain", doc) + var start := _spawn_start(doc) + if start_override != null: + var sp := start_override as Vector3 + start = Vector3(sp.x, 0.0, sp.z) + # Spawn AUF der Terrainhöhe: Kapsel-Mitte = Füße + Halbhöhe (+ Toleranz, + # die Physik lässt den Body sanft auf den Trimesh fallen — wie im Spiel). + body.position = Vector3(start.x, + body.terrain_height(start.x, start.z) + PlaytestBody.HALF_H + 0.05, + start.z) + if start_override == null: + var first := _first_spawn(doc) + if first.has(SpawnOps.YAW_KEY): + body.yaw_deg = float(first[SpawnOps.YAW_KEY]) + # Kollider 1:1 vom Quest-Client (Karte t_1da96275): Terrain-Trimesh + + # Objekt-Kollider aus der Registry + Bauteil-Trimeshe. Alles als Kind + # dieses Modus — exit() räumt es mit ab. + _baue_kollider(doc) + add_child(body) + # Maus-Empfindlichkeit aus den Einstellungen (Karte t_aaff5dcc): der + # gespeicherte Multiplikator (0,1–5,0) skaliert die Body-Basis. + body.call("set_sensitivity", PlaytestSettings.load_sens()) + + # Playtest-Avatar (Karte t_17a35c59): derselbe Rig wie die Bots im Spiel + # (GLB aus dem Nachbar-Klon ../scopedvr-client). Fehlt der Klon/Modell: + # graceful — First Person bleibt, Third Person wird per Meldung gesperrt. + var avatar: Node3D = load(AVATAR_SCRIPT).call("lade_avatar") as Node3D + _avatar_da = avatar != null + if _avatar_da: + body.call("set_avatar", avatar) + # Persistierte Perspektive (Taste V): Third nur mit Avatar — sonst + # First Person wie bisher + Klartext-Hinweis. + if PlaytestSettings.load_third(): + if _avatar_da: + body.call("set_perspektive", true) + else: + show_message("Gespeicherte Third-Person-Einstellung ist ohne Avatar-Modelle nicht verfügbar (Client-Klon ../scopedvr-client fehlt) — First Person aktiv.") + + _build_hud() + exit_requested.connect(_on_exit_requested, CONNECT_ONE_SHOT) + + +## Zurück in den Editor: HUD weg, Spieler weg, Panels sichtbar. +## Editor-Zustand (Kamera, Auswahl, Dokument, Undo-Stapel) wird NICHT hier +## angefasst — das macht main.gd nach dem Signal. +func exit() -> void: + if not active: + return + active = false + _set_status_capture(false) + _set_ui_visible(true) + if body != null: + body.queue_free() + body = null + if _kollider_root != null: + _kollider_root.queue_free() + _kollider_root = null + if hud != null: + hud.queue_free() + hud = null + if help_layer != null: + help_layer.queue_free() + help_layer = null + if _axis_node != null: + _axis_node.queue_free() + _axis_node = null + + +func _on_exit_requested() -> void: + exit() + + +## Status/Maus-Capture-Wunsch: nur der Zustand (Suite testet wants_capture). +func _set_status_capture(want: bool) -> void: + _want_capture = want + + +## Panelselemente ausblenden/einblenden. Nur die als ui_panels übergebenen +## Controls werden angefasst — keine weiteren. +func _set_ui_visible(vis: bool) -> void: + for p in ui_panels: + if p is Control: + (p as Control).visible = vis + if ui_status is Control: + (ui_status as Control).visible = vis + if help_label is Control: + (help_label as Control).visible = vis + + +## Start-Punkt: erster Spawn-Punkt aus dem Dokument (spawn_zones-Team „0", +## erster Eintrag der points-Liste); sonst Kartenmitte aus den Bounds. +## doc-Format (svmap): {"spawn_zones": {"0": {"points": [{"id", "pos": [x,y,z]}]}, ...}} +func _first_spawn(doc: Dictionary) -> Dictionary: + var team0 = (doc.get("spawn_zones", {}) as Dictionary).get("0", {}) + if team0 is Dictionary: + var points: Array = (team0 as Dictionary).get("points", []) + if not points.is_empty() and points[0] is Dictionary: + return points[0] + return {} + + +func _spawn_start(doc: Dictionary) -> Vector3: + var zones: Dictionary = doc.get("spawn_zones", {}) + var team0 = zones.get("0", {}) + if team0 is Dictionary: + var points: Array = (team0 as Dictionary).get("points", []) + if not points.is_empty() and points[0] is Dictionary: + var pos = (points[0] as Dictionary).get("pos", []) + if pos is Array and (pos as Array).size() >= 3: + return Vector3(float(pos[0]), 0.0, float(pos[2])) + var bounds: Dictionary = doc.get("bounds", {}) + var mn: Array = bounds.get("min", [-50.0, -10.0, -50.0]) + var mx: Array = bounds.get("max", [50.0, 80.0, 50.0]) + return Vector3((float(mn[0]) + float(mx[0])) * 0.5, 0.0, + (float(mn[2]) + float(mx[2])) * 0.5) + + +## Echter Kollider-Bau (Karte t_1da96275 — „Editor-Playtest-Physik = Quest 3 +## identisch"): der alte AABB-Blocking-Code ist ENTFERNT. Es gibt genau EINEN +## Kollider-Pfad, denselben wie der Quest-Client: +## - Terrain + Registry-Objekte: KolliderBau.baue_welt_kollider (1:1-Spiegel +## von svmap_world.gd — box/kugel/zylinder/verbund/trimesh inkl. +## library/kollisions-Quelldateien). +## - Bauteile (bau_*) sind normale Registry-Objekte mit Trimesh aus +## library/kollisions — Türen/Fenster bleiben Durchgänge, Treppen begehbar. +func _baue_kollider(doc: Dictionary) -> void: + var kb := load(KOLLIDER_SCRIPT) + _kollider_root = kb.call("baue_welt_kollider", doc) + add_child(_kollider_root) + + +# ------------------------------------------------------------------- HUD ---- + +func _build_hud() -> void: + hud = CanvasLayer.new() + hud.layer = 100 + var margin := MarginContainer.new() + margin.add_theme_constant_override("margin_left", 16) + margin.add_theme_constant_override("margin_top", 16) + margin.set_anchors_preset(Control.PRESET_TOP_LEFT) + hud.add_child(margin) + var vbox := VBoxContainer.new() + margin.add_child(vbox) + hud_pos = Label.new() + hud_fps = Label.new() + hud_hint = Label.new() + hud_msg = Label.new() + hud_dir = Label.new() + hud_hint.text = "WASD + Maus · Shift = rennen · Space = springen/steigen · G = Fliegen · V = 1./3.-Person · 1-4 = Spawnpunkt · T = Test-Start · H = HUD · X = Achsen · F1 = Hilfe · ESC = zurück zum Editor" + hud_msg.text = "" + for l: Label in [hud_pos, hud_dir, hud_fps, hud_hint, hud_msg]: + l.add_theme_font_size_override("font_size", 16) + l.add_theme_color_override("font_color", Color(0.55, 0.8, 1.0)) + vbox.add_child(l) + add_child(hud) + + +## Klartext-Nachricht im HUD (die Editor-Statuszeile ist im Lauf-Modus +## ausgeblendet — hier landet das Feedback für Taste T, Karte t_96e3c4ee). +func show_message(text: String) -> void: + if hud_msg != null and is_instance_valid(hud_msg): + hud_msg.text = text + + +## Taste T im Testlauf (Karte t_96e3c4ee, „jederzeit“): setzt den Test-Start +## auf den Punkt unterm Fadenkreuz und versetzt den Spieler SOFORT dorthin +## (Augenhöhe 1,70 m via look_cam-Offset, Kollision geprüft — nie in Objekten). +## Das Speichern (Sidecar) + Marker-Update macht main.gd mit der Rückgabe. +## Rückgabe: {ok, x, z, ground, msg} aus PlaytestBody.teleport_to_ground. +func teleport_crosshair() -> Dictionary: + if not active or body == null or body.look_cam == null: + return {"ok": false, "x": 0.0, "z": 0.0, "ground": 0.0, "msg": ""} + var vp: Viewport = body.look_cam.get_viewport() + var center: Vector2 = (vp.get_visible_rect().size if vp != null else Vector2(800, 600)) * 0.5 + var origin: Vector3 = body.look_cam.project_ray_origin(center) + var dir: Vector3 = body.look_cam.project_ray_normal(center) + var res: Dictionary = body.call("teleport_to_ground", origin, dir) + if bool(res.get("ok")): + show_message("Test-Start gesetzt: x=%.0f z=%.0f — du bist jetzt dort (Höhe automatisch)." % [ + float(res.get("x")), float(res.get("z"))]) + else: + show_message(str(res.get("msg", ""))) + return res + + +func _process(delta: float) -> void: + if not active or body == null: + return + _speise_avatar() + # FPS glätten (Anzeige-Genauigkeit, keine Physik-Betroffenheit) + if _fps_smooth <= 0.0: + _fps_smooth = 1.0 / maxf(delta, 0.0001) + else: + _fps_smooth = lerpf(_fps_smooth, 1.0 / maxf(delta, 0.0001), 0.1) + if hud_pos != null: + hud_pos.text = "Pos: %.1f, %.1f, %.1f" % [body.position.x, body.position.y, body.position.z] + if hud_dir != null: + # Höhe = FUSSPUNKT (Kapsel-Mitte minus Halbhöhe) — direkt vergleichbar + # mit der Terrainhöhe unter den Füßen (Karte t_1da96275). + hud_dir.text = "Blick: %.0f° / %.0f° · Höhe: %.1f m" % [ + float(body.get("yaw_deg")), float(body.get("pitch_deg")), + body.position.y - PlaytestBody.HALF_H] + if hud_fps != null: + hud_fps.text = "FPS: %d" % int(round(_fps_smooth)) + + +## Maus-Capture-Wunsch für die Suite/Debug sichtbar machen. +func wants_capture() -> bool: + return _want_capture + + +## ESC → Signal an main.gd (die Esc-Priorität gehört in main.gd, damit die +## normale Esc-Kette im Editor-Modus unangetastet bleibt). +func handle_escape() -> void: + if active and body != null: + exit_requested.emit() + + +# ------------------------------------------------- Komfort (t_aaff5dcc) ----- + +## Tasten im Lauf-Modus (Karte t_aaff5dcc): G = Fliegen/God-Mode, 1–4 = +## Sprung zu Spawnpunkt, H = HUD an/aus, F1 = Hilfe, X = Achsen. ESC/T bleiben +## bewusst bei main.gd (Esc-Kette + Test-Start-Vertrag). Die Editor-Tasten +## sind im Lauf-Modus eingefroren (main gibt hier nichts anderes durch). +func _unhandled_input(event: InputEvent) -> void: + if not active or body == null: + return + var key_evt := event as InputEventKey + if key_evt == null or not key_evt.is_pressed() or key_evt.echo: + return + var key := key_evt.keycode + var handled := true + match key: + KEY_G: + toggle_fly() + KEY_V: + toggle_perspektive() + KEY_1: + jump_to_spawn(1) + KEY_2: + jump_to_spawn(2) + KEY_3: + jump_to_spawn(3) + KEY_4: + jump_to_spawn(4) + KEY_H: + toggle_hud() + KEY_F1: + toggle_help() + KEY_X: + toggle_axis() + _: + handled = false + if handled: + get_viewport().set_input_as_handled() + + +## Empfindlichkeit live setzen (aus dem Einstellungen-Panel, Registry-Weg — +## main.gd bleibt unangetastet). mult = Multiplikator 0,1–5,0. +func apply_sensitivity(mult: float) -> void: + if body != null: + body.call("set_sensitivity", mult) + + +## Taste V (Karte t_17a35c59): First/Third-Person umschalten. Der neue +## Zustand wird persistiert (PlaytestSettings, wirksam über Neustarts). +## Ohne Avatar-Modelle (kein Client-Klon ../scopedvr-client) bleibt First +## Person aktiv und der Grund steht im HUD — kein Crash (graceful Fallback). +func toggle_perspektive() -> bool: + if body == null: + return false + var neu: bool = body.call("toggle_perspektive") + if not _avatar_da: + show_message("Kein Avatar-Modell gefunden (Client-Klon ../scopedvr-client fehlt) — Third Person nicht verfügbar.") + return false + PlaytestSettings.save_third(neu) + if neu: + show_message("Dritte Person AN — derselbe Avatar wie die Bots im Spiel. V = zurück zur ersten Person.") + else: + show_message("Erste Person AN (Standard). V = dritte Person.") + return neu + + +## Avatar-Gait aus der ECHTEN Bewegung speisen (Kartenvorgabe: Stillstand/ +## Walk/Jog aus der tatsächlichen Geschwindigkeit, Blickrichtung == +## Bewegungsrichtung über die Body-Rotation). Jeden Frame — die Kadenz- +## Mathe des Avatars glättet selbst (BLEND_SMOOTH_S, wie die Bots). +func _speise_avatar() -> void: + if body == null: + return + var av: Node3D = body.get("avatar") as Node3D + if av == null or not is_instance_valid(av): + return + var speed: float = body.call("horizontale_geschwindigkeit") + av.call("apply_state", PlaytestAvatar.zustand_fuer(speed), speed) + + +## Fliegen / God-Mode umschalten (Taste G). Rückgabe: neuer Zustand. +func toggle_fly() -> bool: + if body == null: + return false + var new_state: bool = not bool(body.get("fly_mode")) + body.set("fly_mode", new_state) + body.set("velocity", Vector3.ZERO) # kein Fall-Übernehmen aus dem Gang + if new_state: + show_message("Fliegen AN (God-Mode): keine Gravitation — Blickrichtung fliegen, Space = steigen, G = aus.") + else: + show_message("Fliegen AUS — wieder mit Gravitation.") + return new_state + + +## Spawnpunkt-Punkt für Taste index (1 = Team A/Zone 0, 2 = Team B/Zone 1, +## 3/4 = weitere Zonen 2/3): erster Punkt der Zone. Rückgabe {} = keine Zone. +## pos = [x,y,z] aus dem Dokument. +func _spawn_point_for(index: int) -> Dictionary: + if body == null: + return {} + var zones: Dictionary = (body.get("doc") as Dictionary).get("spawn_zones", {}) + var zone: Variant = zones.get(str(index - 1)) + if not (zone is Dictionary): + return {} + var points: Array = (zone as Dictionary).get("points", []) + if points.is_empty() or not (points[0] is Dictionary): + return {} + var p := points[0] as Dictionary + var pos: Array = p.get("pos", []) + if pos.size() < 3: + return {} + return {"pos": Vector3(float(pos[0]), float(pos[1]), float(pos[2])), + "label": str((zone as Dictionary).get("label", "Zone %d" % index)), + "yaw": p.get(SpawnOps.YAW_KEY, null)} + + +## Sprung zu einem Spawnpunkt (Tasten 1–4): exakt auf den Punkt gesetzt +## (x/z aus dem Dokument, Höhe vom Terrain — dieselbe Konvention wie der +## Lauf-Modus-Start). Rückgabe true = gelandet. +func jump_to_spawn(index: int) -> bool: + var sp := _spawn_point_for(index) + if sp.is_empty() or body == null: + show_message("Kein Spawnpunkt für Taste %d — die Karte hat diese Zone nicht." % index) + return false + var target: Vector3 = sp["pos"] + var y: float = body.terrain_height(target.x, target.z) + # Kapsel-Mitte = Füße + Halbhöhe (+ Toleranz) — die Physik lässt den Body + # sanft auf den Trimesh fallen (wie beim Start, Karte t_1da96275). + body.set("position", Vector3(target.x, y + PlaytestBody.HALF_H + 0.02, target.z)) + body.set("velocity", Vector3.ZERO) + body.set("on_floor", true) + if sp["yaw"] != null: + body.set("yaw_deg", float(sp["yaw"])) + show_message("Spawnpunkt %d = %s: x=%.1f z=%.1f (Höhe %.1f) — Blickrichtung steht im HUD." % [ + index, str(sp["label"]), target.x, target.z, y]) + return true + + +## HUD (Position/Blick/FPS/Hinweis) an/aus (Taste H). Rückgabe: sichtbar? +func toggle_hud() -> bool: + if hud == null: + return false + hud.visible = not hud.visible + if hud.visible: + show_message("HUD an.") # aus: Meldung wäre selbst unsichtbar + return hud.visible + + +## Hilfe-Overlay an/aus (Taste F1). Rückgabe: sichtbar? +func toggle_help() -> bool: + if help_layer == null: + _build_help() + help_layer.visible = not help_layer.visible + return help_layer.visible + + +## Kartenmitte/Achsen-Linien an/aus (Taste X). Rückgabe: sichtbar? +func toggle_axis() -> bool: + if _axis_node == null: + _build_axis() + _axis_node.visible = not _axis_node.visible + if _axis_node.visible: + show_message("Kartenmitte/Achsen AN (X = aus): X-Rot, Z-Blau, Mitte Grün.") + else: + show_message("Kartenmitte/Achsen AUS.") + return _axis_node.visible + + +## Hilfe-Overlay (F1): Panel mit allen Tasten im Klartext, mittig unten. +func _build_help() -> void: + help_layer = CanvasLayer.new() + help_layer.layer = 101 + var center := CenterContainer.new() + center.set_anchors_preset(Control.PRESET_FULL_RECT) + center.mouse_filter = Control.MOUSE_FILTER_IGNORE + help_layer.add_child(center) + var panel := PanelContainer.new() + center.add_child(panel) + var margin := MarginContainer.new() + margin.add_theme_constant_override("margin_left", 16) + margin.add_theme_constant_override("margin_right", 16) + margin.add_theme_constant_override("margin_top", 12) + margin.add_theme_constant_override("margin_bottom", 12) + panel.add_child(margin) + var label := Label.new() + label.text = "TESTLAUF — ALLE TASTEN +WASD — bewegen · Maus — umsehen +Shift — rennen · Space — springen / im Flug steigen +G — Fliegen (God-Mode) an/aus: keine Gravitation, Blickrichtung fliegen +V — Perspektive umschalten (erste / dritte Person) +1 — Sprung zu Team A (Spawnpunkt) · 2 — Team B +3 / 4 — weitere Spawnpunkte (Zonen 2/3) +T — Test-Start auf den Blickpunkt setzen (sofort dort) +H — HUD an/aus (Position, Blick, FPS, Höhe) +X — Kartenmitte/Achsen ein/aus (X-Rot, Z-Blau) +F1 — diese Hilfe · ESC — zurück zum Editor" + label.add_theme_font_size_override("font_size", 18) + margin.add_child(label) + add_child(help_layer) + help_layer.visible = false + + +## Achsen-Linien durch die Kartenmitte (Taste X): X-Achse rot, Z-Achse blau, +## senkrechte Mitte grün — beim gespiegelten Bauen (M1) auf einen Blick. +func _build_axis() -> void: + var doc: Dictionary = (body.get("doc") if body != null else {}) as Dictionary + var bounds: Dictionary = doc.get("bounds", {}) + var mn: Array = bounds.get("min", [-50.0, -10.0, -50.0]) + var mx: Array = bounds.get("max", [50.0, 80.0, 50.0]) + var cx := (float(mn[0]) + float(mx[0])) * 0.5 + var cz := (float(mn[2]) + float(mx[2])) * 0.5 + var y0: float = body.terrain_height(cx, cz) if body != null else 0.0 + var mesh := ImmediateMesh.new() + mesh.surface_begin(Mesh.PRIMITIVE_LINES) + # X-Achse (rot): ganze Kartenbreite durch die Mitte. + mesh.surface_set_color(Color(1.0, 0.25, 0.25)) + mesh.surface_add_vertex(Vector3(float(mn[0]), y0, cz)) + mesh.surface_add_vertex(Vector3(float(mx[0]), y0, cz)) + # Z-Achse (blau): ganze Kartentiefe durch die Mitte. + mesh.surface_set_color(Color(0.3, 0.5, 1.0)) + mesh.surface_add_vertex(Vector3(cx, y0, float(mn[2]))) + mesh.surface_add_vertex(Vector3(cx, y0, float(mx[2]))) + # Senkrechte Mitte (grün): vom Terrain bis zur oberen Grenze. + mesh.surface_set_color(Color(0.3, 1.0, 0.4)) + mesh.surface_add_vertex(Vector3(cx, y0, cz)) + mesh.surface_add_vertex(Vector3(cx, float(mx[1]), cz)) + mesh.surface_end() + var mi := MeshInstance3D.new() + mi.name = "PlaytestAchsen" + mi.mesh = mesh + # Vertexfarben sichtbar machen: unshaded + vertex_color_use_as_albedo + # (ohne das ignoriert der Default-Material-Shader die Linien-Farben). + var mat := StandardMaterial3D.new() + mat.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED + mat.vertex_color_use_as_albedo = true + mat.no_fog = true + mi.material_override = mat + mi.position = Vector3.ZERO + _axis_node = mi + add_child(_axis_node) diff --git a/editor/playtest/playtest_mode.gd.uid b/editor/playtest/playtest_mode.gd.uid new file mode 100644 index 0000000..76bf77a --- /dev/null +++ b/editor/playtest/playtest_mode.gd.uid @@ -0,0 +1 @@ +uid://spymwdq2qcvr diff --git a/editor/playtest/playtest_settings.gd b/editor/playtest/playtest_settings.gd new file mode 100644 index 0000000..a4f4c58 --- /dev/null +++ b/editor/playtest/playtest_settings.gd @@ -0,0 +1,84 @@ +extends RefCounted +class_name PlaytestSettings +## Einstellungen-Speicher für den Lauf-Modus (Karte t_aaff5dcc, T3 Komfort) — +## bewusst NICHT im .svmap-Format und NICHT in main.gd: der Operator hat für +## Einstellungen den Registry-Weg vorgegeben (Panel meldet sich in +## core/ui/panels/registry.gd an), der Zustand lebt HIER als statischer Store. +## +## Ablage: user://scopedvr_playtest.cfg, Abschnitt [playtest]. +## Wert: Maus-Empfindlichkeit als Multiplikator (0,1–5,0, Standard 1,0) auf +## die Body-Basis 0,25 Grad/Pixel — jede PC/Maus-Kombination ist anders. +## +## Statischer Cache: ein Lese-Vorgang pro Editor-Start; save_sens() hält den +## Cache frisch. Tests können mit reset_cache() neu laden erzwingen. + +const CFG_PATH := "user://scopedvr_playtest.cfg" +const SECTION := "playtest" +const KEY_SENS := "maus_empfindlichkeit" +const DEFAULT_SENS := 1.0 +const MIN_SENS := 0.1 +const MAX_SENS := 5.0 +## Perspektive im Testlauf (Karte t_17a35c59, Taste V): false = First Person +## (Standard, wie bisher), true = Third Person (Avatar sichtbar). +const KEY_THIRD := "dritte_person" + +## Cache (null = noch nicht gelesen). static var ist Godot 4.1+. +static var _cache: Variant = null +## Cache für den Perspektive-Eintrag (null = noch nicht gelesen). +static var _cache_third: Variant = null + + +## Gespeicherte Empfindlichkeit lesen (geclampt auf 0,1–5,0), Standard 1,0. +static func load_sens() -> float: + if _cache != null: + return float(_cache) + var cfg := ConfigFile.new() + var raw: Variant = DEFAULT_SENS + if cfg.load(CFG_PATH) == OK: + raw = cfg.get_value(SECTION, KEY_SENS, DEFAULT_SENS) + var val := clampf(float(raw), MIN_SENS, MAX_SENS) + _cache = val + return val + + +## Empfindlichkeit speichern (geclampt auf 0,1–5,0) und Cache frisch halten. +## Rückgabe: der tatsächlich gespeicherte Wert. +static func save_sens(value: float) -> float: + var val := clampf(value, MIN_SENS, MAX_SENS) + var cfg := ConfigFile.new() + cfg.load(CFG_PATH) # Fehler → leere Config, nur unser Key wird angelegt. + cfg.set_value(SECTION, KEY_SENS, val) + cfg.save(CFG_PATH) + _cache = val + return val + + +## Gespeicherte Perspektive lesen (Karte t_17a35c59): true = Third Person. +## Default FALSE = First Person — der Testlauf startet so wie bisher. +static func load_third() -> bool: + if _cache_third != null: + return bool(_cache_third) + var cfg := ConfigFile.new() + var raw: Variant = false + if cfg.load(CFG_PATH) == OK: + raw = cfg.get_value(SECTION, KEY_THIRD, false) + var val := bool(raw) + _cache_third = val + return val + + +## Perspektive speichern (persistiert über Editor-Neustarts) und Cache frisch +## halten. Rückgabe: der tatsächlich gespeicherte Wert. +static func save_third(value: bool) -> bool: + var cfg := ConfigFile.new() + cfg.load(CFG_PATH) # Fehler → leere Config, nur unser Key wird angelegt. + cfg.set_value(SECTION, KEY_THIRD, value) + cfg.save(CFG_PATH) + _cache_third = value + return value + + +## Cache verwerfen (für Tests / frisches Neulesen von der Platte). +static func reset_cache() -> void: + _cache = null + _cache_third = null diff --git a/editor/playtest/playtest_settings.gd.uid b/editor/playtest/playtest_settings.gd.uid new file mode 100644 index 0000000..8751c34 --- /dev/null +++ b/editor/playtest/playtest_settings.gd.uid @@ -0,0 +1 @@ +uid://1m7xfphtjvwd diff --git a/editor/playtest/test_start.gd b/editor/playtest/test_start.gd new file mode 100644 index 0000000..0918428 --- /dev/null +++ b/editor/playtest/test_start.gd @@ -0,0 +1,92 @@ +extends RefCounted +class_name TestStart +## Test-Startpunkt (Karte t_96e3c4ee): der Punkt, an dem „▶ Karte testen“ (F5) +## den Spieler absetzt — KEIN Spiel-Spawnpunkt (taucht nicht in doc, +## Spawn-Checks/Analysen oder Validator auf, ändert keine Zonen). +## +## Bewusste Entscheidungen dieser Karte: +## - Der Punkt lebt NUR editor-seitig (Sidecar, test_start_store.gd) — das +## .svmap-Format (Validator V1–V16, Client/Server) bleibt UNBERÜHRT. +## - Gespeichert wird nur x/z. Die Höhe kommt IMMER automatisch aus dem +## Terrain an der Stelle (SvmapDocument.terrain_height_at) — Terrain +## formen lässt den Punkt nicht schweben und versinken. +## - Fallback-Reihenfolge F5 (je mit Klartext-Hinweis): gesetzter Test-Start +## → erster Team-Spawnpunkt (Team Blau, wie bisher) → Kartenmitte. +## - Trifft der Klick ein Objekt/Bauteil: landet der Punkt auf dem BODEN +## DARUNTER (nie im Objekt schwebend) — das Tool meldet es im Klartext. +## +## Alles pure Statics (kein UI, kein Node-Zugriff) → headless testbar in +## tests/test_playtest_spawn.gd. + +## Kein Punkt gesetzt (Sentinel-Typ für Variant-Vergleiche in main.gd). + +## Start-Punkt für den Testlauf auflösen (Fallback-Kette). test_point ist +## Vector3 (nur x/z zählen) oder null. Rückgabe: +## {pos: Vector3 (y = Terrainhöhe), quelle: "test"|"team"|"mitte", +## status: Klartext für die Statuszeile} +static func resolve_start(doc: Dictionary, test_point: Variant) -> Dictionary: + if test_point != null: + var p: Vector3 = test_point + var y := SvmapDocument.terrain_height_at(doc, p.x, p.z) + return { + "pos": Vector3(p.x, y, p.z), + "quelle": "test", + "status": "Start an deinem gesetzten Test-Startpunkt (%.0f, %.0f, Höhe automatisch)." % [p.x, p.z], + } + # Erster Team-Spawnpunkt (Team Blau = „0“) — exakt wie bisher (t_1cdc1a72). + var zones: Dictionary = doc.get("spawn_zones", {}) + var team0 = zones.get("0", {}) + if team0 is Dictionary: + var points: Array = (team0 as Dictionary).get("points", []) + if not points.is_empty() and points[0] is Dictionary: + var pos = (points[0] as Dictionary).get("pos", []) + if pos is Array and (pos as Array).size() >= 3: + return { + "pos": Vector3(float(pos[0]), float(pos[1]), float(pos[2])), + "quelle": "team", + "status": "Kein Test-Start gesetzt — Start am ersten Team-Blau-Spawnpunkt.", + } + # Kartenmitte aus den Bounds. + var bounds: Dictionary = doc.get("bounds", {}) + var mn: Array = bounds.get("min", [-50.0, -10.0, -50.0]) + var mx: Array = bounds.get("max", [50.0, 80.0, 50.0]) + var cx := (float(mn[0]) + float(mx[0])) * 0.5 + var cz := (float(mn[2]) + float(mx[2])) * 0.5 + return { + "pos": Vector3(cx, SvmapDocument.terrain_height_at(doc, cx, cz), cz), + "quelle": "mitte", + "status": "Weder Test-Start noch Team-Spawnpunkte — Start in der Kartenmitte.", + } + + +## Strahl → erster Treffer auf einer AABB (Slab-Methode) oder -1.0. +## Für „Klick trifft Bauteil“ im Editor-Tool und „Fadenkreuz trifft Hindernis“ +## im Testlauf (kein Physik-Server im Editor/SubViewport). +## Rückgabe: Distanz t >= 0 (origin + dir * t) oder -1.0 = kein Treffer. +static func ray_aabb(origin: Vector3, dir: Vector3, box: AABB) -> float: + var d := dir + if d.length_squared() < 0.000000001: + return -1.0 + d = d.normalized() + var tmin := 0.0 + var tmax := INF + for axis in 3: + var o := origin[axis] + var dv := d[axis] + var lo := box.position[axis] + var hi := box.end[axis] + if absf(dv) < 0.0000001: + if o < lo or o > hi: + return -1.0 + continue + var t1 := (lo - o) / dv + var t2 := (hi - o) / dv + if t1 > t2: + var tmp := t1 + t1 = t2 + t2 = tmp + tmin = maxf(tmin, t1) + tmax = minf(tmax, t2) + if tmin > tmax: + return -1.0 + return tmin diff --git a/editor/playtest/test_start.gd.uid b/editor/playtest/test_start.gd.uid new file mode 100644 index 0000000..2a04600 --- /dev/null +++ b/editor/playtest/test_start.gd.uid @@ -0,0 +1 @@ +uid://b4barijsv6qs2 diff --git a/editor/playtest/test_start_store.gd b/editor/playtest/test_start_store.gd new file mode 100644 index 0000000..6023828 --- /dev/null +++ b/editor/playtest/test_start_store.gd @@ -0,0 +1,64 @@ +extends RefCounted +class_name TestStartStore +## Sidecar-Speicher für den Test-Startpunkt (Karte t_96e3c4ee) — bewusst +## NICHT im .svmap-Format (Validator V1–V16 + Client/Server bleiben unberührt; +## eine Map ohne den Punkt verhält sich exakt wie bisher). +## +## Ablage: user://scopedvr_teststart.cfg, Abschnitt [test_start], je Kartenpfad +## ein Schlüssel (globalisierter Pfad). Ungespeicherte Maps landen unter dem +## Sammel-Schlüssel UNGESPEICHERT (Session-Speicher über Neustarts hinaus nur, +## wenn die Map gespeichert wird — der Punkt wandert beim Speichern mit). +## Gespeichert werden nur x/z: die Höhe kommt immer automatisch vom Terrain. + +const CFG_PATH := "user://scopedvr_teststart.cfg" +const SECTION := "test_start" +const UNGESPEICHERT := "__ungespeichert__" + + +## Schlüssel für einen Kartenpfad (leer = ungespeicherte Map). +static func key_for(map_path: String) -> String: + if map_path.is_empty(): + return UNGESPEICHERT + return ProjectSettings.globalize_path(map_path) + + +## Gespeicherten Punkt lesen (Vector3 mit y=0 — Höhe kommt vom Terrain) +## oder null, wenn keiner gesetzt ist. +static func load_point(map_path: String) -> Variant: + var cfg := ConfigFile.new() + if cfg.load(CFG_PATH) != OK: + return null + var k := key_for(map_path) + var x: Variant = cfg.get_value(SECTION, k + "/x", null) + var z: Variant = cfg.get_value(SECTION, k + "/z", null) + if x == null or z == null: + return null + return Vector3(float(x), 0.0, float(z)) + + +## Punkt speichern (nur x/z — Höhe automatisch). +static func save_point(map_path: String, pos: Vector3) -> void: + var cfg := ConfigFile.new() + cfg.load(CFG_PATH) # Fehler → leere Config, Punkt wird neu angelegt. + var k := key_for(map_path) + cfg.set_value(SECTION, k + "/x", pos.x) + cfg.set_value(SECTION, k + "/z", pos.z) + cfg.save(CFG_PATH) + + +## Punkt löschen (Datei bleibt — andere Maps sind unberührt). +## Bewusst Sektions-Neuaufbau statt erase_section_key: Godots +## erase_section_key löscht Keys mit "/" im Namen still NICHT (Probe 20.10.). +static func clear_point(map_path: String) -> void: + var cfg := ConfigFile.new() + if cfg.load(CFG_PATH) != OK: + return + var k := key_for(map_path) + var keep := {} + for key in cfg.get_section_keys(SECTION): + if not key.begins_with(k + "/"): + keep[key] = cfg.get_value(SECTION, key) + cfg.erase_section(SECTION) + for key in keep: + cfg.set_value(SECTION, key, keep[key]) + cfg.save(CFG_PATH) diff --git a/editor/playtest/test_start_store.gd.uid b/editor/playtest/test_start_store.gd.uid new file mode 100644 index 0000000..6109a49 --- /dev/null +++ b/editor/playtest/test_start_store.gd.uid @@ -0,0 +1 @@ +uid://b3gc8f1aecsjl diff --git a/editor/playtest/test_start_tool.gd b/editor/playtest/test_start_tool.gd new file mode 100644 index 0000000..702c1ff --- /dev/null +++ b/editor/playtest/test_start_tool.gd @@ -0,0 +1,253 @@ +extends Node3D +## Test-Startpunkt-Werkzeug (Karte t_96e3c4ee): „hinklicken, wo man beim +## Testen spawnt“ — ein Klick auf Boden/Terrain setzt den Test-Startpunkt. +## KEIN Spiel-Spawnpunkt: der Punkt lebt NICHT im .svmap (Sidecar via +## TestStartStore), taucht in keinem Spawn-Check/Keiner Analyse auf und hat +## KEINEN Undo-Eintrag (editor-seitiger Session-Zustand, wie die UI-Größe). +## +## Bedienung (Einbindung in main.gd, wie T1 den Lauf-Modus angemeldet hat): +## Toolbar-Knopf „🎯 Test-Start“ oder Taste T → Werkzeug an +## Linksklick auf den Boden → Test-Start setzen (Höhe automatisch) +## Linksklick auf Objekt/Bauteil → Punkt auf den Boden DARUNTER (Klartext- +## Hinweis: „auf dem Boden unter dem Objekt“) +## Entf (im Werkzeug) / „Löschen“-Knopf rechts → Test-Start löschen +## ESC → Werkzeug beenden +## Rechte Maustaste: bewusst NICHT behandelt — sie gehört dem Freelook-Flug +## (Karte t_2470de89, absolute Priorität wie in jedem anderen Werkzeug). +## +## Marker (schmale Säule + Ring, Editor-Akzentfarbe) bleibt sichtbar, solange +## ein Punkt gesetzt ist — auch außerhalb des Werkzeugs. Vorschau-Ring folgt +## dem Cursor nur IM Werkzeug (wie der Spawn-Zonen-Ghost). + +## Editor-Akzentfarbe (wie Statuszeile/Kurzhilfe in main.gd) — „Farbe aus dem +## Theme“ laut Karte; dieselbe Konstante, keine neue Farbwelt. +const ACCENT := Color(0.55, 0.8, 1.0) + +var main # Hauptfenster (script-erweitert, Variant) +var camera: Camera3D +var view_builder # Welt-Bauer (script-erweitert, Variant) +var interaction # Objekt-Interaktion (für Objekt-Treffer-Test, nur LESEND) + +var active := false + +# Terrain-Cache für Cursor-Raycast (nur LESEN — dieses Werkzeug formt nichts) +var _heights := PackedFloat32Array() +var _res := 0 +var _sx := 0.0 +var _sz := 0.0 + +var _ghost: Node3D +var _marker: Node3D +var _cursor_valid := false +var _cursor := Vector3.ZERO + + +func setup(p_main, p_camera: Camera3D, p_builder, p_interaction) -> void: + main = p_main + camera = p_camera + view_builder = p_builder + interaction = p_interaction + _ensure_ghost() + _ensure_marker() + + +# ------------------------------------------------------------ Aktivierung --- + +func activate() -> bool: + active = true + refresh_from_doc() + return true # nie verweigert — der Test-Start braucht kein Auflösungs-Limit + + +func deactivate() -> void: + active = false + _cursor_valid = false + if _ghost != null and is_instance_valid(_ghost): + _ghost.visible = false + + +## Nach Laden/Neu/Speichern (Pfadwechsel → anderer Sidecar-Schlüssel) und +## nach Terrain-Änderungen: Cache + Marker aus main.test_start_point frisch. +func refresh_from_doc() -> void: + var terrain: Dictionary = main.doc.get("terrain", {}) + _res = int(terrain.get("resolution", 0)) + _sx = float(terrain.get("size_x_m", 0.0)) + _sz = float(terrain.get("size_z_m", 0.0)) + if _res >= 2 and _sx > 0.0 and _sz > 0.0: + _heights = SvmapIO.decode_heights(terrain) + else: + _heights = PackedFloat32Array() + _update_marker() + + +# --------------------------------------------------------------- Eingaben --- + +func _unhandled_input(event: InputEvent) -> void: + var p := MousePointer.from_input(event) + if p != null and handle_pointer(p): + get_viewport().set_input_as_handled() + + +func handle_pointer(p: PointerEvent) -> bool: + if not active: + return false + if p.kind == PointerEvent.Kind.MOVE: + _update_cursor(p.position) + elif p.kind == PointerEvent.Kind.PRESS: + _click(p.position) + return true + return false + + +func _click(viewport_pos: Vector2) -> void: + # 1) Objekt-Treffer? (Kugel-Approx der interaction — derselbe Pfad wie die + # Auswahl; bewusst nur GERUFEN, interaction.gd bleibt unangetastet.) + var obj_idx: Variant = interaction.call("_pick_object", viewport_pos) + var hit_obj := false + if obj_idx is int and int(obj_idx) >= 0: + hit_obj = true + # 3) Punkt setzen: x/z vom Strahl-Treffer, Höhe IMMER vom Terrain (nie + # im Objekt schwebend, nie versunken). + var hit: Variant = _ray_hit(viewport_pos) + if hit == null: + main.call("_set_status", "Da war kein Boden unter dem Mauszeiger — klicke IN die Karte (die grüne Fläche).", true) + return + var p: Vector3 = _clamped(hit as Vector3) + var hinweis := "" + if hit_obj: + hinweis = "auf dem Boden unter dem Objekt" + main.call("_test_start_apply", p.x, p.z, hinweis) + + +func _update_cursor(viewport_pos: Vector2) -> void: + var hit: Variant = _ray_hit(viewport_pos) + if hit == null: + _cursor_valid = false + if _ghost != null and is_instance_valid(_ghost): + _ghost.visible = false + return + _cursor_valid = true + _cursor = _clamped(hit as Vector3) + if _ghost != null and is_instance_valid(_ghost): + _ghost.position = Vector3(_cursor.x, _cursor.y + 0.06, _cursor.z) + _ghost.visible = true + + +## Strahl → Punkt auf dem Terrain (wie Terrain-/Spawn-Werkzeug; +## TerrainField.raycast — favorisiert echte Geländeberührung). +func _ray_hit(viewport_pos: Vector2) -> Variant: + if _res >= 2 and _heights.size() >= _res * _res: + return TerrainField.raycast(_heights, _res, _sx, _sz, + camera.project_ray_origin(viewport_pos), camera.project_ray_normal(viewport_pos)) + var terrain: Dictionary = main.doc.get("terrain", {}) + if terrain.is_empty(): + return null + var plane_y := float(terrain.get("min_height_m", 0.0)) + var origin := camera.project_ray_origin(viewport_pos) + var dir := camera.project_ray_normal(viewport_pos) + if absf(dir.y) < 0.0001: + return null + var t := (plane_y - origin.y) / dir.y + if t <= 0.0: + return null + return origin + dir * t + + +func _clamped(p: Vector3) -> Vector3: + var half := Vector2(_sx, _sz) * 0.5 + p.x = clampf(p.x, -half.x, half.x) + p.z = clampf(p.z, -half.y, half.y) + p.y = SvmapDocument.terrain_height_at(main.doc, p.x, p.z) + return p + + +# ----------------------------------------------------------------- Marker --- + +## Marker an den gesetzten Punkt hängen (oder ausblenden). Höhe IMMER +## automatisch: Terrainhöhe an (x, z) — nach Terrain-Formen bleibt der +## Punkt auf dem Boden (kein Schweben, kein Versinken). +func _update_marker() -> void: + _ensure_marker() + var point: Variant = main.get("test_start_point") + if point == null: + _marker.visible = false + return + var p: Vector3 = point + p.y = SvmapDocument.terrain_height_at(main.doc, p.x, p.z) + _marker.position = p + _marker.visible = true + + +# ------------------------------------------------------- Optik (Ghost/Marker) -- + +func _accent_mat(alpha: float) -> StandardMaterial3D: + var mat := StandardMaterial3D.new() + mat.albedo_color = Color(ACCENT.r, ACCENT.g, ACCENT.b, alpha) + mat.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA + mat.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED + mat.emission_enabled = true + mat.emission = ACCENT * 0.35 + return mat + + +func _ensure_ghost() -> void: + if _ghost != null and is_instance_valid(_ghost): + return + _ghost = Node3D.new() + _ghost.visible = false + add_child(_ghost) + var ring := MeshInstance3D.new() + var torus := TorusMesh.new() + torus.inner_radius = 0.65 + torus.outer_radius = 0.85 + torus.rings = 48 + torus.ring_segments = 6 + ring.mesh = torus + ring.position.y = 0.05 + ring.material_override = _accent_mat(0.6) + _ghost.add_child(ring) + + +## Marker: schmale Säule + Ring am Boden (Karten-Vorgabe), Akzentfarbe. +func _ensure_marker() -> void: + if _marker != null and is_instance_valid(_marker): + return + _marker = Node3D.new() + _marker.visible = false + add_child(_marker) + var pillar := MeshInstance3D.new() + var cyl := CylinderMesh.new() + cyl.top_radius = 0.12 + cyl.bottom_radius = 0.12 + cyl.height = 4.0 + pillar.mesh = cyl + pillar.position.y = 2.0 # Fußpunkt auf dem Terrain + pillar.material_override = _accent_mat(0.55) + _marker.add_child(pillar) + var ring := MeshInstance3D.new() + var torus := TorusMesh.new() + torus.inner_radius = 0.55 + torus.outer_radius = 0.75 + torus.rings = 48 + torus.ring_segments = 6 + ring.mesh = torus + ring.position.y = 0.05 + ring.material_override = _accent_mat(0.85) + _marker.add_child(ring) + + +# ------------------------------------------------------------ Demo/Tests ---- + +## Demo-Hook (Suite/Renderprobe): Punkt programmatisch setzen — macht exakt, +## was ein Klick machen würde (ohne echte Maus-Ereignisse). hinweis = derselbe +## Klartext wie beim echten Klick ("" = freier Boden, sonst „unter dem Objekt“). +func demo_set(x: float, z: float, hinweis := "") -> void: + main.call("_test_start_apply", x, z, hinweis) + + +## Demo-Hook: Ghost an Position parken (Renderprobe ohne Maus). +func demo_park_ghost(x: float, z: float) -> void: + _cursor = _clamped(Vector3(x, 0.0, z)) + _cursor_valid = true + _ghost.position = Vector3(_cursor.x, _cursor.y + 0.06, _cursor.z) + _ghost.visible = true diff --git a/editor/playtest/test_start_tool.gd.uid b/editor/playtest/test_start_tool.gd.uid new file mode 100644 index 0000000..228ca33 --- /dev/null +++ b/editor/playtest/test_start_tool.gd.uid @@ -0,0 +1 @@ +uid://byjsw857bu1k8 diff --git a/editor/pointer_router.gd b/editor/pointer_router.gd new file mode 100644 index 0000000..782764b --- /dev/null +++ b/editor/pointer_router.gd @@ -0,0 +1,13 @@ +class_name PointerRouter +extends RefCounted +## Gibt eine Zeige-Eingabe in derselben Reihenfolge an die Werkzeuge wie Godot +## die Maus: tiefer und später im Baum zuerst, das erste Werkzeug nimmt sie. +## Für Eingaben, die nicht über den Viewport kommen, also den VR-Controller. + + +static func dispatch(main: Node, p: PointerEvent) -> bool: + for key in ["test_start_tool", "spawn_tool", "terrain_tool", "gizmo", "interaction"]: + var werkzeug: Variant = main.get(key) + if werkzeug != null and bool(werkzeug.call("handle_pointer", p)): + return true + return false diff --git a/editor/pointer_router.gd.uid b/editor/pointer_router.gd.uid new file mode 100644 index 0000000..445bba9 --- /dev/null +++ b/editor/pointer_router.gd.uid @@ -0,0 +1 @@ +uid://bem4edb2s282 diff --git a/editor/shortcut_keys.gd b/editor/shortcut_keys.gd new file mode 100644 index 0000000..5327530 --- /dev/null +++ b/editor/shortcut_keys.gd @@ -0,0 +1,121 @@ +extends RefCounted +class_name ShortcutKeys +## InputMap-Actions der Editor-Tastatur-Shortcuts (Karte t_c46d31c2, Karte 1/3). +## +## Konvention (alle Shortcut-Karten): Tastaturcode-basiert — JEDER Action wird +## ein InputEventKey mit PHYSICAL keycode zugewiesen (KEY_*-Konstante). Die +## physische Taste liegt unabhängig vom Tastaturlayout an derselben Position +## (QWERTZ wie QWERTY bei W/A/S/D/Leertaste/Shift), damit deutsche und +## Windows-Tastaturen identisch bedienen — keine OS-Hardcodes (PLAN.md +## Plattform-Regel). +## +## Registrierung per Code statt project.godot: KEY_*-Konstanten bleiben im +## Quelltext lesbar und der Test kann exakt dieselben Konstanten prüfen. +## register() ist idempotent (mehrfacher Aufruf = keine Doppel-Events). + +## Action → Liste von Events. Einträge: +## KEY_X = einfache physische Taste +## {"key": KEY_X, "shift": true} = Taste + Modifier (z. B. Umschalt+F) +const ACTIONS := { + # --- Freelook-Flug (Rechte Maustaste halten bzw. Umschalt+F) ------------- + "editor_freelook_toggle": [{"key": KEY_F, "shift": true}], + "editor_freelook": [MOUSE_BUTTON_RIGHT], + "editor_fly_forward": [KEY_W], + "editor_fly_back": [KEY_S], + "editor_fly_left": [KEY_A], + "editor_fly_right": [KEY_D], + # Flug-Vertikal + Tempo (Shooter-Konvention, Sly-Wunsch 17.10.): + # Leertaste = hoch, Shift = runter (Half-Life/CS-Konvention), Strg halten = + # temporär schneller, Alt halten = langsamer. Mausrad bleibt Grundtempo. + # Konflikt-Freiheit: Leertaste/Shift/Strg SIND im Editor sonst nur als + # Modifier-Kombos belegt (Strg+Z, Umschalt+Klick …) — allein gedrückt + # triggern sie KEINE Werkzeug-Aktion (Tests: test_shortcuts.gd, + # Konflikt-Gruppe). Im Flugmodus gibt der Kamera-Einstieg den GUI-Fokus + # frei (orbit_camera._enter_fly), damit Leertaste keinen fokussierten + # Button auslöst. + "editor_fly_up": [KEY_SPACE], + "editor_fly_down": [KEY_SHIFT], + "editor_fly_fast": [KEY_CTRL], + "editor_fly_slow": [KEY_ALT], + # --- Auswahl / Objekt-Operationen ---------------------------------------- + "editor_focus_selection": [KEY_F], + "editor_cancel": [KEY_ESCAPE], + "editor_delete_selection": [KEY_DELETE], + "editor_duplicate_selection": [{"key": KEY_D, "ctrl": true}], + # Strg+LMB = Mehrfachauswahl umschalten (Maus-Event, handler prüft den + # Modifier direkt am InputEventMouseButton — Action dokumentiert die Idee). + "editor_multi_select": [{"key": KEY_NONE, "mouse_left_ctrl": true}], + # --- Objekt-Manipulation (Karte t_55257792, Karte 2/3) ------------------- + "editor_rotate_90": [KEY_R], + "editor_nudge_up": [KEY_UP], + "editor_nudge_down": [KEY_DOWN], + "editor_nudge_left": [KEY_LEFT], + "editor_nudge_right": [KEY_RIGHT], + "editor_lift_to_floor": [{"key": KEY_PAGEUP, "ctrl": true}], + "editor_grab": [KEY_G], + # --- Terrain-Pinsel (nur im Terrain-Werkzeug aktiv, main gated) ---------- + "editor_brush_smaller": [KEY_BRACKETLEFT], + "editor_brush_larger": [KEY_BRACKETRIGHT], + "editor_brush_raise": [KEY_1], + "editor_brush_lower": [KEY_2], + "editor_brush_smooth": [KEY_3], + "editor_brush_paint": [KEY_4], + "editor_brush_flatten": [KEY_5], + "editor_brush_ramp": [KEY_6], + # --- Datei & Undo (Karte t_11b5c25b, Karte 3/3) -------------------------- + # Strg+Z/Strg+Y laufen seit dem M2-UX-Fundament; hier NACHGEBUGGEN als + # dokumentierte Actions (alle 3 Shortcut-Karten: ACTIONS-Dict = Source of + # truth). Strg+Umschalt+Z ist der zweite Redo-Weg (beide belegt). + "editor_undo": [{"key": KEY_Z, "ctrl": true}], + "editor_redo_y": [{"key": KEY_Y, "ctrl": true}], + "editor_redo_shift_z": [{"key": KEY_Z, "ctrl": true, "shift": true}], + "editor_save": [{"key": KEY_S, "ctrl": true}], + "editor_save_as": [{"key": KEY_S, "ctrl": true, "shift": true}], + "editor_open_map": [{"key": KEY_O, "ctrl": true}], + "editor_new_map": [{"key": KEY_N, "ctrl": true}], + # --- Werkzeugwechsel (F-Tasten statt Ziffern, Slys Weiche) --------------- + "editor_tool_terrain": [KEY_F1], + "editor_tool_objects": [KEY_F2], + "editor_tool_bauen": [KEY_F3], + "editor_tool_spawns": [KEY_F4], + # --- Kurzhilfe-Overlay + Test-Platzhalter -------------------------------- + "editor_help_overlay": [KEY_H], + "editor_test_map": [KEY_F5], + # --- Höhenlinien fixieren (Karte t_89c0ec95) ------------------------------ + # L = Nutzer-Wahl „Linien immer an/aus" — ohne Fix sind sie NUR im + # Terrain-Werkzeug (F1) sichtbar (Werkzeug-Kopplung in main.gd). L ist + # sonst unbesetzt (Kollisions-Prüfung Karte t_89c0ec95: keine Taste in + # ACTIONS nutzt KEY_L, Ziffern bleiben Terrain-Pinsel allein vorbehalten). + "editor_contours_toggle": [KEY_L], +} + + +static func register() -> void: + for action in ACTIONS: + if InputMap.has_action(action): + continue + InputMap.add_action(action) + for entry in ACTIONS[action]: + InputMap.action_add_event(action, _make_event(entry)) + + +static func _make_event(entry) -> InputEvent: + if entry is Dictionary: + if entry.get("mouse_left_ctrl", false): + var mb := InputEventMouseButton.new() + mb.button_index = MOUSE_BUTTON_LEFT + mb.ctrl_pressed = true + return mb + var key := InputEventKey.new() + key.physical_keycode = int(entry.get("key", KEY_NONE)) + key.shift_pressed = bool(entry.get("shift", false)) + key.ctrl_pressed = bool(entry.get("ctrl", false)) + key.alt_pressed = bool(entry.get("alt", false)) + return key + if entry is int and entry >= MOUSE_BUTTON_NONE and entry <= MOUSE_BUTTON_RIGHT: + var mouse := InputEventMouseButton.new() + mouse.button_index = int(entry) + return mouse + var simple := InputEventKey.new() + simple.physical_keycode = int(entry) + return simple \ No newline at end of file diff --git a/editor/shortcut_keys.gd.uid b/editor/shortcut_keys.gd.uid new file mode 100644 index 0000000..3bf4d56 --- /dev/null +++ b/editor/shortcut_keys.gd.uid @@ -0,0 +1 @@ +uid://ctglyo67gpgdc diff --git a/editor/shortcut_policy.gd b/editor/shortcut_policy.gd new file mode 100644 index 0000000..21e7c8a --- /dev/null +++ b/editor/shortcut_policy.gd @@ -0,0 +1,48 @@ +extends RefCounted +class_name ShortcutPolicy +## Esc-Verhalten des Map-Editors (Karte t_c46d31c2, Karte 1/3) — bewusst pure +## Funktion: main.gd fragt pro Esc-Taste ab WELCHE Zustandsänderung fällig ist +## und macht nur noch den Text. tests/test_shortcuts.gd prüft alle Kombos. +## +## Priorität (spec „Esc = Auswahl aufheben / Werkzeug abbrechen / Ghost abbrechen"): +## 1. aktives Sonder-Werkzeug verlassen (Terrain/Spawns → Objekt-Werkzeug) +## 2. Ghost-Preview (Platzieren) abbrechen +## 3. Auswahl aufheben +## Rückgabe-Werte: +## "exit_terrain" | "exit_spawns" | "exit_teststart" | "cancel_grab" +## "cancel_placement" | "clear_selection" | "none" +## grabbing (Karte t_55257792): G-Greifen läuft — Esc rollt die Positionen +## zurück (Blender-Semantik). Vorrang NACH Werkzeug-Exit (im Terrain- +## Werkzeug gibt es kein Greifen), VOR Platzieren/Greifen-Auswahlheben. +static func esc_action(tool_mode: String, placing: bool, has_selection: bool, + grabbing := false) -> String: + if tool_mode == "terrain": + return "exit_terrain" + if tool_mode == "spawns": + return "exit_spawns" + if tool_mode == "teststart": + # Karte t_96e3c4ee (Wiederanbindung 20.10.): Esc verlässt das + # Test-Start-Werkzeug — der gesetzte Punkt BLEIBT bestehen. + return "exit_teststart" + if grabbing: + return "cancel_grab" + if placing: + return "cancel_placement" + if has_selection: + return "clear_selection" + return "none" + + +## Karte 3/3 (t_11b5c25b): Dürfen die globalen Tasten (F1–F5, H) gerade wirken? +## Nein, wenn ein Textfeld/SpinBox fokussiert ist (Tippen geht vor) oder ein +## Dialog/Fenster offen ist (Taste soll nicht HINTER dem Dialog wirken). +## Pure Funktion — main.gd liefert nur die beiden Fakten (testbar, wie esc_action). +static func tool_keys_allowed(text_focused: bool, dialog_open: bool) -> bool: + return not text_focused and not dialog_open + + +## Karte 3/3: Verlust-Operation (Neue Map / Öffnen) bei ungespeicherten +## Änderungen → erst NACHFRAGEN (deutscher Dialog), sonst direkt ausführen. +## Pure Entscheidung — der Dialog selbst lebt in main.gd. +static func needs_dirty_confirm(dirty: bool) -> bool: + return dirty \ No newline at end of file diff --git a/editor/shortcut_policy.gd.uid b/editor/shortcut_policy.gd.uid new file mode 100644 index 0000000..8cde9b1 --- /dev/null +++ b/editor/shortcut_policy.gd.uid @@ -0,0 +1 @@ +uid://0sobeix0nlyg diff --git a/editor/spawn_tool.gd b/editor/spawn_tool.gd new file mode 100644 index 0000000..e30090c --- /dev/null +++ b/editor/spawn_tool.gd @@ -0,0 +1,713 @@ +extends Node3D +## Spawn-Zonen-Werkzeug (M2, Karte t_c4162c5d): Zonen für Team Blau/Rot auf +## den Boden malen — im Editor-Modus (Chef-Grundsatz Sly: easy + Spaß). +## +## Bedienung: +## Linksklick = Zone setzen (Klick wie beim Objekt-Platzieren) +## Linksklick auf Zone = Zone auswählen; ZIEHEN verschiebt sie (Terrain-Höhe) +## Pfeilspitze ziehen = Blickrichtung der Zone (auch Conquest-Zonen; grau = Standard) +## Regel rechts = Radius der neuen Zonen; mit Auswahl: Radius DER Zone +## Entf = ausgewählte Zone löschen +## ESC = Auswahl weg / Werkzeug beendet (ESC in main.gd; +## Rechte Maustaste = immer Flug, t_2470de89) +## +## Jede Operation ist EIN Undo-Eintrag über die gemeinsame ActionHistory +## (Blöcke spawn_zones + design_notes, SpawnOps.snapshot_blocks). +## +## Feedback: halbtransparenter Kreis folgt dem Cursor auf dem Terrain +## (Vorschau VOR dem Klick — wie der Objekt-Ghost), die gesetzte Zone leuchtet. + +const MODE_HELP := "Linksklick: Zone setzen · Klick+Ziehen: Zone verschieben · Pfeilspitze ziehen: Blickrichtung · Entf: löschen ·\nRadius/Team rechts · Mittlere Maustaste: Kamera · Strg+Z: zurück" + +## Symmetrie (M4, Karte t_ffa207b1): Partner-Kopplung gespiegelter Spawn-Zonen. +## Liegt in design_notes (Loader-frei, rundtrip-sicher — wie spawn_radius_m): +## {"A5": "B3", "B3": "A5"} — direkte Partner-IDs, beide Richtungen gesetzt. +const SPAWN_MIRROR_KEY := "spawn_mirror" + +var main # Hauptfenster (script-erweitert, Variant) +var camera: Camera3D +var view_builder # Welt-Bauer (script-erweitert, Variant) +var interaction # Objekt-Interaktion (für Auswahl-Entkoppelung) + +var active := false +var team := 0 # 0 = Blau, 1 = Rot (TDM-Konvention) +var zone_radius := SpawnOps.DEFAULT_ZONE_RADIUS + +var selected_team := -1 +var selected_id := "" + +# Auswähl-Ziehen +var _dragging := false +var _drag_moved := false +var _press_pos := Vector2.ZERO +var _grab_offset := Vector3.ZERO + +# Pfeilspitze ziehen (Blickrichtung): Griff aus view_builder.yaw_handles(), {} = keiner +const ARROW_PICK_M := 2.5 +const ARROW_SNAP_DEG := 5.0 +var _arrow_grab: Dictionary = {} +var _arrow_yaw := 0.0 + +# Terrain-Cache für Cursor-Raycast (nur LESEN — dieses Werkzeug formt nichts) +var _heights := PackedFloat32Array() +var _res := 0 +var _sx := 0.0 +var _sz := 0.0 + +var _cursor_valid := false +var _cursor := Vector3.ZERO + +# Ghost-Ring (Radius-Ring) + Fläche als Vorschau +var _ghost: Node3D + + +func setup(p_main, p_camera: Camera3D, p_builder, p_interaction) -> void: + main = p_main + camera = p_camera + view_builder = p_builder + interaction = p_interaction + _ensure_ghost() + + +func _ensure_ghost() -> void: + if _ghost != null and is_instance_valid(_ghost): + return + _ghost = Node3D.new() + _ghost.visible = false + add_child(_ghost) + + +# ------------------------------------------------------------ Aktivierung --- + +func activate() -> bool: + active = true + selected_team = -1 + selected_id = "" + _dragging = false + _cursor_valid = false + _refresh_from_doc() + if view_builder != null: + view_builder.call("set_spawn_selected", -1, "") + refresh_selection_panel() + return true # nie verweigert — Spawn-Zonen brauchen kein Auflösungs-Limit + + +func deactivate() -> void: + active = false + _dragging = false + selected_team = -1 + selected_id = "" + if _ghost != null and is_instance_valid(_ghost): + _ghost.visible = false + + +## Nach Undo/Redo/Laden/Neu: Terrain-Cache neu lesen, Auswahl weg. +func refresh_from_doc() -> void: + _refresh_from_doc() + var still_there := false + if selected_team >= 0: + for p in SpawnOps.points(main.doc, selected_team): + if p is Dictionary and str(p.get("id", "")) == selected_id: + still_there = true + break + if not still_there: + selected_team = -1 + selected_id = "" + + +func _refresh_from_doc() -> void: + var terrain: Dictionary = main.doc.get("terrain", {}) + _res = int(terrain.get("resolution", 0)) + _sx = float(terrain.get("size_x_m", 0.0)) + _sz = float(terrain.get("size_z_m", 0.0)) + if _res >= 2 and _sx > 0.0 and _sz > 0.0: + _heights = SvmapIO.decode_heights(terrain) + else: + _heights = PackedFloat32Array() + + +# ------------------------------------------------------------ Werkzeug-UI --- + +func set_team(next_team: int) -> void: + team = clampi(next_team, 0, 1) + _refresh_ghost_look() + if active: + main.call("_set_status", "Neue Zonen landen für %s (IDs %s1, %s2, …). Bestehende Zonen anklicken zum Verschieben." % [ + SpawnOps.team_label(team), SpawnOps.team_prefix(team), SpawnOps.team_prefix(team)]) + + +func set_radius(m: float) -> void: + zone_radius = clampf(m, SpawnOps.MIN_ZONE_RADIUS, SpawnOps.MAX_ZONE_RADIUS) + _refresh_ghost_look() + # Ausgewählte Zone? Dann gilt die Regel SOFORT für sie (mit Undo, merge-gekoppelt). + if active and selected_team >= 0 and selected_id != "": + var before: Dictionary = SpawnOps.snapshot_blocks(main.history, main.doc) + SpawnOps.set_radius(main.doc, selected_id, zone_radius) + main.history.commit("Radius von %s: %d m" % [selected_id, int(zone_radius)], + before, SpawnOps.snapshot_blocks(main.history, main.doc), + "radius:%s" % selected_id) + main.call("_refresh_history_buttons") + main.call("_refresh_spawn_status") + _refresh_ghost_look() + var marker: Node3D = _marker_of(selected_team, selected_id) + if marker != null and is_instance_valid(marker): + view_builder.call("style_spawn_marker", marker, + SpawnOps.zone_radius(main.doc, selected_id), true) + + +# --------------------------------------------------------------- Eingaben --- + +func _unhandled_input(event: InputEvent) -> void: + var p := MousePointer.from_input(event) + if p != null and handle_pointer(p): + get_viewport().set_input_as_handled() + + +## Rechte Maustaste kommt hier nie an (Karte t_2470de89): sie gehört mit +## absolutem Vorrang dem Freelook-Flug. Deselect/Werkzeug beenden läuft über +## ESC (main.gd), die Auswahl bleibt im Flug erhalten. +func handle_pointer(p: PointerEvent) -> bool: + if not active: + return false + match p.kind: + PointerEvent.Kind.MOVE: + _update_cursor(p.position) + if not _arrow_grab.is_empty(): + _drag_arrow(p.position) + return false + if _dragging and selected_team >= 0: + var hit: Variant = _ray_hit(p.position) + if hit == null: + return false + var pos: Vector3 = _clamped(hit as Vector3) + _grab_offset + var half := _terrain_half() + pos.x = clampf(pos.x, -half.x + zone_radius, half.x - zone_radius) + pos.z = clampf(pos.z, -half.y + zone_radius, half.y - zone_radius) + pos.y = SvmapDocument.terrain_height_at(main.doc, pos.x, pos.z) + _drag_moved = true + var marker: Node3D = _marker_of(selected_team, selected_id) + if marker != null and is_instance_valid(marker): + marker.position = pos + PointerEvent.Kind.PRESS: + _on_left_press(p.position) + return true + PointerEvent.Kind.RELEASE: + _on_left_release() + return false + + +func _update_cursor(viewport_pos: Vector2) -> void: + var hit: Variant = _ray_hit(viewport_pos) + if hit == null: + _cursor_valid = false + if _ghost != null and is_instance_valid(_ghost): + _ghost.visible = false + return + _cursor_valid = true + _cursor = _clamped(hit as Vector3) + if _ghost != null and is_instance_valid(_ghost): + _ghost.position = Vector3(_cursor.x, _cursor.y + 0.15, _cursor.z) + _ghost.visible = true + + +## Strahl → Punkt auf dem Terrain (Favorisiert echte Geländeberührung wie +## der Terrain-Pinsel; ohne Höhenfeld: Bodenebene). +func _ray_hit(viewport_pos: Vector2) -> Variant: + if _res >= 2 and _heights.size() >= _res * _res: + return TerrainField.raycast(_heights, _res, _sx, _sz, + camera.project_ray_origin(viewport_pos), camera.project_ray_normal(viewport_pos)) + var terrain: Dictionary = main.doc.get("terrain", {}) + if terrain.is_empty(): + return null + var plane_y := float(terrain.get("min_height_m", 0.0)) + var origin := camera.project_ray_origin(viewport_pos) + var dir := camera.project_ray_normal(viewport_pos) + if absf(dir.y) < 0.0001: + return null + var t := (plane_y - origin.y) / dir.y + if t <= 0.0: + return null + return origin + dir * t + + +func _clamped(p: Vector3) -> Vector3: + var half := _terrain_half() + p.x = clampf(p.x, -half.x, half.x) + p.z = clampf(p.z, -half.y, half.y) + p.y = SvmapDocument.terrain_height_at(main.doc, p.x, p.z) + return p + + +func _terrain_half() -> Vector2: + return Vector2(_sx, _sz) * 0.5 + + +# ----------------------------------------------------- Setzen/Auswählen ----- + +func _on_left_press(viewport_pos: Vector2) -> void: + _arrow_grab = _pick_arrow(viewport_pos) + if not _arrow_grab.is_empty(): + _drag_arrow(viewport_pos) + return + var picked := _pick_spawn(viewport_pos) + if picked.is_empty(): + _place_zone(viewport_pos) + return + # Bestehende Zone anfassen → auswählen + Greifen vorbereiten. + selected_team = int(picked["team"]) + selected_id = str(picked["id"]) + view_builder.call("set_spawn_selected", selected_team, selected_id) + _dragging = true + _drag_moved = false + _press_pos = viewport_pos + _grab_offset = Vector3.ZERO + var hit: Variant = _ray_hit(viewport_pos) + var marker: Node3D = _marker_of(selected_team, selected_id) + if hit != null and marker != null and is_instance_valid(marker): + _grab_offset = marker.position - (_clamped(hit as Vector3)) + _grab_offset.y = 0.0 + refresh_selection_panel() + main.call("_set_status", "%s (%s) ausgewählt — ziehen zum Verschieben, Entf zum Löschen, der Radius-Regel rechts gilt jetzt für SIE." % [ + selected_id, SpawnOps.team_label(selected_team)]) + + +func _on_left_release() -> void: + if not _arrow_grab.is_empty(): + _commit_arrow() + return + if not _dragging: + return + _dragging = false + if not (_drag_moved and selected_team >= 0 and selected_id != ""): + _drag_moved = false + return + var marker: Node3D = _marker_of(selected_team, selected_id) + if marker == null or not is_instance_valid(marker): + _drag_moved = false + return + var half := _terrain_half() + var pos: Vector3 = marker.position + pos.x = clampf(pos.x, -half.x, half.x) + pos.z = clampf(pos.z, -half.y, half.y) + var before: Dictionary = SpawnOps.snapshot_blocks(main.history, main.doc) + SpawnOps.move_point(main.doc, selected_team, selected_id, pos.x, pos.z) + # Symmetrie (M4): Zwilling folgt der gespiegelten neuen Position. + var mirror_msg: String = spawn_mirror_move(main.doc, selected_team, selected_id, _sym_mode()) + main.history.commit("%s verschoben" % selected_id, + before, SpawnOps.snapshot_blocks(main.history, main.doc)) + main.call("_after_structure_change") + _point_selection_at_doc() + view_builder.call("set_spawn_selected", selected_team, selected_id) + main.call("_set_status", "%s verschoben — Strg+Z macht das rückgängig.%s" % [ + selected_id, "" if mirror_msg.is_empty() else " " + mirror_msg]) + _drag_moved = false + + +func _place_zone(viewport_pos: Vector2) -> void: + var hit: Variant = _ray_hit(viewport_pos) + if hit == null: + main.call("_set_status", "Da war kein Boden unter dem Mauszeiger — klicke IN die Karte (die grüne Fläche).", true) + return + var half := _terrain_half() + var pos := _clamped(hit as Vector3) + if absf(pos.x) > half.x - zone_radius or absf(pos.z) > half.y - zone_radius: + pos.x = clampf(pos.x, -half.x + zone_radius, half.x - zone_radius) + pos.z = clampf(pos.z, -half.y + zone_radius, half.y - zone_radius) + main.call("_set_status", "Der Kreis würde über den Rand hinausschauen — ich habe ihn ganz nach innen geschoben.") + var before: Dictionary = SpawnOps.snapshot_blocks(main.history, main.doc) + var point := SpawnOps.add_zone(main.doc, team, pos.x, pos.z) + var pid := str(point["id"]) + SpawnOps.set_radius(main.doc, pid, zone_radius) + # Symmetrie (M4): Zwilling im Gegner-Team — innerhalb desselben Undo-Schritts. + var mirror_res: Dictionary = spawn_mirror_add(main.doc, team, pid, _sym_mode()) + main.history.commit("Spawn-Zone %s (%s) gesetzt" % [pid, SpawnOps.team_label(team)], + before, SpawnOps.snapshot_blocks(main.history, main.doc)) + main.call("_after_structure_change") + # Frische Zone auswählen und anfassen — Radius-Regel gilt ab jetzt für SIE. + selected_team = team + selected_id = pid + view_builder.call("set_spawn_selected", selected_team, selected_id) + refresh_selection_panel() + var mirror_text := str(mirror_res["status"]) + main.call("_set_status", "Spawn-Zone %s (%s) gesetzt.%s Radius: Regler rechts · verschieben: klicken+ziehen · Entf löscht · Strg+Z macht alles rückgängig." % [ + pid, SpawnOps.team_label(team), "" if mirror_text.is_empty() else " " + mirror_text]) + + +## Kursor-Strahl → nächste Pfeilspitze in Greifweite oder {}. +func _pick_arrow(viewport_pos: Vector2) -> Dictionary: + var hit: Variant = _ray_hit(viewport_pos) + if hit == null: + return {} + var p: Vector3 = hit as Vector3 + var best := {} + var best_d := ARROW_PICK_M + for h in view_builder.yaw_handles(): + var tip: Vector3 = h["tip"] + var d := Vector2(p.x - tip.x, p.z - tip.z).length() + if d <= best_d: + best = h + best_d = d + return best + + +func _drag_arrow(viewport_pos: Vector2) -> void: + var hit: Variant = _ray_hit(viewport_pos) + var node: Node3D = _arrow_grab.get("node") + if hit == null or node == null or not is_instance_valid(node): + return + var c := node.global_position + var yaw := SpawnOps.yaw_towards(c, Vector2((hit as Vector3).x, (hit as Vector3).z)) + _arrow_yaw = fposmod(snappedf(yaw, ARROW_SNAP_DEG), 360.0) + var arrow: MeshInstance3D = view_builder.yaw_arrow_of(node) + if arrow != null: + arrow.rotation.y = deg_to_rad(_arrow_yaw) + main.call("_set_status", "Blickrichtung von %s: %d°" % [str(_arrow_grab["id"]), int(_arrow_yaw)]) + + +func _commit_arrow() -> void: + var grab := _arrow_grab + _arrow_grab = {} + if str(grab["kind"]) == "zone": + apply_zone_yaw(str(grab["id"]), _arrow_yaw) + return + selected_team = int(grab["team"]) + selected_id = str(grab["id"]) + set_selected_yaw(_arrow_yaw) + + +## Blickrichtung der ausgewählten Zone setzen (yaw = null: Standard). EIN Undo-Eintrag. +func set_selected_yaw(yaw: Variant) -> void: + if selected_team < 0 or selected_id == "": + return + var before: Dictionary = SpawnOps.snapshot_blocks(main.history, main.doc) + if not SpawnOps.set_point_yaw(main.doc, selected_team, selected_id, yaw): + return + spawn_mirror_yaw(main.doc, selected_id, yaw, _sym_mode()) + main.history.commit("Blickrichtung von %s" % selected_id, + before, SpawnOps.snapshot_blocks(main.history, main.doc)) + main.call("_after_structure_change") + view_builder.call("set_spawn_selected", selected_team, selected_id) + refresh_selection_panel() + main.call("_set_status", "Blickrichtung von %s: %s — Strg+Z macht das rückgängig." % [ + selected_id, "Standard (zur Kartenmitte)" if yaw == null else "%d°" % int(yaw)]) + + +## Dasselbe für eine Conquest-Zone (der Griff im Bild, das Panel geht über modus_panel). +func apply_zone_yaw(zid: String, yaw: Variant) -> void: + var zones: Variant = main.doc.get("conquest_zones", []) + if not (zones is Array): + return + var before := {"conquest_zones": (zones as Array).duplicate(true)} + for z in zones: + if z is Dictionary and str(z.get("id", "")) == zid: + SpawnOps.write_yaw(z, yaw) + main.history.commit("Blickrichtung von %s" % zid, before, + {"conquest_zones": (zones as Array).duplicate(true)}) + main.call("_after_structure_change") + main.call("_set_status", "Blickrichtung von %s: %d° — Strg+Z macht das rückgängig." % [zid, int(yaw)]) + + +## Kursor-Strahl → getroffene Zone ({team, id}) oder {}. +func _pick_spawn(viewport_pos: Vector2) -> Dictionary: + var hit: Variant = _ray_hit(viewport_pos) + if hit == null: + return {} + var p: Vector3 = hit as Vector3 + var best := {} + var best_d := INF + for marker in view_builder.spawn_markers: + if marker == null or not is_instance_valid(marker): + continue + var mpos: Vector3 = marker.global_position + var d := Vector2(p.x - mpos.x, p.z - mpos.z).length() + var pick_r := float(marker.get_meta("spawn_pick_radius", 4.0)) + if d <= pick_r and d < best_d: + best = {"team": int(marker.get_meta("spawn_team", -1)), "id": str(marker.get_meta("spawn_id", ""))} + best_d = d + return best + + +func _marker_of(team_i: int, pid: String) -> Node3D: + for marker in view_builder.spawn_markers: + if marker == null or not is_instance_valid(marker): + continue + if int(marker.get_meta("spawn_team", -1)) == team_i and str(marker.get_meta("spawn_id", "")) == pid: + return marker + return null + + +func _point_selection_at_doc() -> void: + # Nach rebuild: Auswahl-Referenzen im DOC halten (selbes Team/ID-Prinzip). + for p in SpawnOps.points(main.doc, selected_team): + if p is Dictionary and str(p.get("id", "")) == selected_id: + return + selected_team = -1 + selected_id = "" + + +func _clear_selection() -> void: + selected_team = -1 + selected_id = "" + if _dragging: + _dragging = false + view_builder.call("set_spawn_selected", -1, "") + refresh_selection_panel() + + +func delete_selected() -> void: + if selected_team < 0 or selected_id == "": + main.call("_set_status", "Nichts ausgewählt — klicke zuerst eine Spawn-Zone an, die weg soll.", true) + return + var label := "%s (%s)" % [selected_id, SpawnOps.team_label(selected_team)] + var before: Dictionary = SpawnOps.snapshot_blocks(main.history, main.doc) + if not SpawnOps.remove_point(main.doc, selected_team, selected_id): + _clear_selection() + return + # Symmetrie (M4): Zwilling mit entfernen (innerhalb desselben Undo-Schritts). + var mirror_msg: String = spawn_mirror_delete(main.doc, selected_id, _sym_mode()) + main.history.commit("%s löschen" % label, before, + SpawnOps.snapshot_blocks(main.history, main.doc)) + _clear_selection() + main.call("_after_structure_change") + main.call("_set_status", "Spawn-Zone %s gelöscht — Strg+Z holt sie zurück.%s %s braucht mindestens %d Zonen!" % [ + label, "" if mirror_msg.is_empty() else " " + mirror_msg, + SpawnOps.team_label(team), SvmapIO.MIN_SPAWN_POINTS_PER_TEAM]) + + +## Panel-Zeile rechts (Welche Zone ist an?) synchron halten — ohne Statuszeile anzufassen. +func refresh_selection_panel() -> void: + if main.has_method("_sync_spawn_selection"): + main.call("_sync_spawn_selection") + + +# ------------------------------------------------- Symmetrie (M4) Statics --- +## Karte t_ffa207b1: Gespiegelte Spawn-Zonen. ENTScheidung (Spec vc27, +## „Teams bleiben einander gegenüber fair"): der Zwilling landet im GEGNER- +## Team — Blau (West) ↔ Rot (Ost), denn genau auf den Gegenseiten liegen die +## Default-Streifen der beiden Teams. Jede gesetzte Zone gibt dem anderen Team +## automatisch die faire Gegenstelle. Alles pure Statics (kein +## UI, kein Node-Zugriff) → headless testbar; spawn_ops.gd bleibt unangetastet. + +## Partner-ID einer Spawn-Zone ("" = keiner). +static func spawn_mirror_partner(doc: Dictionary, pid: String) -> String: + var m := _mirror_map_of(doc) + return str(m.get(pid, "")) + + +static func _mirror_map_of(doc: Dictionary) -> Dictionary: + var notes = doc.get("design_notes", {}) + if not (notes is Dictionary): + return {} + var m = (notes as Dictionary).get(SPAWN_MIRROR_KEY, {}) + return m if m is Dictionary else {} + + +static func _mirror_map_set(doc: Dictionary, pid_a: String, pid_b: String) -> void: + var notes = doc.get("design_notes", {}) + if not (notes is Dictionary): + notes = {} + doc["design_notes"] = notes + var m = (notes as Dictionary).get(SPAWN_MIRROR_KEY, {}) + if not (m is Dictionary): + m = {} + (notes as Dictionary)[SPAWN_MIRROR_KEY] = m + m[pid_a] = pid_b + m[pid_b] = pid_a + + +static func _mirror_map_clear(doc: Dictionary, pid_a: String, pid_b: String) -> void: + var m := _mirror_map_of(doc) + if m.is_empty(): + return + m.erase(pid_a) + m.erase(pid_b) + + +## Gespiegelte Spawn-Zone zu `pid` anlegen (Symmetrie an). Rückgabe: +## {"ok": bool, "status": Klartext}. ok=false + V9-Text = Zwilling NICHT +## gespeichert (Grenzen scharf — Spec vc27). Auf der Symmetrie-Mitte liegende +## Zonen werden nicht gedoppelt (Spec). +static func spawn_mirror_add(doc: Dictionary, team: int, pid: String, mode: int) -> Dictionary: + if mode == SymmetryCore.Mode.OFF: + return {"ok": true, "status": ""} + var original := _spawn_point_of(doc, team, pid) + if original.is_empty(): + return {"ok": false, "status": "Spawn-Zone %s nicht gefunden — Zwilling nicht gesetzt." % pid} + var pos := _spawn_pos_of(original) + var center := SymmetryCore.map_center(doc) + if SymmetryCore.maps_to_self(mode, pos, center): + return {"ok": true, "status": "Spawn-Zone %s liegt auf der Symmetrie-Mitte — nicht gedoppelt." % pid} + var mirror_pos := SymmetryCore.mirror_point(mode, pos, center) + var bounds: Dictionary = doc.get("bounds", {}) + if not bounds.is_empty() and not SvmapIO._inside_bounds( + [mirror_pos.x, mirror_pos.y, mirror_pos.z], bounds): + return {"ok": false, "status": "❌ V9: Gespiegelter Spawn läge außerhalb der Match-Grenzen — nicht gesetzt."} + var twin := SpawnOps.add_zone(doc, 1 - team, mirror_pos.x, mirror_pos.z) + var twin_id := str(twin["id"]) + SpawnOps.set_radius(doc, twin_id, SpawnOps.zone_radius(doc, pid)) + _mirror_map_set(doc, pid, twin_id) + if SpawnOps.has_yaw(original): + SpawnOps.write_yaw(twin, SymmetryCore.mirror_facing(mode, float(original[SpawnOps.YAW_KEY]))) + return {"ok": true, "status": "Gespiegelte Zone %s (%s) gesetzt." % [ + twin_id, SpawnOps.team_label(1 - team)]} + + +## Verschiebung spiegeln: Zwilling bekommt die gespiegelte Position der NEUEN +## Position des Originals (y = Terrain-Höhe am gespiegelten Punkt, wie beim +## normalen Verschieben). Rückgabe: Klartext-Status ("" = nichts zu tun). +static func spawn_mirror_move(doc: Dictionary, team: int, pid: String, mode: int) -> String: + if mode == SymmetryCore.Mode.OFF: + return "" + var partner := spawn_mirror_partner(doc, pid) + if partner.is_empty(): + return "" + var original := _spawn_point_of(doc, team, pid) + if original.is_empty(): + return "" + var pos := _spawn_pos_of(original) + var center := SymmetryCore.map_center(doc) + if SymmetryCore.maps_to_self(mode, pos, center): + return "" + var mirror_pos := SymmetryCore.mirror_point(mode, pos, center) + var partner_team := _team_of_point(doc, partner) + if partner_team < 0: + return "" + if not SpawnOps.move_point(doc, partner_team, partner, mirror_pos.x, mirror_pos.z): + return "" + return "Gespiegelte Zone %s mitverschoben." % partner + + +## Blickrichtung spiegeln: Zwilling schaut gespiegelt (yaw = null: auch er auf Standard). +static func spawn_mirror_yaw(doc: Dictionary, pid: String, yaw: Variant, mode: int) -> void: + if mode == SymmetryCore.Mode.OFF: + return + var partner := spawn_mirror_partner(doc, pid) + var partner_team := _team_of_point(doc, partner) if not partner.is_empty() else -1 + if partner_team >= 0: + SpawnOps.set_point_yaw(doc, partner_team, partner, + null if yaw == null else SymmetryCore.mirror_facing(mode, float(yaw))) + + +## Löschung spiegeln (entfernen → beide weg, inkl. Radius-Eintrag und +## Partner-Map). Rückgabe: Klartext-Status ("" = nur das Original war weg). +static func spawn_mirror_delete(doc: Dictionary, pid: String, mode: int) -> String: + if mode == SymmetryCore.Mode.OFF: + return "" + var partner := spawn_mirror_partner(doc, pid) + if partner.is_empty(): + return "" + var partner_team := _team_of_point(doc, partner) + if partner_team < 0: + _mirror_map_clear(doc, pid, partner) + return "" + if SpawnOps.remove_point(doc, partner_team, partner): + _mirror_map_clear(doc, pid, partner) + return "Gespiegelte Zone %s (%s) mit entfernt." % [partner, SpawnOps.team_label(partner_team)] + return "" + + +static func _spawn_point_of(doc: Dictionary, team: int, pid: String) -> Dictionary: + for p in SpawnOps.points(doc, team): + if p is Dictionary and str(p.get("id", "")) == pid: + return p as Dictionary + return {} + + +static func _team_of_point(doc: Dictionary, pid: String) -> int: + for team in [0, 1]: + if not _spawn_point_of(doc, team, pid).is_empty(): + return team + return -1 + + +static func _spawn_pos_of(point: Dictionary) -> Vector3: + var pos: Array = point.get("pos", [0.0, 0.0, 0.0]) + return Vector3(float(pos[0]), float(pos[1]), float(pos[2])) + + +# ------------------------------------------------------------ Ghost-Optik --- + +func _refresh_ghost_look() -> void: + if _ghost == null or not is_instance_valid(_ghost): + return + # Kreisfläche: flacher Cylinder (Zonen-Scheibe), teamfarbig halbtransparent. + for child in _ghost.get_children(): + child.queue_free() + var disc := MeshInstance3D.new() + var cyl := CylinderMesh.new() + cyl.top_radius = zone_radius + cyl.bottom_radius = zone_radius + cyl.height = 0.25 + disc.mesh = cyl + disc.position.y = 0.12 + var col: Color = view_builder.TEAM_COLORS[team] + var mat := StandardMaterial3D.new() + mat.albedo_color = Color(col.r, col.g, col.b, 0.4) + mat.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA + mat.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED + mat.emission_enabled = true + mat.emission = col * 0.35 + disc.material_override = mat + _ghost.add_child(disc) + var ring := MeshInstance3D.new() + var torus := TorusMesh.new() + torus.inner_radius = zone_radius - 0.2 + torus.outer_radius = zone_radius + 0.2 + torus.rings = 48 + torus.ring_segments = 6 + ring.mesh = torus + ring.position.y = 0.05 + ring.material_override = mat + _ghost.add_child(ring) + + +# ------------------------------------------------------- Demo/Screenshot ---- + +## Demo-Hook (Desktop-Smoke): Zone programmatisch setzen (inkl. History). +## Macht exakt, was ein Klick machen würde — ohne echte Maus-Ereignisse. +func demo_place(zone_team: int, x: float, z: float, radius: float) -> String: + var before: Dictionary = SpawnOps.snapshot_blocks(main.history, main.doc) + var point := SpawnOps.add_zone(main.doc, zone_team, x, z) + var pid := str(point["id"]) + if radius > 0.0: + SpawnOps.set_radius(main.doc, pid, radius) + # Symmetrie (M4): Zwilling im Gegner-Team — innerhalb desselben Undo-Schritts. + spawn_mirror_add(main.doc, zone_team, pid, _sym_mode()) + main.history.commit("Spawn-Zone %s (%s) gesetzt" % [pid, SpawnOps.team_label(zone_team)], + before, SpawnOps.snapshot_blocks(main.history, main.doc)) + return pid + + +## Demo-Hook: Zone programmatisch verschieben (inkl. History). +func demo_move(zone_team: int, pid: String, x: float, z: float) -> void: + var before: Dictionary = SpawnOps.snapshot_blocks(main.history, main.doc) + SpawnOps.move_point(main.doc, zone_team, pid, x, z) + # Symmetrie (M4): Zwilling folgt der gespiegelten neuen Position. + spawn_mirror_move(main.doc, zone_team, pid, _sym_mode()) + main.history.commit("%s verschoben" % pid, + before, SpawnOps.snapshot_blocks(main.history, main.doc)) + + +## Aktiver Symmetrie-Modus aus main (M1-Schalter). Defensive über main.get(): +## Mock-Mains (Tests) haben sym_mode nicht — dann gilt OFF (altes Verhalten), +## statt mit SCRIPT ERROR abzustürzen (Lektion: SCRIPT ERROR in -s-Suiten = rot). +func _sym_mode() -> int: + var v: Variant = main.get("sym_mode") if main != null else null + return SymmetryCore.Mode.OFF if v == null else int(v) + + +## Demo-Hook: Ghost an Position parken (für Screenshots ohne Maus). +func demo_park_ghost(x: float, z: float, team_i: int, radius: float) -> void: + set_team(team_i) + if radius > 0.0: + set_radius_demo_only(radius) + _refresh_ghost_look() + _cursor = Vector3(x, SvmapDocument.terrain_height_at(main.doc, x, z), z) + _cursor_valid = true + _ghost.position = Vector3(_cursor.x, _cursor.y + 0.15, _cursor.z) + _ghost.visible = true + + +## Nur-Editor-Radius (kein Doc-Eintrag, kein Undo) für die Vorschau im Demo-Hook. +func set_radius_demo_only(m: float) -> void: + zone_radius = clampf(m, SpawnOps.MIN_ZONE_RADIUS, SpawnOps.MAX_ZONE_RADIUS) \ No newline at end of file diff --git a/editor/spawn_tool.gd.uid b/editor/spawn_tool.gd.uid new file mode 100644 index 0000000..44902a0 --- /dev/null +++ b/editor/spawn_tool.gd.uid @@ -0,0 +1 @@ +uid://dcr747fch22k diff --git a/editor/symmetry_ops.gd b/editor/symmetry_ops.gd new file mode 100644 index 0000000..b58b318 --- /dev/null +++ b/editor/symmetry_ops.gd @@ -0,0 +1,647 @@ +extends RefCounted +class_name SymmetryOps +## M5 Ein-Klick „Karte symmetrisch machen“ + Symmetrie-Check (Karte t_60014669, +## Spec /opt/data/scopedvr/KARTEN_MIRROR_vc27.md). Baut auf M1–M4 auf: +## Spiegel-Mathe und Partner-Links kommen aus SymmetryCore, das Anwenden auf +## Objekten aus ObjectOps, auf Bauteilen (normale Objekte) und auf Spawn-Zonen aus +## dem Spawn-Spiegel-Mechanismus (spawn_tool.gd — dort NUR BENUTZT, nie +## geändert). Diese Datei orchestriert den GANZEN Vorgang und den Check: +## +## analyze(doc, mode) → ehrliche Bestandsaufnahme (nur lesen): Paare, die +## schon passen, Paare, die widersprechen, Elemente +## ohne Zwilling, abweichende Boden-Zellen. +## apply(doc, mode, quelle_hoch) → gleicht die Karte an: alles aus der +## Quell-Hälfte wird ERGÄNZT (Objekte, Bau-Teile, +## Spawn-Punkte, Boden zellgenau); widersprüchliche +## Paare bekommen die Quelle zugesprochen (nichts wird +## gelöscht, die Zahl wurde vorher genannt). +## check(doc, mode) → Klartext-Bericht: „Alles symmetrisch ✓“ oder +## „N Stellen weichen ab: Objekt #12, Boden (31,17) …“ +## +## Seiten-Logik ohne Mode-Wirrwarr: Jedes Element wird mit seinem Spiegelbild +## verglichen. Die „linke“/„vordere“ Seite eines Paares ist die, deren +## Spiegelbild weiter rechts/hinten liegt (lex-Antwort: erst x, dann z). +## Die Quell-Hälfte-Wahl (quelle_hoch=false = links/vorn, true = rechts/hinten) +## entscheidet NUR, welche Seite eines Paares bei Widerspruch gewinnt und in +## welche Richtung einzelstehende Elemente ergänzt werden. +## +## Ein-Klick-Anwendung (Panel) macht den GANZEN Vorgang zu EINEM Undo-Schritt: +## ActionHistory snapshotet das ganze Dokument — hier wird nur mutiert, das +## Committen bleibt beim Aufrufer (Panel/main, Muster wie beim Resize R3). +## +## Alles static + reine Funktionen (mutieren nur das übergebene doc) → +## headless testbar wie SymmetryCore/ObjectOps. + +const SpawnToolScript := preload("res://core/editor/spawn_tool.gd") + +## Wie nah ein Spiegelbild an einem Element liegen darf, damit sie als Paar +## gelten (Meter, XZ-Ebene). Handgebaute Karten sitzen nie auf den Millimeter — +## aber exakt gespiegelte Paare aus M2–M4 liegen auf 0. +const PAIR_TOLERANCE_M := 1.0 +## Ab wann Höhen als verschieden gelten (Terrain-R16-Schritt ist viel kleiner). +const HEIGHT_EPS_M := 0.02 +## Kleine Vergleichstoleranzen für Position/Drehung/Maßstab/Farbe. +const POS_EPS_M := 0.01 +const ROT_EPS_DEG := 0.5 +const VALUE_EPS := 0.01 +## Wie viele Beispiele der Klartext-Bericht maximal einzeln nennt. +const MAX_EXAMPLES := 8 + + +# ------------------------------------------------------------ Seiten-Logik -- + +## Klartext-Namen der beiden Hälften für den Modus ([niedrige Seite, hohe]). +static func side_labels(mode: int) -> Array: + if mode == SymmetryCore.Mode.AXIS_Z: + return ["vorn", "hinten"] + return ["links", "rechts"] + + +static func _center_of(doc: Dictionary) -> Vector2: + return SymmetryCore.map_center(doc) + + +static func _mirror(mode: int, doc: Dictionary, p: Vector3) -> Vector3: + return SymmetryCore.mirror_point(mode, p, _center_of(doc)) + + +static func _pos_of(arr: Array) -> Vector3: + if (arr as Array).size() < 3: + return Vector3.ZERO + return Vector3(float(arr[0]), float(arr[1]), float(arr[2])) + + +## „self“ = liegt auf Mitte/Achse (wird nie gedoppelt, nie geprüft). +## „low“ = lex-erste Seite (links bzw. vorn), „high“ = die andere. +## Bei Punkt-Spiegelung entscheidet auf der Mittel-Linie z statt x. +static func _side_of(mode: int, p: Vector3, doc: Dictionary) -> String: + if SymmetryCore.maps_to_self(mode, p, _center_of(doc)): + return "self" + var m := _mirror(mode, doc, p) + if p.x < m.x - 0.0001: + return "low" + if p.x > m.x + 0.0001: + return "high" + return "low" if p.z < m.z - 0.0001 else "high" + + +## Templat-loses Sammeln: items = [{"idx": int, "pos": Vector3}]. Paarung +## IMMERS vom low-Spiegel aus (deterministisch, Richtung der Quell-Wahl +## ändert die Paare nicht). Rückgabe: +## pairs: [{"low": idx, "high": idx, "mirror": Vector3}] +## singles_low / singles_high: idx-Listen der Zwillinglosen +static func _pair_items(mode: int, doc: Dictionary, items: Array) -> Dictionary: + var out := {"pairs": [], "singles_low": [], "singles_high": []} + var low_pool: Array = [] + var high_pool: Array = [] + for it in items: + if not (it is Dictionary): + continue + var side: String = _side_of(mode, it["pos"], doc) + if side == "self": + continue + if side == "low": + low_pool.append(it) + else: + high_pool.append(it) + var used: Dictionary = {} + for d in low_pool: + var m := _mirror(mode, doc, d["pos"]) + var best: int = -1 + var best_d: float = PAIR_TOLERANCE_M + for k in high_pool.size(): + if used.has(k): + continue + var t: Dictionary = high_pool[k] + var dxy := Vector2(m.x - t["pos"].x, m.z - t["pos"].z).length() + if dxy <= best_d: + best = k + best_d = dxy + if best >= 0: + used[best] = true + out["pairs"].append({ + "low": int(d["idx"]), + "high": int(high_pool[best]["idx"]), + "mirror": m, + }) + for k in high_pool.size(): + if not used.has(k): + out["singles_high"].append(int(high_pool[k]["idx"])) + for d in low_pool: + var paired := false + for p in out["pairs"]: + if int(p["low"]) == int(d["idx"]): + paired = true + break + if not paired: + out["singles_low"].append(int(d["idx"])) + return out + + +# -------------------------------------------------------------- analyze() --- + +## Ehrliche Bestandsaufnahme (liest NUR). Siehe Klassenkopf für die Struktur. +static func analyze(doc: Dictionary, mode: int) -> Dictionary: + var an := { + "mode": mode, + "objects": {"pairs": [], "singles_low": [], "singles_high": [], "diff": 0}, + "spawns": {"pairs": [], "singles_low": [], "singles_high": [], "diff": 0}, + "terrain_cells": [], + "material_cells": [], # Material-Raster (fein, Karte 24.10.) — eigenes Gitter + "deviations": [], + "links": 0, # positionierende Paare ohne sym-Kopplung (werden verknüpft) + "conflicts": 0, # widersprüchliche Paare + Boden-Zellen + "adds": 0, # Zwillinge, die ergänzt werden + "_dev_total": 0, + "total_changes": 0, + "total_deviations": 0, + } + if mode == SymmetryCore.Mode.OFF: + return an + _analyze_objects(doc, mode, an) + _analyze_spawns(doc, mode, an) + _analyze_terrain(doc, mode, an) + an["conflicts"] = int(an["objects"]["diff"]) \ + + int(an["spawns"]["diff"]) + (an["terrain_cells"] as Array).size() \ + + (an["material_cells"] as Array).size() + an["adds"] = (an["objects"]["singles_low"] as Array).size() \ + + (an["objects"]["singles_high"] as Array).size() \ + + (an["spawns"]["singles_low"] as Array).size() \ + + (an["spawns"]["singles_high"] as Array).size() + an["total_deviations"] = int(an["_dev_total"]) + an["total_changes"] = int(an["conflicts"]) + int(an["adds"]) + int(an["links"]) + return an + + +## Meldet eine Abweichung: Zähler ZÄHLT IMMER, die Beispielliste ist gekappt. +static func _push_dev(an: Dictionary, label: String) -> void: + an["_dev_total"] = int(an["_dev_total"]) + 1 + var devs: Array = an["deviations"] + if devs.size() < MAX_EXAMPLES: + devs.append(label) + + +static func _valid_link(list: Array, idx: int) -> int: + ## sym-Partner-Index NUR wenn der Partner wirklich existiert — sonst gilt + ## das Element als verkoppelt-lost und läuft über die Paarung mit. + var item: Dictionary = list[idx] + var key := SymmetryCore.sym_of(item) + if key.is_empty(): + return -1 + return SymmetryCore.find_partner_index(list, key, idx) + + +## Frische gemeinsame sym-Kennung für ein Paar. Hingen die Elemente vorher an +## ANDEREN Partnern, verlieren diese ihre Kennung mit — sonst bliebe ein +## V16-Waise übrig (eine Kennung = GENAU 2 Elemente). Merkwurzeln einer +## beschädigten Karte können so pro Lauf kleiner werden; ein zweiter Klick +## erledigt den Rest. +static func _fresh_pair_link(doc: Dictionary, list: Array, donor_i: int, + twin_i: int) -> void: + for idx in [donor_i, twin_i]: + var key := SymmetryCore.sym_of(list[idx]) + if key.is_empty(): + continue + var old_partner := SymmetryCore.find_partner_index(list, key, idx) + if old_partner >= 0 and old_partner != donor_i and old_partner != twin_i: + SymmetryCore.clear_sym(list[old_partner]) + SymmetryCore.clear_sym(list[idx]) + var nk := SymmetryCore.next_sym_key(doc) + SymmetryCore.set_sym(list[donor_i], nk) + SymmetryCore.set_sym(list[twin_i], nk) + + +## Spawn-Gegenstück: Kopplung design_notes.spawn_mirror sauber neu setzen +## (beide Richtungen überschreiben, alte Partner beidseitig auskoppeln). +static func _fresh_spawn_link(doc: Dictionary, donor_id: String, + twin_id: String) -> void: + for pid in [donor_id, twin_id]: + var old := _spawn_linked(doc, pid) + if not old.is_empty() and old != donor_id and old != twin_id: + SpawnToolScript._mirror_map_clear(doc, pid, old) + SpawnToolScript._mirror_map_set(doc, donor_id, twin_id) + + +static func _obj_pair_differs(src: Dictionary, twin: Dictionary, mp: Vector3, + mode: int) -> bool: + var tpos := _pos_of(twin.get("pos", [])) + if Vector2(mp.x - tpos.x, mp.z - tpos.z).length() > POS_EPS_M: + return true + if absf(tpos.y - mp.y) > POS_EPS_M: + return true + # 3 Achsen (Karte t_e166e656): der Vergleich läuft über die gespiegelte + # Euler-Orientierung (für reines Y-Drehen identisch zur alten rot_y-Regel). + var gespiegelt := SymmetryCore.mirror_rot_euler(mode, SvmapIO.objekt_rotation(src)) + var twin_euler := SvmapIO.objekt_rotation(twin) + var trot := fposmod(twin_euler.y - gespiegelt.y, 360.0) + var rotd := minf(trot, 360.0 - trot) + if rotd > ROT_EPS_DEG: + return true + var kipp := fposmod(twin_euler.x - gespiegelt.x + 180.0, 360.0) - 180.0 + if absf(kipp) > ROT_EPS_DEG: + return true + kipp = fposmod(twin_euler.z - gespiegelt.z + 180.0, 360.0) - 180.0 + if absf(kipp) > ROT_EPS_DEG: + return true + if absf(float(twin.get("scale", 1.0)) - float(src.get("scale", 1.0))) > VALUE_EPS: + return true + if str(twin.get("id", "")) != str(src.get("id", "")): + return true + var s_tint: Variant = src.get("tint", null) + var t_tint: Variant = twin.get("tint", null) + if (s_tint is Array) != (t_tint is Array): + return true + if s_tint is Array and t_tint is Array: + var sa: Array = s_tint + var ta: Array = t_tint + if (sa as Array).size() != (ta as Array).size(): + return true + for k in sa.size(): + if absf(float(sa[k]) - float(ta[k])) > VALUE_EPS: + return true + return false + + +static func _analyze_objects(doc: Dictionary, mode: int, an: Dictionary) -> void: + var objects: Array = doc.get("objects", []) + var items: Array = [] + for i in objects.size(): + var obj = objects[i] + if not (obj is Dictionary): + continue + var pos: Array = obj.get("pos", []) + if (pos as Array).size() < 3: + continue + items.append({"idx": i, "pos": _pos_of(pos)}) + var paired := _pair_items(mode, doc, items) + var pairs: Array = paired["pairs"] + var diff_n := 0 + for p in pairs: + var low_i: int = p["low"] + var high_i: int = p["high"] + var low_ok: bool = _valid_link(objects, low_i) == high_i + var high_ok: bool = _valid_link(objects, high_i) == low_i + if not (low_ok and high_ok): + an["links"] = int(an["links"]) + 1 + var donor: Dictionary = objects[low_i] + var twin: Dictionary = objects[high_i] + var differs := _obj_pair_differs(donor, twin, p["mirror"], mode) + if differs: + diff_n += 1 + _push_dev(an, "Objekt #%d" % low_i) + an["objects"]["pairs"] = pairs + an["objects"]["singles_low"] = paired["singles_low"] + an["objects"]["singles_high"] = paired["singles_high"] + an["objects"]["diff"] = diff_n + for idx in (paired["singles_low"] as Array) + (paired["singles_high"] as Array): + _push_dev(an, "Objekt #%d hat keinen Zwilling" % int(idx)) + + +# ------------------------------------------------------------------ Spawns -- +## Nur Teams 0/1 (TDM-Konvention wie M4): der Spiegel-Zwilling eines Spawn- +## Punkts liegt im GEGNER-Team. Kopplung läuft über design_notes.spawn_mirror. + +static func _spawn_items(doc: Dictionary) -> Array: + var items: Array = [] + for team in [0, 1]: + for p in SpawnOps.points(doc, team): + if not (p is Dictionary): + continue + var pos: Array = p.get("pos", []) + if (pos as Array).size() < 3: + continue + items.append({ + "team": team, + "id": str(p.get("id", "")), + "pos": _pos_of(pos), + }) + return items + + +static func _spawn_linked(doc: Dictionary, pid: String) -> String: + return SpawnToolScript.spawn_mirror_partner(doc, pid) + + +static func _analyze_spawns(doc: Dictionary, mode: int, an: Dictionary) -> void: + var items := _spawn_items(doc) + var paired := _pair_items_spawn(mode, doc, items) + var pairs: Array = paired["pairs"] + var diff_n := 0 + for p in pairs: + var low_ok: bool = _spawn_linked(doc, str(p["low_id"])) == str(p["high_id"]) + var high_ok: bool = _spawn_linked(doc, str(p["high_id"])) == str(p["low_id"]) + if not (low_ok and high_ok): + an["links"] = int(an["links"]) + 1 + var donor: Dictionary = p["low_point"] + var mp := SymmetryCore.mirror_point(mode, donor["pos"], _center_of(doc)) + var twin: Dictionary = p["high_point"] + if Vector2(mp.x - twin["pos"].x, mp.z - twin["pos"].z).length() > POS_EPS_M: + diff_n += 1 + _push_dev(an, "Spawn-Punkt %s" % str(p["low_id"])) + an["spawns"]["pairs"] = pairs + an["spawns"]["singles_low"] = paired["singles_low"] + an["spawns"]["singles_high"] = paired["singles_high"] + an["spawns"]["diff"] = diff_n + for s in (paired["singles_low"] as Array) + (paired["singles_high"] as Array): + _push_dev(an, "Spawn-Punkt %s hat keinen Zwilling" % str(s["id"])) + + +## Spawn-Variante der Paarung: items tragen team/id; Singles bleiben Objekte +## ({team, id, pos}) statt idx (Spawn-Punkte hängen an Teams, nicht am Array). +static func _pair_items_spawn(mode: int, doc: Dictionary, items: Array) -> Dictionary: + var out := {"pairs": [], "singles_low": [], "singles_high": []} + var low_pool: Array = [] + var high_pool: Array = [] + for it in items: + var side: String = _side_of(mode, it["pos"], doc) + if side == "self": + continue + if side == "low": + low_pool.append(it) + else: + high_pool.append(it) + var used: Dictionary = {} + for d in low_pool: + var m := _mirror(mode, doc, d["pos"]) + var best: int = -1 + var best_d: float = PAIR_TOLERANCE_M + for k in high_pool.size(): + if used.has(k): + continue + var t: Dictionary = high_pool[k] + var dxy := Vector2(m.x - t["pos"].x, m.z - t["pos"].z).length() + if dxy <= best_d: + best = k + best_d = dxy + if best >= 0: + used[best] = true + out["pairs"].append({ + "low_team": int(d["team"]), "low_id": str(d["id"]), + "high_team": int(high_pool[best]["team"]), + "high_id": str(high_pool[best]["id"]), + "low_point": d, "high_point": high_pool[best], + }) + for k in high_pool.size(): + if not used.has(k): + out["singles_high"].append(high_pool[k]) + for d in low_pool: + var paired := false + for p in out["pairs"]: + if str(p["low_id"]) == str(d["id"]): + paired = true + break + if not paired: + out["singles_low"].append(d) + return out + + +# ---------------------------------------------------------------- Terrain --- + +## Abweichende Zell-PAARE (je einmal, kanonisch = lex-erste Zelle des Paares). +static func _analyze_terrain(doc: Dictionary, mode: int, an: Dictionary) -> void: + var terrain: Dictionary = doc.get("terrain", {}) + var res := int(terrain.get("resolution", 0)) + if res < 2: + return + var heights := SvmapIO.decode_heights(terrain) + if heights.size() < res * res: + return + var cells: Array = an["terrain_cells"] + var eps := HEIGHT_EPS_M # absolut in Metern + for j in res: + for i in res: + var mc := SymmetryCore.mirror_cell(mode, i, j, res) + if mc.x == i and mc.y == j: + continue + # Nur das lex-erste Paarmitglied behandeln (keine Doppel-Meldung). + var is_low := i < mc.x or (i == mc.x and j < mc.y) + if not is_low: + continue + var ia := j * res + i + var ib := mc.y * res + mc.x + var dh := absf(heights[ia] - heights[ib]) + if dh > eps: + cells.append(Vector2i(i, j)) + if cells.size() <= MAX_EXAMPLES: + _push_dev(an, "Boden (%d,%d)" % [i, j]) + # Material auf seinem eigenen Raster (Byte exakt vergleichen). + var mres := SvmapIO.material_resolution(terrain) + var mats := SvmapIO.decode_materials(terrain) + if mres < 2 or mats.size() < mres * mres: + return + var mix := SvmapIO.decode_mix(terrain) # weiche Ränder: b + Anteil mitvergleichen + var mb: PackedByteArray = mix[0] + var mw: PackedByteArray = mix[1] + var mcells: Array = an["material_cells"] + for j in mres: + for i in mres: + var mc := SymmetryCore.mirror_cell(mode, i, j, mres) + if not (i < mc.x or (i == mc.x and j < mc.y)): + continue + var ia := j * mres + i + var ib := mc.y * mres + mc.x + if mats[ia] != mats[ib] or mb[ia] != mb[ib] or mw[ia] != mw[ib]: + mcells.append(Vector2i(i, j)) + if mcells.size() <= MAX_EXAMPLES: + _push_dev(an, "Boden-Material (%d,%d)" % [i, j]) + + +# ----------------------------------------------------------------- check() -- + +## Klartext-Bericht (nur lesen). report: {"ok": bool, "text": String, +## "deviations": Array}. „Alles symmetrisch ✓“ / „N Stellen weichen ab: …“. +static func check(doc: Dictionary, mode: int) -> Dictionary: + if mode == SymmetryCore.Mode.OFF: + return {"ok": false, + "text": "Der Symmetrie-Modus ist Aus — erst einen Modus wählen (Punkt / Achse), dann prüfen.", + "deviations": [], "analyze": analyze(doc, mode)} + var an := analyze(doc, mode) + var devs: Array = an["deviations"] + var total := int(an["total_deviations"]) + var text := "" + if total == 0: + text = "Alles symmetrisch ✓" + else: + var shown: Array = [] + for d in devs: + shown.append(str(d)) + var rest := total - shown.size() + var listing := ", ".join(PackedStringArray(shown)) + if rest > 0: + listing += " … und %d weitere" % rest + text = "%d Stellen weichen ab: %s" % [total, listing] + return {"ok": total == 0, "text": text, "deviations": devs, + "analyze": an} + + +# ----------------------------------------------------------------- apply() -- + +## Karte angleichen. quelle_hoch=false → links/vorn ist die Quelle (Gewinner +## bei Widersprüchen), true → rechts/hinten. Mutiert doc IN PLACE (Pattern +## wie die übrigen Tools: der Aufrufer snapshotet drum herum für EIN Undo). +## Rückgabe: {"ok": bool, "report": Klartext (mehrzeilig), "counts": {...}}. +static func apply(doc: Dictionary, mode: int, quelle_hoch: bool) -> Dictionary: + if mode == SymmetryCore.Mode.OFF: + return {"ok": false, "report": "Der Symmetrie-Modus ist Aus — ohne Modus weiß ich nicht, wie gespiegelt werden soll.", + "counts": {}} + var an := analyze(doc, mode) + var c := { + "objects_added": 0, "objects_fixed": 0, "objects_linked": 0, + "spawns_added": 0, "spawns_fixed": 0, "spawns_linked": 0, + "terrain_cells": 0, "skipped": 0, + } + _apply_objects(doc, mode, an, quelle_hoch, c) + _apply_terrain(doc, mode, an, quelle_hoch, c) + # Spawns ZULETZT: die Zwillinge sitzen auf der Terrain-Höhe — die stimmt + # erst nach dem Boden-Ausgleich (M2/M4-Konvention: y = Terrainhöhe). + _apply_spawns(doc, mode, an, quelle_hoch, c) + return {"ok": true, "counts": c, "report": _apply_report(c, quelle_hoch, mode)} + + +static func _apply_report(c: Dictionary, quelle_hoch: bool, mode: int) -> String: + var erg: Array = [] + for entry in [["objects_added", "Objekte ergänzt"], + ["spawns_added", "Spawn-Punkte ergänzt"], ["terrain_cells", "Bodenstellen angeglichen"], + ["objects_fixed", "Objekt-Widersprüche"], + ["spawns_fixed", "Spawn-Widersprüche"], ["objects_linked", "Objekt-Paare verknüpft"], + ["spawns_linked", "Spawn-Paare verknüpft"]]: + var n := int(c[entry[0]]) + if n > 0: + erg.append("%d %s" % [n, entry[1]]) + if erg.is_empty(): + return "Nichts zu tun — die Karte ist schon symmetrisch ✓" + var sides := side_labels(mode) + var conflict_sum := int(c["objects_fixed"]) + int(c["spawns_fixed"]) + int(c["terrain_cells"]) + var text := "Fertig ✓ — " + ", ".join(PackedStringArray(erg)) + if conflict_sum > 0: + text += ". Bei %d Widersprüchen hat %s gewonnen" % [conflict_sum, str(sides[1] if quelle_hoch else sides[0])] + return text + ". Ein Strg+Z macht alles rückgängig." + + +static func _write_object_from(twin: Dictionary, donor: Dictionary, mp: Vector3, + mode: int) -> void: + twin["pos"] = [mp.x, mp.y, mp.z] + # 3 Achsen (Karte t_e166e656): Kippen wird mitgespiegelt; für reines + # Y-Drehen exakt die alte mirror_rot_y-Regel (gleiche Zahlenwerte). + SvmapIO.rot_setzen(twin, SymmetryCore.mirror_rot_euler( + mode, SvmapIO.objekt_rotation(donor))) + twin["scale"] = donor.get("scale", 1.0) + if donor.has("tint"): + twin["tint"] = (donor["tint"] as Array).duplicate() + else: + twin.erase("tint") + twin["id"] = donor.get("id", "") + + +static func _apply_objects(doc: Dictionary, mode: int, an: Dictionary, + quelle_hoch: bool, c: Dictionary) -> void: + var objects: Array = doc.get("objects", []) + if (objects as Array).is_empty(): + return + # a) Paare: verknüpfen + Widersprüche zugunsten der Quelle entscheiden. + for p in (an["objects"]["pairs"] as Array): + var low_i: int = p["low"] + var high_i: int = p["high"] + var donor_i: int = high_i if quelle_hoch else low_i + var twin_i: int = low_i if quelle_hoch else high_i + var donor: Dictionary = objects[donor_i] + var twin: Dictionary = objects[twin_i] + var key_d := SymmetryCore.sym_of(donor) + var key_t := SymmetryCore.sym_of(twin) + if key_d != key_t or key_d.is_empty(): + # Ohne/widerstreitende Kopplung: frische gemeinsame Kennung. + _fresh_pair_link(doc, objects, donor_i, twin_i) + c["objects_linked"] = int(c["objects_linked"]) + 1 + var mp := SymmetryCore.mirror_point(mode, _pos_of(donor.get("pos", [])), _center_of(doc)) + if _obj_pair_differs(donor, twin, mp, mode): + _write_object_from(twin, donor, mp, mode) + c["objects_fixed"] = int(c["objects_fixed"]) + 1 + # b) Zwillinglose ergänzen (aus welcher Seite auch immer — nichts gelöscht). + for idx in (an["objects"]["singles_low"] as Array) + (an["objects"]["singles_high"] as Array): + var res := ObjectOps.symmetry_place_twin(doc, int(idx), mode) + if int(res["twin"]) >= 0: + c["objects_added"] = int(c["objects_added"]) + 1 + else: + c["skipped"] = int(c["skipped"]) + 1 + + +static func _apply_terrain(doc: Dictionary, mode: int, an: Dictionary, + quelle_hoch: bool, c: Dictionary) -> void: + _apply_materials(doc, mode, an, quelle_hoch, c) + var cells: Array = an["terrain_cells"] + if (cells as Array).is_empty(): + return + var terrain: Dictionary = doc.get("terrain", {}) + var res := int(terrain.get("resolution", 0)) + if res < 2: + return + var heights := SvmapIO.decode_heights(terrain) + var hmin := float(terrain.get("min_height_m", 0.0)) + var hmax := float(terrain.get("max_height_m", 1.0)) + for cell in cells: + var cc: Vector2i = cell + var mc := SymmetryCore.mirror_cell(mode, cc.x, cc.y, res) + var src := cc if not quelle_hoch else mc + var dst := mc if not quelle_hoch else cc + var si: int = src.y * res + src.x + var di: int = dst.y * res + dst.x + heights[di] = heights[si] + c["terrain_cells"] = int(c["terrain_cells"]) + 1 + terrain["heightmap_r16_b64"] = TerrainField.encode(heights, hmin, hmax) + + +## Material-Schicht angleichen (eigenes feines Raster, Karte 24.10.). +static func _apply_materials(doc: Dictionary, mode: int, an: Dictionary, + quelle_hoch: bool, c: Dictionary) -> void: + var cells: Array = an.get("material_cells", []) + if cells.is_empty(): + return + var terrain: Dictionary = doc.get("terrain", {}) + var mres := SvmapIO.material_resolution(terrain) + var mats := SvmapIO.decode_materials(terrain) + if mres < 2 or mats.size() < mres * mres: + return + var mix := SvmapIO.decode_mix(terrain) + var mb: PackedByteArray = mix[0] + var mw: PackedByteArray = mix[1] + for cell in cells: + var cc: Vector2i = cell + var mc := SymmetryCore.mirror_cell(mode, cc.x, cc.y, mres) + var src := cc if not quelle_hoch else mc + var dst := mc if not quelle_hoch else cc + var di := dst.y * mres + dst.x + var si := src.y * mres + src.x + mats[di] = mats[si] + mb[di] = mb[si] + mw[di] = mw[si] + c["terrain_cells"] = int(c["terrain_cells"]) + 1 + terrain["materials_r8_b64"] = SvmapIO.encode_materials(mats) + SvmapIO.encode_mix(terrain, mb, mw) + + +static func _apply_spawns(doc: Dictionary, mode: int, an: Dictionary, + quelle_hoch: bool, c: Dictionary) -> void: + # a) Paare: verknüpfen (design_notes.spawn_mirror) + Quelle entscheidet. + for p in (an["spawns"]["pairs"] as Array): + var donor_team: int = int(p["high_team"]) if quelle_hoch else int(p["low_team"]) + var donor_id: String = str(p["high_id"]) if quelle_hoch else str(p["low_id"]) + var linked_d := _spawn_linked(doc, donor_id) + var twin_id: String = str(p["low_id"]) if quelle_hoch else str(p["high_id"]) + if linked_d != twin_id: + # Beide Richtungen sauber neu setzen, alte Partner auskoppeln. + _fresh_spawn_link(doc, donor_id, twin_id) + c["spawns_linked"] = int(c["spawns_linked"]) + 1 + var donor_point: Dictionary = p["low_point"] if not quelle_hoch else p["high_point"] + var mp := SymmetryCore.mirror_point(mode, donor_point["pos"], _center_of(doc)) + var twin_point: Dictionary = p["high_point"] if not quelle_hoch else p["low_point"] + if Vector2(mp.x - twin_point["pos"].x, mp.z - twin_point["pos"].z).length() > POS_EPS_M: + var msg := SpawnToolScript.spawn_mirror_move(doc, donor_team, donor_id, mode) + if not msg.is_empty(): + c["spawns_fixed"] = int(c["spawns_fixed"]) + 1 + # b) Zwillinglose ergänzen (Team wechselt beim Spiegeln — M4-Regel). + for s in (an["spawns"]["singles_low"] as Array) + (an["spawns"]["singles_high"] as Array): + var res := SpawnToolScript.spawn_mirror_add(doc, int(s["team"]), str(s["id"]), mode) + if bool(res["ok"]) and str(res["status"]).contains("gesetzt"): + c["spawns_added"] = int(c["spawns_added"]) + 1 + else: + c["skipped"] = int(c["skipped"]) + 1 diff --git a/editor/symmetry_ops.gd.uid b/editor/symmetry_ops.gd.uid new file mode 100644 index 0000000..1ba1588 --- /dev/null +++ b/editor/symmetry_ops.gd.uid @@ -0,0 +1 @@ +uid://csb4dkvi508of diff --git a/editor/terrain_tool.gd b/editor/terrain_tool.gd new file mode 100644 index 0000000..0404d18 --- /dev/null +++ b/editor/terrain_tool.gd @@ -0,0 +1,765 @@ +extends Node3D +## Terrain-Pinsel (M2, Karte t_9aba04f1): Höhenfeld heben/senken/glätten im +## 3D-Viewport — im Terrain-Modus (Chef-Grundsatz Sly: maximal easy + Spaß). +## +## Bedienung: +## Linksklick-Ziehen = gewählter Pinsel-Modus (Heben / Senken / Glätten) +## Strg+Linksklick = das Gegenteil (bei Heben senkt er, bei Senken hebt +## er — Invert-Konvention wie Blender/Photoshop; im +## Malen-Modus malt Strg+Klick Gras zurück). Karte +## t_2470de89: die RECHTE Maustaste gehört IMMER dem +## Freelook-Flug — sie startet hier keinen Strich mehr. +## Der ganze Strich = EIN Undo-Eintrag (Strg+Z stellt die Form VOR dem +## Strich wieder her, nicht nur eine Zwischenstufe). +## +## Feedback: Pinsel-Ring folgt dem Cursor AUF dem Gelände (ray-march auf das +## Höhenfeld), das Mesh folgt dem Strich LIVE (Vertices pro Frame neu). +## +## Der Doc wird nur ZUM Strich-Ende verändert (encode → heightmap_r16_b64) +## — während des Strichs lebt ein dekodiertes PackedFloat32Array, das Mesh +## liest daraus. Undo/Redo läuft über die gemeinsame ActionHistory (terrain-Block). + +const SMOOTH_RATE_DIVISOR := 20.0 # Stärke-Slider (m/s) → Glätt-Tempo (Anteil/s) +const MODE_LABELS := ["Heben", "Senken", "Glätten", "Malen", "Einebnen", "Rampe"] +const FLATTEN_RATE_DIVISOR := 8.0 # Stärke-Slider → Einebnen-Tempo (Anteil/s) + +var main # Hauptfenster (script-erweitert, Variant) +var camera: Camera3D +var view_builder # TerrainMesh-Ansicht (script-erweitert, Variant) +var interaction # Objekt-Interaktion (für Modus-Wechsel) + +var active := false +var brush_mode: int = TerrainField.Mode.RAISE +var brush_radius := 12.0 # Meter +## Kante beim Malen: 0 = hart, 1 = ganz weich (Karte 25.10.). +var brush_weichheit := 0.4 +## Pinsel-Falloff (Karte 25.10.): 0 = hart (linear), 1 = weich (quadratisch). +var brush_falloff := 0.5 +## Druck 0.05–1 (Pen-Druck / Controller-Trigger / Maus = 1.0), skaliert die Stärke. +var pressure := 1.0 +var brush_strength := 8.0 # Meter pro Sekunde (Heben/Senken) +var paint_material: int = 0 # Material-ID im Malen-Modus (0=Gras, 1=Sand, 2=Fels) + +# Stroke-Zustand +var _stroking := false +var _stroke_mode: int = TerrainField.Mode.RAISE +var _stroke_material: int = 0 +var _flatten_target := 0.0 # Einebnen: Höhe unter dem Cursor beim Strichstart +var _ramp_a := Vector2.ZERO # Rampe: Startpunkt (Welt-X/Z) + Höhe +var _ramp_ha := 0.0 +var _ramp_b := Vector2.ZERO # Rampe: aktueller Endpunkt +var _heights := PackedFloat32Array() +var _mats := PackedByteArray() # Material-Schicht (res²) — seit _refresh_ + # _from_doc immer dekodiert (t_55ed041a), + # Mal-Strich schreibt live hinein. +var _res := 0 +var _mres := 0 # Raster der Material-Schicht (feines Raster, Karte 24.10.; alt = _res) +var _mix_b := PackedByteArray() # zweites Material je Punkt (weiche Ränder, Karte 25.10.) +var _mix_w := PackedByteArray() # Anteil des zweiten Materials 0–255 +var _sx := 0.0 +var _sz := 0.0 +var _hmin := 0.0 +var _hmax := 0.0 +var _cursor_valid := false +var _cursor := Vector3.ZERO + +# Pinsel-Ring +var _ring: MeshInstance3D +var _ramp_line: MeshInstance3D # Rampen-Vorschau: Linie Start → Cursor +var _ring_radius := -1.0 +var _ring_mode := -1 + + +func setup(p_main, p_camera: Camera3D, p_builder, p_interaction) -> void: + main = p_main + camera = p_camera + view_builder = p_builder + interaction = p_interaction + _ensure_ring() + + +func _ensure_ring() -> void: + if _ring != null and is_instance_valid(_ring): + return + _ring = MeshInstance3D.new() + _ring.visible = false + add_child(_ring) + _ramp_line = MeshInstance3D.new() + _ramp_line.visible = false + _ramp_line.mesh = ImmediateMesh.new() + var lm := StandardMaterial3D.new() + lm.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED + lm.albedo_color = Color(1.0, 0.85, 0.3) + lm.no_depth_test = true + _ramp_line.material_override = lm + add_child(_ramp_line) + + +# ------------------------------------------------------------ Aktivierung --- + +## Terrain-Modus einschalten. false = abgelehnt (Auflösungs-Limit) — main +## bleibt dann im Objekt-Modus und erklärt warum. +func activate() -> bool: + var terrain: Dictionary = main.doc.get("terrain", {}) + var res := int(terrain.get("resolution", 0)) + if res > TerrainField.EDITOR_MAX_RESOLUTION: + main.call("_set_status", + "Diese Map hat eine Terrain-Auflösung von %d — das Editor-MVP formt Terrain nur bis %d (Performance). Neu angelegte Maps erfüllen das automatisch." % [res, TerrainField.EDITOR_MAX_RESOLUTION], + true) + return false + if not _refresh_from_doc(): + return false + active = true + _stroking = false + _ring.visible = false + return true + + +func deactivate() -> void: + active = false + if _stroking: + _end_stroke() + if _ring != null and is_instance_valid(_ring): + _ring.visible = false + if _ramp_line != null and is_instance_valid(_ramp_line): + _ramp_line.visible = false + + +## Nach Undo/Redo/Laden/Neue-Map: Feld neu dekodieren (Cache ist sonst alt). +func refresh_from_doc() -> bool: + if not _refresh_from_doc(): + return false + return true + + +func _refresh_from_doc() -> bool: + var terrain: Dictionary = main.doc.get("terrain", {}) + if terrain.is_empty(): + return false + _res = int(terrain.get("resolution", 0)) + _sx = float(terrain.get("size_x_m", 0.0)) + _sz = float(terrain.get("size_z_m", 0.0)) + _hmin = float(terrain.get("min_height_m", 0.0)) + _hmax = float(terrain.get("max_height_m", 0.0)) + if _res < 2 or _sx <= 0.0 or _sz <= 0.0 or _hmax <= _hmin: + return false + _heights = SvmapIO.decode_heights(terrain) + # Material-Schicht mit dekodieren (Karte t_55ed041a): der Live-Rebuild + # beim Heben/Senken/Glätten braucht sie, sonst fällt das Mesh während + # des Strichs auf alles-Gras zurück (Sand/Fels „verschwinden" live). + _mats = SvmapIO.decode_materials(terrain) + _mres = SvmapIO.material_resolution(terrain) + _load_mix(terrain) + return _heights.size() >= _res * _res + + +# ------------------------------------------------------------ Pinsel-Optionen + +func set_brush_mode(mode: int) -> void: + # Clamp bis PAINT (3) — der alte Clamp 0..2 hätte den Malen-Modus still + # zu Glätten degradiert (Karte t_55257792, Ziffer 4 = Malen). + brush_mode = clampi(mode, 0, MODE_LABELS.size() - 1) + _refresh_ring_mesh() + + +func set_radius(m: float) -> void: + brush_radius = clampf(m, 1.0, 64.0) # ab 1 m (Karte 25.10., feines Raster) + _refresh_ring_mesh() + + +## Misch-Schicht (Karte 25.10.) aus dem terrain-Block — fehlt sie, Nullen. +func _load_mix(terrain: Dictionary) -> void: + var mix := SvmapIO.decode_mix(terrain) + _mix_b = mix[0] + _mix_w = mix[1] + + +## Materialpunkt als ein int (a | b<<8 | w<<16) — Spiegeln kopiert alle drei. +func _punkt(idx: int) -> int: + return int(_mats[idx]) | (int(_mix_b[idx]) << 8) | (int(_mix_w[idx]) << 16) + + +## Anteil (0–255) des Materials m an einem gepackten Punkt. +static func _anteil(v: int, m: int) -> int: + var a := v & 0xFF + var b := (v >> 8) & 0xFF + var w := (v >> 16) & 0xFF + return (255 - w if a == m else 0) + (w if b == m else 0) + + +func _setze_punkt(idx: int, v: int) -> void: + _mats[idx] = v & 0xFF + _mix_b[idx] = (v >> 8) & 0xFF + _mix_w[idx] = (v >> 16) & 0xFF + + +## Regler „Kante: hart ↔ weich“ (nur Malen). +func set_weichheit(w: float) -> void: + brush_weichheit = clampf(w, 0.0, 1.0) + + +func set_falloff(f: float) -> void: + brush_falloff = clampf(f, 0.0, 1.0) + + +## Druck setzen (XR-Controller-Trigger 0–1 ruft das direkt; Pen/Maus laufen +## über _unhandled_input). Wert wird über TerrainField.pressure_of begrenzt. +func set_pressure(p: float) -> void: + pressure = TerrainField.pressure_of(p, 0.0) + + +func set_strength(mps: float) -> void: + brush_strength = clampf(mps, 1.0, 20.0) + + +func set_paint_material(id: int) -> void: + paint_material = clampi(id, 0, SvmapIO.MATERIAL_IDS.size() - 1) + _refresh_ring_mesh() + + +# --------------------------------------------------------------- Eingaben --- + +func _unhandled_input(event: InputEvent) -> void: + var p := MousePointer.from_input(event) + if p == null: + return + # Stift: pressure > 0; Maus meldet 0 (oder 1) → bleibt voll. + if p.kind == PointerEvent.Kind.MOVE: + p.pressure = TerrainField.pressure_of(p.pressure, _trigger_axis()) + if handle_pointer(p): + get_viewport().set_input_as_handled() + + +## Rechte Maustaste kommt hier nie an: sie gehört mit absolutem Vorrang dem +## Freelook-Flug (orbit_camera.gd, Karte t_2470de89), in jedem Werkzeugzustand. +func handle_pointer(p: PointerEvent) -> bool: + if not active: + return false + match p.kind: + PointerEvent.Kind.MOVE: + _update_cursor(p.position) + pressure = p.pressure + PointerEvent.Kind.PRESS: + # Karte t_2470de89: Strg = Invert-Modifier. Heben↔Senken + # tauschen (Blender/Photoshop-Konvention), im Malen-Modus + # malt Strg+Klick Gras zurück (alter Radierer-Weg). + var mode := brush_mode + var mat := -1 + if p.ctrl: + match brush_mode: + TerrainField.Mode.RAISE: + mode = TerrainField.Mode.LOWER + TerrainField.Mode.LOWER: + mode = TerrainField.Mode.RAISE + TerrainField.Mode.PAINT: + mat = 0 # Gras zurückmalen + _begin_stroke(mode, mat) + return true + PointerEvent.Kind.RELEASE: + _end_stroke() + return true + return false + + +## Gamepad-Trigger (rechts) des ersten Pads; 0 ohne Pad. Nur Eingabe-Lesen, +## keine OS-Annahme. +func _trigger_axis() -> float: + var pads := Input.get_connected_joypads() + if pads.is_empty(): + return 0.0 + return Input.get_joy_axis(pads[0], JOY_AXIS_TRIGGER_RIGHT) + + +func _update_cursor(viewport_pos: Vector2) -> void: + var hit: Variant = TerrainField.raycast(_heights, _res, _sx, _sz, + camera.project_ray_origin(viewport_pos), camera.project_ray_normal(viewport_pos)) + if hit == null: + _cursor_valid = false + if _ring != null: + _ring.visible = false + return + _cursor_valid = true + _cursor = hit as Vector3 + var half_x := _sx * 0.5 + var half_z := _sz * 0.5 + _cursor.x = clampf(_cursor.x, -half_x, half_x) + _cursor.z = clampf(_cursor.z, -half_z, half_z) + # Ring minimal über dem Gelände, damit er nicht im Mesh verschwindet. + _ring.position = Vector3(_cursor.x, _height_at_stroke(_cursor.x, _cursor.z) + 0.3, _cursor.z) + _ring.visible = true + + +func _height_at_stroke(x: float, z: float) -> float: + return TerrainField.height_at(_heights, _res, _sx, _sz, x, z) + + +# ----------------------------------------------------------------- Stroke --- + +func _begin_stroke(mode: int, material_id: int = -1) -> void: + if _stroking: + return + if not _cursor_valid: + main.call("_set_status", + "Der Pinsel braucht einen Punkt AUF dem Gelände — führe die Maus über die Karte und halte dann die Maustaste gedrückt.", + true) + return + _stroke_mode = mode + _stroke_material = paint_material if material_id < 0 else material_id + _stroking = true + if mode == TerrainField.Mode.FLATTEN: + _flatten_target = _height_at_stroke(_cursor.x, _cursor.z) + elif mode == TerrainField.Mode.RAMP: + _ramp_a = Vector2(_cursor.x, _cursor.z) + _ramp_ha = _height_at_stroke(_cursor.x, _cursor.z) + _ramp_b = _ramp_a + # Im Malen-Modus lebt die Material-Schicht während des Strichs + # (dekodiert — Legacy-Maps ohne Schicht starten mit alles-Gras). + if mode == TerrainField.Mode.PAINT: + _mats = SvmapIO.decode_materials(main.doc.get("terrain", {})) + _mres = SvmapIO.material_resolution(main.doc.get("terrain", {})) + _load_mix(main.doc.get("terrain", {})) + _refresh_ring_mesh() + main.call("_set_status", "%s läuft — Maustaste gedrückt halten. Beim Loslassen wird der ganze Strich EIN Rückgängig-Schritt (Strg+Z)." % _stroke_label()) + + +## Lesbarer Stroke-Name: Heben/Senken/Glätten bzw. „Malen (Sand)". +func _stroke_label() -> String: + if _stroke_mode == TerrainField.Mode.PAINT: + return "Malen (%s)" % SvmapIO.MATERIAL_IDS[clampi(_stroke_material, 0, SvmapIO.MATERIAL_IDS.size() - 1)] + return MODE_LABELS[_stroke_mode] + + +func _process(delta: float) -> void: + if not _stroking or not _cursor_valid: + return + if _stroke_mode == TerrainField.Mode.PAINT: + var painted := _paint_step(_cursor.x, _cursor.z) + if painted: + # Karte t_7a0a6b79: Malen lebt im Sub-Rect — update_terrain bekommt + # das betroffene Zellrechteck (inkl. Spiegelzellen) und leitet nur + # die Splat-Region neu ab; das Mesh selbst bleibt unangetastet + # (Vertex-Farben hängen NICHT vom Material ab). + if view_builder.has_method("set_terrain_mix"): + view_builder.call("set_terrain_mix", _mix_b, _mix_w) + view_builder.call("update_terrain", _heights, _mats, _splat_rect) + _ring.position.y = _height_at_stroke(_cursor.x, _cursor.z) + 0.3 + return + if _stroke_mode == TerrainField.Mode.RAMP: + # Rampe wirkt erst beim Loslassen — hier nur der Endpunkt + Ring-Hinweis. + _ramp_b = Vector2(_cursor.x, _cursor.z) + _update_ramp_line() + return + var amount := _step_amount(_stroke_mode, delta) + # Während des Strichs NICHT auf die Format-Range clampen — die zieht der + # Range-Expander danach nach (sonst friert Heben/Senken an der Kante ein). + var changed := _height_step(_cursor.x, _cursor.z, amount) + if changed: + _expand_range_if_needed() + # Karte t_55ed041a: Material-Schicht MITGEBEN — ohne sie hat der + # Live-Rebuild alles als Gras gerendert (Sand/Fels „verschwanden" + # während des Heben/Senk-Strichs und kehrten erst am Stroke-Ende + # mit dem Vollrebuild zurück). + view_builder.call("update_terrain", _heights, _mats) + _ring.position.y = _height_at_stroke(_cursor.x, _cursor.z) + 0.3 + + +## Stärke dieses Frames: Meter (Heben/Senken) bzw. Mischfaktor 0–1 (Glätten/ +## Einebnen) — skaliert mit dem Druck. +func _step_amount(mode: int, dt: float) -> float: + match mode: + TerrainField.Mode.SMOOTH: + return clampf(brush_strength / SMOOTH_RATE_DIVISOR * dt * pressure, 0.0, 1.0) + TerrainField.Mode.FLATTEN: + return clampf(brush_strength / FLATTEN_RATE_DIVISOR * dt * pressure, 0.0, 1.0) + return brush_strength * dt * pressure + + +## Höhe spannt das Höhenfeld automatisch auf, wenn der Pinsel über die +## Format-Grenzen (min/max_height) hinaus will — sonst wäre Senken auf einer +## frisch angelegten (flachen) Map unmöglich und langes Heben würde clampen. +## Die Range gehört zum terrain-Block → Undo stellt sie mit zurück. Spannweite +## bleibt ≤ 500 m (V6). +func _expand_range_if_needed() -> void: + var lo := TerrainField._min_h(_heights) + var hi := TerrainField._max_h(_heights) + if lo < _hmin: + _hmin = floorf(lo - 1.0) + if hi > _hmax: + _hmax = ceilf(hi + 1.0) + if _hmax - _hmin > 500.0: + if lo < _hmin: + _hmin = _hmax - 500.0 + else: + _hmax = _hmin + 500.0 + + +func _end_stroke() -> void: + if not _stroking: + return + _stroking = false + if _stroke_mode == TerrainField.Mode.RAMP: + _ramp_line.visible = false + if not _ramp_apply(): + main.call("_set_status", "Rampe: Start und Ende liegen zu nah beieinander — Klick, ziehen, loslassen.") + return # nichts geändert → kein leerer Undo-Eintrag + # Doc erst jetzt ändern: der GANZE Strich ist ein History-Eintrag. + var before: Dictionary = main.history.snapshot(["terrain"]) + var terrain: Dictionary = main.doc.get("terrain", {}) + if _stroke_mode == TerrainField.Mode.PAINT: + terrain["materials_r8_b64"] = SvmapIO.encode_materials(_mats) + SvmapIO.encode_mix(terrain, _mix_b, _mix_w) + main.history.commit("Boden gemalt (%s)" % SvmapIO.MATERIAL_IDS[clampi(_stroke_material, 0, SvmapIO.MATERIAL_IDS.size() - 1)], + before, main.history.snapshot(["terrain"])) + else: + terrain["min_height_m"] = _hmin + terrain["max_height_m"] = _hmax + terrain["heightmap_r16_b64"] = TerrainField.encode(_heights, _hmin, _hmax) + main.history.commit("Boden geformt (%s)" % MODE_LABELS[_stroke_mode], + before, main.history.snapshot(["terrain"])) + main.call("_on_terrain_stroke_committed") + + +## Rampe anwenden (Strichende): Start-Höhe = Höhe beim Klick, End-Höhe = Höhe +## unter dem Endpunkt. Breite = 2 × Radius. Symmetrie wie bei den Pinseln. +func _ramp_apply() -> bool: + if _ramp_a.distance_to(_ramp_b) < 1.0: + return false + var hb := _height_at_stroke(_ramp_b.x, _ramp_b.y) + var width := brush_radius * 2.0 + var snap := {} + var g := _world_to_grid(_ramp_a.x, _ramp_a.y) + if _sym_active(): + var g2 := _world_to_grid(_ramp_b.x, _ramp_b.y) + var r := _brush_region(g).merge(_brush_region(g2)) + snap = _snap_heights(r) + var changed := TerrainField.apply_ramp(_heights, _res, _sx, _sz, + _ramp_a, _ramp_b, _ramp_ha, hb, width, brush_falloff) + if changed and not snap.is_empty(): + _mirror_heights(snap, g) + if changed: + _expand_range_if_needed() + view_builder.call("update_terrain", _heights, _mats) + return changed + + +## Rampen-Vorschau: gelbe Linie vom Startpunkt zum Cursor (auf Geländehöhe). +func _update_ramp_line() -> void: + var im := _ramp_line.mesh as ImmediateMesh + im.clear_surfaces() + im.surface_begin(Mesh.PRIMITIVE_LINES) + im.surface_add_vertex(Vector3(_ramp_a.x, _ramp_ha + 0.5, _ramp_a.y)) + im.surface_add_vertex(Vector3(_ramp_b.x, _height_at_stroke(_ramp_b.x, _ramp_b.y) + 0.5, _ramp_b.y)) + im.surface_end() + _ramp_line.visible = true + + +## Programmgesteuerter Stroke (Demo/Screenshot-Hook): macht exakt, was eine +## Maus auch tun würde — inkl. History-Eintrag. +func demo_stroke(x: float, z: float, mode: int, seconds: float) -> void: + _refresh_from_doc() + _cursor = Vector3(x, 0.0, z) + _cursor_valid = true + _begin_stroke(mode) + var steps := int(ceil(seconds / 0.05)) + var dt := seconds / float(maxi(steps, 1)) + var save_x := _cursor.x + var save_z := _cursor.z + for i in steps: + var amount := _step_amount(mode, dt) + if mode == TerrainField.Mode.PAINT: + _paint_step(save_x, save_z) + continue + _height_step(save_x, save_z, amount) + _expand_range_if_needed() + _end_stroke() + _refresh_from_doc() + + +## Demo-Hook: Pinsel-Ring sichtbar an einer Weltposition parken (für +## Screenshots ohne echte Maus-Ereignisse). +func demo_park_brush(x: float, z: float) -> void: + _refresh_ring_mesh() + _cursor = Vector3(x, 0.0, z) + _cursor_valid = true + _ring.position = Vector3(x, _height_at_stroke(x, z) + 0.3, z) + _ring.visible = true + + +# ------------------------------------------------------------- Symmetrie ---- +## M2 (Karte t_f9eff526): Im Symmetrie-Modus (main.sym_mode ≠ AUS) schreibt +## jeder Strich seine Zellen EXAKT gespiegelt in die andere Kartenseite — +## Höhe ist ein Skalar → 1:1 identisch übernommen, Material ebenso. Die +## Zell-Abbildung kommt aus M1 (SymmetryCore.mirror_cell), nichts neu erfunden. +## +## Ablauf pro Pinsel-Schritt: +## 1. Pinsel EINMAL an der Strich-Position anwenden — bewusst NICHT zweimal +## (Strichpunkt + Spiegelpunkt): sonst bekämen Zellen im Überlappband den +## Effekt doppelt und an der Rastermitte entstünde ein Grat. +## 2. Die seit dem Snapshot geänderten Zellen des Pinsel-Rechtecks ermitteln +## und jede Änderung in die gespiegelte Schwesterzelle kopieren. +## Liegt der Strich genau auf der Mitte/Achse, bildet mirror_cell die Zellen +## auf sich selbst bzw. auf Partner mit IDENTISCHEm Wert ab (spiegelsymmetrischer +## Fußabdruck, gleicher Falloff-Abstand) → nichts wird gedoppelt. +## Überlappen Fußabdruck und Spiegelbild (Strich nahe der Mitte), gewinnt pro +## Zellpaar die Seite, die NÄHER am Strichpunkt liegt — die andere Hälfte ist +## exakte Kopie der Strich-Seite; bei exaktem Gleichstand entscheidet der +## kleinere Grid-Index (deterministisch, Row-major-Verarbeitung). +## Bei Modus AUS: keine Snapshot-/Kopierarbeit — exakt das alte Verhalten. + +## Zusätzlicher Rand um die grobe Pinsel-Region (TerrainField arbeitet mit +## floor/ceil ± 1; hier großzügig ± 2 — der Snapshot-Vergleich entscheidet +## ohnehin zellgenau, was wirklich geändert wurde). +const SYM_REGION_MARGIN := 2 + +func _sym_mode() -> int: + if main == null: + return SymmetryCore.Mode.OFF + # .get statt direkter Property: Haupts ohne sym_mode-Feld (z. B. alte + # Test-Stubs, Tools außerhalb des Editors) fallen auf AUS zurück — + # exakt das Verhalten vor M2. + var mode: Variant = main.get("sym_mode") + if mode == null or not (mode is int): + return SymmetryCore.Mode.OFF + return int(mode) + + +func _sym_active() -> bool: + return _sym_mode() != SymmetryCore.Mode.OFF + + +## Welt-X/Z → Raster-Koordinaten (gleiche Konvention wie TerrainField.height_at: +## Index 0 = −X/−Z-Ecke, x-Index läuft MIT +WeltX). +func _world_to_grid(x: float, z: float) -> Vector2: + return _world_to_grid_r(x, z, _res) + + +## Wie _world_to_grid, aber auf einem beliebigen Raster (Material: _mres). +func _world_to_grid_r(x: float, z: float, r: int) -> Vector2: + var last := float(r - 1) + return Vector2((x / _sx + 0.5) * last, (z / _sz + 0.5) * last) + + +## Grobes Rechteck um die Raster-Position (g), das den Pinsel-Fußabdruck +## jedes Modus garantiert abdeckt (Radius in Zellen + Margin). +func _brush_region(g: Vector2) -> Rect2i: + return _brush_region_r(g, _res) + + +## Wie _brush_region, auf dem Raster r (Material-Schicht: _mres). +func _brush_region_r(g: Vector2, r: int) -> Rect2i: + var cell_x := _sx / float(r - 1) + var cell_z := _sz / float(r - 1) + var rx := brush_radius / cell_x + float(SYM_REGION_MARGIN) + var rz := brush_radius / cell_z + float(SYM_REGION_MARGIN) + var x0 := maxi(int(floorf(g.x - rx)), 0) + var x1 := mini(int(ceilf(g.x + rx)), r - 1) + var z0 := maxi(int(floorf(g.y - rz)), 0) + var z1 := mini(int(ceilf(g.y + rz)), r - 1) + return Rect2i(x0, z0, x1 - x0 + 1, z1 - z0 + 1) + + +## Abstand einer Rasterzelle zum Strichpunkt in Metern (gleiche Zell-Metrik +## wie TerrainField.apply_brush: Zellindex-Abstand × Zellgröße). +func _cell_dist(pos: Vector2i, g: Vector2, cell_x: float, cell_z: float) -> float: + var dx := (float(pos.x) - g.x) * cell_x + var dz := (float(pos.y) - g.y) * cell_z + return sqrt(dx * dx + dz * dz) + + +## Ein Pinsel-Schritt HÖHE (Heben/Senken/Glätten) inkl. Spiegel-Kopie. +## amount: Meter (Heben/Senken) bzw. Mischfaktor 0–1 (Glätten) — unverändert +## zur bisherigen apply_brush-Semantik; ohne Clamp (Range-Expander zieht nach). +func _height_step(x: float, z: float, amount: float) -> bool: + var g := _world_to_grid(x, z) + var snap := {} + if _sym_active(): + snap = _snap_heights(_brush_region(g)) + var changed := TerrainField.apply_brush(_heights, _res, _sx, _sz, + -100000.0, 100000.0, x, z, brush_radius, _stroke_mode, amount, + brush_falloff, _flatten_target) + if changed and not snap.is_empty(): + _mirror_heights(snap, g) + return changed + + +## Ein Pinsel-Schritt MATERIAL (Malen) inkl. Spiegel-Kopie. +func _paint_step(x: float, z: float) -> bool: + # Material lebt auf seinem eigenen (feinen) Raster _mres (Karte 24.10.). + var g := _world_to_grid_r(x, z, _mres) + # VOR dem Pinsel: Zellrect des Fußabdrucks merken (deckt Spiegelzellen mit) + # — der Live-Splat-Refresh (t_7a0a6b79) leitet genau diese Region neu ab. + _splat_rect = _splat_region(g) + var snap := {} + if _sym_active() and _mats.size() >= _mres * _mres: + snap = _snap_mats(_brush_region_r(g, _mres)) + var changed := TerrainField.apply_material_brush_mix(_mats, _mix_b, _mix_w, _mres, + _sx, _sz, x, z, brush_radius, _stroke_material, brush_weichheit, pressure) + if changed and not snap.is_empty(): + _mirror_mats(snap, g) + return changed + + +## Snapshot {Vector2i(x, z) → Höhe} über das Pinsel-Rechteck (NUR bei +## Symmetrie AN erzeugt — bei AUS bleibt es bei exakt dem alten Verhalten). +func _snap_heights(rect: Rect2i) -> Dictionary: + var snap := {} + for z: int in range(rect.position.y, rect.end.y): + for x: int in range(rect.position.x, rect.end.x): + snap[Vector2i(x, z)] = _heights[z * _res + x] + return snap + + +## Spiegel-Pass für die Höhe: jede seit dem Snapshot geänderte Zelle wird in +## ihre gespiegelte Schwester kopiert (Strich-Seite ist Master, siehe oben). +func _mirror_heights(snap: Dictionary, g: Vector2) -> void: + var sym := _sym_mode() + var cell_x := _sx / float(_res - 1) + var cell_z := _sz / float(_res - 1) + var done := {} + var positions: Array = snap.keys() + # Row-major (kleinster Index zuerst): der Gleichstand-Tie-Break „kleinerer + # Index gewinnt“ ist damit deterministisch, und ein Paar wird genau einmal + # an seinem kleineren Index entschieden. + positions.sort_custom(func(a: Vector2i, b: Vector2i) -> bool: + return (a.y * _res + a.x) < (b.y * _res + b.x)) + for pos: Vector2i in positions: + if done.has(pos): + continue + var idx: int = pos.y * _res + pos.x + var mirror: Vector2i = SymmetryCore.mirror_cell(sym, pos.x, pos.y, _res) + done[pos] = true + if mirror == pos: + continue # Selbstabbildung (Rastermitte/Achse) — nichts zu kopieren + var midx: int = mirror.y * _res + mirror.x + var value: float = _heights[idx] + if snap.has(mirror): + # Beide Seiten wurden vom Pinsel geändert (Fußabdruck überlappt + # sein Spiegelbild): näher am Strichpunkt gewinnt, Gleichstand + # → kleinere Index (== diese pos, da Row-major zuerst kam). + if _cell_dist(mirror, g, cell_x, cell_z) < _cell_dist(pos, g, cell_x, cell_z): + value = _heights[midx] + _heights[idx] = value + _heights[midx] = value + done[mirror] = true + + +## Snapshot {Vector2i(x, z) → Material-ID} über das Pinsel-Rechteck. +func _snap_mats(rect: Rect2i) -> Dictionary: + var snap := {} + for z: int in range(rect.position.y, rect.end.y): + for x: int in range(rect.position.x, rect.end.x): + snap[Vector2i(x, z)] = _punkt(z * _mres + x) + return snap + + +## Spiegel-Pass für die Material-Schicht (identische Paar-Logik wie _mirror_heights). +func _mirror_mats(snap: Dictionary, g: Vector2) -> void: + var sym := _sym_mode() + var cell_x := _sx / float(_mres - 1) + var cell_z := _sz / float(_mres - 1) + var done := {} + var positions: Array = snap.keys() + positions.sort_custom(func(a: Vector2i, b: Vector2i) -> bool: + return (a.y * _mres + a.x) < (b.y * _mres + b.x)) + # Karte 25.10. (Sly: harte gerade Kanten mit Symmetrie): NUR Punkte spiegeln, + # die dieser Pinsel-Schritt wirklich verändert hat. Vorher wurde das ganze + # Snapshot-Quadrat auf die Gegenseite kopiert — weiche Verläufe drüben + # wurden an den Quadratkanten hart abgeschnitten. + for pos: Vector2i in positions: + if done.has(pos): + continue + done[pos] = true + var idx: int = pos.y * _mres + pos.x + if _punkt(idx) == int(snap[pos]): + continue # nicht bemalt → Gegenseite bleibt unangetastet + var mirror: Vector2i = SymmetryCore.mirror_cell(sym, pos.x, pos.y, _mres) + if mirror == pos: + continue + var midx: int = mirror.y * _mres + mirror.x + var value: int = _punkt(idx) + if snap.has(mirror) and _punkt(midx) != int(snap[mirror]): + # Beide Seiten bemalt (Pinsel überlappt sein Spiegelbild, z. B. nahe + # der Kartenmitte): der Wert mit dem GRÖSSEREN Anteil des Mal- + # Materials gewinnt. Vorher „näher am Strichpunkt“ — das zog entlang + # der Mittelsenkrechte eine harte gerade Kante durch weiche Verläufe + # (Sly 25.10.). Max ist stetig und symmetrisch. + if _anteil(_punkt(midx), _stroke_material) > _anteil(value, _stroke_material): + value = _punkt(midx) + _setze_punkt(idx, value) + done[mirror] = true + _setze_punkt(midx, value) + + +# ----------------------------------------------------------- Ring-Optik ----- + +func _refresh_ring_mesh() -> void: + if _ring == null: + return + if _ring_radius == brush_radius and _ring_mode == brush_mode: + return + _ring_radius = brush_radius + _ring_mode = brush_mode + var torus := TorusMesh.new() + torus.inner_radius = brush_radius - 0.25 + torus.outer_radius = brush_radius + 0.25 + torus.rings = 48 + torus.ring_segments = 8 + _ring.mesh = torus + var mat := StandardMaterial3D.new() + mat.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED + mat.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA + match brush_mode: + TerrainField.Mode.RAISE: + mat.albedo_color = Color(0.4, 1.0, 0.45, 0.9) + TerrainField.Mode.LOWER: + mat.albedo_color = Color(1.0, 0.45, 0.3, 0.9) + TerrainField.Mode.PAINT: + # Ring in der Farbe des gewählten Materials (Karte t_603ec1a8). + var mc: int = clampi(paint_material, 0, SvmapIO.MATERIAL_IDS.size() - 1) + mat.albedo_color = (terrain_mesh_color(mc) as Color) + mat.albedo_color.a = 0.9 + TerrainField.Mode.FLATTEN: + mat.albedo_color = Color(1.0, 0.85, 0.3, 0.9) + TerrainField.Mode.RAMP: + mat.albedo_color = Color(0.85, 0.5, 1.0, 0.9) + _: + mat.albedo_color = Color(0.4, 0.7, 1.0, 0.9) + mat.emission_enabled = true + mat.emission = (mat.albedo_color as Color) * 0.5 + _ring.material_override = mat + + +## Material-ID → Renderer-Farbe (gleiche Palette wie terrain_mesh.gd). +func terrain_mesh_color(id: int) -> Color: + match id: + 1: + return Color(0.78, 0.70, 0.45) # Sand + 2: + return Color(0.45, 0.44, 0.42) # Fels + _: + return Color(0.30, 0.45, 0.22) # Gras + + +# ------------------------------------------------ Live-Splat-Sub-Rect (Karte +# t_7a0a6b79): Zellrechteck des letzten Mal-Schritts für das Live-Update der +# Splat-Gewichtstextur. Am Dateiende angefügt (Karten-Regel). + +## Zellrect des letzten Mal-Schritts (Pinsel-Fußabdruck ∪ gespiegelte +## Schwesterzellen) — vom Stroke-Code als 3. Parameter an update_terrain +## (view_builder) weitergereicht. +var _splat_rect := Rect2i() + + +## Zellrect des Pinsel-Fußabdrucks (∪ Spiegelzellen): dieselben Region- +## Grenzen wie apply_material_brush, mit dem SYM_REGION_MARGIN-Rand — der +## deckt auch die Kernel-Nachbarschaft der Splat-Ableitung mit ab. +## g und Ergebnis im Material-Raster (_mres) — so rechnet auch die Splat. +func _splat_region(g: Vector2) -> Rect2i: + var rect := _brush_region_r(g, _mres) + var sym := _sym_mode() + if sym == SymmetryCore.Mode.OFF: + return rect + var a := SymmetryCore.mirror_cell(sym, rect.position.x, rect.position.y, _mres) + var b := SymmetryCore.mirror_cell(sym, rect.end.x - 1, rect.end.y - 1, _mres) + return rect.merge(Rect2i(mini(a.x, b.x), mini(a.y, b.y), + absi(a.x - b.x) + 1, absi(a.y - b.y) + 1)) diff --git a/editor/terrain_tool.gd.uid b/editor/terrain_tool.gd.uid new file mode 100644 index 0000000..101a4a2 --- /dev/null +++ b/editor/terrain_tool.gd.uid @@ -0,0 +1 @@ +uid://bo7va0ktrfvrj diff --git a/editor/test_run.gd b/editor/test_run.gd new file mode 100644 index 0000000..1dbf3c2 --- /dev/null +++ b/editor/test_run.gd @@ -0,0 +1,110 @@ +class_name TestRun +extends RefCounted +## ALT (Karte t_1cdc1a72): dieser Client-Start ist seit dem Lauf-Modus im +## Map-Builder selbst NICHT mehr der Standard-Weg — „▶ Karte testen" startet +## jetzt IN DIESER APP (core/editor/playtest/, kein Client-Ordner, kein +## zweiter Prozess, kein VR). Der Rückbau dieser Datei kommt in einer +## späteren Karte; bis dahin bleibt die Export-/Such-Logik als Fallback +## erhalten und getestet (tests/test_testrun.gd). +## +## Ursprünglicher Zweck (Karte t_b84af40f): Export der AKTUELLEN Map nach Temp +## + Start des scopedvr-client als EIGENES Fenster im Testlauf-Modus +## (--testmap ). Der Editor bleibt offen — der Client ist ein eigener +## Prozess; das Spiel beendet sich selbst sauber (ESC = „Zurück zum Editor"). +## +## Client-Suche (erste Treffer-Zeile gewinnt): +## 1. Konfigurationsdatei user://scopedvr_editor.cfg, Abschnitt [test]: +## client_dir="/pfad/zu/scopedvr-client" +## 2. Klon neben dem Editor: /../scopedvr-client +## (erkennbar an project.godot im Ordner). +## +## Godot-Binary für den Start: das Binary, unter dem der Editor selbst läuft +## (OS.get_executable_path — Sly startet den Editor über den Godot-Editor, +## also kann DAS auch den Client starten). Läuft der Editor irgendwann als +## exportierte App, muss [test] godot_path gesetzt werden. +## +## Alles static + testbar ohne UI (tests/test_testrun.gd). + +const CFG_PATH := "user://scopedvr_editor.cfg" +const TESTRUN_DIR := "user://testrun" + + +static func load_cfg() -> ConfigFile: + var cfg := ConfigFile.new() + if FileAccess.file_exists(CFG_PATH): + cfg.load(CFG_PATH) # Fehler → Default-Logik greift weiter unten. + return cfg + + +## Liefert den Client-Projektordner (mit project.godot) oder "". +static func find_client(project_dir: String, cfg: ConfigFile = null) -> String: + var candidates: Array = [] + if cfg != null: + var configured := str(cfg.get_value("test", "client_dir", "")) + # Explizit gesetzter Pfad gewinnt, sobald der ORDNER existiert + # (bewusst ohne project.godot-Check — wer ihn konfiguriert, weiß es besser). + if not configured.is_empty() and DirAccess.dir_exists_absolute(configured): + return configured + var parent := project_dir.simplify_path().get_base_dir() + candidates.append(parent.path_join("scopedvr-client")) + for candidate in candidates: + var dir := str(candidate).simplify_path() + if FileAccess.file_exists(dir.path_join("project.godot")): + return dir + return "" + + +## Godot-Binary zum Starten des Clients (Editor-Binary oder Konfiguration). +static func find_godot(cfg: ConfigFile = null) -> String: + var exe := OS.get_executable_path() + if exe.get_file().to_lower().contains("godot"): + return exe + if cfg != null: + return str(cfg.get_value("test", "godot_path", "")) + return "" + + +## Deterministischer Temp-Pfad aus dem Map-Namen (erneuter Testlauf +## überschreibt die alte Export-Datei — kein Müll-Berg). +static func temp_map_path(doc: Dictionary) -> String: + var raw := str(doc.get("info", {}).get("name", "")).strip_edges() + if raw.is_empty(): + raw = "karte" + var safe := "" + for ch in raw: + var c := ch.to_lower() + if (c >= "a" and c <= "z") or (c >= "0" and c <= "9") or ch == "_" or ch == "-" or ch == " ": + safe += ch + else: + safe += "_" + safe = safe.strip_edges().replace(" ", "_").rstrip("_") + if safe.is_empty(): + safe = "karte" + return TESTRUN_DIR.path_join(safe + ".svmap") + + +## Exportiert das AKTUELLE Dokument (auch ungespeicherte Maps!) nach Temp. +## Rückgabe: {ok, errors, path} — path ist globalisiert (für den Client-Prozess). +static func export_temp_map(doc: Dictionary) -> Dictionary: + var rel := temp_map_path(doc) + DirAccess.make_dir_recursive_absolute(ProjectSettings.globalize_path(TESTRUN_DIR)) + var result := SvmapIO.save_to_file(rel, doc) + result["path"] = ProjectSettings.globalize_path(rel) + return result + + +## Hand-Haltungs-Tool: liegt im Client-Projekt, weil es dessen Rig und Waffen +## direkt benutzt (kein VR, eigenes Fenster). +static func hand_pose_args(client_dir: String) -> PackedStringArray: + return PackedStringArray(["--xr-mode", "off", "--path", client_dir, + "res://tools/hand_pose_tool/hand_pose_tool.tscn"]) + + +## Import-Lauf für den Client, nötig nach neuem Stand (neue Modelle/Skripte). +static func import_args(client_dir: String) -> PackedStringArray: + return PackedStringArray(["--headless", "--path", client_dir, "--import"]) + + +## Argumentliste für den Client-Start (getestet: exakt diese Form). +static func launch_args(client_dir: String, map_path: String) -> PackedStringArray: + return PackedStringArray(["--path", client_dir, "--", "--testmap", map_path, "--mock-master"]) diff --git a/editor/test_run.gd.uid b/editor/test_run.gd.uid new file mode 100644 index 0000000..4ba94ac --- /dev/null +++ b/editor/test_run.gd.uid @@ -0,0 +1 @@ +uid://cd3gmuvpf5ldv diff --git a/editor/updater.gd b/editor/updater.gd new file mode 100644 index 0000000..17a62df --- /dev/null +++ b/editor/updater.gd @@ -0,0 +1,428 @@ +class_name EditorUpdater +extends RefCounted +## Editor-Selbstupdate (Karte t_d95f087a) — Update-Check über Git, Update- +## Ausführung (git pull + Godot-Import-Lauf) und plattformneutrale Restart- +## Auflösung. Alles static und ohne UI (tests/test_updater.gd). +## +## Regeln (Karte + Sly-Ansatz „das Programm sich selbst updaten lassen“): +## - Transport = Git (Klon des Editors), KEIN Binary-Download. +## - Keine Linux-Pfade hartkodiert: git (default "git") und ein optionaler +## Restart-Befehl kommen aus user://scopedvr_editor.cfg, Abschnitt [update] +## (git_command / restart_command). Ohne Konfiguration: unter Linux wird +## erkannt, ob eine systemd-User-Unit „map-editor“ existiert — dann klingelt +## ein Transient-Timer-Kick (systemd-run) den Unit-Neustart (der Kick läuft +## im EIGENEN Scope und überlebt die Stop-Phase). Sonst: der Editor startet +## sich selbst neu (mode "self", self_restart_args). +## - Import-Lauf-Lektion 17.10.: ein --import-Lauf kann mit Exit-Code 0 +## ENDEN und trotzdem Parse-/Script-Fehler enthalten (class_name-Cache). +## Die Ausgabe wird deshalb zusätzlich gescannt — bei Fehlern wird NICHT +## neu gestartet (Abbruch mit Meldung), sonst würde Sly einen Editor ohne +## Map-Ansicht sehen. +## - Offline / Tunnel weg → status "unreachable" → die UI bleibt still +## (kein Banner, kein Fehler-Geballer). +## - Git darf NIE interaktiv werden (Karte t_1457e935): kein GUI-Credential- +## Dialog mitten im Editor! Jeder git-Lauf läuft deshalb mit +## credential.helper=store und abgeschaltetem Askpass (spawn_argv) — +## fehlen die Zugangsdaten, endet der Lauf sofort mit einer klaren +## Fehlermeldung (status "auth_failed"), nie mit einem Prompt oder Hang. +## Hintergrund 17.10.: der systemd-User-Manager exportiert SSH_ASKPASS +## (ksshaskpass) — ein nackter git-Spawn hat damit mitten im Editor das +## Login-Fenster geöffnet. GIT_ASKPASS-/core.askPass-Override schlägt das +## geerbte SSH_ASKPASS (verifiziert am PC, 17.10.). + +const BRANCH := "main" +const UNIT_NAME := "map-editor" + +## Statuszeilen-Text für den auth_failed-Pfad (UI + Tests). +const AUTH_ERROR_TEXT := "Updates nicht prüfbar — Zugangsdaten fehlen (kein Login-Dialog geöffnet)." + + +## Belt-and-braces (Karte t_1457e935): argv für einen NICHT-interaktiven +## git-Lauf bauen. Rückgabe: [0] = Programm, Rest = Argumente. +## - "-c credential.helper=" leert ERST alle geerbten Helfer (sonst öffnet +## z. B. der Windows-Credential-Manager sein GUI-Fenster), danach +## "-c credential.helper=store": ausschließlich der Credential-Store +## (~/.git-credentials per HOME). +## - POSIX: Spawn über /usr/bin/env mit GIT_TERMINAL_PROMPT=0 und +## GIT_ASKPASS=/bin/true — das überstimmt auch ein GEERBTES SSH_ASKPASS +## (KDE/GNOME-Login-Dialog!). HOME kommt aus der eigenen Umgebung +## (OS.get_environment, kein Hardcode) und wird nur mitgegeben, wenn da. +## - Fallback ohne env-Wrapper (env fehlt / kein HOME): trotzdem kein Prompt +## möglich, weil core.askPass=/bin/true das Askpass-Fallback abschaltet. +static func spawn_argv(git_exe: String, project_dir: String, args: PackedStringArray) -> PackedStringArray: + var git_args := PackedStringArray(["-C", project_dir, + "-c", "credential.helper=", "-c", "credential.helper=store"]) + if not OS.has_feature("windows"): + git_args.append_array(PackedStringArray(["-c", "core.askPass=/bin/true"])) + git_args.append_array(args) + var home := OS.get_environment("HOME") + if not OS.has_feature("windows") and FileAccess.file_exists("/usr/bin/env") \ + and not home.is_empty(): + var out := PackedStringArray(["/usr/bin/env", + "GIT_TERMINAL_PROMPT=0", "GIT_ASKPASS=/bin/true", "HOME=" + home]) + out.append(git_exe) + out.append_array(git_args) + return out + var out := PackedStringArray([git_exe]) + out.append_array(git_args) + return out + + +## Ein Git-Kommando im Projektordner ausführen — IMMER nicht-interaktiv +## (spawn_argv). Rückgabe {ok, code, output} (output = stdout+stderr gemischt, +## damit Fehlerklassifikation sehen kann, was git gesagt hat). +static func git_run(git_exe: String, project_dir: String, args: PackedStringArray) -> Dictionary: + var argv := spawn_argv(git_exe, project_dir, args) + var exe := str(argv[0]) + var rest := argv.slice(1) + var output: Array = [] + var code := OS.execute(exe, rest, output, true) + var text := "" + for line in output: + text += str(line) + return {"ok": code == 0, "code": code, "output": text} + + +## Pure Prüfung (testbar): deutet die git-Ausgabe auf FEHLENDE Zugangsdaten? +## (Askpass ist abgeschaltet — „could not read Username“ ist dann der +## dokumentierte Nicht-Interaktiv-Fehler, kein Anlass für einen Retry.) +static func looks_like_auth_error(output: String) -> bool: + return output.contains("could not read Username") \ + or output.contains("Authentication failed") \ + or output.contains("terminal prompts disabled") \ + or output.contains("Unauthorized") + + +## Git-Binary: Konfiguration (user://scopedvr_editor.cfg → [update] +## git_command) gewinnt, sonst das Standard-"git" (PATH). +static func git_exe(cfg: ConfigFile = null) -> String: + if cfg != null: + var custom := str(cfg.get_value("update", "git_command", "")) + if not custom.is_empty(): + return custom + return "git" + + +## Lokaler HEAD-SHA. "" = kein Git-Repository (oder git nicht gefunden). +static func head_sha(git_exe: String, project_dir: String) -> String: + var r := git_run(git_exe, project_dir, PackedStringArray(["rev-parse", "HEAD"])) + if not bool(r["ok"]): + return "" + var text := str(r["output"]).strip_edges() + if text.is_empty(): + return "" + return text.split("\n")[0].strip_edges() + + +## Remote-SHA per git ls-remote (cheap, lesend — keine lokalen Referenzen +## verändert). "" = nicht erreichbar / Branch fehlt / Credentials fehlen. +static func remote_sha(git_exe: String, project_dir: String, branch: String) -> String: + var r := git_run(git_exe, project_dir, PackedStringArray([ + "ls-remote", "origin", "refs/heads/%s" % branch])) + if not bool(r["ok"]): + return "" + var text := str(r["output"]).strip_edges() + if text.is_empty(): + return "" + return sha_aus_ls_remote(text, branch) + + +## Update-Check: lokaler HEAD vs. origin/main. +## Rückgabe {status, local, remote, error} — status: +## "update_available" | "up_to_date" | "unreachable" | "error" | "auth_failed" +## "error" = kein Repo/git nicht da (Editor-spezifisches Problem) +## "unreachable" = Origin nicht erreichbar (offline, Tunnel weg) +## "auth_failed" = Zugangsdaten fehlen → UI zeigt klaren Hinweis, NIEMALS +## einen Login-Prompt (Karte t_1457e935). +static func check_update(git_exe: String, project_dir: String) -> Dictionary: + var local := head_sha(git_exe, project_dir) + if local.is_empty(): + return {"status": "error", "local": "", "remote": "", + "error": "Kein Git-Repository (oder git nicht gefunden)."} + var r := git_run(git_exe, project_dir, PackedStringArray([ + "ls-remote", "origin", "refs/heads/%s" % BRANCH])) + if not bool(r["ok"]): + var text := str(r["output"]) + if looks_like_auth_error(text): + return {"status": "auth_failed", "local": local, "remote": "", + "error": AUTH_ERROR_TEXT} + return {"status": "unreachable", "local": local, "remote": "", + "error": "Origin nicht erreichbar (offline oder Tunnel weg)."} + var text2 := str(r["output"]).strip_edges() + if text2.is_empty(): + return {"status": "unreachable", "local": local, "remote": "", + "error": "Origin nicht erreichbar (offline oder Tunnel weg)."} + var remote := sha_aus_ls_remote(text2, BRANCH) + if remote.is_empty(): + # Kein echter Commit in der Ausgabe (nur Warnungen/leer) — NICHT als + # Update deuten, sonst hängt das Banner endlos (Karte t_50a07d4b-Live-Bug). + return {"status": "unreachable", "local": local, "remote": "", + "error": "Origin lieferte keinen Commit (nur Warnungen)."} + if local == remote: + return {"status": "up_to_date", "local": local, "remote": remote, "error": ""} + # Befund 25.10.: „Update verfügbar“ blieb nach dem Update stehen, weil nur + # HEAD != origin/main geprüft wurde. Steht der Klon auf einem anderen + # Branch oder VOR main (z. B. Feature-Branch), ist das KEIN Update: + # nur melden, wenn der Remote-Commit NICHT schon in HEAD steckt. + if remote_in_head(git_exe, project_dir, remote): + return {"status": "up_to_date", "local": local, "remote": remote, "error": ""} + return {"status": "update_available", "local": local, "remote": remote, "error": ""} + + +## Ist `remote` schon Vorfahre von HEAD (Klon gleich oder VORAUS)? Unbekannter +## Commit (Exit 128) = noch nicht geholt = echtes Update → false. +static func remote_in_head(git_exe: String, project_dir: String, remote: String) -> bool: + var r := git_run(git_exe, project_dir, PackedStringArray([ + "merge-base", "--is-ancestor", remote, "HEAD"])) + return bool(r["ok"]) + + +## Aus der gemischten ls-remote-Ausgabe den Commit für `branch` lesen. +## WARUM: `git_run` mischt stdout+stderr, und der git-Client schreibt bei einer +## HTTP-Umleitung zuerst "warning: Umleitung nach ..." — die alte Fassung nahm +## stumpf die ERSTE Zeile und hielt "warning" für den Ziel-Commit. Ergebnis war +## ein Banner "Update verfügbar: → warning", das nie verschwand, obwohl +## der Pull korrekt lief (live belegt 20.10., Klon stand auf origin/main). +## Regeln: nur Zeilen "\t" zählen, sha = echter Hex-String. +static func sha_aus_ls_remote(text: String, branch: String) -> String: + var ziel := "refs/heads/%s" % branch + var locker := "" + for zeile in text.split("\n"): + var z := zeile.strip_edges() + if z.is_empty(): + continue + var klein := z.to_lower() + if klein.begins_with("warning") or klein.begins_with("hint") \ + or klein.begins_with("fatal") or klein.begins_with("error"): + continue + var teile := z.split("\t") + if teile.size() < 2: + continue + var sha := teile[0].strip_edges() + if not ist_sha(sha): + continue + if teile[1].strip_edges() == ziel: + return sha + if locker.is_empty(): + locker = sha + return locker + + +## Sieht der Text wie ein Git-Objekt-Hash aus (7-40 Hex-Zeichen)? +static func ist_sha(text: String) -> bool: + var t := text.strip_edges() + if t.length() < 7 or t.length() > 40: + return false + for i in t.length(): + var c := t[i] + if c >= "0" and c <= "9": + continue + if c >= "a" and c <= "f": + continue + if c >= "A" and c <= "F": + continue + return false + return true + + +## Kurzer SHA für Anzeigen (7 Zeichen, wie git log --oneline). +static func short_sha(sha: String) -> String: + return sha.substr(0, 7) + + +## Banner-Text (pure, testbar). +static func banner_text(local_sha: String, remote_sha: String) -> String: + return "🔄 Update verfügbar: %s → %s" % [short_sha(local_sha), short_sha(remote_sha)] + + +## Klartext-Status für die Statuszeile (Karte t_f73a1cc5): Wenn lokale +## (meist von Godot erzeugte) Dateien das Update blockieren WÜRDEN, legt der +## Pull sie selbst beiseite — Sly liest diesen Satz statt einer rohen Git- +## Zeile („Bitte verschieben oder entfernen Sie diese…“). +const AUTO_STASH_INFO_TEXT := "Update blockiert: eigene erzeugte Dateien — werden automatisch beiseitegelegt und das Update läuft weiter." +## Ehrliche Meldung, wenn das Zurückholen kollidiert ist (Stash bleibt als +## Sicherung liegen; Godot baut die erzeugten Dateien beim Import neu). +const STASH_KEPT_TEXT := "Erzeugte Dateien bleiben beiseitegelegt — beim nächsten Start neu aufgebaut (Sicherungs-Stash bleibt liegen, nichts verloren)." +## Kennung der eigenen Auto-Stashes (Verwerfen alter Einträge, damit sie +## sich nicht anhäufen). +const AUTO_STASH_MESSAGE := "auto: Selbst-Update" + + +## Update ausführen: git pull --ff-only (Klon zieht nur nach, dreht nichts +## um). Vorher werden lokal Erzeugtes/Geändertes AUTOMATISCH beiseitegelegt +## (Karte t_f73a1cc5): `git stash push -u` erfasst GEÄNDERT **und** UNTRACKED +## Dateien (`--autostash` allein reicht nicht — es lässt untracked liegen; +## genau die haben am 19.10. den Pull blockiert). Nach dem Pull wird das +## Beiseitegelegte zurückgeholt; kollidiert das (Typfall: lose `.import`- +## Datei trifft auf dieselbe Datei neu getrackt), bleibt der Stash als +## Sicherung liegen und die Statuszeile bekommt den Klartext — NIE ein halb +## gepoppter Zustand. Rückgabe {ok, output, errors, info} (info = Klartext +## fürs Statuszeile-Fenster, leer wenn nichts besonderes passiert ist). +static func pull(git_exe: String, project_dir: String) -> Dictionary: + var stash_info := _stash_local_changes(git_exe, project_dir) + # Gezielt origin/main ziehen (nicht den Upstream des aktuellen Branches). + var r := git_run(git_exe, project_dir, PackedStringArray(["pull", "--ff-only", "origin", BRANCH])) + var errors: Array = [] + var text := str(r["output"]).strip_edges() + var info := "" + if not bool(r["ok"]): + # Pull fehlgeschlagen (z. B. offline): Beiseitegelegtes zurückholen, + # damit nichts „verschwindet", wenn der Fehler nur am Netz lag. + if not stash_info.is_empty(): + _restore_stash(git_exe, project_dir) + errors.append("git pull --ff-only fehlgeschlagen (Exit-Code %s):" % str(r["code"])) + if not text.is_empty(): + errors.append(text) + else: + errors.append("(keine Ausgabe — git nicht gefunden oder Verbindung sofort weg)") + if looks_like_auth_error(text): + errors.append("Zugangsdaten fehlen — es wird bewusst KEIN Login-Dialog geöffnet (Credential-Store prüfen).") + else: + if not stash_info.is_empty(): + info = AUTO_STASH_INFO_TEXT + var restored := _restore_stash(git_exe, project_dir) + if not bool(restored["ok"]): + info += "\n" + STASH_KEPT_TEXT + # Der Map-Kern ist ein Submodul: ein Pull allein holt ihn nicht nach. + var sub := git_run(git_exe, project_dir, PackedStringArray(["submodule", "update", "--init", "--recursive"])) + if not bool(sub["ok"]): + errors.append("git submodule update fehlgeschlagen (Exit-Code %s):" % str(sub["code"])) + errors.append(str(sub["output"]).strip_edges()) + if looks_like_auth_error(str(sub["output"])): + errors.append("Zugangsdaten fehlen — es wird bewusst KEIN Login-Dialog geöffnet (Credential-Store prüfen).") + return {"ok": false, "output": str(sub["output"]), "errors": errors, "info": info} + return {"ok": bool(r["ok"]), "output": str(r["output"]), "errors": errors, "info": info} + + +## Lokales Beiseitelegen vor dem Pull (Karte t_f73a1cc5). Rückgabe: Referenz +## auf den eigenen Auto-Stash (z. B. "stash@{0}") oder "" wenn es nichts zu +## beiseitelegen gab / der Stash nicht angelegt werden konnte. +## - Zuerst alte EIGENE Auto-Stashes verwerfen (gleiche Kennung) — sie +## enthalten nur erzeugte Dateien und dürfen sich nicht anhäufen. +## - "No local changes to save" endet ebenfalls mit Exit 0 → NICHT am Text +## matchen, sondern prüfen, ob ein Eintrag mit unserer Kennung entstand. +static func _stash_local_changes(git_exe: String, project_dir: String) -> String: + _drop_auto_stashes(git_exe, project_dir) + var r := git_run(git_exe, project_dir, PackedStringArray([ + "stash", "push", "-u", "-m", AUTO_STASH_MESSAGE])) + if not bool(r["ok"]): + return "" + return _auto_stash_ref(git_exe, project_dir) + + +## Referenz des eigenen Auto-Stashes ("stash@{N}") oder "". +static func _auto_stash_ref(git_exe: String, project_dir: String) -> String: + var r := git_run(git_exe, project_dir, PackedStringArray([ + "stash", "list", "--pretty=format:%gd|%s"])) + if not bool(r["ok"]): + return "" + for line in str(r["output"]).split("\n"): + var parts := str(line).strip_edges().split("|", true, 1) + if parts.size() == 2 and str(parts[1]).contains(AUTO_STASH_MESSAGE): + return str(parts[0]) + return "" + + +## Alle EIGENEN Auto-Stashes (Kennung AUTO_STASH_MESSAGE) verwerfen — von +## hinten, weil die Indizes sich beim Drop verschieben. +static func _drop_auto_stashes(git_exe: String, project_dir: String) -> void: + var r := git_run(git_exe, project_dir, PackedStringArray([ + "stash", "list", "--pretty=format:%gd|%s"])) + if not bool(r["ok"]): + return + var refs: Array = [] + for line in str(r["output"]).split("\n"): + var parts := str(line).strip_edges().split("|", true, 1) + if parts.size() == 2 and str(parts[1]).contains(AUTO_STASH_MESSAGE): + refs.append(str(parts[0])) + refs.reverse() + for ref in refs: + git_run(git_exe, project_dir, PackedStringArray(["stash", "drop", ref])) + + +## Beiseitegelegtes zurückholen. apply (nicht pop), damit die Referenz nicht +## am Stack verschiebt; bei Erfolg wird der Eintrag gedroppt. Kollidiert das +## Zurückholen (Typfall: erzeugte Datei ist inzwischen getrackt), wird mit +## `git reset --hard` der halb gepoppte Zustand weggeräumt und der Stash ALS +## SICHERUNG LIEGEN GELASSEN — kein Datenverlust, Godot erzeugt die Dateien +## beim nächsten Import-Lauf neu. Bewusst KEIN `git clean`: untracked +## Nutzdaten (z. B. Maps/) dürfen nie angefasst werden. +## Rückgabe {ok, kept, output}. +static func _restore_stash(git_exe: String, project_dir: String) -> Dictionary: + var ref := _auto_stash_ref(git_exe, project_dir) + if ref.is_empty(): + return {"ok": true, "kept": false, "output": ""} + var r := git_run(git_exe, project_dir, PackedStringArray(["stash", "apply", ref])) + if bool(r["ok"]): + git_run(git_exe, project_dir, PackedStringArray(["stash", "drop", ref])) + return {"ok": true, "kept": false, "output": str(r["output"])} + git_run(git_exe, project_dir, PackedStringArray(["reset", "--hard"])) + return {"ok": false, "kept": true, "output": str(r["output"])} + + +## Import-Lauf: --headless --path --import. Muss NACH dem +## Pull laufen (neue class_name-Dateien in den Cache), FEHLSCHLAG = Update- +## Abbruch OHNE Neustart (Lektion 17.10.). Rückgabe {ok, errors, output}. +static func run_import(godot_exe: String, project_dir: String) -> Dictionary: + var args := PackedStringArray(["--headless", "--path", project_dir, "--import"]) + var output: Array = [] + var code := OS.execute(godot_exe, args, output, true) + var errors := import_errors(output) + if code != 0: + errors.append("Import-Lauf fehlgeschlagen (Exit-Code %s)" % str(code)) + return {"ok": errors.is_empty(), "errors": errors, "output": _output_text(output)} + + +## Pure Prüfung (testbar): enthält die Import-Ausgabe Parse-/Script-Fehler? +## Exit-Code 0 allein beweist NICHT einen sauberen Import (Lektion 17.10.). +static func import_errors(output: Array) -> Array: + var errors: Array = [] + for line in output: + var text := str(line) + if text.contains("Parse Error") or text.contains("SCRIPT ERROR"): + errors.append(text.strip_edges()) + return errors + + +static func _output_text(output: Array) -> String: + var text := "" + for line in output: + text += str(line) + return text + + +## Restart-Auflösung (plattformneutral, getestet): +## 1. cfg [update] restart_command gesetzt → mode "command", argv = an +## Leerzeichen gesplittet. (z. B. systemd-Unit-Kick, Batch-Skript — jede +## Plattform setzt hier ihren eigenen Befehl ein.) +## 2. Linux + systemd-User-Unit „map-editor“ existiert → Transient-Timer- +## Kick (systemd-run, 3 s): der Kick läuft in einem EIGENEN Scope und +## wird beim Stoppen des Editors (Unit-Neustart) nicht mitgekillt. +## 3. Sonst: mode "self" — der Editor startet sich selbst neu (gleiche +## Godot-Binary, --editor --path ) und beendet sich danach. +static func resolve_restart(cfg: ConfigFile = null) -> Dictionary: + if cfg != null: + var cmd := str(cfg.get_value("update", "restart_command", "")) + if not cmd.is_empty(): + return {"mode": "command", "argv": PackedStringArray(cmd.split(" ", false))} + if OS.has_feature("linux"): + var probe: Array = [] + var code := OS.execute("systemctl", PackedStringArray([ + "--user", "list-unit-files", UNIT_NAME + ".service", "--no-legend"]), + probe, true) + var text := "" + for line in probe: + text += str(line) + if code == 0 and not text.strip_edges().is_empty(): + return {"mode": "command", "argv": PackedStringArray([ + "systemd-run", "--user", "--on-active=3s", + "systemctl", "--user", "restart", UNIT_NAME + ".service"])} + return {"mode": "self", "argv": PackedStringArray()} + + +## Argumente für den Selbst-Restart: dieselbe Godot-Binary startet die +## Map-Editor-APP über deren main.tscn (kein "--editor" — das würde den +## Godot-Editor-Shell öffnen, nicht unsere App; Live-Befund 17.10.: +## Nach dem Selbst-Update ging der Godot-Editor auf statt dem Map Editor). +static func self_restart_args(project_dir: String) -> PackedStringArray: + return PackedStringArray(["--path", project_dir]) \ No newline at end of file diff --git a/editor/updater.gd.uid b/editor/updater.gd.uid new file mode 100644 index 0000000..3edbb95 --- /dev/null +++ b/editor/updater.gd.uid @@ -0,0 +1 @@ +uid://nxdbipruop30 diff --git a/library/svmap_wasser.gd b/library/svmap_wasser.gd index 755f89b..ec5e21f 100644 --- a/library/svmap_wasser.gd +++ b/library/svmap_wasser.gd @@ -34,7 +34,7 @@ extends RefCounted ## byteidentisch, siehe tools/sync_wasser.sh im Map-Editor). const SHADER_KANDIDATEN: Array[String] = [ "res://shaders/wasser.gdshader", # scopedvr-client - "res://src/viewport/wasser.gdshader", # scopedvr-map-editor (Spiegel) + "res://core/viewport/wasser.gdshader", # scopedvr-map-editor (Spiegel) ] ## Plausibilitätsbereich des svmap-Feldes `water_level` (Meter, y-Höhe). diff --git a/scenes/main.tscn b/scenes/main.tscn new file mode 100644 index 0000000..b999e5e --- /dev/null +++ b/scenes/main.tscn @@ -0,0 +1,12 @@ +[gd_scene load_steps=2 format=3] + +[ext_resource type="Script" path="res://core/ui/main.gd" id="1_main"] + +[node name="Main" type="Control"] +layout_mode = 3 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +script = ExtResource("1_main") diff --git a/server/admin_client.gd b/server/admin_client.gd new file mode 100644 index 0000000..ccc41b2 --- /dev/null +++ b/server/admin_client.gd @@ -0,0 +1,112 @@ +class_name AdminClient +extends Node +## Client der Match-Server-Admin-API v1 (Doku: docs/admin-api.md im +## scopedvr-match-server-Repo). Knoten in den Baum hängen, dann +## `var res = await client.call_api("GET", "/status")`. +## +## Antwort: {ok: bool (HTTP 2xx), status: int, body: Dictionary, transport_error: String} +## transport_error ist deutsch und leer, wenn der Server geantwortet hat. +## Das Token geht NUR als Header raus und wird nie geloggt oder zurückgegeben. + +const TIMEOUT_S := 30.0 +const MAX_RESPONSE_BYTES := 8 * 1024 * 1024 + +var host: String = "" +var port: int = 24580 +var tls: bool = false +var token: String = "" + + +## Server-Eintrag aus dem ServerStore übernehmen. +func use(entry: Dictionary) -> void: + host = str(entry.get("host", "")) + port = int(entry.get("port", 24580)) + tls = bool(entry.get("tls", false)) + token = str(entry.get("token", "")) + + +static func base_url(p_host: String, p_port: int, p_tls: bool) -> String: + var h := p_host + if h.contains(":") and not h.begins_with("["): + h = "[%s]" % h # IPv6 + return "%s://%s:%d/api/v1" % ["https" if p_tls else "http", h, p_port] + + +## Prüft die Eingabe für „Server hinzufügen“. Leerer Text = ok. +static func check_address(p_host: String, p_port: int) -> String: + var h := p_host.strip_edges() + if h.is_empty(): + return "Bitte eine Adresse eingeben (IP oder Name)." + if h.contains("/") or h.contains(" ") or h.contains("://"): + return "Nur die Adresse eintragen, ohne http:// und ohne Schrägstriche (z. B. 192.168.1.20)." + if p_port < 1 or p_port > 65535: + return "Der Port muss zwischen 1 und 65535 liegen." + return "" + + +func call_api(method: String, path: String, body: Variant = null, query: Dictionary = {}, raw: PackedByteArray = PackedByteArray()) -> Dictionary: + var err := check_address(host, port) + if err != "": + return _transport_fail(err) + var url := base_url(host, port, tls) + path + if not query.is_empty(): + var parts: PackedStringArray = [] + for k in query.keys(): + parts.append("%s=%s" % [str(k).uri_encode(), str(query[k]).uri_encode()]) + url += "?" + "&".join(parts) + var headers: PackedStringArray = ["Accept: application/json"] + if token != "": + headers.append("Authorization: Bearer " + token) + var payload := raw + if body != null: + payload = JSON.stringify(body).to_utf8_buffer() + headers.append("Content-Type: application/json") + elif not raw.is_empty(): + headers.append("Content-Type: application/octet-stream") + var http := HTTPRequest.new() + http.timeout = TIMEOUT_S + http.body_size_limit = MAX_RESPONSE_BYTES + http.accept_gzip = false + add_child(http) + var m := _method(method) + var rerr := http.request_raw(url, headers, m, payload) + if rerr != OK: + http.queue_free() + return _transport_fail("Anfrage konnte nicht gestartet werden (Fehler %d)." % rerr) + var done: Array = await http.request_completed + http.queue_free() + var result: int = done[0] + if result != HTTPRequest.RESULT_SUCCESS: + return _transport_fail(_result_text(result)) + var code: int = done[1] + var parsed: Variant = JSON.parse_string((done[3] as PackedByteArray).get_string_from_utf8()) + var out: Dictionary = parsed if parsed is Dictionary else {} + return {"ok": code >= 200 and code < 300, "status": code, "body": out, "transport_error": ""} + + +static func _method(m: String) -> int: + match m.to_upper(): + "POST": return HTTPClient.METHOD_POST + "PUT": return HTTPClient.METHOD_PUT + "PATCH": return HTTPClient.METHOD_PATCH + "DELETE": return HTTPClient.METHOD_DELETE + return HTTPClient.METHOD_GET + + +static func _transport_fail(msg: String) -> Dictionary: + return {"ok": false, "status": 0, "body": {}, "transport_error": msg} + + +static func _result_text(result: int) -> String: + match result: + HTTPRequest.RESULT_CANT_CONNECT, HTTPRequest.RESULT_CONNECTION_ERROR: + return "Keine Verbindung zum Server. Läuft er, ist die Admin-API eingeschaltet, und stimmen Adresse und Port?" + HTTPRequest.RESULT_CANT_RESOLVE: + return "Die Adresse wurde nicht gefunden. Tippfehler?" + HTTPRequest.RESULT_TIMEOUT: + return "Der Server antwortet nicht (Zeitüberschreitung)." + HTTPRequest.RESULT_TLS_HANDSHAKE_ERROR: + return "Sichere Verbindung (https) fehlgeschlagen. Gibt der Server wirklich https her?" + HTTPRequest.RESULT_BODY_SIZE_LIMIT_EXCEEDED: + return "Die Antwort des Servers ist zu groß." + return "Verbindungsfehler (Code %d)." % result diff --git a/server/admin_client.gd.uid b/server/admin_client.gd.uid new file mode 100644 index 0000000..5985b57 --- /dev/null +++ b/server/admin_client.gd.uid @@ -0,0 +1 @@ +uid://dd3mjb50m63hm diff --git a/server/admin_texte.gd b/server/admin_texte.gd new file mode 100644 index 0000000..c7adf5b --- /dev/null +++ b/server/admin_texte.gd @@ -0,0 +1,101 @@ +class_name AdminTexte +extends RefCounted +## Verständliche deutsche Texte zu Admin-API-Antworten (kein Fachchinesisch, +## kein rohes JSON) – inklusive der Fehlerliste (422) beim Map-Upload. + +const TUNNEL_HINWEIS := "Tipp: Die Admin-API hört standardmäßig nur auf dem Server selbst (localhost). Von außen erreichst du sie sicher über einen SSH-Tunnel (z. B. ssh -L 24580:127.0.0.1:24580 benutzer@server, dann hier Adresse 127.0.0.1) oder über einen Reverse-Proxy mit https. Die Verbindung selbst ist sonst unverschlüsselt." + +## Erklärungen für häufige Prüfregeln der Map (Server und Editor nutzen dieselben IDs). +const REGEL_HILFE := { + "V1": "Die Datei ist zu groß.", + "V2": "Die Datei ist keine gültige Map-Datei.", + "V3": "Format-Version passt nicht – Editor und Server müssen zusammenpassen.", + "V4": "Ein Pflichtbereich der Map fehlt.", + "V6": "Das Terrain ist zu groß oder zu detailreich.", + "V8": "Zu viele Objekte oder zu viele Polygone – Objekte entfernen.", + "V11": "Pro Team werden mindestens 4 Spawn-Punkte gebraucht (Spawn-Zonen malen).", + "V14": "Die Map ragt über die erlaubte Größe hinaus.", +} + + +## Antwort → Text für den Nutzer ("" bei Erfolg ohne Besonderheiten). +static func erklaere(res: Dictionary) -> String: + if str(res.get("transport_error", "")) != "": + return str(res["transport_error"]) + "\n\n" + TUNNEL_HINWEIS + var status := int(res.get("status", 0)) + var body: Dictionary = res.get("body", {}) + var server_text := str(body.get("error", "")) + match status: + 401: + return "Das Token stimmt nicht (oder fehlt). Es steht beim Server in der Admin-Datei (state_file) – bitte neu eintragen." + 429: + return "Zu viele falsche Token-Versuche. Der Server sperrt dich kurz – bitte in ein paar Minuten erneut versuchen." + 404: + if str(body.get("code", "")) == "not_found": + return "Diese Funktion kennt der Server nicht. Ist er auf dem neuesten Stand?" + 413: + return "Die Datei ist größer als der Server erlaubt. " + server_text + 422: + return erklaere_map_fehler(body) + if server_text != "": + return server_text + if status >= 200 and status < 300: + return "" + return "Unerwartete Antwort vom Server (Status %d)." % status + + +## Fehlerliste einer abgelehnten Map als Aufzählung mit Hilfetexten. +static func erklaere_map_fehler(body: Dictionary) -> String: + var errs: Array = body.get("errors", []) + var out := "Der Server hat die Map abgelehnt" + out += " (%d Problem%s):\n" % [errs.size(), "" if errs.size() == 1 else "e"] if not errs.is_empty() else ".\n" + var hints := {} + for e in errs: + var t := str(e) + out += "• " + t + "\n" + var rule := t.split(":")[0].strip_edges() + for k in REGEL_HILFE.keys(): + if rule == k or rule.begins_with(k) and not rule.substr(k.length(), 1).is_valid_int(): + hints[k] = REGEL_HILFE[k] + if not hints.is_empty(): + out += "\nSo behebst du es:\n" + for k in hints.keys(): + out += "• %s: %s\n" % [k, hints[k]] + return out.strip_edges() + + +## Dateiname für den Upload: a–z, 0–9, _ und -, höchstens 40 Zeichen (wie der Server). +static func slugify(text: String) -> String: + var t := text.strip_edges().to_lower() + for pair in [["ä", "ae"], ["ö", "oe"], ["ü", "ue"], ["ß", "ss"]]: + t = t.replace(pair[0], pair[1]) + var out := "" + for c in t: + out += c if ((c >= "a" and c <= "z") or (c >= "0" and c <= "9") or c == "-") else "_" + while out.contains("__"): + out = out.replace("__", "_") + out = out.lstrip("_-").rstrip("_") + return out.substr(0, 40) + + +## Wirkung einer Einstellung in Klartext. +static func wirkung(effect: String) -> String: + match effect: + "live": return "sofort" + "next_map": return "ab der nächsten Map" + "restart": return "nach Server-Neustart" + return effect + + +static func neustart_zeitueberschreitung(seconds: int) -> String: + return "Der Server ist nach %d s nicht zurück. Er kommt nur von selbst wieder, wenn Docker (Restart-Policy), systemd oder tools/start_server.* ihn gestartet haben." % seconds + + +static func sperrdauer_text(minutes: int) -> String: + if minutes <= 0: + return "dauerhaft" + if minutes < 60: + return "%d Minuten" % minutes + if minutes < 1440: + return "%d Stunden" % (minutes / 60) + return "%d Tage" % (minutes / 1440) diff --git a/server/admin_texte.gd.uid b/server/admin_texte.gd.uid new file mode 100644 index 0000000..88dcc8e --- /dev/null +++ b/server/admin_texte.gd.uid @@ -0,0 +1 @@ +uid://baspf3qu07cwi diff --git a/server/map_push.gd b/server/map_push.gd new file mode 100644 index 0000000..28c0260 --- /dev/null +++ b/server/map_push.gd @@ -0,0 +1,40 @@ +class_name MapPush +extends RefCounted +## „Map auf Server pushen“: aktuelle Map lokal prüfen und signieren +## (SvmapIO.to_signed_text), dann per Admin-API hochladen. UI-frei und testbar. + +## opts: {name: String ("" = aus Map-Name), overwrite: bool, add_to_rotation: bool} +## Rückgabe: {ok, stage ("lokal"|"upload"), text (verständliche Meldung), +## id (Server-Map-ID), exists (bool: 409 – Nachfrage nötig), status} +static func push(client: AdminClient, doc: Dictionary, opts: Dictionary = {}) -> Dictionary: + var signed := SvmapIO.to_signed_text(doc) + if not bool(signed["ok"]): + var lines := "Die Map ist noch nicht gültig und wurde nicht hochgeladen:\n" + for e in signed["errors"]: + lines += "• %s\n" % str(e) + return {"ok": false, "stage": "lokal", "text": lines.strip_edges(), "id": "", "exists": false, "status": 0} + var info: Dictionary = doc.get("info", {}) + var slug := str(opts.get("name", "")).strip_edges() + if slug == "": + slug = AdminTexte.slugify(str(info.get("name", ""))) + if slug == "": + return {"ok": false, "stage": "lokal", "text": "Die Map braucht einen Namen (Tab „Map“), bevor sie hochgeladen werden kann.", "id": "", "exists": false, "status": 0} + var bytes: PackedByteArray = str(signed["text"]).to_utf8_buffer() + var query := {"name": slug} + if bool(opts.get("overwrite", false)): + query["overwrite"] = "1" + if bool(opts.get("add_to_rotation", false)): + query["add_to_rotation"] = "1" + var res: Dictionary = await client.call_api("POST", "/maps", null, query, bytes) + var body: Dictionary = res.get("body", {}) + if bool(res.get("ok", false)): + var msg := "Hochgeladen als „%s“ (%s, %d Objekte)." % [str(body.get("name", slug)), _groesse(bytes.size()), int(body.get("objects", 0))] + if bool(body.get("replaced", false)): + msg += " Die vorherige Version wurde ersetzt." + return {"ok": true, "stage": "upload", "text": msg, "id": str(body.get("id", "")), "exists": false, "status": 200} + var exists := int(res.get("status", 0)) == 409 and str(body.get("code", "")) == "exists" + return {"ok": false, "stage": "upload", "text": AdminTexte.erklaere(res), "id": "", "exists": exists, "status": int(res.get("status", 0))} + + +static func _groesse(n: int) -> String: + return "%.1f MB" % (n / 1048576.0) if n >= 1048576 else "%d KB" % maxi(1, n / 1024) diff --git a/server/map_push.gd.uid b/server/map_push.gd.uid new file mode 100644 index 0000000..f15652d --- /dev/null +++ b/server/map_push.gd.uid @@ -0,0 +1 @@ +uid://cmuts8c8t2d5i diff --git a/server/server_store.gd b/server/server_store.gd new file mode 100644 index 0000000..06eb350 --- /dev/null +++ b/server/server_store.gd @@ -0,0 +1,114 @@ +class_name ServerStore +extends RefCounted +## Gespeicherte Admin-Server des Editors (Name, Adresse, Port, https, Token). +## +## Das Token liegt NICHT im Klartext auf der Platte: die Datei ist mit einem +## aus Rechner-ID + Nutzerordner abgeleiteten Schlüssel verschlüsselt. Das hält +## Zufallsleser, Cloud-Sync und Screenshots von Ordnern raus – gegen Schadsoftware +## mit Zugriff auf deinen Benutzer schützt es nicht (dafür gibt es keine +## plattformübergreifende Lösung ohne Passwort-Manager). Tokens werden nie geloggt. + +const DEFAULT_PATH := "user://admin_server.dat" +const DEFAULT_PORT := 24580 +const MAX_SERVERS := 50 + +var path: String = DEFAULT_PATH +var servers: Array = [] # [{id, name, host, port, tls, token}] +var last_error: String = "" + + +func _init(p: String = DEFAULT_PATH) -> void: + path = p + + +func _key() -> String: + return ("svr-editor-admin|%s|%s" % [OS.get_unique_id(), OS.get_user_data_dir()]).sha256_text() + + +func load_store() -> void: + servers.clear() + last_error = "" + if not FileAccess.file_exists(path): + return + var fa := FileAccess.open_encrypted_with_pass(path, FileAccess.READ, _key()) + if fa == null: + last_error = "Gespeicherte Server konnten nicht gelesen werden (andere Installation oder beschädigte Datei)." + return + var parsed: Variant = JSON.parse_string(fa.get_as_text()) + if parsed is Array: + for e in parsed: + if e is Dictionary and str(e.get("host", "")) != "": + servers.append({ + "id": str(e.get("id", _new_id())), "name": str(e.get("name", e["host"])), + "host": str(e["host"]), "port": int(e.get("port", DEFAULT_PORT)), + "tls": bool(e.get("tls", false)), "token": str(e.get("token", ""))}) + + +func save_store() -> bool: + var fa := FileAccess.open_encrypted_with_pass(path, FileAccess.WRITE, _key()) + if fa == null: + last_error = "Server-Liste konnte nicht gespeichert werden (Fehler %d)." % FileAccess.get_open_error() + return false + fa.store_string(JSON.stringify(servers)) + return true + + +## Neuer oder aktualisierter Eintrag. Rückgabe: id ("" = Eingabe ungültig → last_error). +func upsert(entry: Dictionary) -> String: + var err := AdminClient.check_address(str(entry.get("host", "")), int(entry.get("port", 0))) + if err != "": + last_error = err + return "" + var e := { + "id": str(entry.get("id", "")), "name": str(entry.get("name", "")).strip_edges(), + "host": str(entry["host"]).strip_edges(), "port": int(entry["port"]), + "tls": bool(entry.get("tls", false)), "token": str(entry.get("token", "")).strip_edges()} + if e["name"] == "": + e["name"] = "%s:%d" % [e["host"], e["port"]] + if e["id"] == "": + if servers.size() >= MAX_SERVERS: + last_error = "Maximal %d gespeicherte Server." % MAX_SERVERS + return "" + e["id"] = _new_id() + servers.append(e) + else: + var i := index_of(e["id"]) + if i < 0: + servers.append(e) + else: + servers[i] = e + save_store() + return e["id"] + + +func remove(id: String) -> bool: + var i := index_of(id) + if i < 0: + return false + servers.remove_at(i) + save_store() + return true + + +func index_of(id: String) -> int: + for i in servers.size(): + if str(servers[i]["id"]) == id: + return i + return -1 + + +func get_entry(id: String) -> Dictionary: + var i := index_of(id) + return servers[i].duplicate() if i >= 0 else {} + + +## Für Anzeige/Logs: nie das Token. +func public_view(id: String) -> Dictionary: + var e := get_entry(id) + e.erase("token") + e["has_token"] = str(get_entry(id).get("token", "")) != "" + return e + + +static func _new_id() -> String: + return "s%d_%d" % [int(Time.get_unix_time_from_system()), randi() % 100000] diff --git a/server/server_store.gd.uid b/server/server_store.gd.uid new file mode 100644 index 0000000..2a1a4cc --- /dev/null +++ b/server/server_store.gd.uid @@ -0,0 +1 @@ +uid://dkwfi2v8nu03w diff --git a/shaders/selection_outline.gdshader b/shaders/selection_outline.gdshader new file mode 100644 index 0000000..60d7f07 --- /dev/null +++ b/shaders/selection_outline.gdshader @@ -0,0 +1,40 @@ +shader_type spatial; +render_mode unshaded, cull_front, shadows_disabled, blend_mix; + +// Außenhüllen-Kontur (U6, Karte t_639135dd): dezente Auswahl-Markierung +// statt Vollflächen-Orange. Das Grundmaterial (inkl. Textur) bleibt komplett +// sichtbar — die Kontur lebt als eigene Hülle um das Modell: +// +// VERTEX += NORMAL * breite_m bläht das Volumen entlang der Normalen auf, +// cull_front rendert nur die RÜCKseiten der Hülle. Sichtbar bleibt darum +// genau der schmale Saum, der außerhalb der Silhouette liegt (der Rest +// wird vom Objekt selbst per Tiefentest verdeckt) — die klassische +// Inverted-Hull-Outline-Technik. +// +// Farbton, Deckkraft und Breite kommen aus dem Theme (theme/editor_theme.tres, +// Abschnitt "Editor") — der Shader selbst kennt keine festen Farben. +// +// Gestrichelte Variante (Spiegel-Zwilling): streifen_hz > 0 unterteilt die +// Kontur in Bänder entlang der Welthöhe — dünn + gestrichelt statt voll. + +uniform vec4 linien_farbe : source_color = vec4(1.0, 0.6, 0.15, 0.95); +uniform float breite_m : hint_range(0.0, 1.0) = 0.08; +uniform float streifen_hz : hint_range(0.0, 40.0) = 0.0; + +varying vec3 welt_pos; + +void vertex() { + VERTEX += NORMAL * breite_m; + welt_pos = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xyz; +} + +void fragment() { + if (streifen_hz > 0.5) { + // Gestrichelt (Zwilling): Bänder entlang der Welthöhe, ~55 % Strich. + if (fract(welt_pos.y * streifen_hz) > 0.55) { + discard; + } + } + ALBEDO = linien_farbe.rgb; + ALPHA = linien_farbe.a; +} diff --git a/shaders/selection_outline.gdshader.uid b/shaders/selection_outline.gdshader.uid new file mode 100644 index 0000000..ae9b0ac --- /dev/null +++ b/shaders/selection_outline.gdshader.uid @@ -0,0 +1 @@ +uid://b1wjgw8l4w77m diff --git a/svmap/group_state.gd b/svmap/group_state.gd index e6c2d01..0eaee95 100644 --- a/svmap/group_state.gd +++ b/svmap/group_state.gd @@ -1,7 +1,7 @@ extends RefCounted class_name GroupState ## Gruppen-ZUSTAND über das Objekt-Feld "group" hinaus (Karte t_a4bf9b8c, U3 — -## Gruppen im Szenen-Baum). GroupOps (src/editor/group_ops.gd) besitzt die +## Gruppen im Szenen-Baum). GroupOps (core/editor/group_ops.gd) besitzt die ## Zugehörigkeit (Optionales Objekt-Feld "group", int ≥ 0) — diese Datei ergänzt ## NUR ADDITIV, was der Baum additionally braucht: ## diff --git a/theme/editor_theme.tres b/theme/editor_theme.tres new file mode 100644 index 0000000..569c234 --- /dev/null +++ b/theme/editor_theme.tres @@ -0,0 +1,281 @@ +[gd_resource type="Theme" load_steps=23 format=3] + +[sub_resource type="StyleBoxFlat" id="panel"] +bg_color = Color(0.12, 0.14, 0.17, 1) +border_color = Color(0.3, 0.36, 0.42, 1) +border_width_left = 1 +border_width_top = 1 +border_width_right = 1 +border_width_bottom = 1 +corner_radius_top_left = 4 +corner_radius_top_right = 4 +corner_radius_bottom_right = 4 +corner_radius_bottom_left = 4 + +[sub_resource type="StyleBoxFlat" id="tab_sel"] +bg_color = Color(0.24, 0.3, 0.36, 1) +border_color = Color(0.35, 0.55, 0.7, 1) +border_width_top = 2 +corner_radius_top_left = 4 +corner_radius_top_right = 4 +content_margin_left = 10.0 +content_margin_right = 10.0 +content_margin_top = 4.0 +content_margin_bottom = 4.0 + +[sub_resource type="StyleBoxFlat" id="tab_hover"] +bg_color = Color(0.19, 0.24, 0.29, 1) +border_color = Color(0.35, 0.55, 0.7, 0.4) +border_width_top = 2 +corner_radius_top_left = 4 +corner_radius_top_right = 4 +content_margin_left = 10.0 +content_margin_right = 10.0 +content_margin_top = 4.0 +content_margin_bottom = 4.0 + +[sub_resource type="StyleBoxFlat" id="tab_unsel"] +bg_color = Color(0.15, 0.18, 0.21, 1) +corner_radius_top_left = 4 +corner_radius_top_right = 4 +content_margin_left = 10.0 +content_margin_right = 10.0 +content_margin_top = 4.0 +content_margin_bottom = 4.0 + +[sub_resource type="StyleBoxFlat" id="tabbar"] +bg_color = Color(0.1, 0.12, 0.14, 1) + +[sub_resource type="StyleBoxFlat" id="btn_normal"] +bg_color = Color(0.19, 0.23, 0.27, 1) +border_color = Color(0.3, 0.36, 0.42, 1) +border_width_left = 1 +border_width_top = 1 +border_width_right = 1 +border_width_bottom = 1 +corner_radius_top_left = 4 +corner_radius_top_right = 4 +corner_radius_bottom_right = 4 +corner_radius_bottom_left = 4 +content_margin_left = 8.0 +content_margin_right = 8.0 + +[sub_resource type="StyleBoxFlat" id="btn_hover"] +bg_color = Color(0.25, 0.31, 0.37, 1) +border_color = Color(0.35, 0.55, 0.7, 1) +border_width_left = 1 +border_width_top = 1 +border_width_right = 1 +border_width_bottom = 1 +corner_radius_top_left = 4 +corner_radius_top_right = 4 +corner_radius_bottom_right = 4 +corner_radius_bottom_left = 4 +content_margin_left = 8.0 +content_margin_right = 8.0 + +[sub_resource type="StyleBoxFlat" id="btn_pressed"] +bg_color = Color(0.14, 0.19, 0.24, 1) +border_color = Color(0.35, 0.55, 0.7, 1) +border_width_left = 1 +border_width_top = 1 +border_width_right = 1 +border_width_bottom = 1 +corner_radius_top_left = 4 +corner_radius_top_right = 4 +corner_radius_bottom_right = 4 +corner_radius_bottom_left = 4 +content_margin_left = 8.0 +content_margin_right = 8.0 + +[sub_resource type="StyleBoxFlat" id="btn_disabled"] +bg_color = Color(0.16, 0.17, 0.19, 1) +border_color = Color(0.24, 0.26, 0.29, 1) +border_width_left = 1 +border_width_top = 1 +border_width_right = 1 +border_width_bottom = 1 +corner_radius_top_left = 4 +corner_radius_top_right = 4 +corner_radius_bottom_right = 4 +corner_radius_bottom_left = 4 +content_margin_left = 8.0 +content_margin_right = 8.0 + +[sub_resource type="StyleBoxFlat" id="btn_focus"] +draw_center = false +border_color = Color(0.55, 0.8, 1, 0.85) +border_width_left = 1 +border_width_top = 1 +border_width_right = 1 +border_width_bottom = 1 +corner_radius_top_left = 4 +corner_radius_top_right = 4 +corner_radius_bottom_right = 4 +corner_radius_bottom_left = 4 + +[sub_resource type="StyleBoxFlat" id="line_normal"] +bg_color = Color(0.09, 0.11, 0.13, 1) +border_color = Color(0.3, 0.36, 0.42, 1) +border_width_left = 1 +border_width_top = 1 +border_width_right = 1 +border_width_bottom = 1 +corner_radius_top_left = 4 +corner_radius_top_right = 4 +corner_radius_bottom_right = 4 +corner_radius_bottom_left = 4 +content_margin_left = 8.0 +content_margin_right = 8.0 + +[sub_resource type="StyleBoxFlat" id="line_focus"] +bg_color = Color(0.1, 0.13, 0.15, 1) +border_color = Color(0.55, 0.8, 1, 1) +border_width_left = 1 +border_width_top = 1 +border_width_right = 1 +border_width_bottom = 1 +corner_radius_top_left = 4 +corner_radius_top_right = 4 +corner_radius_bottom_right = 4 +corner_radius_bottom_left = 4 +content_margin_left = 8.0 +content_margin_right = 8.0 + +[sub_resource type="StyleBoxFlat" id="tooltip"] +bg_color = Color(0.08, 0.09, 0.11, 0.96) +border_color = Color(0.35, 0.55, 0.7, 1) +border_width_left = 1 +border_width_top = 1 +border_width_right = 1 +border_width_bottom = 1 +corner_radius_top_left = 4 +corner_radius_top_right = 4 +corner_radius_bottom_right = 4 +corner_radius_bottom_left = 4 +content_margin_left = 6.0 +content_margin_right = 6.0 +content_margin_top = 4.0 +content_margin_bottom = 4.0 + +[sub_resource type="StyleBoxFlat" id="split_grab"] +bg_color = Color(0.22, 0.27, 0.32, 1) +corner_radius_top_left = 2 +corner_radius_top_right = 2 +corner_radius_bottom_right = 2 +corner_radius_bottom_left = 2 + +[sub_resource type="StyleBoxFlat" id="split_grab_hover"] +bg_color = Color(0.35, 0.55, 0.7, 0.6) +corner_radius_top_left = 2 +corner_radius_top_right = 2 +corner_radius_bottom_right = 2 +corner_radius_bottom_left = 2 + +[sub_resource type="StyleBoxFlat" id="scroll_bg"] +bg_color = Color(0.1, 0.12, 0.14, 0.4) + +[sub_resource type="StyleBoxFlat" id="scroll_grab"] +bg_color = Color(0.42, 0.49, 0.56, 0.6) +corner_radius_top_left = 3 +corner_radius_top_right = 3 +corner_radius_bottom_right = 3 +corner_radius_bottom_left = 3 + +[sub_resource type="StyleBoxFlat" id="scroll_grab_hover"] +bg_color = Color(0.55, 0.63, 0.7, 0.8) +corner_radius_top_left = 3 +corner_radius_top_right = 3 +corner_radius_bottom_right = 3 +corner_radius_bottom_left = 3 + +[sub_resource type="StyleBoxFlat" id="scroll_grab_press"] +bg_color = Color(0.55, 0.8, 1, 0.85) +corner_radius_top_left = 3 +corner_radius_top_right = 3 +corner_radius_bottom_right = 3 +corner_radius_bottom_left = 3 + +[sub_resource type="StyleBoxFlat" id="progress_bg"] +bg_color = Color(0.09, 0.11, 0.13, 1) +border_color = Color(0.3, 0.36, 0.42, 1) +border_width_left = 1 +border_width_top = 1 +border_width_right = 1 +border_width_bottom = 1 +corner_radius_top_left = 4 +corner_radius_top_right = 4 +corner_radius_bottom_right = 4 +corner_radius_bottom_left = 4 + +[sub_resource type="StyleBoxFlat" id="progress_fill"] +bg_color = Color(0.55, 0.8, 1, 1) +corner_radius_top_left = 4 +corner_radius_top_right = 4 +corner_radius_bottom_right = 4 +corner_radius_bottom_left = 4 + +[sub_resource type="StyleBoxEmpty" id="scroll_empty"] + +[resource] +default_font_size = 16 +Editor/colors/accent = Color(0.55, 0.8, 1, 1) +Editor/colors/status_ok = Color(0.75, 0.95, 0.75, 1) +Editor/colors/status_error = Color(1, 0.6, 0.5, 1) +Editor/colors/muted = Color(1, 1, 1, 0.74) +Editor/colors/field = Color(1, 1, 1, 0.9) +Editor/colors/title = Color(1, 1, 1, 0.82) +Editor/colors/warning = Color(1, 0.62, 0.3, 1) +Editor/colors/badge_outline = Color(0, 0, 0, 1) +Editor/colors/help_bg = Color(0.09, 0.11, 0.13, 0.97) +Editor/colors/help_border = Color(0.35, 0.55, 0.7, 1) +Editor/colors/update_bg = Color(0.36, 0.25, 0.06, 0.97) +Editor/colors/update_border = Color(0.95, 0.72, 0.15, 1) +Editor/colors/rubber_fill = Color(0.45, 0.8, 1, 0.16) +Editor/colors/rubber_line = Color(0.45, 0.8, 1, 0.9) +Editor/colors/selection_outline = Color(1, 0.6, 0.15, 0.95) +Editor/colors/selection_outline_hover = Color(1, 0.6, 0.15, 0.45) +Editor/colors/selection_outline_partner = Color(1, 0.78, 0.4, 0.85) +Editor/constants/selection_outline_width_mm = 80 +Editor/constants/selection_outline_width_hover_mm = 45 +Editor/constants/selection_outline_width_partner_mm = 45 +PanelContainer/styles/panel = SubResource("panel") +TabContainer/styles/panel = SubResource("panel") +TabContainer/styles/tab_selected = SubResource("tab_sel") +TabContainer/styles/tab_hovered = SubResource("tab_hover") +TabContainer/styles/tab_unselected = SubResource("tab_unsel") +TabContainer/styles/tabbar_background = SubResource("tabbar") +TabContainer/colors/font_selected_color = Color(1, 1, 1, 1) +TabContainer/colors/font_unselected_color = Color(1, 1, 1, 0.88) +Button/styles/normal = SubResource("btn_normal") +Button/styles/hover = SubResource("btn_hover") +Button/styles/pressed = SubResource("btn_pressed") +Button/styles/disabled = SubResource("btn_disabled") +Button/styles/focus = SubResource("btn_focus") +Button/colors/font_hover_color = Color(1, 1, 1, 1) +Button/colors/font_pressed_color = Color(0.8, 0.9, 1, 1) +Button/colors/font_disabled_color = Color(1, 1, 1, 0.5) +LineEdit/styles/normal = SubResource("line_normal") +LineEdit/styles/focus = SubResource("line_focus") +LineEdit/colors/font_color = Color(1, 1, 1, 1) +LineEdit/colors/font_placeholder_color = Color(1, 1, 1, 0.58) +HSplitContainer/styles/grabber_area = SubResource("split_grab") +HSplitContainer/styles/grabber_area_highlight = SubResource("split_grab_hover") +VSplitContainer/styles/grabber_area = SubResource("split_grab") +VSplitContainer/styles/grabber_area_highlight = SubResource("split_grab_hover") +ScrollContainer/styles/panel = SubResource("scroll_empty") +VScrollBar/styles/scroll = SubResource("scroll_bg") +VScrollBar/styles/grabber = SubResource("scroll_grab") +VScrollBar/styles/grabber_highlight = SubResource("scroll_grab_hover") +VScrollBar/styles/grabber_pressed = SubResource("scroll_grab_press") +HScrollBar/styles/scroll = SubResource("scroll_bg") +HScrollBar/styles/grabber = SubResource("scroll_grab") +HScrollBar/styles/grabber_highlight = SubResource("scroll_grab_hover") +HScrollBar/styles/grabber_pressed = SubResource("scroll_grab_press") +ProgressBar/styles/background = SubResource("progress_bg") +ProgressBar/styles/fill = SubResource("progress_fill") +ProgressBar/colors/font_color = Color(1, 1, 1, 1) +HSlider/styles/grabber_area = SubResource("progress_fill") +HSlider/styles/grabber_area_highlight = SubResource("progress_fill") +TooltipPanel/styles/panel = SubResource("tooltip") +TooltipLabel/colors/font_color = Color(1, 1, 1, 1) diff --git a/thumbs/acacia_003.png b/thumbs/acacia_003.png new file mode 100644 index 0000000000000000000000000000000000000000..3875411311adf6fcaf63701bf2a365ec50430cd4 GIT binary patch literal 1891 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 literal 0 HcmV?d00001 diff --git a/thumbs/acacia_005.png.import b/thumbs/acacia_005.png.import new file mode 100644 index 0000000..94bf388 --- /dev/null +++ b/thumbs/acacia_005.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dpng4qbmhgaxn" +path="res://.godot/imported/acacia_005.png-f44002b723f89b248078d6195e099cbf.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/acacia_005.png" +dest_files=["res://.godot/imported/acacia_005.png-f44002b723f89b248078d6195e099cbf.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/acacia_006.png b/thumbs/acacia_006.png new file mode 100644 index 0000000000000000000000000000000000000000..8ac1e72719effeada2ec52c113739ba66cb71a49 GIT binary patch literal 2585 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 ZYS?_tb$>M<>2JLS?5rFu$>!ck{{xNiJ5m4u literal 0 HcmV?d00001 diff --git a/thumbs/air_defense_002.png.import b/thumbs/air_defense_002.png.import new file mode 100644 index 0000000..b322dec --- /dev/null +++ b/thumbs/air_defense_002.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dmkfqnti7k861" +path="res://.godot/imported/air_defense_002.png-2f8aa6e0069f96ad4eeacf95eb7535f5.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/air_defense_002.png" +dest_files=["res://.godot/imported/air_defense_002.png-2f8aa6e0069f96ad4eeacf95eb7535f5.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/air_defense_platform_001.png b/thumbs/air_defense_platform_001.png new file mode 100644 index 0000000000000000000000000000000000000000..a676ea6e55d383c65f52e5bb6b4f5d3c576c1662 GIT binary patch literal 1854 zcmd5-{Xf$Q9RIGdY&NT8=G1V~EZRJE<1FN8oGe7WIu9Evlc#m6O=Cvx#5oUzCXJK1 zQx^^~Y|?U_$0q59m`!(BIyU?N+WO72fWSk#(PD0hZJ^WHBf$a~^e^@S^espW$>#~y${#I5 zVFb1Ui0%1S?)1}qWOFmW^E^|(n7{ft-FKwSF-BT3u3$>b%G{pSwyz&I^|rNow9E|( z3kIfZfro*htm-X#WZiA~F!NnT9?tu?jQ^3*rgv-qKn_P9_D^CMDwz9I)xF$=P+=oG zZTE1UO|HD$FDky#)ovfoeyr_{xhWHK1l75wOqfjbLuAbvMtqFl?n)%(4QmQ4tIIJE zb8*x_iFQ(kzwpXaNgz($=aEI!{0P*eJv2C3AQ>T28Y1R+l5q8K|_Rdv) zptEMLZC@DhQHFxPhg9Ux!|;c*=zf;dv*nKc&P;>)&Z<8S!@GU$=9k-wQbuEndtO8XJkq%>BR%gWnsdDDAz=Kn z;`6A*qGBC4AF~cp9MnZSJ8l$J_c-q9MRl+#_|+c_C~7!dfHHWCCH@XxmYLAtVQ6y) z_N`+xWsQUR-*|b>4kG=l-!)F${;U*=E5nbZV!78X$ps)r(~wE5KIYQTo$NJ-`c9)> zGt!KKd)%wS9jUUWtM(@+a!n_P6XwsyCgm~X87^Uf(*ja|#A&@{-EDqSU(4g?1iB~g%NDV@m|y*OQyFGj?rRKK zl47Qe0(YkUmVH+x1*UGh2VGlV-HTFDU;q@#?K2DltCkys-V?R4k!VP3!kbBcb8Ur@ z4?1=m=f#L8p--scK<&7+g<^|>^p-QjG|jAq-tp6QC&I%I3C<+Wfh?D>S~P9qtBWrJ z3F1}9KO}jd9$zpTAl*k zIZ7p!C*FWZ_ZV6wquFx?eDNZL6oO99Fz#mRY_>6 z_sNqc0QGJMyLZURRb*XG%IGs3Ddncu6|3FPy8E-)uCECqInM4|I%|GDl3Gp0-2kSB zmup&6T!H;@7}~otF=^@SzAa>~h3C%kc>0ie8R@U=);8lb0iWL#T0 zwt1Cn+b@wYM=9%tX@3&MjeL(^oC3QFUX}iK<{5d zX~|8Out6z)k;wTe67KfOOGqji<_xVE;y%a^%0h(F`CGNb4AG6n+S*_|{2%|LdN4nU8)b9vVey85~q6$(6&&5%TFt0zjbfdZ<0DmzcWzL2V@2+oYU4(KnD ktfdaOSdeDFWk+kc|8^H-CH1n=?MpMH`u8K~m z2%FBlqIbW+vIq8^XAE|~GYai8BdGDu&Z40I2o$sTQw61LXIuali(~ee1+?kHjd2{O zhS^=@qp7B;67q|jOu78V2IxZ~H^tP-H!W@peUBAu>!T-*kDek4ML)Fa^PM8TV)2Bg zraVt4kQfDC*Mj@8unQfKQ6}8lK+o6e6Dqo6#@7m&)4om5N3NPh@m$kBBp{}^|7dG} zlrSeVD0d|b(h5<_Ccy?56x>O9>?QpkwDmA)F+Kn5dzr6vNEY1_f>hkIcd{yBqmbxdj0_|zx1-}<&{-AshLJ;{VlR|U&y`*r|(?D=i}hsoiWIuV9fBD~ad!R3QPwDiJ- zoTR_!x@b#@EX0iD#+T#r_^Gp z$6IXn8*n~{2&ENpH*Xwii-Hg8hUqjyCxfKn)ou;Obc?Jz(VN3;E2;)^&k;#}O;*{} zd?TpNiQ3z(Q%UM6n1E^CPWF_Odo;?xkOsTzLWyb6? zA>>%pIel?Okm!09xz;zmsi7vJQj9Lnt=a{PlZOysm35)C<7RMk$nf@2BLmQSVo8C4KLCqv^P?qDJ!YTRl~{eHyroL*k1K3!xk= z#$Gli*_ZXf{nD*9Ojx>5+^`VHs3`dCV7C9jdgaWVzV0QBn_0V>{mxCfoyr>f{0Qyk!x}Jf z2p;uTb~h>&>0D?%RK8#nXnnjS=$G@oBfCb>oqqY6r6<mli^Xp~yZJIT^ zAbi^9pefiQ<|=Dq^#DYv*-QT0_Mo4Gp#85UR7>jcVaHGc-zWl}u^aKz;hG2YSvR+C zxdsE5xXVsEHzPUt?by5vr__j|PGQo*g8I1^`Uh9q%c7NzQe$akpNWbS+YH)X;`&`p zf76OtXQ@&U=j9oaSW-L z^Y-r9V4*^WV;|GSCz_{LYP&3XnObyg=BCNZ`(%GtTc;lHt6ZVBcIKITX@>+@gLzV3 zP7qzciEYQH>Url2Bj?;dbp5X`x6ZXwucEk}PJgRrc%;wj;Kw*2nBj>CgC!N14+8B( zKUQ-HFJ!REGMin;pQt3#;J&;!cz?TrAlHG#Rf`{f7f^FztO&`!@>lMViv~mgtJ1fO zE4D_hyYD=MgY`k6_LL7m?T&&DXUvNK$+34aSy;lb!RJid*Ut$)i+4t8 zFiDj1CqzH9^LdsRDSdjI+rIsLOv`7OKC0jFjUiY^nqO(EPeP^U-S6M#2uuAk*U8>u zdm_~A@plG2=cQ4sAFSCJ3LX_Q9N4X2J@4ImhGh|U^N$~U#;0WA$eWn*_+X#HooU@U zHXP~ybh_5pE;9K3)7-j2dZuMg&N~K%ERMr7a~DOtjZuHz@?cv`2;c5+Lg|hS2MXW* z2s-wfeKGS3yIZP$C~S#e<+JGp4xh{=d%AXwu0(|2fuCi zI{)dN`u_Rf6pA_pVy?I5vNO#1zEUAMo^{H%Q_T6VEmoVS)a@^?7d@KA{Pgc%!`?Sp zhDHtS<=iXGn3(hPTZQKNy?r)0am{*rR)!s$3ssz+{oU0!k#SGW->er_ap&IXJ`uCN zwmPJG`IOA`7>0g%Tba|Dx1FrI#PhdVPuuFm*^+o|;(|g(o62uBI`!&i=GV)Aaw_c* zleXFGBmJ03qJ8%D=NrEkmOpsAbkla@j>`>p4R!iVZF?(IE?GB!VJz7_+53U>#XZe? z9Yq|j+dWtiB)ehWOc96KPnT|4ZrrLC$dJ2dpKXp1a;i%BaD4Bc0L;YJXUFjAG6Pq` zTqcF(3@6kXe=#Us#5wklb=A_w#?NZb{a>_#*+We@BIZQm_YWfGMuz*_ zA9KHA`1bvOt>c&AmmDuO?uR%?JJ?A&e%$c+kU&qk$kW@8jQbvc(fR#vaVOJFpyYvP zx7Y4FZ9lzlLgyzN9h>M|&%(^=-hKZa<6JMjK>id%+u5&Ar81T=Wv7;&-Sc{0kEdGJ z;*=lZM_+tnIPEQY{`IVXPncU6MatRZe>4h)GPIWPOtreI#_#$yBCduxU{6t>c}IV{-2P-YJ~u~TS;64x>gTe~DWM4fluFi( literal 0 HcmV?d00001 diff --git a/thumbs/antenna_001.png.import b/thumbs/antenna_001.png.import new file mode 100644 index 0000000..c8f376b --- /dev/null +++ b/thumbs/antenna_001.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cu2km1kitwe32" +path="res://.godot/imported/antenna_001.png-384a2221c556e630d3471ecce14aaa32.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/antenna_001.png" +dest_files=["res://.godot/imported/antenna_001.png-384a2221c556e630d3471ecce14aaa32.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/apc_001.png b/thumbs/apc_001.png new file mode 100644 index 0000000000000000000000000000000000000000..d48571c9a319f4e6bd1852c1ac7e008dd295e171 GIT binary patch literal 2798 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 Ly=IIzbc_8LdWtqm literal 0 HcmV?d00001 diff --git a/thumbs/apc_001.png.import b/thumbs/apc_001.png.import new file mode 100644 index 0000000..ffd1c28 --- /dev/null +++ b/thumbs/apc_001.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://ckp5nasktsw6d" +path="res://.godot/imported/apc_001.png-d008eeb8b81737eb9d55844b93c0ebbc.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/apc_001.png" +dest_files=["res://.godot/imported/apc_001.png-d008eeb8b81737eb9d55844b93c0ebbc.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/apc_002.png b/thumbs/apc_002.png new file mode 100644 index 0000000000000000000000000000000000000000..d262e0aab22c8524e684c47c0c4a8c56a92eb826 GIT binary patch literal 2756 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 RRnKcFU}9)tP^0e__b<9s4R-(l literal 0 HcmV?d00001 diff --git a/thumbs/apc_002.png.import b/thumbs/apc_002.png.import new file mode 100644 index 0000000..0b9026d --- /dev/null +++ b/thumbs/apc_002.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b75b4yhnejh2m" +path="res://.godot/imported/apc_002.png-7b6a91012ea309e1a9cb9b866229ce8b.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/apc_002.png" +dest_files=["res://.godot/imported/apc_002.png-7b6a91012ea309e1a9cb9b866229ce8b.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/apc_cap.png b/thumbs/apc_cap.png new file mode 100644 index 0000000000000000000000000000000000000000..675b864d6fa8f79a018c5a7d0f5c1b259259bdf9 GIT binary patch literal 1534 zcmd6n`BTyf0L8zG;sK$!u7Fvhl}B2L7vO~;LWf$RiI!w$YK59%leB9|nj;=LVyxF< zmX$@Jty6hs!s-C6hLv5EC~jM3DVS#7xbAKbL_{N+Ux7z1x$ZVG_1GjoB)@7BpV1q{>S=Ispg*jCP&;G z{;?t-(I=C(5#HWz1a!3=jw&2)DNZ$RW6xr|hkN`XNc0vG503Mt&g&M#fn-&9fTdUr z3|49JX3M&ic-3G^9cOIF?!ak}7=pp}H&+j}FXFh3t3|91XUW8M;CpDS4=S35GmdZszG;`bBVkql0j8RL>y9*HO&KnH3i;{${UpoRD zI#r)e;bIb>aS9-}O4T2Kvl-BAl`I|r!9}|Xs`Q&gk$G27`ov~wx;;)NLFNgKX%_c% zlgTDL(tfTzk#ND6(kno_SWO7Kd|IFC@ASYJDt$s24!+Jc;UzVDMH{)){lp3-0Mbf$ zSce8E-xgraA>SN#&_+N@@=kKAJl|PjPi*p~O>T%wJqz8%MG(7qzD_p;{QDB5#J{-V z+c9C@{WI|gALTQ9KQjlApfUGHSyRe0OAzMNdoHefIW2jGX_WUn=s{XiINN;g(|r<|OaJZ4;=~NY)E0yA z56?Izx}Sgx4_hFm&0tuA7+M=_RCcZyt)60@+7Wd1h(6w|2&BdmN6MIX)AB z`X@rOaCty;rKjMJ$HS6NdTH&$jM-z2YAbJeds0^hq^nha7wWYU_N5)Ui5xZyhm+x& zPsznO_eLZKW07}MMDdf6DpE86;OC@+cs8fYXy^ck;W-iu`YLn8 zb9B$=eUJx}Ps@-JKgj~y8(@R!7khaEM|P2du<7Q-sw0)(T$6gElm&vmqRmcmoy}Oq zgbCOk0J7&sPjPgA^=F?j&1fkdoel8NZ;&+h8Hr{dD!|x0F>nZ+bvJet&!TeeX5PY<+854~ABrkarw3@_M$C$dg2G`jKorfvYyGIGy z`HFrF22F3_#QUublHawvM;`*%zk+9(Ky{#XFya58RZy!xMLmadUS2zNU}tCqrHOnv F_g{w&hLivR literal 0 HcmV?d00001 diff --git a/thumbs/apc_cap.png.import b/thumbs/apc_cap.png.import new file mode 100644 index 0000000..042d9ac --- /dev/null +++ b/thumbs/apc_cap.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://08m553i6la3k" +path="res://.godot/imported/apc_cap.png-232f17eb7efe055b948255afbdd4217f.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/apc_cap.png" +dest_files=["res://.godot/imported/apc_cap.png-232f17eb7efe055b948255afbdd4217f.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/apc_cap_1.png b/thumbs/apc_cap_1.png new file mode 100644 index 0000000000000000000000000000000000000000..aa217f7cc164300fd6905b54edb2c23c76f92ce6 GIT binary patch literal 1533 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 literal 0 HcmV?d00001 diff --git a/thumbs/barracks_001.png.import b/thumbs/barracks_001.png.import new file mode 100644 index 0000000..2e21676 --- /dev/null +++ b/thumbs/barracks_001.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bhqfuk76plea1" +path="res://.godot/imported/barracks_001.png-12946249c6dd7571051e0a5b3c7cecad.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/barracks_001.png" +dest_files=["res://.godot/imported/barracks_001.png-12946249c6dd7571051e0a5b3c7cecad.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/barrel_001.png b/thumbs/barrel_001.png new file mode 100644 index 0000000000000000000000000000000000000000..6cf0f22a87763c90d5d4b69aa955c0bdad285f19 GIT binary patch literal 2140 zcmc&$`#;l*AO38Hxoy*wg=9=4G`U3OvMp>wa<8*;Tnjn5RLbzpEIBAst7Ih#x#boe zk=sfxO)jU)+|8xrei;pC*zx@*zTY37=lS7zUa#l<+xtm&b|NXrs>lKWpg11g8f~w7nSKa0@KKJ8c{sQkB=h6FB<2tlQ*%#?Ku%DVh8-azIFy8hTW2cnX}29n zb_rLzuYV+@+wqijamtCcPhE%n1F!w`^2j!s$y#8~sC?`782%;xGBPyoo7znMP@^}B z!Z`sQ5#TdSB)vx^VLraSoVEQu(9Y}Ey)pJ`UQbn%r2>b`l_el{vf1MI%4{~9 z03|%eB>3Jm4m3J!(OnlvvoDJDbARc<(MRY1PWQ}}IM)#UPy?!?Bs(|o*UN@2cA!=2 z{&h?QQOWdZjBqYL&8@tb^5uca$^P0afia?wrz{8gaFnqd4j(-?SpUyc?AwKyCgXZ< z*o`gaxf(&$b9Mhd$1PJjFQwo{xTH(rlHf{=*_gcZ2kBZ4gv%d)*tjdml&?6L7Z6> z%z`H+l`7T4#!~}vuequgXLB&rj=2U_VWE?2Oj`d+ciMIv40U1>bafPd#J+Yt&i`Zpn757aBU>Vl32Ia z{io_fSoP*%-vl5;J{mQ3&Fh}bsBW)>BkXOYo_VDNtFWkv26o(~QJ1ai9`D8F^4}z? zo-iZ=!!w|Pd80fj?oT<#T1m(W$Qe~|V%&upp6xR<3e7=EPbT&Wy<~YQ{v;TDmaf$T z1+gxq=B8QK^K9Qtx1^kWoNG#gbt26|!xmzYDT?5ssCl(uwaTlbT9&cVRSJ#U^RI4- z$hmjV_ImTr9Yu0iNfPnb#q0i7HDZeFi-QhwaP%fHCaRAf>pYpBS68NPy{==QUuc33 z<&htohHg(6NEC@`4if?T%IUC(s8Fd=B~2(o(o!W>qtS37c(|J2hi|*6ZhJ-xsg`#GtGyS@*ulU z5_olZ&zjRp-;g|~RYv>LkclA*gRhhB>%rf=ROXVOl`7>AF~1zd+*T=Q%X2M_npsb_ zVjBO3(xN-&fF>bVn==0R0miua18o`dcN8^JRn)vSXhX}q3f|IEsmhY z>@MYgsp&snUF(sQ19Vk1#6N=)BlZ86G<6h&TLR{UJ}j;V)( zt)nKIGiktRd05HP_wg-#gIK7wj>ababXS;>X3cYB^N1ktJ<4Ri@rqW#i#Qb|6x<8} z$hnA8jHb@0NRrvT*p(B1L&!qZxi9ssWb70|{w32ywl?=8(1#9AZ26RDbSCz%qz!gNY!Y^ZxNUX2Uu` z;k`ac5K`?RHfSym2)mpmsD?Y2jF6sNI5_M7^c~mtwSn$em=8$v>@!Oyj<+7{95A>j zuI;L;lI|&H@Jw^Z0iO&&efEm5eD~T3{iR)SPv29UX7*Ksx}Mc8I^75*ZcwG32vef? z?X*l-d3b|Gwk;63dtva~vLkTG9fOcZJ`-7NQGKSU(}&6JzrXPfiv^`lQhlwbE(KZ2 zJ(ON#tz{3(2Iow)!|Y@KY%h(3&e0d)k? A!~g&Q literal 0 HcmV?d00001 diff --git a/thumbs/barrel_001.png.import b/thumbs/barrel_001.png.import new file mode 100644 index 0000000..fb3d14d --- /dev/null +++ b/thumbs/barrel_001.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://8d3x37mwv6xr" +path="res://.godot/imported/barrel_001.png-bef224f28b42bc3c1cb70c9153b02176.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/barrel_001.png" +dest_files=["res://.godot/imported/barrel_001.png-bef224f28b42bc3c1cb70c9153b02176.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/barrel_002.png b/thumbs/barrel_002.png new file mode 100644 index 0000000000000000000000000000000000000000..25079d5028f66cb011f0e922387fd0a9b948cf8a GIT binary patch literal 2148 zcmc(h`#;l<0>(d^rH!-=m0K)#**Eu4E}P335^}Wqx<)J|jmn*|F^jg9TS=R~rPIar zu!LOljie=)a!F$mj*!VUV>`}2an29V^Zwy^JwHDW-OJNOPDVur0023>tCPW8@|*pb?q!a+~pEo->Blp zI@(rt<7273J@BUWkePEmOCxcXX7;l&^>d>m4ZP@xwP{J~Quy@Ai)w?KSplH8S4dz2 zL!m9E1Sp(@RIBNcr>sEex3FMqPvHIkEP7pSSk3XU7sW(O4h4baxK-k;-UGhiCj}@W z_Hect(aqI#*!5Fk%-|8Wt)N&#jg2?V^t2br3;O)iG``WG_JVCrS~{H$qawmCxG7p# zZB`sH5&krEnMBI4+#b|97|;uqQxm}C=h85fHSqVF>{`;CN;@2ZrT=)KwXnUo^&Oom z$kR0-eGS`8s#@27s^w56VU?e8dAFy+wEGloG`cmBM8a^wta6)ykp>Op+KrC2we6wh zo)xh$FlblvW)mldxKPw&Gf6aATL;b>`WdxSq0f`gUH=A>Yn<~r9=?JInJPHYb#!sh zcaOir=XYTYehv1Q2mID!>$NR6vTfN`;x{iSn{#@DV+2q|uiIZa5&1mHlg~Z7nXphJ z%tkl!7N_auWKv~7D`SSM!XGvLauK*M`{XtBn(S2BZ_=HSqQ z>uJ8sp;6}I>X9f9crXKyQrQ++7Y#NlC3b2!LWq4Fh%>E~wya-Qm}HfD)z|^3vb`R+ zc<>6d_vd!bH{5y3A8D>ihcGlOT&nq}VGPJ-Dv{iWt#6T0ABN#S6FzddCNAVH(MYMx zytiKsU*+DPh*Uo$UTT^$?3Ya-a45}7&-Oet{8>QGa z4@Xg=`8IKp#c0OMq~#C%0<*tzQ;eYkN~<`RSz_f*sH`zxk7p}Rh_kPO)yDvX5Ink7eq3Uim_-!d;y%w6iXK!|DgL8p|+@RPQz9Dr=1^d*^>zRPIZ>#!iVY`Bz!$!Qrcf3}w=jOcss==8r+U~_+ zBuZTaUga}gbxvSEhLH9 zm-$$~03S;ElWSeKw=YuukG+m39Ac%STv5l$=FX!k#Q zi|ZQRC4G+Q{e;nQ5Xsm+O$?k>iPcOGW&!tSM+W^dabrO({N|bFAO1@RjrMy-G^`Lpx^_{b3 zPkjyTV#V$1J!WT>w8$QlplQfT%iT*;;76oTU`9zU7m3PIMfYfokH5m0=g8J-d#AKb z?S+Rz2!Rb*9`|hgAKD9UjNc9e6HgR6p{x88o*ZLnc0v(>o5(Y2HRh5fP*M3Pv*Wkk zy9sI9AX`;vokg==2HM7}_|x-SG(xdRDV0?P7fwtC;2`zaqz~+Wy!;YV%yPO`czWDa z7XitF0jv(>S-cZsLUd>*f;ruXu}49{frK$@hGgWVUFN(DM92H!-HtAEoNkRb2{85q zKKxoeZj(are&&hH@6ImuU6D>;vShza%BCYy?JC{rXfT#kcZ-%XU}J|GxMNOtJvww| zJ8nrfgktPYo?u6$yhEOc}7!yih(+ zK3*o~+)Fl2kgs?~46r=B7s!GMYAhloxLJrc*l0EQAVWt|YV%va?1y5=`3zKf>AS`G zfhV4?8a%Hq9!&syv6&*7cw`csk4?wDXMIBRkwovg^jYJyhV z^(`Ywv!_#~LvY4_ E0C&;s0RR91 literal 0 HcmV?d00001 diff --git a/thumbs/barrel_002.png.import b/thumbs/barrel_002.png.import new file mode 100644 index 0000000..1dfb055 --- /dev/null +++ b/thumbs/barrel_002.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://x036pdk80s03" +path="res://.godot/imported/barrel_002.png-7062eaf20902780bd584d834de43d6da.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/barrel_002.png" +dest_files=["res://.godot/imported/barrel_002.png-7062eaf20902780bd584d834de43d6da.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/barrel_003.png b/thumbs/barrel_003.png new file mode 100644 index 0000000000000000000000000000000000000000..286909d1e15b80a39a1cfd5f5b75058c86d38ce3 GIT binary patch literal 2097 zcmc&$=~vPT8~uT(l$xkhE~&XDZmBsnChkkdF?!D)pbI-ZwJYSxBBfuZ2v{!2{002tf zULHZaO8PILa=YB+6g99bAY2gA4QPC!Jr4l#i{2itzu;+0v;nNPw+@NjxU9+UTE0rh zpDEXdxuK(48nRnLGoFL)DS-?iVJ^99dEGh^kObJLBERq1nIlkry=dc&o5e2XsGF(q z<~m?+ZrpKUwgWa~m7RO+bxW1(JS#8~bBrRk*JS6;`{9QI0M)Ra6 z%Vodvgk08E;UszhJQa{O@_%mj_#FK)7KDiIn^_1;7bVSN-+^vGMuy7$>JTp+nRlZhfUHK;A^4Cv8 z6~hcR`;<1XJ8^JrEh%1X;v}M0?SN_rUn{KA-{iI(Vo%}tQO4izf1evw_|?kk_xf48 zOEnT*J)70d;fSagXK3QiQ%^TEaSoT*q9^Ka_H@N~i|L1_8Z&FVV%a95XmDn>~F z!ttf=y)e%Bd9x`ERhg;3$D>IxNsHaoZ$1FWTwxE66@A*&Vc0!YH}5g9jh$mzXpkJr z?;SfC&587S6xmK}H@?rc*?fKzTiR133FZ~R|x7_`}B3Kd)B& z9Zy`x(d14;BOOluk-C!QTjn^wv5q{Oq!vjAM#9}*i6s2bOyW(_V=NGZ_<+p;9E|VLWa!8j_(W;_9HnB)9}6Hx zX-O6;<%AtOt6`b&3pG##M1Vg#>pOAl_`Wxp`@tRJ?flSHMjQx-68$T_WgUR>`^KC- zemrO3V|Fwd5C``5hhcgjZj+2;bZAZ&X%XgudrIBu7lT^dND)%8^N*Fe#iEABCC8Yl z_GJ7OLX)s8)I2cXK=K$zoJ{aH3g#b#u1-s*Yu7(B2KVoEXnX8k{sSxMb~}HLI075% zS>PgX6lHtGKaA>4*H~jF&CF?*0lSCNd%A;MIMm@1t(Xx6VMWh(8GrYc<8OY+0@wk9 zWvky7soW<+KIn!U4E;#DE9KE}f!!y`TOv@yHi22F0uIlevB5-s4t&c=wmL{931nZ= zBeJ|51h2N{mNOEGV^^6vTOMkQ*#Yqe4L4N%49AU#O!DJdeU2_@jo11XasHEnY-|>o z;mS#X1+1s#vG~SW{ahuD(ay3&o+`%Aw(tSZMg*@s;Q5*CXI5}{_`DEofsucNB+=S( zQUdYw9GFY0F7`-+^%=OeI%E(6vSpQxtFn~2unT^{@mh%u@2VZ%EC4otZ6R4N_01T0{r4WnEujrG{nj|}dts^M{ z{VUZk4PDQ2!Jklu9KyIyj92wpRh)p)cOj!-l*hf?*vHWVX(fK2)Qa57Tx=^GpbQ~p zCiZnW*bku$T^#d5LszEVQ}CD^4=!mZyIFH%sZp zU)t4gE{UEic!a6N(%m*Ctx6VuSPs_~gn)t9RZzN7L(RMDHa{@mq&HT^RJtJI=@K^# z51G6`kRFx)B(%GDq%fw=K9h44qzGe+5XmptWj#~_M*4_qg}@vrD@PNKN-1y0J5+ARPytK`du^CqPFhN#3;Uj&D2a_lSsb7$ zWhT^7lDSZjWHuJ&}*FP4l*#khj^Om6Et@X=gA&F{Go`_ZSE z5a2D0Bk^e`@RYc0T!mnLt+K(VnW`l* zbReQZ(LT__>KormLs0s15FUC5U9Se5T=}*{FF{Iv{<{EW%27|wDP>nluen^bVX?3? z?0$a`(CDO*D5s3O+_T!ov^j@%Yk8<6&?{r|O9XKPJsE|4LTS%*m&x50P@U}D$2I@W ze_2gV)0W-EI)v+~N?EpG?T+S{sygmIr J8r>o@{{zw$$mIY4 literal 0 HcmV?d00001 diff --git a/thumbs/barrel_003.png.import b/thumbs/barrel_003.png.import new file mode 100644 index 0000000..fab904b --- /dev/null +++ b/thumbs/barrel_003.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://clandxfaibniy" +path="res://.godot/imported/barrel_003.png-5fcd83720a21d80d1a51cd0c221f64ca.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/barrel_003.png" +dest_files=["res://.godot/imported/barrel_003.png-5fcd83720a21d80d1a51cd0c221f64ca.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/barrel_004.png b/thumbs/barrel_004.png new file mode 100644 index 0000000000000000000000000000000000000000..09fda6dca78466df02ef303ed0e7fddd6a117563 GIT binary patch literal 2111 zcmchZ`#;l*1I9nQ#E6iJvN#yh(1bYHh&9bE*K!SwTq~Dq?uIB8%CXpzk;^&4SZ>7( zF*+%fN-h~8m!_u0T$+7-|B3U%^E|KjPtPyU4^Nhpqm8uWAxQuLr17V*E;~v3zhGiJ z-i-<9-w9BRi;WdPAAm0cfcOR;d(thoXt~JY3LJlsM5BK%Ua48;+I$?i+;jA_-HG~9 z>1J}xCD~gLxFt*#YTT2xn>ck73%@7Zk*Wk=OKS`vOW#j*fVFK{-hNt-VDR;ugDWkb z+_5I+26GQ4m^aT*o(QsV6iP9jKAZHUwRLi7jTJqecQW$8wTb<*ISO)}QCOf)4g|M> zM#BGd&@%Zh3D+>zE4tJndb_EqxZcghGf_9f_J@R9y)ED@xu&(Oo`Ai4dRM1^$P-5m zvKNa>VBl{tet_u2#-C<`OE+wtoo|nN?I$7USv?8H7HpZsJQLO1UcZbdhaUXlumY&? z$Z8*{TFzK%kWWXw#!wqUulv((-gfQ7#I4#EP%NJ<|LD@QHy>IC53ifJ20WW-;X?tVJDP0|$!HKMV7zbtWlaxq7t;PHTG8>Ep(pcV-|eq5Bk5K&Ig9^V`1p^V8F% z<~(y5nb?_M3OA2#tqI#g2rs2V2xG?}igq|h!m-Y}GRY2^WW_>o1CZd~-^(q=>_7f(B=^A|C=D4Cj@6A10d_<=th;$t}xq0=|9I>GI zaF>1#1PMhcTlX>rj+KKCesBHGZ4Q+6&j5yI%-j2qC0tQKlz2lr-{-84tCG6Djfb@@ z9D?srISE-P6)5Z0$o?_TR~S!6$MT5W(A(9!9_{hzJwmt%94?4%*QRc(ULD^6>dRj1 z_w5C>TByt|#+A6fQ4F{Vz?Zp2i}7=RVVifV{GLTt!IGnN{nwU?6KH$IB&+{TAtnce zrjX&zHM0H&Srm%*MDPgHAusj%K;4Of*SapbWl4uGxiPFrx!Zg{FZ_$wzoSP4Xu?h(o9fBeH{7ZL;ZPz5ZbzY(ZEd=LhimfB!Hec^{wzpcbLf|Yc@LMo2e zwT13CY5Jwx__5q;K7|NHYfrYk%kQK8h7`uLM4jp{4uLw=S0sbK#dO#ivZM$XiC_O4XCl{(%dSAD7W7N7k^*6wR6 zSFR-R`zU0ea`AjAFc;_ZsJQe%=KC~Kn5@&PkXgV>LS=e{tJQ{9NMs`_?)TK#$k}CU z`65#r^=lwiFjRbF@Pg@qwFf$Mi=$^H;+7p$9NTSmVJJ)WEYC@geyx0aOjAwvD1~pl zVHg?q7JJVKoG(%80Su=ZA16nH$hmr6wQyCtPHfW?MrM2X0|D%xa%& zoTvI}>QpA5s}p9V+mE+jU-^dcl2^c&+K7BWnliNmecA3{!0<2VqoC!g$;F*9akO|z ziJaioS2W`1l(qINc@HE?)E1nnUx(SDVeV=$9r;dRv17Y;j1pt-j3w799Q0Li zbn>5Pq>&jvg^3sIPKz|X8s3IAc_)?|MN!|K-n-=7vs-Z4Gsea#D+oO6D|{^+KjJ^f zc4hih>-*LocdtUpLD^m)6%L>0j)5LEAk9@vtq-5QGdS{1$C&0~lqt=%g{B69Ed^J3 z>`m+U@x|bu=Fj3UJSfoAETp?pYTW)2!}QLoZ)KZ&@kCyzed`}ZAma&zMw!Ohp`2ZT zvLGDw?q~6zcUEnj24{jv9mR!gpr9B%1?9Es2mb09eyM2vxari0W3$AN!RkoI^Yc$E zCeFq8(Hl~7PU#INC)y35`dM3qVQW=WhAqi2;s9TOhFq(ko2o3-Wx`qJfy+4gYA8v$ z%dA|<3RHbr0?BYB(LRbNIbn}&<|;_>`pZr2$+$z`prmQnj`seaN3KXT$RT&FuM7*( z9c3auskvu;qmnFgzb*;zy0xq^UEL8P|Mk&LRksin{bxMO_n4fTqDJCQ$~lxQYg2%*P)Zf zg&fCCBvHAUbg~?F89HQ|jb+&s$Mr{C*W>Yiy(Oo8WQQ&jnG@>V5NSj*@pzbdD$$y!jpL?rkq6cf?toRfMT}9@Y+Y<`5j-9# zDDqxj%Hv8%B1_!-O}2PBfxpHKnO=}MEm2t`or3x@R;OTSqtlr8`RfP<+3Itk3(@-; z4<|Yz&t*eBI1Jq!4`S@VdPDREzn(+$i7~T16<;Xn4_NV3v)T zYz>?=&4B#EKgMTUuyTG~WL`dGA<1(VNc$+dB)u#A(#L@Qq>5R&I>ON)T2?f}gm>4j$<2+BME>#JXl$1o_P|T&-p(5k8)!OpS!w~}x z#WfjoPJ~^i){g6S-&WbI z*+JH^0l$H^B54f3_r@4?A_vxl-vnixuN<>={{3AT>12>z;+ShUD5j)I-W+VO)_W>g zo1$I6TGQ0f`Az@mVwIBq2+CH!$K$ zenroX8j4}LDx+iD7Dg?zEZ5rHv1vEm${};-jd$vgdkZarC;-zw(e_ zxqF$2Wt|i%3qDq3osXbg93m3W-34l1b5kT3VJL-|QIXnqcDxCCa$3Re7eb~=xYq^g ztxUahZ}{rx56LsrQ=g6;SUsbgVh*R6s5{lMBq;y)Fa5OT^UhyuBCfm8dB-7SX~{b{ z_OKFQ&}4<1nYyQjYlu#CX7wr|==(Dw=k##J}Bv=|$OLc631qX$Y{?R*wnFzL@RUz_5w zIz0iVrgv-P=**t%$`1Ejq=1$b^-ZQ+r5}n4nX}y&%^2~>`9br;8|6Y%VrYkW7C%cU zmTK5^91g*Oo&Z4-Lp+AhFBp08@2tw{H7gDr)IF=@7bqI!2YkB1^Cx4GAKI=Zx+W$c z!R`lSr&;WAw!O`(=*Fb$m9FTC#z@q$@oA2lsB0#G>Z_Ma4n9IaBWl8OAeVQ2g^OIZ zi*jW9gThjpRp!Kmd0Uycm0ryo^r7+q!q|(`IjZ<7>f-cXC{xGMEvu(iF4rtwK${aK zCx>}z0-_r|cQ`S?S}*NX*^N_ok`!V@qQcVBw59k)K5v42S`Y9#lQHY)Xq>k2S_Ccm z_Eu!1b~EnNWvq`MJ^dZ$!A4j%cT2fq*$Pw;1%8EAYtY4od7`l~f-M5@+R>9yJvphPJo-4XD3-C4JHECwKyjf3E++|R z4&UP#Fm_gGy=Z|szSeU6(Lug(Q#^UYo5IoZ>TZZ#*&HsZ=6l*6-X^9`qG*_OLiTqU z=a>rn-qx0+f2Q2f!VtSs@hb4=)v<@tW{*qk{Xth#y%lA{@b%qm>`aA(ydfl-Q6?#HI*Q47tV@P6QhQ$U4}QT{fBh z9}qH|z0u02b(0|BE)-i(+O9ed0DQrLY~vQ4FUs!-+0m@jT=)F>iHXaizt-ScBuH}r zjSwJvT>ddx+Jlai@Lez7Rp8uS>hyHBL(jVurt*>Bsfw0+i6>!Ciz-sDzjt@_+%g1? ze7?WcMbRdxvVX8j9M(IMmF1B7mv*4pOgzZ@5*8UbF3HUuh#{4P51Kh+dx!Gpw;+B` zL)5FvvCXtVI2nwlfHpZu&Q2*q3XGBQzaBJOjw_fR@~*g085=Lc)WH!;pPUnrU%NxS zaNb1_o=Li<@9|4}TQf(@hD`ZKJ3_o;$19xIda3)?T*goawFnUXqDGcyqRRU@7gBaI zAwfN37=PF`*@s=YwmLVh7Wh?x$PQCX-!nkD+ZfaiK&kgrO3GuL;Fr-Dm@Q9Ma?(0w^_MfN$zOwIH2QO*;R_v#l{*(w4Sg*Xj{Dz*Y*l@iaBC}T zrH6MudA(hD%@z894nCi)^z`(k9F$b}?CDWP=MJg3oj_%3vJqt00j9fS z4UkL+pA_~fp@UvYtlwaYmoc&h#6>F{=6ThL4&z%R4{BE6dUNq|pNo{|^eA`z5sg@yiqG2UHi`Io1Q8e69lEBMyv4oamA7=>`)nrB z2gqpw zqSeEW;dcC~?U*|Eov~Cv^uHQisX}=D5MF*#9jF+gOn*YvI(#xvX|S=tTf=P&)~`DF z_O2%6-eeOg?u%~&a)Rc#EsHf&?1jed5Pn}TF>4oym5PHkp3fpgM-4B2-)*JI zl@mHe^P8QM6NE;2kA9x*c=yOxvh(K*ho}KC~xZ`Yfv9Hf;Gm_FtccTDanjgknYWksB;>KB$ z4pfwik13VYqGDog9bFrvR)lD_yP)XcPdzbxSQGC`d60P%eHg~R`~DN(?+@p^9_KtB&&PS3^Ei*kE5q?TK~nsnH~;{WHr9A& zfs+3lP_Q7sGxzBi2q?yxUEdm0;%QX2}5orW%k^bkg-P4#crL3X4s{}6+{Tslm~Dnt7)u$y?$oc z>FEK%@-RWI(AEb;32nR=@k$xKe z`3>5A8%bWqy=7e9S>>Iy8RoSYgBNu9VDjSFOW8CPALROTU5j_)mfgzq1Iv(4pFSmfT88}rGQmL#i;K~)GnE>?Tgxogo`c1naf%*_5j|u$GyK;D zt-2Q@Ax?6lR!-EIIr{Q`2BwqRB&|m@Y6rY0np1;FtBqw0))LHHYijqCLc)A%!^>Ds z$vF$K9-6mP(yJ&YTxPO%KY@|K>0R=^F#BcUdXgxwnxdbAs4xVp3OQ#4372$80NkB!Ru&$Vjq2KHGnR2-ks*UjI&Q(j znU6suE56yrwK|fq{co7I+<#m`{Vc91Q~i&WA9_z3)!QAfl<$%Ojdp47MB!Y>KE8B4 zV)i5pj0gv%$<2G{4%SQ#6`GGU)w`*Xr$6V)Iuo7VI7`dhnH~h}MA-P?{lIpud3haj zAa6+e|&R^Yw+5sMY%3n&-X&Hm2vVV1Db2UtC#?k1Xk?Z%uMB3P4`!#Il^bGHgf?&R=#lOIlwUeLL%Dzh ztA-4l#!@UT{mX+Q?9BBV+Vyfd({+G&4|uH2+AIp?)`sA$a|kotBcBtQ1_qXmh|lSo zDwTR_;==esg;lkF!QRK03U?bzkO(2wFj=2r|wgx|v2FbnKep^^woM3Z7SHU6pwT28ZTRX_6F>BBr@DednaKfw7eFIi2c zF43Mhfe-n3xSN4AP*YOoIm#JK=|h#s;E4Bukr4WkpoV5*BE)~+RsPh)T2Z%mI4PA; z=<3J%zM~~;BRyejiO=>C>Q8olY1%5Cryx+Y1qqYg_%!j0mtUA9*v9EF^A@fxf&hgkacSWM^>GVxCQX#L{pymd+b5p=OhpE!Wt;3; zdUfqsBArCF2mUN(4EVOr!gub168EE`L0TF46Zh#Z#@M| zd(Dc7*-%!fwH3J;AOxTW%UbZ?6YL|~a}%4g>tnA;_|eo=v;UN@u$8a-%rtl^ zMNL5EY){$W4LwRyzm25mdXDj4|`09xmuOQqY9Cpx7$mocyN_B}}^SV|Futf?~GH%bG??op2+ zL>`K*&Pt3`L$t()hw=y7Z`;pR6HC-@b{T+7I63^Ums4N;PQnhjVY=cN`*&i+F6N@W z+6>z_qwl~LMc4{PQb4yes4RJQA=7KBCdLi9to*pMX<=3|kRk_6n9U95xM#hBvt;yx0=@f79l&MW!1M-^7` zGp;do+#mG*A(PzcvgQ%=-6=xiQIxy%T^pdjl%S3@ODDKjzqSi*ymTLzQzo+=G+AMn za{*GJarOqh=v8OS9*UTtKNvsJGM=rrcW^M+uRXQMx4xb&_%YZ&y+2^_x#c|Vh+N2) zR6LN~_65vR(WWe%1L=25`&qaGePLqW+3?m|#X$btKb2~?Q?s>+6*N7p6+CW^R0b!+ zZbK4aNAq#i1(^hxI=*~66E)-(>zd!m=Fyk8ItpB6zic*23{_aBwtQcE4@_V7Mnc8x zXBV}ZkFSS@LTC4SUS#S#+v%mbM!oUMzhQ-%b-c%5V?we#ih?V_t;U9eFdrd(-ET=E zNb(f->$)Y?&Q=#%IBhjTKI~=|YeK{uOip93`o;;R2z@I;+9r&VkJPDj$L~~b)qi|3 zboifF*AQe7edcZ2)0Uk9dS2s!O~-1?{0H;T^JBzk#7Oz%QZ?})g+brjk8ud2$W7Zl zrAW?3!fz3!wVdT0-YupoX>Hvyw^YfN>KR(sPw3i1z4>S!6NB1*H|`Z@-hesA>>nsa z59252KnnNmQE*YWgr99Fo05ax2D|Bo`{bMJlct+*vfZ5L(o7QI3hd#DI#oYASki^Z za?v~ToPP0l_>yR5a1ih0m>5E{RdK?>#-L`#9ty`mSb+!@dV`db9s-Ke8Ey1s_%z{G ztv~$PjL@KPM`&;lM)~i5Ko#?pWhokBCgtqg?^kj7)FbL-z70qe3CiJ|V>mCxg`OYL zL)11Sn(Ds=0Sq7SR)E+4W7 zZa4nSyCIH&xY6Kpr>yEZznJ~^hk_(Ywm=(J$d?{#2kqC^Y&Vcdf_Vl2NkAh(_24WEF%=FLf2 zCtZ2R`nd#c;mz%LLCZX4DotOKPgNdo8l7*_^s=~Im%&}kFzMqj^`gtIB@m}=AFiq; z;$GsP;0-RE&C@Ax&UMyUFbZvy93U|fDtfgii7i@Q=+=k&r?JLm$TPU3isgl=_!0u; zsPQ)7cOMwgpQ-Ee;lI3!cDv)a(Kaw5g{Zz*l`krj3ad1#I3}6S(&vU1dC=gBs|xa! zR~Tpr+eo9m>f>0Y1|517FK}`o&x2Vj#B0U3H^CRlv;L>aV)x z(&G>9w9X{AB0(7+iV1^(q^>C0{41*L+o#mmyBJ#jnSi5ff8AszN$YwEFNafL^g}S{ z+;``A0N81?W@33xS??IZCAUKGJn+%47>W+o!o=!*y=_E?HKb;ekiN;^(ym5dM<%zb zgX)TZIF}z^iifizf?!W|6D<>;EJi|Q0>Cl*E2yxdFqWEf+Z_W{Iy+3euudqE^hk#>%Q9IZrQRiWVHOz4pz6NW5u2j}6M#$csRvPxo3Il@Z=Y?5nnh5p!SVWaol$C+5w!Hv=r&y(^* z3vA}x@#1OJN#;flH-~(a82W%P7m!K2s9fu*Q;-oS?8M^EW;b~~H%=ra^(-0SsTqnb zdM9RdykP+b(jixKfjvuewW@fz-63pJt~~_wUH>!2p$dXRq7_*o`yLTWTK>7fNf$_b z?AF_^L+jxiC0yJ=^!_r}NJMA`)y>#vTrQYrboTE-HmCX;GfHG7f+Ml{pY5N-USeS% z+KTvedEK2DQrqTfU^Cr=&~9ZK9H!B!&zuzuuawM^n=GMo;3Xw3IiSrAIhN`ni*b@Bxsc|VXDy1C{Qjy?fgH%>K{%^NVD6fXU VVb(ds{wn$g04&(dEDwh^3Nz2+|UCC62Xf*jYmql|8#g>RBR7V?{jj-fMx?zUoe$Op5 z*<7L!y12#KBCW}+6Xu)Cd^`WdIX^tl`}O?(yk5_fc*YSAQH7}j006PGwQ>GK=6|KU z;g7dll6(FDbln+m4OI5&NC05tyqyismBx{BdQx=oa3-&EI-5>I+z38)s=Ma7t=3G3 zR!y8pdvloWi7=&(7&S|NDi3+=YTVYeudlOM&@Iqw9V%yRP-k@cILF&k)Sc={n)sby zK{W8PwzhWe(}HC{X>?8pso?fM&KVOyob>a~^A})~FbsqRagMxJNO1E{O$ZIyt z*Z=$Qe$tRn{#E`cstT#a&{ZA+PfKhyG1^IbxnXInQt@ zH8pPDA=gy#(;Ju-aPjQI{Ge`X%QDuHV;1AA>hid5>`-HS)qn*zU_$dC*BvsL&h7c#j+riOl?1-&akC<$?UT4 z>XIo!rgS$WW4q`FqgNU%cD-w0vBX2XUBI-kj zzckXPreuEJSts8t7iZ8x9F}>X2O}DCf2rH)ehB1eX9}abs=P`u!xCXX|F+-jQB=a4 z3)4^6BYz780gE{d@R8*1f8_wcm~OBD8aX*sfokq@8HT;Y3GKPkx*mt|0M@>>mf8lR zq+U6sJYXgMJ3bh~2&MV7ba6)aDuYT%e+!5@P(7=#MU?EL?;bEgUFBmc4B2X#zF%!0 zm;fC-{Upjl76ng1C_usnB1Y4O8FXRTZhlZU8JBMM5W7QSG=WF}+$dRHm5SBM4(4jh z^oAQ8dNVq6ORR$b!JhUl{`jeW&0BE~TmSBKxVcTcH} zxLZbmiqervuh;0?)6&Y%ne!+@5p$NIb!lpJuCY0Pp>>rmK76`Y5sZAcBxcoRA1*%D z-o1T@=#~3$qIFCbf_OM%Pv|YVgcg;zdnR4kKH~W1L8!6%)9+o58ergSgO#<_swOSv zgKELHvi|biI$gIr1j@JY?hEYy$TLHUiO*`I&+=+;A)5;7wLR94?_fzZX)Xol$$_il z%{^V$9&dCq0t3dvRc3rYXSW?D(H&KYQn^16i-mb`@1< z4ZWBhoFyzwC%@Xs(uYX7h>e44%6O*vUa7^}$$o!SvgV*I(eqBXv0W+AE46sqsYDtM z?sLN}dRKK$*x%CMWN6yh%zv&%(8pt3>rIdvu~1T(wbM6E%d0dO(Un9gYUDAlzW|lI z$qlVj5;p+2Jxi`w=QHtZ%UIt#hwCEv=ZO0TyU%C0huk5&;1u@BS38(WkVy(PB+Rs}sU4f4htdX(ur***?MH}F=e%7X z?9O=lwS5sxTiA=0^Ebj@d-7jN0T)v(CcB~AT`FV)vpZdJaw_Je+ooG=6D?IPuyVv{#`Xj}dkGZxRa1ntoVIV!@p zdZb5s(RAA5zEc(!tFHyY|5Qk@>6=h%zzi6Okez)0D%{<2&C?Y-zbvZoJ|X*i;4=(d zl+8WUujYC*=51z!r}_6-gdR=>ASG>)oud|0{rw;nn2e#`ptn*+vkRgr%0xpnGu2P@ zO2W7eoGvO(xZ~iBFllzHscEtW3d_yH~K#P7hZwHc!8Nj_dD&?Wn&_G_HKOsS5Ep# zbZ@TssOw|!uFRe1iulIYd-Jp+5C5=)Wmg&oryPkye6-O}+Q%<0JBmZ+iwvF*wwbiv zC~eilRQ>Qf9$9j@hK;V+^Q6z^ESQEDRE~{iIYfTI=EX*~n6D-x7G`@al-h_pHd6}? z`57ma3Cuw&DZNB4N-`g%6W)G0T>>iPR9uRd?=1du6ra0t&=%dQ^0R}2P^VFsN3Dbn zf;8<$6(*~ep)%>o^oiXHj5MK0feV%*RfPLORB29v+CAiYvxQ}K*36FRP()Y8Fk*&# z`~%@07~rf31gX6F>PdGa5(8bdMw5wDP5hNGn+N*e{Gf6rEMes3pSWA%xKkf>$_0pn&<6kj literal 0 HcmV?d00001 diff --git a/thumbs/barrel_009.png.import b/thumbs/barrel_009.png.import new file mode 100644 index 0000000..5f6cb14 --- /dev/null +++ b/thumbs/barrel_009.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cwb0huh22ist2" +path="res://.godot/imported/barrel_009.png-e043f7c4f9963d112dec1b21b2a559c0.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/barrel_009.png" +dest_files=["res://.godot/imported/barrel_009.png-e043f7c4f9963d112dec1b21b2a559c0.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/barrel_010.png b/thumbs/barrel_010.png new file mode 100644 index 0000000000000000000000000000000000000000..cb94d3e9b8d4498bd1398bd9895dbee7aaa219da GIT binary patch literal 2104 zcmchZ{Xf$Q0LQzP4gwV8Zf^xJ`jzGYK>WL-jipC?3BTm$7$ti}5_PF;jNKG6c@8Uk+*C^3 zH2NqqNl5_bbuf8gaS_z7Ss*W?Rv>08`&J@Y>oEOS2PFrqlbRZVzK!**1|zCU*BX5I zg|VT=2};LpO&7~L?%=iVvnT{1`Vg4!xVb$lA1O>2uT)z7P*#zNk^?&B@( zSJvG0+fJ`(@z|o{;|lddxArEZUN9K6hOW!9{Md{=)x@x`%d+qGAIV1C=6-qo?jB_m zH1cAgu!!sx4_c(ObDZTjRg#Bhdvl^{HrfOBw?7s2Vhdz#hdM=H8_MzdC??#t1Lu@1 zfT;fcp)g@#Z9vX9^?^L^%kza7Z99J*i`i$TOlim2jS79;15B8if6sZbdRt2tq$X1S9PjWiwBg7&fGBOG_hn^^<6^ zOQHJl>0Vfx6mRy#U~35+U*@8)pQ2ZbHA32u?gh`PLFYF|$VDdk1jSnYV_ zh*;R*H#^ukF;lMjSpN)J3xcLBi0Zvl9d+b$93VxaHEMZ<9zjF$CnUIpd&)H8*T6S0 zH=-y-GWRa%xD4oW>TzUSLzHV`5f$ldB^R@MlfBmx)^lf?pIqGhlwvOv)TmR_d zSc@Akd_0QT^kU{zm=S5x0B@zj)mtTwNgSJ869tKxJ+WzBg?{Y>||^0^v)AB5Gj z??)HRC_X=y2-@m6pLPtq>}yp5yvO4(lxle?3cx9<-xQ@?pP}2OMuyCqS$~5Tu#M8S z{r9gE@T`ZMxIxxX6>h70(mCU-Zo5`AU*?nc;1P5DA01#s7GN*ia^ptwcZjcy--87$ zznmvU>)w}?4`*w~P5nNHyl2ewRI>cl76r~~#0tEvb)zJ2@X zZ1$YiU2f5x_$IFXw0Z8@Gj-#`MQCS(ga>+4?>= z^OyRe8j9n~&6kr*7qML8PmOK^l4J`HgCwb^fY^t)hJ5Lgw<=zXL6Q@(MQn|0 zuhPA{hweckenG3HG6`ORs!e)2_m=fnZ^dlK=j)T{2SYFcX_S^8t}983YrZTQ2V-1< ztIVAm;b;Voq7cuwyNyrGo4q|{v2ynlPO~+p8pAQt4u3q)qVBjYC%wL^rc&@_uK&F) z8Uf3dsNEKhMX^-~?$5tOwA`A=MFsX7-=F#RA_;|wLH77s?xeer&hE_!q$gA`LV4(8 zaT#@a5bX9eCE84K(Dg1D(2SB$@NJ{quliV2jlnWeXRK&Q-mot<%iBOSo`@#k>7U@?~U5kQcM4e5s;=vUF9Bo}}7*>JF{{k&2)s_GN literal 0 HcmV?d00001 diff --git a/thumbs/barrel_010.png.import b/thumbs/barrel_010.png.import new file mode 100644 index 0000000..21bdd19 --- /dev/null +++ b/thumbs/barrel_010.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://nwboqq7bq5cc" +path="res://.godot/imported/barrel_010.png-ed0ca45716a8fbc4149d53c7fbdd2318.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/barrel_010.png" +dest_files=["res://.godot/imported/barrel_010.png-ed0ca45716a8fbc4149d53c7fbdd2318.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/barrel_011.png b/thumbs/barrel_011.png new file mode 100644 index 0000000000000000000000000000000000000000..1f707212fcb78b86f057b5e8770c12c6a622a4a5 GIT binary patch literal 1718 zcmb`I`6JT}0LH&N>|LhV=1Qv#9dF)plvqp5%)*3F^5$4CIdZLB88Kralw38Dg=*2e zIo`>U(SbKNixO#Xr#VuNIikJZKj8hXAD-v=;rZeD?enBLIUL!jsHF%1z(!jevh#W} z{}UXx?oZ86cdiF0-1!Iz;P+sp005)gk}X{?6iyeNO2=5MGMlyhTd~N;nn`KTZoo@e zKY)uUvL(4x^eZX}`DlkS(%1_uO2v^{vbb4Hic=C2%hDuyy(>tspKcqCC$i3+GvyG> zBNpu)!)B(s%KW2bg>#RmB4(lnWpt7GanIxX(I@!vM0%I=sc|%2U0tIEug^T^0lcpR z+RlM8-h(yU6%4N+XqcZ@6t0kpTPl|>h$oYQvf`A1m6N%?)N1ckl^xZ~IlU>dECjjl z2hwQ7By77Kl$27sT@4qbjwBLkb0%+ecxsZ;Xj4FYL#z!8Td+yhSH;o>V!*m6ft>3G#w_C z>mZTZZE-F*>5NXM=J3j}j2&}ZtyBl{NdBoJ)n@UN=jdvf2cFV8zjF|{`G zhQKwdRZK_{r8Pt%twFz-jGR~?bmr@aC^XvKga+QQE~vU*>v3Zc7gE%|ADv_G=r}j? z!gbKV$I?j~ka})uVW(?s5NZjtH;qkG^NnjrqJR@7$z_}CB9`|ZgQit+W_>cAQIbcu zvS2UfK|_a^@jeTLg_XVGiiR4?r$i5wopusSksJ=^G=otvlW-XS%*_<pNj`~#bl^rfA#eUzVo1q1oEvlc;3l4c$oyf;< zDa_H28!o2sT<-rhCVI{3x4s6?H2EDIh3f|?QvWBn=iZKaOYme6M-!=4gsi@ z1@0bpAV6+`C|P;bXypf?&qLr(JgM=RS8^>A!X=i=m-@LaZEfItJ%WnLp&`k@HSeXg&03!>JH1#&FnsykZKg8FWa4)36V-6g=TW&CS^#JxtC(f9V(1dH-EDC zvuQaGNqafAR)}A;zpj|O^|+U_VywTu*<*uWuFf+Uy6IY=eGc~KBd?|SgRf$@Su8KQ zbWlLX3m|7G-sD?cPzY_W6C!c2GkV^&x9a)lY-^m9ltl>!_LpBuw7dz_5E8*C70LLp zhMfl6H;FKfuuw?-Q?EcwY=9*a-O)~QjcysGVu@B^=p5ZReT+olUxTJC+F`POUA zt9S33Cj0VG+_g;D#&98(C`kZ=AH)rs!|^K?+2L&WsUcBJ9jF!1H@85Z4^-}0N-7<8Zk5sP^D#! zr#G8}svT%@A5cwaz*ZQH4Q?@e82Kjurttky=2kn#wc*ROka0BEaLWa;QRj2X(Uy`D zQwTv{RbvLSM=L6>@v2Dh{U8D4-adN|k`nf=i-L{>1Ho_CtY+8*7*;lQi0<;)xSXd7 zlsBDuD~wKH3p3TvDlE-THen9Ov-p0DPbAtOvmSZ(4xArn_}C=AmE#9%6XXTo8}y=A z1v!B6c6z|-3$r5zp{@wPsd2#se67NbPxoEz<#%{A_v11$k*czlbe_7TKV=9-h6iE< zM~@oCujl|*A9#YgdQi$^jTpeT*-`S(f#~pn)%m`jm{&Y?-0e6(j6I#w)BJ5nyZWK<1NZtbYN-a0~eW literal 0 HcmV?d00001 diff --git a/thumbs/barrel_011.png.import b/thumbs/barrel_011.png.import new file mode 100644 index 0000000..6b30511 --- /dev/null +++ b/thumbs/barrel_011.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bf2orfs8g27pk" +path="res://.godot/imported/barrel_011.png-957b808a7a32d2d91071d777b4ec67af.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/barrel_011.png" +dest_files=["res://.godot/imported/barrel_011.png-957b808a7a32d2d91071d777b4ec67af.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/barrel_012.png b/thumbs/barrel_012.png new file mode 100644 index 0000000000000000000000000000000000000000..b5389376727f43152ba2796977cdd0a2b3a62119 GIT binary patch literal 2550 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 As{jB1 literal 0 HcmV?d00001 diff --git a/thumbs/barrel_013.png.import b/thumbs/barrel_013.png.import new file mode 100644 index 0000000..a0b6c9b --- /dev/null +++ b/thumbs/barrel_013.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://8wcuxv0v56js" +path="res://.godot/imported/barrel_013.png-fbb3bded70190f8bf9c6b2f0790f15f9.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/barrel_013.png" +dest_files=["res://.godot/imported/barrel_013.png-fbb3bded70190f8bf9c6b2f0790f15f9.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/barrier_001.png b/thumbs/barrier_001.png new file mode 100644 index 0000000000000000000000000000000000000000..f061b984858ac9390f97f692ead6ef931cd77677 GIT binary patch literal 1581 zcmd6n{XY|U0LQ-@wwZaTRLpwtbdHndag=GzG(#Hcl?a=M<67O6iac%RmLYT=uJZhJ zOEbGEz9*Srdsy0su5A?j+w0 zvi~&#wvk;f^u7&1VtmO&aAyEB3xJxGLOSRdSG-UnU>dmTrm@~SP>yL~a-+dIL^VG( z(0n@g+){x@2UT^N>b)Gxhp3xa)j-eHkYWf#-p-6y9$WWVoE;`;`BeK6qsy~%>Udjh zF!N(i2L|F|kD8UPD3WrgMf0Ph-5nek}e8pW5*S{Dy=V~ejt!52DZ1szf2l?xqpeh?nFo>m0drjdtN=Uc1B zE1tLqgCgO=MTgRolK$>T;Bvr ze14Kw`jl#v9eOap)tuYGbptQMug5PL0ouh=Hbu8k>d5kZjxRDm`gL6V`ms^ATzWA! zHZ_OIjJJ<0$DLB8 zdPK;7+!k$Zh9-wBLuj|3i@Kj5y6j?RRV@7d<^E!i z2By0QXoK8mBuC9BwBwm10P@!~z+hu|+)A%$OZ{>KHkG)~#>ALkAIpNVhfxxPk%jHO zg~H$D*vc@aGv4XO_?nYthb6C5i{f@tJ$iKb(2tOOHQS*`Tb5$volldyt8d8m}7;j;^4@K)}Spdg4-4xC^9JForlqV ztx~y4&!12}Yw{#ql0mh`lL#9Xa`G4kFdHg#Y4Gvp?h{2-q>K)xxc2Hbel<(2Trsta&;JU*$s`wQt~bf_e3AGV8oI$4_c4DMlvtlZ8Y zEG`lbEBAxH$u9YGYW>DSew8!H9ThT3i%@H`obr4U3)qWQwzuzo%Q$Y zM-~+o`M`F$djZ#=P1$Q*%?aFf$ALk)`{yNSVa%#PV(|>l?DTYeS4Uqo$eQR#N{z$> zikm4mDx;`g*w~Piq06}Xe)F+HPgl_iS4$Ht+i=U9*JqZ@X*E8WCn<&QGW!a92L}hO z&nPl+*pyG+n7trEaIelznc$n$;N{2&i=0;l@ne!T9a7I+Yh>WdKwf?4m(%`C`3*f! z2}!`_9Das*3iqNH;H7gQ!4FH|OJ(Tp6P2(b~cRt6wB4 z>B=BJ-N%B%WoF@THFeL;ouX%D?ET2*ZK78%I5*UK13^)1!`++r*Ost#*+kyvz>HCmI+v}7L2GqnM>Q^4|#5a zCjLslbjeA+3jZ0ti>6IgSBwk+ma>^*xD5NAUDz_lA3W6rs<$Sx@q{xI>-=w;Br3WR s{^;iW0d*#++6}6_G<|}j?th}MDz#<2-i|g)hmHRS6gO|u9U_hM4_2hXCjbBd literal 0 HcmV?d00001 diff --git a/thumbs/barrier_001.png.import b/thumbs/barrier_001.png.import new file mode 100644 index 0000000..dd3cbb3 --- /dev/null +++ b/thumbs/barrier_001.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://drn6mij5p6hv5" +path="res://.godot/imported/barrier_001.png-03e35352f861807cedd8f27bcb81da2e.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/barrier_001.png" +dest_files=["res://.godot/imported/barrier_001.png-03e35352f861807cedd8f27bcb81da2e.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/barrier_002.png b/thumbs/barrier_002.png new file mode 100644 index 0000000000000000000000000000000000000000..525111495a7b8f9d5a3246d32473a0996851c9a8 GIT binary patch literal 1263 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-HD>U|H$u;uumf z=k4A7dAGx4j($9RORV|S%scKUgiJXeSZv&Mqx&h#3+*M2%DnF`*-z#w$!X6p2w3n= zggL76Y2M;%J9rsZ*zYv|clPMc%~Kfz7 z+l&A4Jgoe{5OVGG!R|mkW`jeDSLD|JP^{pnyX>xYj`?Wio0^YB4@{CdcFtg&G=t-v z-t>U%AFCY?bqH)YyXL~%U+OyCeyfH5RIjWmtrDN*cFWPow<0)` zJkoxyKgya=$Y_1_;M#?owsiqbI&f!#y0Im*ie`Hn%Yk^oMa2yp_ih!h-nVaerJ2RI znHFAK|D55P!r0Q9{6pi}#l#SX26;w?KeAj8m!II8_*FtyL}_WgYNhVxKM!JRh` zcFf$noa2{n!jy-W4-LN6J`Up$?kK+`ZSg-eTiK#+;-}yiCJzHoj>#?z3~|fZKWhl} zF?i^+uY zN>DA9bYZ63npmAJKfkV?+2NPDd;r6AB^l@S&+9d&fRuCZ5V`nPQQKVp0+)loHiIRrgCFCB hV1_3mbY=cym$@1KsinMdHn0R^@O1TaS?83{1OS#IAkF{) literal 0 HcmV?d00001 diff --git a/thumbs/barrier_002.png.import b/thumbs/barrier_002.png.import new file mode 100644 index 0000000..7bfd6ed --- /dev/null +++ b/thumbs/barrier_002.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dbhbgk7y8j54p" +path="res://.godot/imported/barrier_002.png-70a9b4c4a6cd81f603b1ab063fe157d2.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/barrier_002.png" +dest_files=["res://.godot/imported/barrier_002.png-70a9b4c4a6cd81f603b1ab063fe157d2.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/barrier_003.png b/thumbs/barrier_003.png new file mode 100644 index 0000000000000000000000000000000000000000..22d927a8ef6a224e5700ac225845475b81825f23 GIT binary patch literal 885 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-HD>VAl6^aSW-L z^Y*S`MsT1++r#xqtofI&?({4z2w43fsWjMpuGNkgAtEemn>mu$+aD?L9dk4gVK;s; z!PEV&OL^fMsX+1Fv!oC5SRI+YB(urPx2pKlUj8ZfmU#YbpI+>j*Y5YmzT(UFglzX) z%nGqA34IJ_1RE@w4BQ!>aU76goT1E6Oh>`I^jpkd9$&nBTYBE^lH|w5Kej6{|M>KE zw#rJWa(a z>ET_$t;#<{7fipJwWjFGj(fAuW|Z|#T{!zeIK#?~TxYJURsZ|rymh0|p4zWT(#yFH zyR7(c@#)%BR?oG~2@gMBUbkM`{cCA|{k?h(&sis*m%e#2Q_)YNZ6l|{D_O_oK^r%` z``Ebj^{m*{-z&aWaDU^Oa56>Y_{L?MX8P{`{^#h?XQeA6F8qF4trfpp2dLl8Do4b5 zg7$&Av%4?dUzxr28rOzD2}|GKzqvEiL(Z`0sG`BflG26mzn{CVHaotv|LUw$fw4=I z9P{Js=oCM^3VQN~_Zq0*qMCCYu4L+EGD66MAt4h+nf-Uhdr{4x|cAn;|^ z?-}#YWxo58F;|i!;lw0~NgOJg=68Rn6xOgLDKzAQR9@*&JS(t+e}k`8zP-BEeC^Dh y%PtI>FGQWCZZMtcy?UQ%LnR%P2jRqdM?QYjioKpSwP%3&h{4m<&t;ucLK6Tj<#CJv literal 0 HcmV?d00001 diff --git a/thumbs/barrier_003.png.import b/thumbs/barrier_003.png.import new file mode 100644 index 0000000..062c734 --- /dev/null +++ b/thumbs/barrier_003.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://ccvfh73fkfikq" +path="res://.godot/imported/barrier_003.png-616cb65cc5947621f3ffa5b1eb50ee51.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/barrier_003.png" +dest_files=["res://.godot/imported/barrier_003.png-616cb65cc5947621f3ffa5b1eb50ee51.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/barrier_004.png b/thumbs/barrier_004.png new file mode 100644 index 0000000000000000000000000000000000000000..71096125872eb30498c95335e151d553a848d34e GIT binary patch literal 2388 zcmc(h`#%%}iE zC>zR{9GB9zT&E179p*mc>--Vl$M=W#`}KJJ^m_gBem>r}J=~q-Wi@000P;9ztk;%O z{v9}MYqw$oJGTT9<>h1#D*xU!1%QkK4r_NRu3)wRN8076%G@;ZFP1?_v``b1Bfd*0 zr%M(=BLkKGF$o$)Qp{0%MpILLw^#n7#8E&oJmL8tw%6=~-bP3tKpfaJ#}S%G>sP&O zWY%(?{=6nIywFhA*l@9QlfL{jCdP_SwG!+r|M1e}mtm1cl`7zQfm9a=!a&NF_J1*@ zOtDm~L)yr-mZ|^?I*hZ4jH!DsZ4`g8cPbj_n!48$5(mc1Y&iV_3xzzKs47Ui)`tz^ z=t{$gv!74qa*a~B*0mfC2Wm@&P})uN6Ld7>7`%F|<>{R6fR|S-c5FX4LKpGAVG1o* zA1)TG_i0Yx)0=bWmI@st=Z^%ACv^Iqt~zt z8-jq1m(#}QOkkk$4Si#7+U(E_vrhm?FRAxtcWS={8r#!T^$mplL|Xv9<>i%u4=ttOgZ zou?&j{%V%q3#S%X?$(UweX#(a26fBCrggQ&L-zubeE!e}!dXWK(A)fYv%mU)aQ>Q>#l7nTLIGcIvwN+kUdX z&Q1_ti@5g7NL5O+Blau1C7}t!_Ft%dyH7p#OjNw$inC&`dmxfy9C?ei18CtQN=R{1 zgAd;}uMax{1}mviuEkG85xz71iG!&7f5g>xjQBs@o)M(Mz6aq>`31Xr8VAK+zIiGt zUTrX%U{fenc}uGqP=_BeTrAvo$%Tm~)IG4Y~Nw*=OmogrGTPYxIA-zcgyyc(=2C z2Qar18z1E^D60P?`NCsTWrVT{sTwEm9LKm1EqWFbgJb0O!shp(1|}e2^qJaIDAAP} zI+#kZ%p4#gcJNFqBjxW3WYDnBMxQUaaj#J-rYHT**OxA*UvGS+yTIb7%|wj#ch`N7 zo=HFQH>iG&;Y!iX3PU8#RB6P~G>Jl|b<4~eCap$exV@>QDFhSN)os24G3M1oBvFUn zm<;f`Ni5kigK#>Kyj*oReNk{W8w)Uy`4H9n{tpXg_11X z#YxGJ$#$kx=;hs)IojW9>oqQNi{YDn*F}l8A>4{-*)#0f;~Jq$KeF9+{-HkMnx;1v zmv%o=^^IFuO#T&2&lYtdsG`ZDYG*H6_sXI9+pP>E31sqKVW^x?+kD=87@(cb8>^A- z8WP3^eqJ;JUy4BX*Ql9jDYsqlb$-t7~Nv$FmZ8p6${EQ7GJ?=egeZNjT zNY;{pdj7WN=TRwFOy%4gr5@L|S({PnA_2)&NrrnwcMYx5K<6$()llpyF;30$hn^)IVAAcp_UNwV%bfE9nq8@V?s-Gc&@BhVPBGhe=%;`ZpwQr8Hx zL$~^9BdzN&r5<%aeLpWl8N;%7;E9cwk;AHn<8W$5{nbWDmo!gQpA|018nN5L9Lkn* ze-Atblcd>^FwneAGGQhZ1p-iF%W#9`Lyyb4;BAEt`K5V^#t4A-h0kE>@Fnzss=~?J zT_;M#8ljkbt0$YqlRdRrO9@9f)(UOA;V^v9)FN-3F)=8FjrP5;(1`Pq=AoOGBX~asW$uDxKvy205 zj(p%l0^S|~SQ^6#Qz2PAoqQ>sFtEQp0WT3o(bc^E>+ljATe{A+Z-Sw>QhVRlQM(r9 zPY+2#3OweLmfLc^ui9Ca-|hf@O#cmsq|ZNRmu1grOT_Ud?YBx=udILncwzLIr({9g;^)Yu=QYlU wz)Sn$TfqB_EG6O~Xn79cIT9$p|Akq!(JLsc@R6f6ZoNqW=je{Dw8tm^7jK(c?f?J) literal 0 HcmV?d00001 diff --git a/thumbs/barrier_004.png.import b/thumbs/barrier_004.png.import new file mode 100644 index 0000000..6e3baf5 --- /dev/null +++ b/thumbs/barrier_004.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bgc3wwy6b41b0" +path="res://.godot/imported/barrier_004.png-956d7320130d7ba7733eeaea925df58e.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/barrier_004.png" +dest_files=["res://.godot/imported/barrier_004.png-956d7320130d7ba7733eeaea925df58e.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/barrier_005.png b/thumbs/barrier_005.png new file mode 100644 index 0000000000000000000000000000000000000000..88e1ddab7e5118f5db7e427f0b33c5b74cf54647 GIT binary patch literal 2404 zcmc(h`#TeS1IE8QG>oxFqzF^wRH&v!H6uAadz8u)g&gJ- zd59G`WX`7;4P_{s!-x@H?;r7A?+^EVU!ULZpYH2UaJ08ZA(fE;0FN3fp#00U)JjYiaHp`CRb)!ex~c3U_(M-!e*u(WLFKD# zZ0vfLz^gX2`**~Q^5@A(Nq2Ymm+#st1SP9-YBz&dzx|N4MGaCES9`@3!4wS~_a2}efzD<)seB^DrXtRxKNMbf})?*36-o?+)>I41O>yjP9O&;AnCN*51>rhZlntPb1F?cp}IAo$z zLuIzLy>_h9MF}UOoqLl-XIIwpgDIp9JePU6V^zi=jd|Hc3r$u{q`&A+#=FRoQs>%? zabsL2R*kck!w^bUE6`slFt{aoA)Oi7yY?G{p$KittL`&K=3&Z>g7(q6l|xYU+y z@5q2qJy-Qb(&ZE)4;$j;&z*QAw-6b4JeOErrzvV8rdow~EiO?uxV~WU2m_j-Yb}*` z06d=h@`o1peLXt67~B8*_srAgTlbziQ8Nycr`{HS6ReJQjYE&TC`-TdZuqSlP}N%w z>{qH@TXNuihj@E~=S&4!b*;jk-|B{~ipY*Dv_`0%qU(Ophf7^Qzs&tT^DO;S*ZCGa z@1V;P=FCdwxaw;6xEYdlUU)f_MWY$$W4Ah&0BnOc1mtZDwN=#X&wD;t4)fk`M)2O~ z@f`YhNH01)<(kWk`O-^P0tFp{qs!! zeO2{PY8b3xA>XJ+jC$qDI1EVTzQLD*pkHMqV{;q62!awFeDtlao<>924OzA)#%YBR z?*r|U$h?icmACss=@qk4Dn|?VA9|q58cxivhzlQMcx!>lti306^4F_+!h_6uw=@5I2MdnEMu`MJI*G`DDL~RnojSrWABGNNl`a> zX3mq0G^P=xd0h%4Z7>2@P;_y!i{0 z*L|*Mrh3SIJ*mEbqp515d{!^mzS(NCQbqA#nx8W*0b%D)J{3T<2_?Ux+DhB`?n4O- zu2o%Ld{t_KuNf(ZqQ@g1ggVe#XPvfD7iWKDzvp2tWsR95FlbvGc7iPp#X zfvi&=wlHF%glqa3JsfiKr$iEBj^(GbMGdIQ=-inz`ce1%h`jK)$R!!rZq%VqsUbCt zrym8h^X=0>qSU%MI#PdN;3Dh^9Q{bIf@wQ9ZL#$IWMv`-g(%ATQP zzeOXtJz<0{u|ig{ji%3qp8jU4U9 zmCjGe2MoruSU(^D{nS_M9Xkp$OPozIFs`jDVUcU}F)r@&;ErNcIVuCauuXBANV)OE zPm0wcO-yKw45&FLG!f;=LpQf;3g-}wxPe}%KFL`PDGGaFN&O_w9Q9oCsp(^Px~MO0 z&=x$JVW6Iq95+7wawn8`#?ax}OBEw^E&geZKQK24P>E+tb3KtwjX!7qEbM%chUseH zWIJj3x#~P;$1xcG+bgvjoRu-=8Nk1&|G6@U)Wnjs4+W~;Ytrxy=_kbK4lOs2e zTK^+U!m2uO`s-(D;=x-^TB2L`A;1UC_Kbx8rGYJi!PCmbR?5Ome&!?bzgPJ%MK}Pm zFP2jX8PW$2oz(_-cu1D2N}7FZvQl(TnV2wEixi$vA|+dBtO_WjN*_r_f=jixzwLKo z^%nI7jE0mZkiuSPimx?WyL1$HD_tLPS#n?`0@wI&roTw0#;lgBotB_#rwsjgdrZnA zKFHi7TyzTpz&!%mn8%tAHoklnA9L>_18+k?b0iROfT3nwl8zMf_}9&#XGEhqxq}yK zJYB`gm^buNYkH*_IsRvO&%83Ra=#pZI#KLvekOYqi@XUaV$4=?5I zl`wfKC!+%h5t8Kfr4XUd?(?6`*nAi)4Qdg)((pIA04(NLiU0rr literal 0 HcmV?d00001 diff --git a/thumbs/barrier_005.png.import b/thumbs/barrier_005.png.import new file mode 100644 index 0000000..fb1ef8f --- /dev/null +++ b/thumbs/barrier_005.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dmkxussbxmumo" +path="res://.godot/imported/barrier_005.png-270d3266428b02a1bd0bb2fb38555a3f.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/barrier_005.png" +dest_files=["res://.godot/imported/barrier_005.png-270d3266428b02a1bd0bb2fb38555a3f.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/barrier_006.png b/thumbs/barrier_006.png new file mode 100644 index 0000000000000000000000000000000000000000..bea628a02ef6b1306d521c7f21b125aac56f720e GIT binary patch literal 3050 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 Q)A9}iv<nYOt1S^F zMy-}!<65y-Nob9GLw$Y!i~Ga-KIikp^TT`2`<(M6SeO}}=N9G$008HWVEV{2#r%Ib z+0S;Dw#&eou=pbl^#E1Fq8k7Jmy(gbu2oR(_Ux38qah1sm!7NQF~38aYtpE-gz0f! zJrCown&Z~HcnK(Ft>hEmf!Q-g!*=8(u-( zX@=PcKaYR=8H`i)BOfX|rs_vYGJ-euK@~!YC2LXA0SWo3A#SX_kLRP8?CdZ=oE41g zeT-PghUcM`4xhqJ4EoxV*A@6iN$3;L55>PVIxQZ<@GXDxus|5ch z@R0kgi)I-Re=cBW6-jVouu7rQ5s+f^Rqx2I<1E{ zcoQ6Z(G+4|jn7c>Kt z8f@YRWjI|GpNrd0w*NX7*e7E`cCfNhatA>_ny&YQGtQ{E@-IsH)N7eMea3lX_9x*cu}(tK;OmNdgYso50m29>ZCq_)I+qMIL=Z?|dH`VyDJ}QVCF9 zVk8JBgeI3^?QE#6zjMh|O6|v+%Ay>J`TgCKe(Y^wdk^>~dEI)85MT82Y836-WQoO^ zZu7rEc9#X9P=sP#vqm&7F_y|UjL%uw-xV^$D=Sdy{P)5*;>^E)yqBOL?O(qJ+md2E z(Y{4*iRafC9KtzAq8)ewCNzHaK&wnMG}KK7!ur=+g;`I++iU!>`CgUh{QZBTvYZNw z2Rwr07O5oNwqho^GFyw1y)4*kE)!WEEM41MU?M^>7$T-OC8r=V>z{jJC4H~_ zxBzq272pES7gS`QBh#|hhIeD9Lo>uLPN>H*K8Pv!xRt;GujtPMbBpS`uE8Bg3(X8C zdV`#MZ=L-Xj9-@qsuRzU6M!5p3WSqbf@S%Vp{;*D;Q>lWiQ?qb>hjCVwv=)27uz&9 zxACi?b$>{(oc8D4MMAbz8{H6>L4!l&q4j?=I~U@I@tEB%+ZvQe>|**iTwY|%EOTz* zIQHq*zjik)z%{2WS^p`_|+b{Bzf(@Z1Y?TADb6`5dJ*t>CV<-oiIy5)gCMZDwNMqe~qof;)sja2N*)aiZ z>a1X%yU}s!BQj}RG}$wQ8NRi`o?tOBOPuJ_u2QH`#BkeN3%ElO#%JdmQ4b}aotjAV zQ{Vw>2Ti3bH|-a}RB@M78uNw)(z+hE0(7@`JPnTxcr26yr@_?&R0|Y3FnW1bTd)!< zBfbOdS`!9oXA|qDkeI(XK4d$!|A<-j)^@h~wGxNeJDiRtp-~M-l3Qk$<`P@3G3646 zE=wx)4I8=S_AnxsA!>37NhP=Nb^eO)_lMW}`NQk+ct74hydRI(D~aUdAcxqC002PF z$&pCjCgWd0vfH!K=1j*nU}0nj0>JP3Wd;Bs(20omxWbz+=t$A>Qo0^DHNw8fMBN!2 zJ*Eu343!kuUo?u5w3u(o6dQ#1q*`X(!kZtw1bRcC!R8q^<>XO`bW_1Nl~hA+x>4OL z@e3f1g#E>f*3^7*KgzG{Jhnu%I!^Hmux59DYhJkh0!8}%Zn=(%dT}kHPP%~(hw&7o zj_86RF3>nnzTQHE5k>%}SU}hR+UT8&+QCmgMO`r`!jy0x8dB`RAJ=Uohxrk~!G*6s z#>ra8&T8Y7?&Ttl(1X129pr+_^<5ROJ{3n6bSK;f<4&E9+k$yqAoHeurU=SDv`@xsp zdNyC=EffL0rz&_bL^Tg0jptMAY;{^p$KoUK9|hyXKs zbn1QJ=phdCsZN4eRKZknM8rr8w(xE;uCWV?+%pvS`V4CA^#o}d(|A>TQ0xd|UXlQU z-e>US{TJDYtv4clu4cNtDFoK+ULF{e;M22_ADg}{y^HPdU0o~ zQ+Lf_Qmc`@KFKn_DqCcNFfaX{b>2a>OmJnc1|W>#i3gC`an!$ zBJ@;4+C;~l<%H9!+2}qU?*#{djx3*N=t~BX#&Ts9l^RSO@j{?yKZ>r`&0Gz^rq$2T zHmvr$um)XZop)gJzVCS1qgJkOv$YuadBwek=d}a?m7dU77@ozoS2x0Ec0)t8ogjs& zBW0jjk+~{Hkn@QF)kJmK286TU>jVOzRF3fYc7(AuBGA3rAv!bLdT2lcl!x)D!(-`@ zam#aP`dD3(Ys~mBtMW%^a17Yyhk;50+r5}lNzE)rGeNb*ar7~{3x6H~!V>a6-jnu_ zE#D=tdTenA`#WhK);hQpe20+i0apx654(I>3aEdy8G-~>Ivq9>4OxaPiprbzqkEy8 z$>Z>L;0ZnLuH#`op2oq&FcOV^;2A-Q6T7@9oLWMcGoadgvMK8BaMfdi^EZpS)~Am; z$&B{-8uP`r-M4eV%5VV1Gy~m^`r_L4iYqf+V!dN1@l}lG4}WQupyI2Ot54A0aJ32d zRT5<=9dWSfA9#qv>Jt$(apdQ`Z@A6u8TC|P?}S}+I{Bu zSNhNJxQ7lzb^Q=?2F~fMx1ZGnfS(^C@&mig?3p)#!>ATB`Kk)WKwv$u!AjjZJ<}4| zC}k%E+z4GeGc=buJZ`hg;Zns~zV!roMW85LSdK6ne~d2tI#O^pX036GwvRxETPWnU zq-}aA6qUuxlL=mZCaB!IkO?C!y>mbNij{OL7FVSR3+ih`*jjwLSahr>oC`d%6bVTp z#boFfCm*W~X=+@I3b-r)m z*&U9Ig3$HPCN8dBA@lRsX{H+HsUCZqLjQEEruh7!kOKK8;j~eoGZS4~W_MF! z@U}EPfzMmL?2c6Bh2@$}m4p5ib567b2hF!~8GPQ?`Hr literal 0 HcmV?d00001 diff --git a/thumbs/barrier_008.png.import b/thumbs/barrier_008.png.import new file mode 100644 index 0000000..146ff73 --- /dev/null +++ b/thumbs/barrier_008.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cgio2t6y3iuik" +path="res://.godot/imported/barrier_008.png-bdf1979ff38855e76f8c7a5e87b6501c.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/barrier_008.png" +dest_files=["res://.godot/imported/barrier_008.png-bdf1979ff38855e76f8c7a5e87b6501c.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/barrier_009.png b/thumbs/barrier_009.png new file mode 100644 index 0000000000000000000000000000000000000000..805fa6fcdad8afd6be2d1773153b2568daa65756 GIT binary patch literal 2102 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 Is%?+^A7@&uQvd(} literal 0 HcmV?d00001 diff --git a/thumbs/barrier_010.png.import b/thumbs/barrier_010.png.import new file mode 100644 index 0000000..26743ea --- /dev/null +++ b/thumbs/barrier_010.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cjs7nqt4rl4qr" +path="res://.godot/imported/barrier_010.png-f6f1216f1256d287e14df4fbbd041a2f.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/barrier_010.png" +dest_files=["res://.godot/imported/barrier_010.png-f6f1216f1256d287e14df4fbbd041a2f.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/barrier_011.png b/thumbs/barrier_011.png new file mode 100644 index 0000000000000000000000000000000000000000..506a77af31f7d538e0aa8f6634f4a1a038615f77 GIT binary patch literal 2168 zcmd5;`#;nB1Ac#IW^}M+u`?Bk_==csa$7UnTubXh<~nvN(peqX%5|;_sqaA~&Zuyb zhB#e#HQRcP;}Q$usN>f8x~(-Up|$4g{1xZ>!}B~pJik0YJgTDgh0_86XnT8+ zk8f(m-#{WZ`2{heZ&RSSBjYMz6NMEiENyYBqLcU_Hv7PScPIa5s}cL z#m}=S96}W8J1MXeKRBGl!5(eWw<`>IBKV|KWSk0{GPM9FgPg& zXi;(EVADW}j!!;!R~Oz)@ol_bu#T(U-{|kC=yAv`OP@Y5_;$9qqKK9NrC<4?S=q_Z z^@!mwm}U-awJ1GJrP!6o!U{4>R0aF0FJK(*Sx}%zl?xuGOHfK%iPC?c4$vh1N9?2< zqitm}A|8~Cn33)EL$`gUzBv(bxA{=Z=L9l4Lueto-IR7v=0R9q?&8NI`h9>A4CG*U zn|vQ=IP4Qph#hT$TkrRg6X)t9^D5&AP*? zMaCSq%wLqzwMq5D82ZysV_lktBAL;eNr;0wSL!@6aiE8UkqeH>9wS?Wv{Zdls-pHq z@nfBbaSP7Z2QJ4?W~G1>uhwkd=TEAaypU}S_1gRvGV=^$3d?6k&z002_d%mo%HHDQ zuvSC-UWoTmX&7j4y;MgTPK-6Zh6&FEDl{;`--xfJ{74cavbOt1f-p3c;rcPAmYxf{Pn@5*LV zDAn7a-yB*89%?NXleS^~1>V0WDR006!}sz%IN`)S6LveR3Gvu&%eBeWdHAWNx$;n0 z%9m$ja?S(akkHXUZY*wON5x~xuyb3eLmg`kIiR+$Ff?mT!pPwzgGT^in|S_P=;W4> zzM&JCon-cxEb}{+fJN{B5H|OR82|*8un7Pg;wmb|c%4G3wrqNLih)B3uxh^WLx_r4 z4wvDV!{b~Bhb`-@yMUG`&kIfk7${p>;5lMWRjsr{b@YB{xU5I`_*UXbq(#si0=YP= z+xidcb_`W74xO(_*jW{KabUNzhNJ6&DVYo3g`cpv*$Oz@ZB%OzT@z&+?lv?0f`JfMH{s8fyUC`h+ zENYi_?f-pPlr}nD^~MWc7BmKhZfVmNk3>t_YsMLpg78TxM0A)}3z`?l|2a}NfAS0m zn1z267=jF=(8JNw?tGz!RYOK^5IlyS#rh2)KsDlR??tTKBqN<`SqJX>QX8I1JfSzeBuu)At=6;AZ!S$s8xL^c`|awI_31t z!<;ACy+zUV!hKua4#jBy7~d}WY7e7hm7>|AqoTEo1NG3^vi8b4Db>N+FW_bNsaZvN z5>Fy@s3)>p{~AkI?)}iYtW)Wl&Md#(js4{Q@~P3-DxMH(jM^Ns-5B zRt;LE_P;h*v1kTv|0*4JeTc3ndBv%C>kQ6R4b!=@@tpGOI((3)cyo1drK=fJJ-Oz* z9f@yyffEt8fp2g63WP8J cueNa##{P~sl%7?)ck@aBZ;Bt8>rT)7A2fl)>;M1& literal 0 HcmV?d00001 diff --git a/thumbs/barrier_011.png.import b/thumbs/barrier_011.png.import new file mode 100644 index 0000000..1d87fd4 --- /dev/null +++ b/thumbs/barrier_011.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://j0rac170fjwn" +path="res://.godot/imported/barrier_011.png-787b75d54921f93ff80ac93815d9255f.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/barrier_011.png" +dest_files=["res://.godot/imported/barrier_011.png-787b75d54921f93ff80ac93815d9255f.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/barrier_012.png b/thumbs/barrier_012.png new file mode 100644 index 0000000000000000000000000000000000000000..19e3578c85fd8e4ab724f7f043e4d4134d117019 GIT binary patch literal 2066 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 literal 0 HcmV?d00001 diff --git a/thumbs/bau_boden.png.import b/thumbs/bau_boden.png.import new file mode 100644 index 0000000..5508187 --- /dev/null +++ b/thumbs/bau_boden.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://df5wy3ry0lc4m" +path="res://.godot/imported/bau_boden.png-16f161cbea0d6be194e9e46a2048ae39.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/bau_boden.png" +dest_files=["res://.godot/imported/bau_boden.png-16f161cbea0d6be194e9e46a2048ae39.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/bau_bruestung.png b/thumbs/bau_bruestung.png new file mode 100644 index 0000000000000000000000000000000000000000..ef51bc73cc5b845167871a8d26081279f89358dc GIT binary patch literal 1134 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-HD>VA1e&aSW-L z^Y+eZKjA=zV;}Q-xP{FZG<3$q>@di?vyYiw|ADoH2bx0 z#j5<)g=RBcEaUTMEK%RndGVfPQr$6@jXUD<1?reM1mupNc`H|%-XYB}dGTK3BY)29 z*tloMzUluD@I6&;h&lS2li`ibT&eB8Jv_6u8D?}hFf^$42MREG+<#Zd)Dcj8S*>d+ zZ@ohWrvgJk^2^Kx>H9hN^EXS#OFE@Tb(lyqZhT|Fq0cB185LfAyuRn@$9Csueoklo z?9HZ4H~+SIZVY23x59m$340Q!-F-KAhJswXW6L*ghWvT=4!`QJXO>$yV-M?ts^5kR zb#hzQSv{I>vFhY$e`e{k#SBO9P2BeV@9PIkCj5PN)|hD560^Q(4_NXXOX_*1pWD`$t!LblZF1gvzChWk z1eZsAm6fHnuiwY45M#L2Dj4!L!tdTKTehuC3^O)623%yVF3JAhwl_L=zu*n4WyZU4fG^gOTTv2|?QRC%v{>5WhJdCc0?n%izMGemK0a^5g;H;)Fx7HOHL z-OTCQS`2U5nkUFQz81Rhu)NWMYeDQxf9}3MdvgYbw>c9^f9&f2cmDp}-AoKD3xex8 zzShi+U{H#zk1DAAqR6oEuAMZG#jM89kM$Wmk2-7o^j^ZM&Y=0K^}*o_%e)!bGA3MS z55IobpDAW9P=CUMU7H+Z#F}0=^K&#@ qJtR;gQRBeCb#nQ2Hd<$|zwAs-cOx&)=}!a}APkVE*dq;uumf z=k4s%Ww#7OT>BN0H{JT@a%l}~$%X&_TUs11&3~a>BD0`*fkN`h6Z~1P=WSO1$gP_` zw|0HX1CerIOU-Mlg1p{JWg!JTP>GUJJf3{N~5ic}aZg&Jfy9r^}VIDmUY$@(3) z|H}L}b88K2SX%w}M%uK7paz2){?#lcOh*oVH}G;$bqM|;XU4gLMW8f;<;2Q5{$TM1 z0tw7D{C$Fr(v#A=W9x&Cq|G0L8TB9UmnD4{wZ6S}qf5&-Wqdywv0lToNr{EyusqB38|&Ub>lIum!l|ZzVEb%? zn(+Hl8@RX3{yBSnIfI-*El}7Yev;tVNX@kU!4mHleu?slVu=5%_pwZGIrkHzlCRZr zAC_O;@qhO0jrj{Yk8fvf_?)?*i@9Kjf!`;o@ShXgPw)5_@%Q|XD``&xXOysiu-T_O zDR#ljfVwSv_v!V_(^RZkAi&tLn5DB=HvY4G|8|c5PG5g#{+FEp`MAu?Bo>B-<9C&A zWZ!3Pi=1S-zez{4W`O}C!-JJd2Rm1<-)_8W|CSGpo%&3{6`c3t1?K9$U!=Y7^1(T- z$-Vs_9&_#4@u}&%$aO}ibGseiB|n^SchQp%jfYqn8kXP9O|Ad1a>2r1-u&_g3Jd|$ z84etXJ&^XpVPSTIL|oI?n%lYa`UN9@L~`CsUc}rIvdeM4o*FMmIe%-u6{1-oD!M<2|&rw literal 0 HcmV?d00001 diff --git a/thumbs/bau_dach_ecke_aussen.png.import b/thumbs/bau_dach_ecke_aussen.png.import new file mode 100644 index 0000000..4d1e3b3 --- /dev/null +++ b/thumbs/bau_dach_ecke_aussen.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://djm3tfu1hf0wu" +path="res://.godot/imported/bau_dach_ecke_aussen.png-8540e959d5c1b3c2880a370a7918ed4c.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/bau_dach_ecke_aussen.png" +dest_files=["res://.godot/imported/bau_dach_ecke_aussen.png-8540e959d5c1b3c2880a370a7918ed4c.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/bau_dach_ecke_innen.png b/thumbs/bau_dach_ecke_innen.png new file mode 100644 index 0000000000000000000000000000000000000000..cd24ae4425b6b5112cf48c8d5c891626ada7ac4a GIT binary patch literal 1299 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 literal 0 HcmV?d00001 diff --git a/thumbs/bau_dach_giebel.png.import b/thumbs/bau_dach_giebel.png.import new file mode 100644 index 0000000..7126d96 --- /dev/null +++ b/thumbs/bau_dach_giebel.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dcja1snb22xuj" +path="res://.godot/imported/bau_dach_giebel.png-2fa317ef54f706102717076165b19ca6.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/bau_dach_giebel.png" +dest_files=["res://.godot/imported/bau_dach_giebel.png-2fa317ef54f706102717076165b19ca6.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/bau_dach_giebel_4.png b/thumbs/bau_dach_giebel_4.png new file mode 100644 index 0000000000000000000000000000000000000000..385910f5ef35746fd6da1a1290f0ce59c378c3ad GIT binary patch literal 1122 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-HD>V3F~3aSW-L z^LFk@zdH^REvK1-JWd>Hb$>9yyG^EO_Hp&+9pW5!BK#y3PAI!tuwSm2_&xPcd3dc* zhvbWci}tO{tJV>${rgS1aY5?VFN__j6B(X(FchgUSPC`Ba60s{D7Z6CP-Z+qXW=gi z#WKmoGWxX=lZ$qIVT@R&m-GG4(ff;Q<<9ANGzitE{di{aEsm**(M-Om(Vh8NwI1VA zhSm$8pZu@B#2{JI;?!{K!0ZB}5`lxy#W=zm92bUP3}lH{<#1~_$+TYCal+}Q>r7|l zs%B0z`>>I9k5IziTaPYZ+`W{4@kZX7$qwO6?UNQ%TzjB-k7GkzE+a$#N51}#c@Gz# z3{-6NpWeM!a6wNgXU#!w#%t`im+~*1JBelAmWE2kS%>O-djC$eopN9g!&#RK1HHyl zAMS#A^Z%}29(%p~`;L9P_3dpZu}sc;U96wHm-P%+LEQ(21rh~zKYI4*P6(+nsjXL- z=aCTBVD@YKfeQ}qCmtLuN(f>w|NS}Ue%RT6J-@_eeCj&eaJ}kp;cDFkzlNkAFYm15 zw$E-{v5fWEtR`Dm1D!@o##5egThILY6BLlsSo>u?yX^fYO~!rlc3*B?&G$dQ!Pd6A zdQR_J{$*L*7JA3}7WZyz&}2LnbN61TT|D2vPfxjH{)ARH>N)mLUijFfS!hO$wMAFM zeeDtQedcVGEZJu(po8<0|M?#qY{Q55GVEE@#&ichSn09-9`*-;E0!i=h z+%s|-)@|O~$MJG^Yw#T#qcyy%mj67udF}(*Wl{_$q7pbVxz9NNH`D0bAYqpf(D2bE zfBy1)=?O0;C7ISJI50lTVO+4DrSs(n#>Le@Nrp+D-d{iYz$qx z2G=FSgN1(x*$J#*U?})m^y%AIyZ7>6G;0)Ys4h4$NB2S8?d=a_51KJ-m@nq>ApeKM z1Ewc4A8!$0sH>8(bJ)NVvu{qq-e1fKx0W9G{y^4*_rZ)stWKQr3W5sz#U*YtDYo(p z=rBsYJgUf0(N+HA#^*-?83(O3q!=X1J1wq!U{qoZ+Qj-`<>NSoCm$GBsVd|$mb+bW zdvVbEgw%o^ifghNr+r{_VhnmUooU$z#!adR0=J56V12KU%b;+dY0X3CCAYq>0 l7cg&NP+_p8O=kPU{`Qr%KbPP855Pi$!PC{xWt~$(696~+)OG*> literal 0 HcmV?d00001 diff --git a/thumbs/bau_dach_giebel_4.png.import b/thumbs/bau_dach_giebel_4.png.import new file mode 100644 index 0000000..19913fd --- /dev/null +++ b/thumbs/bau_dach_giebel_4.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bt6lbs34ymm1a" +path="res://.godot/imported/bau_dach_giebel_4.png-f5b5c10da45fdf3193cbf9e3d48df649.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/bau_dach_giebel_4.png" +dest_files=["res://.godot/imported/bau_dach_giebel_4.png-f5b5c10da45fdf3193cbf9e3d48df649.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/bau_dach_giebel_6.png b/thumbs/bau_dach_giebel_6.png new file mode 100644 index 0000000000000000000000000000000000000000..385910f5ef35746fd6da1a1290f0ce59c378c3ad GIT binary patch literal 1122 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-HD>V3F~3aSW-L z^LFk@zdH^REvK1-JWd>Hb$>9yyG^EO_Hp&+9pW5!BK#y3PAI!tuwSm2_&xPcd3dc* zhvbWci}tO{tJV>${rgS1aY5?VFN__j6B(X(FchgUSPC`Ba60s{D7Z6CP-Z+qXW=gi z#WKmoGWxX=lZ$qIVT@R&m-GG4(ff;Q<<9ANGzitE{di{aEsm**(M-Om(Vh8NwI1VA zhSm$8pZu@B#2{JI;?!{K!0ZB}5`lxy#W=zm92bUP3}lH{<#1~_$+TYCal+}Q>r7|l zs%B0z`>>I9k5IziTaPYZ+`W{4@kZX7$qwO6?UNQ%TzjB-k7GkzE+a$#N51}#c@Gz# z3{-6NpWeM!a6wNgXU#!w#%t`im+~*1JBelAmWE2kS%>O-djC$eopN9g!&#RK1HHyl zAMS#A^Z%}29(%p~`;L9P_3dpZu}sc;U96wHm-P%+LEQ(21rh~zKYI4*P6(+nsjXL- z=aCTBVD@YKfeQ}qCmtLuN(f>w|NS}Ue%RT6J-@_eeCj&eaJ}kp;cDFkzlNkAFYm15 zw$E-{v5fWEtR`Dm1D!@o##5egThILY6BLlsSo>u?yX^fYO~!rlc3*B?&G$dQ!Pd6A zdQR_J{$*L*7JA3}7WZyz&}2LnbN61TT|D2vPfxjH{)ARH>N)mLUijFfS!hO$wMAFM zeeDtQedcVGEZJu(po8<0|M?#qY{Q55GVEE@#&ichSn09-9`*-;E0!i=h z+%s|-)@|O~$MJG^Yw#T#qcyy%mj67udF}(*Wl{_$q7pbVxz9NNH`D0bAYqpf(D2bE zfBy1)=?O0;C7ISJI50lTVO+4DrSs(n#>Le@Nrp+D-d{iYz$qx z2G=FSgN1(x*$J#*U?})m^y%AIyZ7>6G;0)Ys4h4$NB2S8?d=a_51KJ-m@nq>ApeKM z1Ewc4A8!$0sH>8(bJ)NVvu{qq-e1fKx0W9G{y^4*_rZ)stWKQr3W5sz#U*YtDYo(p z=rBsYJgUf0(N+HA#^*-?83(O3q!=X1J1wq!U{qoZ+Qj-`<>NSoCm$GBsVd|$mb+bW zdvVbEgw%o^ifghNr+r{_VhnmUooU$z#!adR0=J56V12KU%b;+dY0X3CCAYq>0 l7cg&NP+_p8O=kPU{`Qr%KbPP855Pi$!PC{xWt~$(696~+)OG*> literal 0 HcmV?d00001 diff --git a/thumbs/bau_dach_giebel_6.png.import b/thumbs/bau_dach_giebel_6.png.import new file mode 100644 index 0000000..ad9ebef --- /dev/null +++ b/thumbs/bau_dach_giebel_6.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dbvqftv8ptl76" +path="res://.godot/imported/bau_dach_giebel_6.png-3e64c0259033a9acd1db41d449df7982.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/bau_dach_giebel_6.png" +dest_files=["res://.godot/imported/bau_dach_giebel_6.png-3e64c0259033a9acd1db41d449df7982.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/bau_dach_giebel_ende.png b/thumbs/bau_dach_giebel_ende.png new file mode 100644 index 0000000000000000000000000000000000000000..43f9adf4ca88841f7d957008d2183d43b0c06c14 GIT binary patch literal 867 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-HD>V3zfCaSW-L z^Y)Hyp0J}#+sAT2Sys&#Cs;4Fm}J%p7O~H7HNK(#km-j|$+RS;pxK9_((T{Om3*9G z`u}^Sia?9P+7JHkdl;AQ++BaCJLk8-cjgOw7!TMm%wT8u%#a|*aE7^|lEHwV;Te?# zSFvx1xs$bX$K2nBtJY>Q+!dE&nI3A|@b+}P=kLen0#m|G8wzVq9=-%rS6lh^Z_Umh zR+lGViM+}%Yp1+|Lnw1bGOM0G3xnsaf0e%VLcOcx4(v>B5IwQFisAUIk6aB3u^bFB zZ2I~v4S8!EB14%Y^2`468?YV?BJ<#$G~w;T&O{%ukp+wrUcecT-**q+7kjZ7}hxKdd1lD&o&_?P z2){yT7V8~ueuqmQjP3`c#Ta&Q&pXf5pc3}L$BdyU?0{e+FN5bv(SkEv2Udy}*mJF6 z@CZ8GyCIx|;s5VhR_h%&7?y5i%4cP~Fl9YMKDR0>J_z{9#naDp ze0yslL(I#Va%-+b3=w~;u9=1%SZlzr^PdIh$z+1lz#s#|EjW@X>7$ z0=JkZ2xVXJxzE06O@nE}Hcgh?!0-jYCIyfDkd^m!u`*1a_=eE U30Z%h19J_7r>mdKI;Vst0J^14rT_o{ literal 0 HcmV?d00001 diff --git a/thumbs/bau_dach_giebel_ende.png.import b/thumbs/bau_dach_giebel_ende.png.import new file mode 100644 index 0000000..c6a9d54 --- /dev/null +++ b/thumbs/bau_dach_giebel_ende.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://d4mwoant504rw" +path="res://.godot/imported/bau_dach_giebel_ende.png-c95a748350e9d9a3ab4f408ee390f044.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/bau_dach_giebel_ende.png" +dest_files=["res://.godot/imported/bau_dach_giebel_ende.png-c95a748350e9d9a3ab4f408ee390f044.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/bau_dach_plateau.png b/thumbs/bau_dach_plateau.png new file mode 100644 index 0000000000000000000000000000000000000000..997db212d260d2da0fe41f60fd0b13166d4788fa GIT binary patch literal 1439 zcmchX`#;lr0LDMxF`K0@*NTmhl4&_EDQA5}Y?MaMRLXKr33<6!s>OHKaY>P!&@0z; z$|baNIW;+)c4BSEqB6HM#ORP|?$_h|59f7WujhH*KRwTnPYT`BZ9Q%i4gj#8Ms@LC zBl54YDr@?f{_S)R7;>ToN>E~_qr}lDmox@2h@rQu6b4^jnno@D`y{3la4g6TM;j~Q3#(H~> zL}vX!!=zCrT+QkcZys}Z3g zZ?7J43wlKHYq^@8FyC+qKmCHv2(#LtLJZVnuMBN8@<+}uWM41+P&Cy$Fc{j@pi?wxr2(;#+J_sT(j$QOKb2fih%JNSo{uFB9 z$8);@&e|vK?km9bSe7B>x{trr_-+JJ+UNR!yu;r$&*wC`T2EYi41g0#O+P)_hPgA| zvM&CLc2@r<#gl84ggyGQhgcU?y6Lb<9*ei>4cT^tWaN(M<8)P6yajfFL=uci|MY#3 zF=-JR6)RBzZiV;)9^M_D8MvP-CxNK5M(p$P@7J`bMV>^P?SucL2B$%<@|c>mI@HGhTdSI?pKG zM<<)lWd1gq*MV=1`GP-{6dAN@5t>BtnJU*A(Csk{f1MO=mBFp9HKX2aFj;pbRV|J& zgCSt`LK3M^y@yk3GDMLIP_C8z^g zsnf;`!0g~V-pM0ows-B6;JGNZ?Ka7kVWQZ~kp>IrYVfWM{_3nBT%{HmKYTY-iHpkh zPk*c&Mb01ZuZp~Sqxw>6ai@P>+EK`|{D;O#7tbb(TbH#iIxY^G_#-Fk*)1vbm>Hp@ z5C=t-!Be}i&xjf;RRI?W@ z9Uo_gU@7zz0GqRA;SP1lneMC9nI2)o`^6QjGED$HeJQ5yRj4zSfA#y_vPBb14uZy2 zTK{Wvf6XqYpB(DXgo%uV?8WTl1-sI|)*RX(az_3UM`d-}XMM4N3#LOfc$SvONFf_2 z^ydJ`hleAEW(Tqp;28;lRR}>ykut#fvh6tPK6@|`0cNq!_Z3{oyV##ISA&oB(9$Us zyW6&uqSD$w9hb9J&_EY|&4aaYu;@>z(oGzgGR?8xaYDGl;HcZ!tkrj7nimz)mym>s z)GCDs*P^BzqAT#Mn6~({aUVqjEN4FeyLsnnWEMe$n9qR>fE-S^(wU%sOBE=al37id zO$EvePw)m4qz1F4Wdc)5`UQ2gHB4RgoYdlTIMWMi`42Tu?1|(FR2``NwZ{dt1D-CG I`%fkO1O82QmjD0& literal 0 HcmV?d00001 diff --git a/thumbs/bau_dach_plateau.png.import b/thumbs/bau_dach_plateau.png.import new file mode 100644 index 0000000..b9bb981 --- /dev/null +++ b/thumbs/bau_dach_plateau.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dd36il31xybcr" +path="res://.godot/imported/bau_dach_plateau.png-6e69eb7af00bc7c0bf5ef85f249900a2.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/bau_dach_plateau.png" +dest_files=["res://.godot/imported/bau_dach_plateau.png-6e69eb7af00bc7c0bf5ef85f249900a2.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/bau_dach_pyramide.png b/thumbs/bau_dach_pyramide.png new file mode 100644 index 0000000000000000000000000000000000000000..548e5506e3cec053691093df2505ac5720855ea7 GIT binary patch literal 980 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-HD>VD9sDaSW-L z^LFl8zpDWfuH}rJi)=cC(|abISnSPYEPt$prnz?siAzA!lz{4892c+rLTo330AUg;F1 z`SRO8l`ogV*sn8${+RUT@$=?wyXUH`oKRBuOQIk(@qo#J;t#H`)44q3{p3SeU3vTW z_tk4+LN3f#%4;Xr{x{heu(11bd#bo7XQa8q{Mh?$3z;sm-86H!zE0lhUG9WfW}lm1 zbD!K{i!?nDvwL5!%x#5kwuq$b+b2d#tK4Vse*ep?D6@G9>kg~iY@GWSWi?OnEMhsc z|Mly9=C=9fPbW@@Vb`=H$B6e)!(Yvgb7t=#G;#4DipN9}Kv;!^1&E2JNM zI_%cY{@Ugq@8U@dUUx4wkrQ8>+wlCu^XEtH-q}BkK6l0UO|C#Jv(C=f@yA2|{kQ#> zl`k(_EbVfY!Tas6cPC@_{W!D3$>aMy1ue#DT=i!RAG^L-*72rJO^b2gUD@+h`#c}l ze))LU{jSTm^7e~&nL~tP=H{x;P0#vq_A}4z?d#ujCvopnTE(`)cq#8QuKHV+^ZPqY zYc!J>mlO)=2>zQ=d|YOq$U}|{qZAb#$-2K%wZ{(nru0|my4+&Rmq! zY}Z${V44;4fAWLZN5tKoJKuWG-KYXIbzQg&=gt=WRF#G;eJqx(`l$v?vv_1VYu_^$ z0bRNp=+boQCsO;SY-G4(BlJXO-xQGRzG*6cf1tf7uffXsR)f$!79odQ$_M9JI|Tg@ zN?Ks$gp;Q6n25$f;zw%mNX;i2~dwiTcMUXOgC%EEq|;hDY|Lmz8HGUI~? e1`Db(>ls2hUp(9z6WRjIrVO60elF{r5}E)~2bZY; literal 0 HcmV?d00001 diff --git a/thumbs/bau_dach_pyramide.png.import b/thumbs/bau_dach_pyramide.png.import new file mode 100644 index 0000000..adce5f5 --- /dev/null +++ b/thumbs/bau_dach_pyramide.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dc3wyq1p7b1nm" +path="res://.godot/imported/bau_dach_pyramide.png-01db43c636390d1a8148124f6269839d.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/bau_dach_pyramide.png" +dest_files=["res://.godot/imported/bau_dach_pyramide.png-01db43c636390d1a8148124f6269839d.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/bau_dach_pyramide_4.png b/thumbs/bau_dach_pyramide_4.png new file mode 100644 index 0000000000000000000000000000000000000000..548e5506e3cec053691093df2505ac5720855ea7 GIT binary patch literal 980 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-HD>VD9sDaSW-L z^LFl8zpDWfuH}rJi)=cC(|abISnSPYEPt$prnz?siAzA!lz{4892c+rLTo330AUg;F1 z`SRO8l`ogV*sn8${+RUT@$=?wyXUH`oKRBuOQIk(@qo#J;t#H`)44q3{p3SeU3vTW z_tk4+LN3f#%4;Xr{x{heu(11bd#bo7XQa8q{Mh?$3z;sm-86H!zE0lhUG9WfW}lm1 zbD!K{i!?nDvwL5!%x#5kwuq$b+b2d#tK4Vse*ep?D6@G9>kg~iY@GWSWi?OnEMhsc z|Mly9=C=9fPbW@@Vb`=H$B6e)!(Yvgb7t=#G;#4DipN9}Kv;!^1&E2JNM zI_%cY{@Ugq@8U@dUUx4wkrQ8>+wlCu^XEtH-q}BkK6l0UO|C#Jv(C=f@yA2|{kQ#> zl`k(_EbVfY!Tas6cPC@_{W!D3$>aMy1ue#DT=i!RAG^L-*72rJO^b2gUD@+h`#c}l ze))LU{jSTm^7e~&nL~tP=H{x;P0#vq_A}4z?d#ujCvopnTE(`)cq#8QuKHV+^ZPqY zYc!J>mlO)=2>zQ=d|YOq$U}|{qZAb#$-2K%wZ{(nru0|my4+&Rmq! zY}Z${V44;4fAWLZN5tKoJKuWG-KYXIbzQg&=gt=WRF#G;eJqx(`l$v?vv_1VYu_^$ z0bRNp=+boQCsO;SY-G4(BlJXO-xQGRzG*6cf1tf7uffXsR)f$!79odQ$_M9JI|Tg@ zN?Ks$gp;Q6n25$f;zw%mNX;i2~dwiTcMUXOgC%EEq|;hDY|Lmz8HGUI~? e1`Db(>ls2hUp(9z6WRjIrVO60elF{r5}E)~2bZY; literal 0 HcmV?d00001 diff --git a/thumbs/bau_dach_pyramide_4.png.import b/thumbs/bau_dach_pyramide_4.png.import new file mode 100644 index 0000000..9256b6a --- /dev/null +++ b/thumbs/bau_dach_pyramide_4.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://y5g22t4cndf0" +path="res://.godot/imported/bau_dach_pyramide_4.png-63d9288171351a9022d670cdc8d3b721.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/bau_dach_pyramide_4.png" +dest_files=["res://.godot/imported/bau_dach_pyramide_4.png-63d9288171351a9022d670cdc8d3b721.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/bau_dach_pyramide_6.png b/thumbs/bau_dach_pyramide_6.png new file mode 100644 index 0000000000000000000000000000000000000000..548e5506e3cec053691093df2505ac5720855ea7 GIT binary patch literal 980 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-HD>VD9sDaSW-L z^LFl8zpDWfuH}rJi)=cC(|abISnSPYEPt$prnz?siAzA!lz{4892c+rLTo330AUg;F1 z`SRO8l`ogV*sn8${+RUT@$=?wyXUH`oKRBuOQIk(@qo#J;t#H`)44q3{p3SeU3vTW z_tk4+LN3f#%4;Xr{x{heu(11bd#bo7XQa8q{Mh?$3z;sm-86H!zE0lhUG9WfW}lm1 zbD!K{i!?nDvwL5!%x#5kwuq$b+b2d#tK4Vse*ep?D6@G9>kg~iY@GWSWi?OnEMhsc z|Mly9=C=9fPbW@@Vb`=H$B6e)!(Yvgb7t=#G;#4DipN9}Kv;!^1&E2JNM zI_%cY{@Ugq@8U@dUUx4wkrQ8>+wlCu^XEtH-q}BkK6l0UO|C#Jv(C=f@yA2|{kQ#> zl`k(_EbVfY!Tas6cPC@_{W!D3$>aMy1ue#DT=i!RAG^L-*72rJO^b2gUD@+h`#c}l ze))LU{jSTm^7e~&nL~tP=H{x;P0#vq_A}4z?d#ujCvopnTE(`)cq#8QuKHV+^ZPqY zYc!J>mlO)=2>zQ=d|YOq$U}|{qZAb#$-2K%wZ{(nru0|my4+&Rmq! zY}Z${V44;4fAWLZN5tKoJKuWG-KYXIbzQg&=gt=WRF#G;eJqx(`l$v?vv_1VYu_^$ z0bRNp=+boQCsO;SY-G4(BlJXO-xQGRzG*6cf1tf7uffXsR)f$!79odQ$_M9JI|Tg@ zN?Ks$gp;Q6n25$f;zw%mNX;i2~dwiTcMUXOgC%EEq|;hDY|Lmz8HGUI~? e1`Db(>ls2hUp(9z6WRjIrVO60elF{r5}E)~2bZY; literal 0 HcmV?d00001 diff --git a/thumbs/bau_dach_pyramide_6.png.import b/thumbs/bau_dach_pyramide_6.png.import new file mode 100644 index 0000000..aadd2e0 --- /dev/null +++ b/thumbs/bau_dach_pyramide_6.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cao1art7cdwnm" +path="res://.godot/imported/bau_dach_pyramide_6.png-be41aa37fd0a6516700239e68f4ebfef.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/bau_dach_pyramide_6.png" +dest_files=["res://.godot/imported/bau_dach_pyramide_6.png-be41aa37fd0a6516700239e68f4ebfef.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/bau_dach_schraege.png b/thumbs/bau_dach_schraege.png new file mode 100644 index 0000000000000000000000000000000000000000..8475dd5ec86ec251e38e8b2524ef11f5dccb44c7 GIT binary patch literal 1197 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-HD>U`h9MaSW-L z^LFmZpvMLxuIq)aT{!ITP#(HK{O|wy2Lf3C3fnSdPx_*yabsi7>1{&xFYj$`;Bhkh z+P7XMeZ%gkzjvH2Y?@Kceq@gaLy-!DrBH(mr$Zl$f;-a$WyTW|8J^HXc+TdXM$qaW|L)K3ubG}J$!xccblf8P#2yWCS9 z#Ae1?@WbNCZTU$&oEtO`aC|e$X>4Dc(s8th;rr|ETV4uB^jMuD1Ja+)%l@wFVx7j4 zaUuSB#wsU|HmhYU9zmby`KdV1eRGawS4-{MJH~p~_X~fUA-|2)Bl0cZ3{?ZQhVC_$ zRmKrOmV?aRr}8h^7qcv5*%3XT*_l*Za2 z$<{ZMQAbEZ^nlwQV~>Q82HC$-U$)G6HIZ4*Jk>kFk72)1hQVQj2bz&g#Y{C1wCsQ1 zmYse2?EJ|&&#y>`Da`X@J@!j*Mr)j?hGQJl84L3-v-NzL9y1-`XZ8$Ukj@)5iRBn8 zhk-L!i&5gQKxj%D%Uz4wYW1_y_Bsj8~}oVz*mC$prn?x=ko$?0=&>z%xNy|0xW^n_-J9tiel zyuN3u0c+d7vujrGW&R-hP1QjEKuDCgNvfCNUb(Fwk4@9tB#_|6<&v-b@#6cRef7=1 zY)zNhNmq2tXa8eSotrECx$@98vvuFJ`NV(kWNCM=k-PL+CuJhT_Wb8-H7|S(*d*-1 zeCv05k%rxbPKE=!S#;0)TDsb3{HpG&vwvg%$h&5~@#J0xhJxtoi5V4KOJ+_go!@k3 ziG^X75QE1Yrc^Qc6D52ChrA0m z*GQV5Yv=I!VxP#XU&G^b;XV|8cR?7 guT`X82L8kDy>1oj+Rtx;f#nZ_r>mdKI;Vst0Q0cvU;qFB literal 0 HcmV?d00001 diff --git a/thumbs/bau_dach_schraege.png.import b/thumbs/bau_dach_schraege.png.import new file mode 100644 index 0000000..93e122d --- /dev/null +++ b/thumbs/bau_dach_schraege.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://chval4fuxxbsh" +path="res://.godot/imported/bau_dach_schraege.png-f2c5e27e91d7dd98421746f2b6a6528e.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/bau_dach_schraege.png" +dest_files=["res://.godot/imported/bau_dach_schraege.png-f2c5e27e91d7dd98421746f2b6a6528e.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/bau_fundament.png b/thumbs/bau_fundament.png new file mode 100644 index 0000000000000000000000000000000000000000..6a803370b92333fc8ba2d36d49faf0ec794aa479 GIT binary patch literal 1170 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-HD>VDa&EaSW-L z^LFm(yvq&@uJ0A5ZQ=NMLxGXWOeaHiK|RA;bLXGTazT@I6&xNZ3guj?VCCNIp+5JB zoOuKR9c@^QZZ?S=2(M~_`nJ=_|^`?v3( zzWw2j`E3G$+y>HBk;VEtSB+MzZ=aFc;nncG|9!jMp<@MCE#B30ne|mRac>BEaZ!W& z{hWlzIQD6ZFQy)7uHK#|KE?Z<-hoZ4V+y~n4c}G&`}?mFTEM*@Yjnyl5NH`(MyvaFfklhq0zAE$h&jrZcdtEwXgG)#cOvv=}!iy z&xy73%6Ggxt-w5|@3@EhpYDP>9f=zsloeMn<>o#AE)sOprqT;@H@@bJm51A*L zHk{tP+dO;Pw2Rvh8k}aF(RE_)iKgu?R~hv3_w!^;*EjX#IiPU*{2_Ovhs=WJ4X1OY zr)bO-jK9lyo8v0yy`T5wi$6@ukUntqIvc~Ebgt+fSI@l@=92eV!Wg5LYjB%sTJBl? z8ey9Q3%)D&KG5|vY48q~{&8O9TDyIXin!f`1q=)yzMZ~MExGsSl)}=s$~ftLOTQ;? z`Iej4{DhD3v(4V(#UDRzYj0h4fpNk7j1SXPqz^p3dp+^-(fpT#V2>Vi2nwU75a-v9p}V?p_kSNHB;{m{r~*5JLBm#1gyfrH|8 z)0?-KWbr*nF3Wphzi+oe3xCNT#+W;11{U^QXWswSIT)=Wbs$x#Y3A-pCnW70t}y6r zVEXOp;uumf z=j~m?ykJKWhl}Yhol_JpZe)^r(>ASFWliJO4Q)516Is70y_nFU`YRwpSg88XThD!8 zY~SCDR`dGu)Uqyr$q9qsUw)o;me^($rKP zzpzk|;SJw@xmvCz>;@%2oC5`xuov8TD5Vh35zL%X`8_z?F^XY(clP_5^eI9I-X?uN zXJ7a4>wAIa4pt0LKgdfba;3OU;5u;d;c<&#h2l(xD}4Vq9@BJ)V$EdWxoXAgv6R8! z$2)yX)>Wna57r#+|G3P-j3t)&$F_?5-=nId1wIb_~sIH>tyzX^j^y7LO92fmFZ3|`9x_M~v6 z>=9VTDo|J@btT-o$_CE0w^Evsi zh9~}5`m^Bcy9e2OYxfCQGR_OT##Ac$fN{#S*S{ljv&4_yS?$13eN}MF)ypCW?lZPk z{oC2}SU>o!p1{T9wFfv2E@XW!(R~ub%4D(lxxl&g?V$<{ZDF(DUVQ)6ik0QUjjYYG zEgSAH^=H&?T%YqlUiRf%rxz?0slP8T*v6&z^@B2tftPdk!%6)1N{`-N;h(Uw=|S4Q pXx8aVEXOp;uumf z=j~m?ykJKWhl}Yhol_JpZe)^r(>ASFWliJO4Q)516Is70y_nFU`YRwpSg88XThD!8 zY~SCDR`dGu)Uqyr$q9qsUw)o;me^($rKP zzpzk|;SJw@xmvCz>;@%2oC5`xuov8TD5Vh35zL%X`8_z?F^XY(clP_5^eI9I-X?uN zXJ7a4>wAIa4pt0LKgdfba;3OU;5u;d;c<&#h2l(xD}4Vq9@BJ)V$EdWxoXAgv6R8! z$2)yX)>Wna57r#+|G3P-j3t)&$F_?5-=nId1wIb_~sIH>tyzX^j^y7LO92fmFZ3|`9x_M~v6 z>=9VTDo|J@btT-o$_CE0w^Evsi zh9~}5`m^Bcy9e2OYxfCQGR_OT##Ac$fN{#S*S{ljv&4_yS?$13eN}MF)ypCW?lZPk z{oC2}SU>o!p1{T9wFfv2E@XW!(R~ub%4D(lxxl&g?V$<{ZDF(DUVQ)6ik0QUjjYYG zEgSAH^=H&?T%YqlUiRf%rxz?0slP8T*v6&z^@B2tftPdk!%6)1N{`-N;h(Uw=|S4Q pXx8aVEXOp;uumf z=j~m?ykJKWhl}Yhol_JpZe)^r(>ASFWliJO4Q)516Is70y_nFU`YRwpSg88XThD!8 zY~SCDR`dGu)Uqyr$q9qsUw)o;me^($rKP zzpzk|;SJw@xmvCz>;@%2oC5`xuov8TD5Vh35zL%X`8_z?F^XY(clP_5^eI9I-X?uN zXJ7a4>wAIa4pt0LKgdfba;3OU;5u;d;c<&#h2l(xD}4Vq9@BJ)V$EdWxoXAgv6R8! z$2)yX)>Wna57r#+|G3P-j3t)&$F_?5-=nId1wIb_~sIH>tyzX^j^y7LO92fmFZ3|`9x_M~v6 z>=9VTDo|J@btT-o$_CE0w^Evsi zh9~}5`m^Bcy9e2OYxfCQGR_OT##Ac$fN{#S*S{ljv&4_yS?$13eN}MF)ypCW?lZPk z{oC2}SU>o!p1{T9wFfv2E@XW!(R~ub%4D(lxxl&g?V$<{ZDF(DUVQ)6ik0QUjjYYG zEgSAH^=H&?T%YqlUiRf%rxz?0slP8T*v6&z^@B2tftPdk!%6)1N{`-N;h(Uw=|S4Q pXx8aU=s9naSW-L z^Y)Hmo^YUu!$orqYmc)`85$FA{O59F&SBtkXle?W$i|g&LglfBuZ`IAd*|fD{i~kW zhkyI@=;`bD;GFZ{WvF00z|9cH@PVm8oM8{c16Bro;)QnKsBQ@U`s(M?XTR<9 z^UUto|9^TsxUbl(lo?_UPlLJqe%oK0PksN-!?Iu-x;@{czR5jU!ur7P+Arn;_1wRV z5l`3JGt@_)_{yG;c4l(D27~ctrH0H0j4Q(bE6N?vy5IzKW&wxIUt`7}!n^*=Wca|! zUpB6LNJX`%6}H=u>(GgYl_6F5BHS1 zw2&*^Ttasq!iGpWdA6j4)MaBdmc})^?*DMl{o(z7o%25D{r>TN&EJ=a(c7#C0Kj;8 zdIYQy`d90aYu@S_*0}~)LIBeZly{lR06>tvJQzXe^A-6a3H|#`1ev=(h%5_tHaZoa z`MD%8*Uf>Vg?jFYRzBry8l&p6TGm&hSG~)xI?M_hs!p)0PQ2n;d)5Ls@IW#%94AD@Ez| zkfDCQE`>_o(i0Yq0Ar0;q+h5eu5-3No~ z!#5D=SfT4s-kf)CNn*n^7gqNBWAeN2*fzG;2 z<1b+?mNgu$d-v!nmsiIvW3O$~trQXPP{rx)#Xi^VM;tT`$IK2TA%G_o)U}*?^yTF1 z8tXT7oiz2tYEARvI|5s|P&_JRi|q{wX|~I`@2Lr5X`2de2*jh>Z9}WhCi|Nz1nx3a z#~f0WhY=427FR5UtGT<-q7WY%eHbQOnR(Pi&9_cIOi+f!mx$$d0D204mUr{WcxRpd zZ2U4T2ip_t6gT~sF({y#?rXv~vp?L!Z5#Y>Czzo?obRj8_;@Oa)vO=JY|JhFwy`Jn zWBW!)m-L`)E+kzA->CqoKb`|<_0)~k(odh^(h`f(d!XcNYOk}Sys!)rx+A7U`$hTE z=l%gow55a*g9r8|nU$Kh$!7Hx_5(~tKW>17iR&3|<6JbKNw1kaU8;xe)*vHYBok7~ zm5Bwycy>#AQD_w2)2VrL{tU>Ry=WGcXp*P4IW`p&H9*in$IZr+e$P!pj)FiAH#s{w zZcrbf`f$!xbbmEseqe|uGPR?Se!1H_BjYbgZ`lD!wk>CmT{3|oeYAbUu&VtWQ3Gw& zDXyG9D{qUvlWbi6MuQ~js=t?}PBQOLaS9`!bdq1oGX;|qBH36PxMGct2zrmm8SPzE z!Ed3#4$r3%c$+!>NZvW=+ZABq-td&%+ zGbCJYrH))(_p#-m*>#*JbUV$uwtjvNKJc3w((Uj#oU+@Rhk@FT2`w;tIUd{q7 XT;EaL!o|j|y(sY7=j&1K#!2}HZkS|0 literal 0 HcmV?d00001 diff --git a/thumbs/bau_treppe.png.import b/thumbs/bau_treppe.png.import new file mode 100644 index 0000000..b1f7520 --- /dev/null +++ b/thumbs/bau_treppe.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://drcqrvbsee3tf" +path="res://.godot/imported/bau_treppe.png-7f9b2e6783e1060189b445b811aa2cb7.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/bau_treppe.png" +dest_files=["res://.godot/imported/bau_treppe.png-7f9b2e6783e1060189b445b811aa2cb7.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/bau_wand.png b/thumbs/bau_wand.png new file mode 100644 index 0000000000000000000000000000000000000000..ed18606aa8046742db53baaacf7ff4ecddfec0ae GIT binary patch literal 938 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-HD>U{3LLaSW-L z^Y-rUJmEwU*N3(pa<2jyMOpohUVdWR@ZFHN{9cPj(~>5>s0j?5MS>!a6~9%iI~Vh5 z{?>3twxfv`em?6-7M^SyVe?D7{q3<^xuWq2UTV8h&y&hUYUVIJcFV}=SghVzsN znm@N|P_(+SfA7cFNB`QUF72=U^Q>YQv)2j%hEuY&zjo~^{rOCt{rC25c6o*G{ht1v zzvpQJC+C7}_xbxn{?$pIKD@hn>-@(rcTaZg&wRB>!NEi!-q!@f0t{1etbTaKlR)O1~$t=Vf){z1`I3T1qmdqvUOtK5#%_hh516c-WOc~ zz5{v_1zA`oIJ%kpd}K(GwlCcu-LG3vRd@08=J@-E7$f%mUlx1a{9}*+UxSJ+e=*DM zo^|JIl`e2_I-C;JiQb>ON9l$b2ls*%e`}eyy)M!`p|aQGPi6uq15o-)tHAd;_jwo> ztPpQHWnO>kT3wGISHqQJX_GjvB!dHt8n3z%cGNqT*dAt@uq(g$l((aRL9& zsq>GB(5PWo4YnUBHK)z4*}Q$iB} DMg)Ye literal 0 HcmV?d00001 diff --git a/thumbs/bau_wand.png.import b/thumbs/bau_wand.png.import new file mode 100644 index 0000000..55ccebb --- /dev/null +++ b/thumbs/bau_wand.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cot5xrbwq6bvs" +path="res://.godot/imported/bau_wand.png-d50b92c7e96fb6280b87f1258860da3d.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/bau_wand.png" +dest_files=["res://.godot/imported/bau_wand.png-d50b92c7e96fb6280b87f1258860da3d.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/bau_wand_fenster.png b/thumbs/bau_wand_fenster.png new file mode 100644 index 0000000000000000000000000000000000000000..d15431692ef0c17c4883579215a50394ce0cb5cd GIT binary patch literal 1063 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 literal 0 HcmV?d00001 diff --git a/thumbs/blade_002.png.import b/thumbs/blade_002.png.import new file mode 100644 index 0000000..7de0373 --- /dev/null +++ b/thumbs/blade_002.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b8hxsbrheb3w0" +path="res://.godot/imported/blade_002.png-7d1f50fa246404478314c6a3e39bdc87.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/blade_002.png" +dest_files=["res://.godot/imported/blade_002.png-7d1f50fa246404478314c6a3e39bdc87.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/box_001.png b/thumbs/box_001.png new file mode 100644 index 0000000000000000000000000000000000000000..1a59233be4127df7ba5892f0037c7a6753765631 GIT binary patch literal 3132 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 literal 0 HcmV?d00001 diff --git a/thumbs/box_002.png.import b/thumbs/box_002.png.import new file mode 100644 index 0000000..d16b00a --- /dev/null +++ b/thumbs/box_002.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dlcrn3bwh1cbf" +path="res://.godot/imported/box_002.png-ecd6dbcfe2551793255ec183f817b34b.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/box_002.png" +dest_files=["res://.godot/imported/box_002.png-ecd6dbcfe2551793255ec183f817b34b.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/box_003.png b/thumbs/box_003.png new file mode 100644 index 0000000000000000000000000000000000000000..d6e68f7e12f0cede54061c79d36f826e2b796f99 GIT binary patch literal 3100 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 L%B0lzX5{|?$?M2@ literal 0 HcmV?d00001 diff --git a/thumbs/box_003.png.import b/thumbs/box_003.png.import new file mode 100644 index 0000000..de39e46 --- /dev/null +++ b/thumbs/box_003.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dcsubl8p7c8p5" +path="res://.godot/imported/box_003.png-6bc8a4ffcbd97d4e9f23ae1331c26107.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/box_003.png" +dest_files=["res://.godot/imported/box_003.png-6bc8a4ffcbd97d4e9f23ae1331c26107.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/box_004.png b/thumbs/box_004.png new file mode 100644 index 0000000000000000000000000000000000000000..7db894c067bbd59f3a91f0024c609b91d19c03e7 GIT binary patch literal 2010 zcmcgt`8(8m8~)6UVHjgyql|4xmPwYOV<#i;OC*Y9Ih-!eSSIT^#COV`m^XX&rA9PH zozxUE_TEKjBKy-Pn;i~=lO5w7;upy8e3-v9{YI@nsd#g?p;3^*xx$ffv5HvacP&)vk4BukxF z#O|uvVq2GJN*ok9-oH>cKH`no_H}2Be5cAOGO!opbf~E0jCjk`N7gU;bN)( zHZgboCZhb-iqb@x1$WQAY`Ap6x#!!V?z9gH5KInG;LUtk5SQaO8Hr@7dgnx>Z?Mmy}20H;&E+! zKYn#-Qcd}r3_uaFCq4esXPTH5NyV$$dG3{2qKupQ(Uo)nnIhei`qnP|PZ+H2(JX8j zTbyyjb>GPiKYd#>?rN5a^+KB{)#@?d%H|13{H-)s__NvS;l^ftlTE@&Uc#YnkFt?)9i{#dEeTMnq*4hMvuKG?%}YBIWh&$JEpT>1u3VsC;ZH+7cyxi8uFm;KIwnWD__b>@AtO_jj|_ z$1)Z;1aVMtCcn~6#2E<)$7ScQ5MS)BJCfHPX1l7-E5_)lMrpQmp2NS&rhK$E20;0V2LJ0++o6W%_hr zcySmJN6BCYpmLN+)7T)xPP7lhVLty}b{2Tb$DXyw96SGh$KgCJqwGm!2s*2IorRs%q1-QA~qcbTr=?2v?&|fls%2U7|oCx7+t+v)@yt)LG)H~upSnHVd}x8?N-L7ALl-FUrfua@s5Iq+ zU@n}*7}VIAe4|P^e}C+}5l;LZYK7eWB{&E+<_haAt!F!6@Hkk0zO0LOx=5>BK&i1; z21v8<^KMYlmL9=Tc6X-S9CN1L2LHCf9G46-T9O975NP_OuMZwODY?_K{ZFI&HxhJ6 zH1ge2vT>?I;{;RWIIb#105C89d8$S%$9zJjJ9pT}yH%lu#Vg6Op?rrE17fb^r_JB7 z;+M4v8+>U;o!y)+D0JhCY5(kLG>uW2)*25{RNBX|Cid^qETlRZr&Tk>D%`!!(Vs7y z%%$OlMOs`Wt*^{#io3NmEe}O(h*Z7usTvgmcw5j{W)1IOobi|Y&uzlJG-?0?D>=6R z+UtHZeQ+D7ePY1(h=P-!rNx5q@C^UzT6{r#OkDqq^x1NB7enaJo?5=}8D|7&)P7>9 zkjL+LoGa_+S@r60q4B}kk^N<0NyLj=wamEF1nNg^o=EM}zZgV72IWf3(C*G*zf)6& z=91^o*!7xr-oOh}6->s1Nw;)7rmn~WFTeYh??RIo;ncH30zpTiSc601Uh10{!OZgykKcX`tsGav-WLA8-B$F&{J=TX7S8-wPxoa!mmug$Dz5}9 zOJ_I^PRSguJu^LE6RYP0!VyU7^2#IiM$^_u`FBTeM8@)ih3j_Ph@pqOFhl_*h$=xM zmBeQC8(4PuDU;+EvJ#~uUi4e;3U3$4kl!z6^(M6HvwLum!lh$ixU++N9je|;s566( z;&)~mQMKFJJ)W&#EST9@&M#r&5WgJ_eZhaM!)n3Y+ge2@5>o%j=QTjf38fq*tR@iC zweqauqn3)Mak$*2C+jn*HQ-*YLHL}Yc-H_70QriBpmi7rPUNH{cT8$Vi?RIoUQ?``-FLWRrRl literal 0 HcmV?d00001 diff --git a/thumbs/box_004.png.import b/thumbs/box_004.png.import new file mode 100644 index 0000000..e3b6cff --- /dev/null +++ b/thumbs/box_004.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://7infi8h1h28x" +path="res://.godot/imported/box_004.png-681cf2a7b653e95bfcf7efada4c26bb6.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/box_004.png" +dest_files=["res://.godot/imported/box_004.png-681cf2a7b653e95bfcf7efada4c26bb6.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/box_005.png b/thumbs/box_005.png new file mode 100644 index 0000000000000000000000000000000000000000..8acc2b9c88b412f7791be621fd46b64181699457 GIT binary patch literal 2122 zcmcgu{XY|W8~)B_#x^z-EoGLX43Tq`Fyu8gqMGr<($JE(LTeT?k1Un+qImK$O6?@e zoQjT|P3q)rOXMYS+9{P0Q!Q_sJo+cj57&MDaDDFUm;3sB?(0l2*$=IU(*ppY1N^;1 zmYMSt2>9}BbwAj-OpxOteqKN*GgAP7fCYGa?q!xvmcC8u-EaI{?3r_m!6%8S z-FhAM(7;TyD762tscq&PtwopP-+z1bsXQaWpPf0wMxv+%scKm9)DtaCo;F?|>0!2# zvy})^!oa&a@bn;r*ZOY@=4oo!OwN2wukgh{;;^!(#Jj?Kc&TY_-X?1Pp)Dy(7x-7R zHeXT?HY^QEb<~-WDHiEk_mPd)_TG8ka6UKLhyfAWa1V6DR)d9toA=e>?I$`WTlFl2 zMuvoXt^fS#1P5(4TCie*YK;Ot5}6s@J)0q^STE4Uo`lf9TJ<^ZrQm)jSz7uax9YOn zf?3P3AZ_1pQMqq6q^i;>TF|D<*^%evhfFWjY{i10%>R61oNh*4CPorvj zD7{X~oNzzw3;&*C1UU1ix+&KEkUREo!L*L0vja^mR*l$K4t@Q8Iw7u>X#e1o+e5Y{ zp2Sux$TYQLuQg4ppAw))6DRpW4%JX&$nR}&eN+gzQ{B+GDJFY$d8G1)A66A-b9&Le zFJsqI#O~PqOBfNxA8>tYPz1z})W$t?&vN3G-{s-Qk?e z8^IJ#Ios1~>klS%`a22){iRN2-`Wa8VG%3G=kqO2r{4^BD^Ic@e2X%81Z^ zJQb+pO@s{&54Ci>O`|WA@ugDZ?t0$%yLA-|L(h$hrp)a?TGlWf&5!C78b&?}%Vr<;y-KWU#B6 zT6ChndhinU5XIL<%(R9M?d_kWg!Lam-|fTQV&qdY*&ZF=rplgO!kTKVF-QoI2*fQW zz3YSt?{G3I6@Lx^TufRH58AH}`Fyt8CBOQQhqbIUXmkINr?D9?6I;v~={)yGXrokS z3;@Z#tX{jgjGEpD@iZ+;<7?A>TMZ2AVOCqn)ltNW9J|Z1hKl;NPNH^jJz_hMcWNEK ziXbZ~vo)_vxVGod!f1DeZ|;$qjF?=$+@$jdBg&XX!sMYqqws2*R@LpZe3_Kkbn8IK zyJU+%S{!m)=Uw56D_E|8;+(7z{O~MFG`fzORxshO&rypysUGBcT^==iSgblFEm}cu zcjAMJoV{aPIGK*7Quhr+?DarCQm@cI%@iY+KsM4=!Bu&Hi);_f38 z(8+1q#Z|cOoucOEi3K+6SlAn~i0-}NJCY#Q2jH4ml&BXFx2eA61}SRr&C{vZB{7;W z^3vwr`@S?F=bpHQ8lSXoL!l+i58{;36(0E6OyD0@8Duc~IwJ9H&5;-X@Of-F=pxoJ zZ+{-|`K1O|;qpnfRTNRK&&ntro1Apy>g}6u9%G5w`t73*&!}k^!Vvi2fZ#2-Vi)Jn zh8CyP-i2J*;U)39*Z}W7zi47t-qQPI(|-;3m@Z`( zqal$il~+Z~hR;L$Yn+2?oR4C6X%;u9q6-Jr_k-Q@cuX1OpOr5nmAK-Bl~Bw69UQ%p8>57EuBzdXDOjIv%t=HtQXY1QylCjZ;X>7G zr;2#F1+5|&jpUSI!@(`rS;HCVwu8mZr0fNxvI~zhbAiA%>7HXjeVem?Q(Qb{?qUk!lmjwwS&{=VP#f$*t5YgOa~V2o{Tsv!SD5nMv^bijaQ^S z&bYUvv({0Fl0SNp#X4pzjqNqjSXXCp_<$41B{QrfgNKJ!Xaw4k9w8u`0!y)|S9lKW ztkRDFA41(_w*_!>ydB4bCvV0?hcQ#dRZ-BocdqXLgM%xS30~kdgy2KNRQapy=FY@? zs0;PoGN-@Cz+JLR^87>Kp~{Kugo&4S`^GQqn1;xJ`|?3Z@~gWaa}AQ=hdXB>OFq){ z;{yZg_r`3FHsWR(?42SKj|-Zc(q4(TjKq%qZ9X7}5TApUp2!)sN h({1!0)W7x@mms}YzCfK-tkmUl00Ml--a;=L_y5OlxDx;X literal 0 HcmV?d00001 diff --git a/thumbs/box_005.png.import b/thumbs/box_005.png.import new file mode 100644 index 0000000..277301f --- /dev/null +++ b/thumbs/box_005.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cfe5j170txkck" +path="res://.godot/imported/box_005.png-06f91eff984c454019cbf8211521e664.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/box_005.png" +dest_files=["res://.godot/imported/box_005.png-06f91eff984c454019cbf8211521e664.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/box_006.png b/thumbs/box_006.png new file mode 100644 index 0000000000000000000000000000000000000000..ff094d0ed969f6c4a6682435e70d400a5d5ea412 GIT binary patch literal 1186 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-HD>V2SZ`aSW-L z^Y-q3zu-ifV;`3vTf)P{D8|+OVo7HLyRgvRlu6kQ+z$GTYE|4-j8(i=FC#8>HcJ#L zZ3u|C)n@N(eUtFACS+|2)s0Z&{qq{*}%dwo+gDPGo2@ z6md1oVNzJmaAF{tA&hUMpT=|bS?@C#`VZXR`QsA2u^NJK#HU*XD@=f%ak`{gaanBA-UFPZ<`=J`>s zf*37Ehszh<=Dua)W4PJcdhGSeyLY$UKO4PXGUufLCeeA^%2d;KT>``LBp{+%(8o5QqkUE1xsy3n4!DsufBO=b?xJuZ*neI7oXdI>*mXh-9OK4y{l?da(|w7g)oCa?P>9};{v50 z*>@yo94+0_?(b|jhwqpbL$c-;tuK$t*_+Efvv}fI7{16cKHz(}B&Lt&h-nE!#LI*a z2M%Y?P&xYGYOX@T@98&lS=65vJ>F{jCG2*!>>j~;_s`#){zF3M=r3Egqq`Y?9hKXa z{X2B)tu40iF5Hehm-2!2Kp2zK2epP?rwbOmUp8?a**fXuoqYv&%&eB)F<;yM{P_%@ z<%O}UUGH7vn{0laVVlMF*1J)&X1+ZAzPO_BVukHYzsJkMm?!ismjCd?G2n)qqQsBD zlAx7eWMln73b!s@f zTY~NBmY~cd0!#TGT>bOM;rsIWd-xAXl&~DA4GgSZZl&O&T%a!o@dFH|Phs<0DR^ApkbMgJ@4~(oA!qf$4 zEN?iuYuo!dOdSH{rXOCuU>9*Xe(bB`B&H5cna0ZfqB51`Uzm6CE?F*0*Btntafx$u V%c&_=8o)w_!PC{xWt~$(695wf5cvQA literal 0 HcmV?d00001 diff --git a/thumbs/box_006.png.import b/thumbs/box_006.png.import new file mode 100644 index 0000000..04ec5fd --- /dev/null +++ b/thumbs/box_006.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dcykj0beb31kr" +path="res://.godot/imported/box_006.png-5ba357d8c76465ff6e00378ddb8b4e3f.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/box_006.png" +dest_files=["res://.godot/imported/box_006.png-5ba357d8c76465ff6e00378ddb8b4e3f.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/box_007.png b/thumbs/box_007.png new file mode 100644 index 0000000000000000000000000000000000000000..dd70ef2919937d9bada22ba229eb43bdb03b0ae6 GIT binary patch literal 1276 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-HD>VAwC=Yp-57{n?p+|JgZi$?7dsJXd~hj-*)EzJJelOEgXM z53^<57^T8sDbygt>Cnfb;LbEbneoI#h9@2jMFS%o!en!6Z@c^M?_svQ>pNb3v2Q-b z_I>?5f&KsNVlL$zdT=?^|ABMmj^A&;Sh?*xy}mksy5-yl9BvHO7gA4f{Ro%VWw;}% z(4ndz`{&>Xp0{6L7tcS>^Xu-l-`ywv{(2n$Ps4Wq1kOcFJZXEZ*kw`yUUkN@1K7yzDUMRfL%ESw!|R<}R4Q#aecGbt zFxPzinSSo$*|q5%k1L+t`?KU_&U;;%ANNjj?42CA^7{`5U9E<*RoXXY^73q%8TM3t z3|?6Hc~GxRnr*LFRM@-?!<78X>`Q_JLqF*W>+qyq!Tz%m9jOuw$o)rb% zzn}m3=|uUxPP(iN&%6^Pq8!V6_e;mC9DANxeeu)G2&25a2l&4?I`gY=xHbIE+h3v| zz`FGGADODZ!6vhLd(___)e5zo=3!vl;4AvqLGHDvY2Wc{MoBCk58S^oH_EZRE&ts* zKi1^(GhM;d4bAy#kG!8rH$^gClHi=SQ%8dHR9JJe`{x@m*&#;DS8;A)y78v`_fFA= z&YSZrtn@<#-!1#yHk0#5Fng2ufeksF4cdaAQVK#D;yKGW3qBf7V{M+8P_r{O$4vV2 zYZke5dw~~v3pDfuSN+@Y_#^AAv&X(zHD3L(cCD$w%ov7_f{HKYM>j{zxuwIX7xVXE z*5~u<->_%tH7q={ZKF}p&G*_OObjQpHhi)9QgZ%%lN&>`pkm8|8lD#{20%AiL>#*` zVe(%)(*}l(3~j4a3i22k83g%u)%vLYuN1FY@a*=1O@AUj{YiMnqcHXFzM6-VTUiPM zLRwlFR<5sf=CD&>G&(7qIFDf=i+lk81kZ{84$NUV5#?XaSW-L z^Y-ppKjA=$V;|EySWFJObhvaJVbv)(+?U9v0W`E0#nPzWie82ybi}T>`y?+IqvJ>w~D|}wca6*%zh^t`^ zlfv==WCpTssJ?OJU1IUQ*$=0rf4+3N=T3jWha;ijNBCOnJu$KG)^GU#A@;+T?DJho zxsP4{?B##-{_o$@uM5qtTF0>zTz$pB5Vub6>-DYg7nPpgdA~@(?n~5HlkZza-+YlX zKJvho;aKSI$(!EkZOqFx{-+5&m@}jecs=Hse8Xye1D)+ zCE{}ar?l6D!|{A~@BE+pIj5t2cV5y9x3yJL(k1ugfEsi6zSG&Lr&&4Yqi$Q!9rlQr zx?lM%%=Yu`=PK|V&aix=?{43mb=COFs&o#$Am~uP<*opPzjCZ1Vnh+EerxZg-Vl%3zzf{KbXF zCl44CN*`C|{A@41_h3~Jd%_Jxp4x6j^Y$(tyWZ7?6@m;C#2r7L_2+)L>+Zo*t9u+4 zNnC2(^43*nYWDr9J7t+@6USpZ&V$A7fFp&Ox-{?JuKB zf5sQbKNQ^WU8`^Ng(+@tB_E4@;m6W{f)&CJi~pHDHV{ada@b+job5BNJh)w-zj4Qw zhU0$Q|Ig(6pvLe(lPTeb=fnC<>_UEJA2R1ZJ+xi^!xy&+oQYXYZ=8>41hv1HSpSV- z+sb#mN@`7KR=4nEHpj;lect`-Sy=Ca!1`{t+U!;H3u|vmX7*30{!#GcMt+5SgW+3_ zhB}VJNgoog=T}s7cqA*`xbxri>v$Xiy5*HI#(tbYrF}M7Fox}9TFI(8@nNRQ7mvv_GhAy?e3@n!zJYD@<);T3K F0RUF{CCLB) literal 0 HcmV?d00001 diff --git a/thumbs/box_008.png.import b/thumbs/box_008.png.import new file mode 100644 index 0000000..2bbd9fc --- /dev/null +++ b/thumbs/box_008.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://d2ynvj116h1ra" +path="res://.godot/imported/box_008.png-7bf97d200ebd04f21c42353d62fe9f65.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/box_008.png" +dest_files=["res://.godot/imported/box_008.png-7bf97d200ebd04f21c42353d62fe9f65.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/box_009.png b/thumbs/box_009.png new file mode 100644 index 0000000000000000000000000000000000000000..478d3d7a0e01ffc20fc03fe43b44bb1306f8c325 GIT binary patch literal 1164 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-HD>U~%(waSW-L z^Y*TzpKzee@sIZvB1{@vggS*TwyHcjCYyeM`9$IqhJqPYjC&fmg@jX>1;dhDJ#MoI zonl}V|1iV+t&ilg;9vLt)XndGyXC=&|F_MJbvqBX_jg|xh*Ca$k5N*O)xnQ(LNLP< z5eCbFWopMVaL?~c+Wz+UCEX8y?R!rdJ#hOgvV*N}+daEOaz9f`ZdiX1h&}vnV&399 zsrv#V`|VR7xH4?+{yk&PIv43T2jiJJ8jj7s-B`|3_3LW!>oSoG-+pyJD!<|!$HKsH zyjOt1Aad=49hGbhJ1lm;s+wo}Ax>Esw$sd{56@~FzKAN+epg?0acZ;VpHHW1a%R`s zzpdQ+X3hB{k2Y-oz2FMtjY&x_rj)*jH2uG=@XO`5=JPX{4BiM7)phS^F`qH3{x-vd zKOY$TnGAM0pV$J z%V#!76R#Klw%5wpBD2-@@dkGOJNAG4^o~5JWpLOi$Pmb(zSdydff=9M>)7+9%UG6H z$S>Gu$i85QfL~PNr*CN;-Jf3o<$%_#t$+J_zDdGTjsqH2EDRST_iYvWV*KNpqx9mb zf-&>T>nE78%!~WGw)xxL)%9OiM%#Z1l4qL4^W@Ki zX`K(0_8f{xWtsl)ZRfmZ@BI(M`uZ~h+FSKF50^jXVo=~aP_aco##O!{Foh#|s*Zh_ zc^@~|0_XjTF)i0V-Ag{!K0CkYzpQHzgC<*HhQah&y_kQJTo2?bm3QzwR+#D6FzlT2@=_qU`g|IaSW-L z^Y*Txzi^?@4Oa^BSWz8V~si2 z<^KQty*}4|f8+M3_{=qGXAD);7!LE?|8_*GYQoc;vt5bJI&CiZS$lf>5^_qGy#6aL zwtd5f9aleomA}6)DK~YUW|s-buG)gOrLCFwuXjJ6zG6{X)d!>hpO_gQB$V&Woc-9s z_xH@}(i2U-`M*9jp@U)9!v%#^AGjGajxaD>&D#2Q>*2lEb8k0(nWrXHD9*6pF;~Kt zeG^x9vVT4PSwDOJtHXPrF3bH^y#KG&%^NnyZk^J};=FZxvY_WGCWb%yOv~jW4S&S2 z%e*Ty|6CjQphA56k_P5KQ^3R(yl|kX#VRoS{ zOcIWMtZ`~LifylZbC=DTP1 zf+I+<;i0J0mHc%v>#oSROWH6z`Lusy{TJ;wimj7Y?QVG6Y|L=?z7d;f+J~JroHNfD z#C*3pq|Buk$|zCBQMbL-kyZ9z=DsK2OAk6MHDWl-r?`sa&FiMT_i~S{Y7|nhGiL)fh4+vk1TE$%Qfa2*IQ(RO-#IloPA`a|ZF z`^+p?Ps=*rT&pl!vMoBEGmG&^<_j~{3(a{>1$R%KE&nTeq!wrb$C6-IN*RJ$@ V7X0v+46yiN@O1TaS?83{1OV>k2BQD~ literal 0 HcmV?d00001 diff --git a/thumbs/box_010.png.import b/thumbs/box_010.png.import new file mode 100644 index 0000000..a227f03 --- /dev/null +++ b/thumbs/box_010.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dpw1i2soeg0oo" +path="res://.godot/imported/box_010.png-80d0a7d6d1be33149f6e5747e3e0297c.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/box_010.png" +dest_files=["res://.godot/imported/box_010.png-80d0a7d6d1be33149f6e5747e3e0297c.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/box_011.png b/thumbs/box_011.png new file mode 100644 index 0000000000000000000000000000000000000000..7478731eb5eae913524c7ae4a7ffd6a4890bb522 GIT binary patch literal 1179 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-HD>U#(vz!d|PD z&C}V4i*;dScfldg87n0;DQXQ~(T{l`)jPrto=_c-_U$Hm*sG~WdPy7%HdWsf z_b`9yxgO5A`SRr%bLW-KWB)RHb(mrJ+FkW=Tf2U}Q_r!jzSO(u#hwVpu=1=MG3zYi z|6k2vVt9A%y!$@8-5VJher(=$?Q@I(i|u>k^|L*;t+^h?wachtFVmObS98jeC62HN zwk4hq|Nq%+vzAD1>W61`2WCI@db9N2hHw_+JNsY1wmpCI{_cC`Cr<6=pBVUKQ<8`k zL-ftA#CJ(2{{A~6V|BqYQ6}yE3y$?!_mlsh@%->e<^acoeIJd_{5yIrVBUOxlZ@$( z$3H%O!NE{uUvprw=mCimqZuwY3lCZF8CNjusDB;y{o`YqeD-^+2}?wo7^dXk>#0-h z*nEMxdVhWSdW|;+-A_jI++#~fkvvql`e`5YTwA#VPd|u@CAl*{QD%G3%y6lfVFyp* z{;ORzb?2jAF+Mmr!N0bDpM#ogW4L;w-fC-8hL^1u>??j({(jHj$(A4SUHnzA+o$^Z zo19n@mdG}B-+aD!+POq&hrJgM^sdyLv+edu`Rf{7q74&MIS%`Mius+n_hLus`v>*f zDGY96iZT(m56@*(@7T77PhR7MXF^P5E^ndJkF2-f)3_^UHcPv<{z|@Jkml-f+i~^P z%|`bk#VA^k=X!_# z`SZqq_j+DnOZd|-u;|I-&+8d>UE)bpOaJ{xfos9}9g1^~>^LaQP_glM?vwiy)mR@) zIC?EX@AoI8nua%a2UbjqF$6k);`XY~1!v`5wHJW6M`9@h%i{P(u4U<{_2kalUqg! RXMv>+gQu&X%Q~loCIHro1I_>d literal 0 HcmV?d00001 diff --git a/thumbs/box_011.png.import b/thumbs/box_011.png.import new file mode 100644 index 0000000..a81fddf --- /dev/null +++ b/thumbs/box_011.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c0y6x2hlgl1f1" +path="res://.godot/imported/box_011.png-0b4dd9817af85a16eeb47d3714b0a53e.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/box_011.png" +dest_files=["res://.godot/imported/box_011.png-0b4dd9817af85a16eeb47d3714b0a53e.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/box_012.png b/thumbs/box_012.png new file mode 100644 index 0000000000000000000000000000000000000000..999ab7a8a1c7d4940fbcdadf66ec532630f22414 GIT binary patch literal 1659 zcmcgt`9ITt0DgaFZFA4D9Pu@`68S12vAJ5r`1(4dO`-@zVVJ+$&s1$)s4lXNU2$-m!PYi9umSK3hIXY3;H5 zq@L#*b^|7sH5WJFKIs{6ZPbve73YkQ_bC~C#LmPQKJry5p@CW@zdF5(Qhhi(&nqjd zRb^Hi*DH{5TKey|AnFe#m<|E%nSyGP6QdX^fe;HYbpw19gB~gW9^<*rf~bylOysgT zV?Ns?_E$E}DpY4_jWMQvw?Wh+EPUu%=jXchIR8=nBIn2QxUYy0xQhh?}gO3*`3+Y$`;<_{OiySBsq~L3<3#brqW5{nGjeWtrv{GGvxc_ zEBQ`a^xXuT9C($;-MJY*cZBAO+1a<1^GvH&y&deAZ-@~>jTGi*`s?B|jjqM6w&vh` zp3M5T8@3N-;P=M6X2P9Zw^d<$rq;b@A&6%ccfzKlW`grnbRqsLMV7uQpVjId{!^ZOyBk!m?adSBO zAEBIM18b41Mv=DjOEq#~UG`d-%e)}@IRI=w!3)!q?-h>rtCKF6-s;tGY@ZaB!ML=Z#$I?YIKa@aa8ige2xTph(^>)LwhO?= zHWlY_Z=(i*hxkac8)j*EnsaYP0BspqbsYcZ5U_yjfU9MtFb?gej;|m&Yrk*}Ex_Ci zU`cehLX;yS4#1`XNkBp(mkokf!N-Whj0qjb0$~_LJwQqI+Q0pm$v_eQ3C#)*wyIqZ zK9snLu13-&KjcvW1UWnFn{(9fdFD$ub>LnaBLEuRq*RxtR)R=C`%6E<&$zJA*eR)F z)?!OAVQ9CmrAl4f7$vi)Z>X^XnEz~stGg&pADqC(Khw<$J!V?0%P$XsjT1ta=PefT zs!^15z_AHm7*AGavi|hlBM;|?oJjXtAbKET@L1>qX2Z zGfd71&v){>kx(0d@U>{=soqVww5jP=TvxWIGJ9LOY|oc;h>G-#-~ifDnAbW}t{RMJxs&36&OwBeYpuTmHWv5aj ztI`Y>`@+a?(!!hd@kUYDiEiYLjtSb&hSthu@X_Yip`M7BukRS8H}KY5p8Cf`mL=v~ zV`|>s#`QNNZ@7S#53{zPzrzs};|qFgb+-)O@hh|u)<91PkY5Rpn=Vwcj(fs2~ySVL{dS}a`$GAsPBK( zR8(j6!$hpLH7ThN*(LqWrs1Lro>)L9!bHaT3@^dz3e*(;9ZK+scPTFb#2C);t7c5C uC`vA%kYFjh2^oRCz0EIRsOaCZtJ}zR=7-Br+e*gnn*b|IqD85hXZ(Ll!qJ)l literal 0 HcmV?d00001 diff --git a/thumbs/box_012.png.import b/thumbs/box_012.png.import new file mode 100644 index 0000000..aa8bfd6 --- /dev/null +++ b/thumbs/box_012.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cwvro43pb88ye" +path="res://.godot/imported/box_012.png-7bbc57f804e492415843e69b221cd02b.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/box_012.png" +dest_files=["res://.godot/imported/box_012.png-7bbc57f804e492415843e69b221cd02b.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/box_013.png b/thumbs/box_013.png new file mode 100644 index 0000000000000000000000000000000000000000..662f2076633cec5638f9055821e3f859e0be9a2e GIT binary patch literal 1672 zcmchY`#;lr0LDLCGqa10=!G~m=C!EEiR3yn%}_1X5yR-5RE}CAD`xv@lTj|+71`=_ zB1tYwb4eDRbdp(Rq=a5bqUet4eu5AWZfCzH9IjzgQF0RT9LKP`Bf(EmXp zm%GI)x@{S-gkU-q+*6v50)V74Xg<476n-h}KhjGx$`BMEw(_A|QsK5Gt?`4ALTMZ9 z?&UF$4B*fl&_S`3YQO9EK_TSLjiR=I28MC)E0==5LXA4}w&Kj*D6EM-Byn3@nXp1g9MU^WyFXGN~o>Y)bx5K%cOg}DK=g$NR8;G-D4Fo5M-!yV~A zM<|EmB?@xr(r5v7teiJDsUyksM(ml7c&wDNi*Akd=lgf)PH!tCBTvG*1c{>5s zi`Yu-#8zd(&i)01^E zNuJrRiLLpMH~XUqkuQg`MxHZoU$m!{hvT>7-&2ZjtwdXDPGEs(5E2zt?JV2W$31K6 zbSu@fA*beU$)Os_D)+6H>^T7xqyxU&MeQ3ow7E$6Ov-VS!^g`r1n;_b9xP{3Lw4j^ z@iEfP$0|gxADsofB#(^f_QqTG)G1N4v z-ZeQsY|*@UR$lb}%eOg`UpFC8)w0qmij6PB02veOCa@r?2nr~kVv?y^;pk2@6%S5f z*0A5#Nfs)ncUEQNA2ds%XC`xRxM*ig0i_21orJ1yD&Sz$-=qP|`*yX|j^1xQ6R@?t z7ReE?W2Nig&Mlm&oi#GFAUMGb7v|Wm=g@0V2O@~rwi-OHbz2Tcm}UP5;-~>TEt^JtL|>Sde+|(%K{TCUMxNh+%b*{7H}OZ<*jdT_8PiL z*8&jKF7o!PBkR@Qdq-QM!}~B%yj4=ez=7LvYenKXiz~30If>2E!i}h&W>d4SSdZY1c~+-*EF~i98WN9$4HfdzMc`^+N~Mmu$MgPT zF>2&ItNOx%Z=2T8W7$BY5+S{g2*~};L(hCd4z#B zcP(rvd{>||`MU6T-`6+CFjJlL<(BhJItVdJy6ewynZvqQq@j&c=k@~o{GyW$-=_yf zg`i@V3!hSxIzz6!us@`Zl6oAA1TVGfhgTnlJrbMO4z zBxKr#vny!B?D_ej{T_$;Rj(%;xcY%4dnl{Q%;fw>6E6h?STzL>n0YCr7!~8VUSlPO zsWV{6L!3cN&)-49_GaK6jesLp&%8y~Bnd_}yKGGHC;Wt6ow59MF*B}wOBZ+fS^&du KJMA7d>ePST=g;Q= literal 0 HcmV?d00001 diff --git a/thumbs/box_013.png.import b/thumbs/box_013.png.import new file mode 100644 index 0000000..41fe49a --- /dev/null +++ b/thumbs/box_013.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b4wos88frshbo" +path="res://.godot/imported/box_013.png-8fb350f7b7ca866e686c1633a186457f.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/box_013.png" +dest_files=["res://.godot/imported/box_013.png-8fb350f7b7ca866e686c1633a186457f.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/box_014.png b/thumbs/box_014.png new file mode 100644 index 0000000000000000000000000000000000000000..b4bdaa7e44de839f931592588cd525aff2c11615 GIT binary patch literal 1806 zcmchY`8ykS0LH%wkvJ+Tbqpoh8bT3ebxf-fX^D2OxvFgv)m5K*3{_1Wx!c6iZLG?i zRi({bHETP%Q6qCSrKr)mQe#?YqKGJA_D}4G_x-%j^Zx$683BIYd$dfn004W)KBS;s za{d!SW7pd~A|<8#Q-be9Dgt*1^4!FO!tFX#R38;!s&&bWBwW^<*Lul>O${6FXr9@wh zR&+Yo{~}%Y$;ej~oZIqP>3L0=8r!%~rzx;6AQaZDH!lHWatmv)ZC%?PP@rSAa$)}PM|%uH6h3pSO~!1z%DB>si)VxZ1E zES$MdPcd7-QU!eSnzEqlQ8am%Z2Y-bW2}PiR|NEnN8>(z0jNOT!U(5o=`;}2@*tMYjBuT zqPsDO)vH-;@Sr1bFqX{mcWNNycM@lGC=ROQw9Nw6ouV7z!;gdB=o}LgBRbiwg<3!q zLg*Ztp`^N@`SkaJql?zF zhJ@*ODf9P3*~-3f$4BY=pJueH-So>{ZdmrGFP_z#H6qkPh44#;54h}|C6OCh&~UK* z`7idw^%Qm;Sg55>^cv)_AQ7tu8VQQ0lMlO)8=x9*WafMFOw&q&&~Q1va-_D08U4$G^Jwm*cEl;>p@rOtJ?wbz(5B5oj7X>Ka{xW=83MP)e+A<&pmh;iw{ zTu|Is2p`%vX`Mf~aKRZ^Kwvc?yP^kG;Q^iaQ$2TK);Q zB1kt{SYFH?GuD8O!*)}0(MVq3CjS9>=M;JkDw4r`#0A=nQ@vL1Ka+Xut8`s=@XfoI zl}TAhe51)4XHXlJf%9C-qwq4+C$sj5^hDp@ai&?Snk~9`ATWycU^11V=i0Zv-SZ$c zkAZ`&E~zSImw0GwOM4q^!%$~{SZYUv3rsz1RI4-P-Iec9GOSL6|u*dKew z(K#H`>Vhl<=?p)s88y82XWt(>kD!iyalgO_VY^+tozLN5p``OBvZ=I)AJy0FsGhtx z_-7x6&kSrrv}JHt_KIQUMk?Tp49Hr=M%hbRI6pYg|BAcYm9`5n2RC8jw{#O>=nZ6e z1myDk(yxq@E9(I!O@hAYW~|q6la4>E9sh1ba{Jxrccl2st)@}ag30f+_ET?j&$cOTh#jiG!6pDyn(JHc63jP*Zwd_^8;j^Pn{W&Nd4|=QXMU95coH%^YG! zIOV^3xj@IFivu_t_xJkq(EWO2su!wTPAs|OX@o_6nr_+DvI@5NabP-jkdjVpe5Pn| zgg0&`XmYF>R!)DUUMPpAUk_FLNm8_V?6#b%qXkG~-nhNF=y@y^o9M;Kyyk;qO{u1C zDH`f5ZSQYMO2&Wa)%jNH^CL?FM6La0TY>tS+P+1oPI>fe=!~<+q%x wO5h0rs%*lcG|pR8Ygcv+xQYB9R=sy;BkA|A%qJdQ+&wrzKJG`VBhq;P0>Z2(aR2}S literal 0 HcmV?d00001 diff --git a/thumbs/box_014.png.import b/thumbs/box_014.png.import new file mode 100644 index 0000000..f03bf5f --- /dev/null +++ b/thumbs/box_014.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://clqa7fvr1ijvo" +path="res://.godot/imported/box_014.png-ee7ed02ace3c25e82c08415d6baaafb5.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/box_014.png" +dest_files=["res://.godot/imported/box_014.png-ee7ed02ace3c25e82c08415d6baaafb5.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/box_015.png b/thumbs/box_015.png new file mode 100644 index 0000000000000000000000000000000000000000..e71162cc988e811c50d54007c6a945c40baf4117 GIT binary patch literal 1875 zcmchY`#%%6<++wS*rOp&eI8>C(+($E{qHmE-v$>>P zvK$VR6-$qD4i2Lv#Pkhu9O1Bw+d9raaejEepFg~QdB5I2yk0p}KMw?aD;xlT@bYv& zzDd?U1Jm5xukayVn}Ea~_c#OuJ=?wm9qdNw(2@v$DXN!LuF4eQ8-iMQ#qTrEMYJDAD_-TIIsD>Zu$Xz;CnN8o_Mk$0`;-F$tq2l?L(SEOZG%yFc-j=N8ZDe-_7cT z??~yYp7a&l|FRPQU9otnB`%9&l2Z%X_S~fwnIHqdRg50d60e5YykDdg<0t7&q6X6y z7pX7bBRs8b)@gPU{uRH=11~?8KMkjjrk*48j5rjv>LJrKfRfR9q4Ap_`p7{hf4JAT z*b!-fQYE_biadPFG^kb2LS5$Q(K!HQ?hhAj_le)oVg(6Q+nOnj&p#!O^_eVJ2hOdw zc(HE)Y~!5S+U3-bIC9)uvlAipA{2?4SN?gx=!Jxa9?=5bsYJu84$3Ci{W%^KRiB{i zydNjAxUzJoY!!*B1*CUlSD)$vs$KLjY4AZUS*I9Yg(e;@urS7uonq^wf)?Vu$pIEt z;vSI#u-=wi-B#3!LaAA4s=kfc+UtyjlMK3fOl$t(rPFrueYemKYDJ}2>z2N{O@)O^ zD&Lrf4M<(irTA#Z`{Ws`n0xcS;0DjlC2{lhG4YXxvQeRY=|X7);j0HHkN>0>TBb$d zb&cfh;vlK3F3svEE!~m9@^_gWa$mK>&Shh|Z zecYc;$X|fhJ(u^(zIS%IUVDW%ZtbB2d|jq3$pym;yWeFnmsrV&S90{h#z zvy&<;C^_&SKUiG1)GoPE)_eDnL`5uDMBkoO;NPMCkMyIr0@38zk(Swf*PZMmYGEsUDSy}Wn?!P_X;7{?wf zyfUi=gKe6!j5%G@%6i>j@!IpLsWoZGoxb^CFsIlvxFpKETHz@~@@Ax@yY&XL z9N$GbeQUT^MZ;X`Qk2y|8M9hdn)BCg0bcwNp(ozy*Bj?GjapNVR>+(m_zuoI5xCMy zh9VPsb__}M0nlB#INqA44x;CUR z;96FOkIgvf|}^tk;=3t>-(8+3|<>7&8Io} zKdXWxoUo4jlQR#nkq?PL{6Dc-J>&!0#ixBgA&Rjc_|h)RldJ@bc-F1i&ZpNazkP6C z+1(V0kjlsK;-NBE{fUcL~IFyOC zl*<^!DdNf9+5(UD(p@;Owr34N$4^203kT1<;TifRDST!V-SDU!um8DE?j_c)Ig%P3kUfy#?muevkQ)K`8PUa9hv21Yrr1IRBg5-@H*`0 JE;tmN@iz>VO~L>G literal 0 HcmV?d00001 diff --git a/thumbs/box_015.png.import b/thumbs/box_015.png.import new file mode 100644 index 0000000..e82d4b0 --- /dev/null +++ b/thumbs/box_015.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://8ni3pgocqepn" +path="res://.godot/imported/box_015.png-86ea2accb1bfd48d8e5318f9eb8c0400.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/box_015.png" +dest_files=["res://.godot/imported/box_015.png-86ea2accb1bfd48d8e5318f9eb8c0400.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/box_016.png b/thumbs/box_016.png new file mode 100644 index 0000000000000000000000000000000000000000..1f5eeea62f65ad57573ee75dce055b4462b3a07a GIT binary patch literal 1392 zcmcJP`#aNn0LMSO#hKU^bFHQ5 zoGzY2HJQsYj1;QVg(sO)IWEUGxy+(t$veCZD4cEGQTmPr-Y8>sjxgjkVX&(f?v<}vl4?YBglk34&JY@52ZvPrEKV1DBsfGFI>ANQ|}iLO0OZHaO8%;`*? z`&^r&sAuok2=!2`z*W8b%?X{yA(y5x>Dw=kT*A*5o8S%1!E(GFASz#R-D8z)QXGyoOr=Z`^zp38`sDnhwV^ZT54_UZxetQGWY8<98c!-%nb0M# zKX7o26a&&KNv|9ZD_VeU^+qM->Bem~d$2p1nZ{@C;Ts`?#zS1;%v zRcVZFJxFBi7y^BK{pL58>mobyvd%6|8T?7?$(^@w>ye^?C=Tl25gMXV152aAA;p5cPQFHa2nyENnb z@x|Lm8;Q+8d>?}Ey@6cJYs;qfg|wi7r7_3srXie(xeBu7mqFlNRPZ&!Y9x27`(iyti>94KGU*6nk3kYhW?EX_p(Mf-g?6 zNj=Uu76?<~m6#FJc*u=9jOvszYAvM9okhyC&d&ge zJ!p?D)}&)Fz*XzpR!9n4prL9YVyvI1St-1!9|29E)w{dVyzaN?b0f>cf&l`@$j)8_ zzecY)r+w`$Ca177wBlnxSmMRY@{L*mVj#PXwA~_KVNe51vg%-T=o>yv@7FZ9qS52f RK>hNC0!Cmc{cZp!<3FWIRRsV5 literal 0 HcmV?d00001 diff --git a/thumbs/box_016.png.import b/thumbs/box_016.png.import new file mode 100644 index 0000000..9a9759d --- /dev/null +++ b/thumbs/box_016.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://uoyv3t570mmc" +path="res://.godot/imported/box_016.png-df24f45c3486224667e7ec5060ba241a.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/box_016.png" +dest_files=["res://.godot/imported/box_016.png-df24f45c3486224667e7ec5060ba241a.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/box_017.png b/thumbs/box_017.png new file mode 100644 index 0000000000000000000000000000000000000000..d034d286fbf640910c445a5396ecea10305d8826 GIT binary patch literal 1571 zcmc&!`8(8k0RGIE8H1T-+;uG(nOLXPJ(aGw!y-j?Z|-LtNjH4_&CLubUykK|IzDUZ5L&xgv_CAqKF@MGC+Juf=hS4(Wo@+Qy>;$u>avHG0ZdP9;F zr;br`MzN!}hn%QPH0736f_c16!p4N(qFi5EVUMFY*CQ!NbzW7#N=ui z_-@59sK`$(t{bsFovB+`sdY&UQz-9WCsOrl+wx~`^+La?;8H}QG@J2gJc+s1@8nDF zo2#tN*K+QtwknXOW_ZF;e4EhjjI)#ORayP~6Ep5^6fV*{>Z@`ZCMsbKFBkIAo(XFt ztg7=g{i@7LhcXH`ZL|&!#XLvvC{69}Wa^WqBCs z@s>{o1N*;C3LXbH8UVjz^$N>Y(F+mPuTB_+M49d7?!FGfR{|9XxTg@HOUZ1_MU1MK zll3g6yn{^AR~nQ`22^~OUt(tPJ1@A*buEb?wKbP`1YlJGqMr)#T!~T9vIzQQ-=I+$ z4i}i0)~0Wsff+Cuw(@#JkUsU|NS#7>zSzZ&$e$?zkDCc7&6baf?WohCS-G zEs}Hiyt-Vp4gpK@{eCAWp#WwGxxH<<`E3uPW-0PkyD04C5)Ib00HzB~tBdsy z)XBZ1A#hxj0tAlteGcz!&A4+;L7!+a)r2#lHGI*Ie#^r0rrN7~T$qWgHxc)|Hp2xftqv20`%V85Gn&o9zwujDT;UBsSLeM7@1qBNgt*Rau8gp+%9+A9yt&_L1J1`X( zUmz@%M&)+L$Od39!mQH8(mV>*9eoN7?;5V@qzUFDXGJbW1Kw!)u$7?)Hos`{TO~Vy zZ3StXHfU!vt3)Ye62F!^0N$UHl4Qk(^ z&90n{6+LegzJ4Qgkk6xyq#b25R<D^UDjmyAa)MvU^@f}zJoNK2V3BamXZc5iAk#;7S6M#b5EFk_qd9EHw4sj5 zj~>T9JOpt_R#*wUUF+IKSdeST7-<9#i@@x{VS%~g?oLet(OjA#D-rS9&zj+Yy#R4r z&PPf7PIguRBg5#c-aCC!yKvf27A{MLsPSLFq0pw@$baGBgoMBS`harW(Uwj2N&E+| C)Wtji literal 0 HcmV?d00001 diff --git a/thumbs/box_017.png.import b/thumbs/box_017.png.import new file mode 100644 index 0000000..76a7142 --- /dev/null +++ b/thumbs/box_017.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://exse4rpkggsj" +path="res://.godot/imported/box_017.png-8cb0240c67fbcd8d9ad515cb1bf9502c.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/box_017.png" +dest_files=["res://.godot/imported/box_017.png-8cb0240c67fbcd8d9ad515cb1bf9502c.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/box_018.png b/thumbs/box_018.png new file mode 100644 index 0000000000000000000000000000000000000000..da779e1aee0b0ef758c0923033b7f34c8040dc36 GIT binary patch literal 1707 zcmcgt`8(8m6#jf?zJoDYCNtbLWh<2I3b%}z$u@~B(>1b-R8&SPC43FTBzsz9h!ma{ zNtVhoV`;IZjA$Kcs;lf-Q!#h$KhY28ywCH#?|IHI?{m%>H&;gmd3AXJfCAmg&O?gG z|0O3Q?QP_sE-64qJsfGEvWN5y0GUv_9hDKo8|S&~TJ1$h`EWpmrmzFfkT*Pjx$Mo$ z3MZ!$NipN#MXj5n{;wU6l z#A*{@{ZZj)&a`o*f*JS8JPX#3xo!p zMfY245>AGg9ple6)LeT(L;n3VdDXbnA+E8oy4(#;PvLMUYT_5l^WsJ_s!^Ma4U2zv zq)wlo;CkYU&h<_WcPP2!UvqnijW`rx?YxF@CxIXe45?;fGwayT+h|svJFRk}RcQyH z(<^HH8|QnTT-Hyrx}!nl$w@fL_em?o-FWfEY~_VnJWT~+Uo!TO?W!H6xjX3n{-RT| zXppu&U%8}NJhn+2F0LeW&I3dw%ScHLY_ewge{1jV+)|sh_f!fk7NZm2AKGDY?D$4e zP5k6A`*Gju&JWm{L0+-hHkc{7b~wEGJ$o_A;9+oxFk$vqtll!~M`vtwrs2@6#r#as zd&$FBi3GO4CsK<;_n6-H%@FO()6A7GjT>8)yd)b%%P#I^Iz}h8l+*$L+V#wa`43oa zFubmfV;cCwL#*rn5eiLHsxYFgfQ)_d$Z0cQoCsFOt3Uk|p%5}GGW}~(;lXp|%CR)h zXwJwQY8(`tS!6*nD?@=x1sX3- z5Rk%^qqwCI+FPAXku%>7Uca#w6sGdS29MbGI)GJlLlolMhtAHG$F>v6k=6AJChkp% zg-c1@zigE9npf}=rfTjNdN)wDJWMR>n;c2fJ+tEag|XDD`*Xm+I~9hJ0{zwXGD=9; zq6fs)-G1;TdV{@JIbIqEizw%z+Rte8D`8-B58#i?RC3G>V(YU8R@$=;iOKc}Hw2Vp`?k!)%4B*ZVXtyP069iIr&u~7Wp^jX=hjxL zcrLFWV$&`nh%O4$!5>rHcB1p;nhIk&CVLu>gthUBjWBGnQedx371q4SntkSZn$xF& zIJgvZ4O*s^aD(Bu`-@?^i}t5dKNJ@h3atC>@V=|k{>CX~zV+iRISg&?f3XJ$E(lbp z*_u2#d(y8dwQbcAKK#vI0=)&LaZF^6$TaVI%Yz{XKYkPkT+#ah&i2MJ49If=0(#OT zw{!Z}sE78c*2bS5vg7;w-nZAU-t9&pvP+yNRP5-Ig!^!fr+2wVWgUmB4qnvmUZi?1;W1Hr<;hB*AWN#~UUBE<=LEjBp*&P!$k1iVlZ$NBhg z$$D&PX7P$}QfBR1oDEVtOlJ7uIt zvR07x?~k)GW@GTwZuf7$mPD;sWwAlIrJPE-B#NLh1UuR7M1LPMcK!~zB6jQpZp~se q59FVWk`xGu8iCN$HqSqEahGLDZ|9ci0i;~%_W^W!SG!7DAp1X+V&Ag> literal 0 HcmV?d00001 diff --git a/thumbs/box_018.png.import b/thumbs/box_018.png.import new file mode 100644 index 0000000..0281e02 --- /dev/null +++ b/thumbs/box_018.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c5jfr0tnkerkx" +path="res://.godot/imported/box_018.png-6f5beb2788189a96a38142383f02ee0b.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/box_018.png" +dest_files=["res://.godot/imported/box_018.png-6f5beb2788189a96a38142383f02ee0b.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/box_019.png b/thumbs/box_019.png new file mode 100644 index 0000000000000000000000000000000000000000..465096df8c4525e2237163b8eaffcfdedf06ff49 GIT binary patch literal 1584 zcmc(g`#TeQ9LK+#%NQO;8*)u9!*W;a2(!%0IU$#!5J%}8X(XDE%`z-Cmo7XZdN?8X zgt=|8SU02#A~u{(4ks<4b;_KbKjJ*+d0y|&`=|Hw`Qh_?o;Si-FV!ZOLzBPg}}L%Cmq9zkcgl91vb3`LN>TbwZ| z)+?E+3tFxxQWBSoGSwui%!0$%ajnFKDXo1kY;pct7MteHp2eD4)}{Q|iT0H@?&l^p zFALvWgw0N09eFsGAgp*}F!L?><2dldd>rYOJI?h7^Zzez%c!tBBVA)$cvmG)a-Qwl zrj<~{-4m{U)LutbbpBSGD>E^ap1_qlgt%;Tkd%;Fk8v=lgAEtHTB(^Ha{l%T2G-6qzRhPP>f|G3THve@oflI zPQJS_q&=t$Nxr*sYWV%e=Pjo^_fa~BksauL5obGP>&Mm3n zSnXUTsg(?j3#00T22*&IbK*_gx*H=7$#*apld3v9T-R=Xz=zVz#63bmKz(+*uS@&s z8FxO5ws$S#M2usGd}kfezOLWEh^uV09loK-htX^OZZfx|y`opwaS@CTpA-or*UnEp z&)YvgnE7NlaXDliW5T6r!E#^f-S=e#LYL6Gc!ZO3aRJO!6Fpr!o0uN1yFQt#N}CzDz3GU`RmYk>@VcNPAm(;YTOr6#Uthif@yX#R z;R2>&O$OwK#qQx!@Lszl^=q8_m&{t0BlIWyq|q(IwMT_y$w$UvGHcPwDfiA1)~U|QF~WAp9QaKR@gDX35Mj6 zbDsQdC4KV4f~%;>uxIEZu#hiB&Dsm#z=2Oo-{~@aWqu|m`xnTLt3gcc?g2ro#TuGi z09kmpa7drp2x_uhQY2R^X2p+7TBN0oX9MX-<1C)7jd*-5DXy%sI`Z}bEH8s9h(s0y zBCE*4d!5(VB7(FHwW5GdvcfvX`$h26AjuOU?uw$(Z!38B3WTUfNNkuLh^)@)_llXD zB@HuQIhP}F<8f5klk1s@FPD)Qv%#k`xQ1B|8P(&h0okb%zNK;FO(>MD1mrbKJpnzo zI_r-{LSAk8nMX5N1$liTPxbU=ItW&w{`3CK8+gF=Ot``*%WOn?VLf<@zI3A zZg^Epk5^Ux^LW%zL~~mIc(rgywj2fQ3e?zxFB!S9?GN5f9+7-X|4uT@kcy*Y%g!(K z0eFlvR++NwR5pV5)KRwEeHbbI`pzX4WZsKc1eijA!#iVt)wY4spY7+tx5xIKvw?+# zZjHD07OuY;Oxwc|@_3b8^yj%PSZG)zyAiXxHKWqi+eL*g&X+N|HkM$hP{1U~n?VXO zgQieZgN@FJ@8e;0fpk_)TUO=~@7*7qKBh_Nba<7cuQPgCnEhNd}_Bc(F^%X{&2UmT)+tAIJ z16``gG`O<4x`Z^QknRwA!Is2vta<&0c8F;Tt(njE@9ZuC9PJ5+kbs NKqB~hHshlh{{Z0G%((yn literal 0 HcmV?d00001 diff --git a/thumbs/box_019.png.import b/thumbs/box_019.png.import new file mode 100644 index 0000000..2f0912a --- /dev/null +++ b/thumbs/box_019.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b24ievpudu6v6" +path="res://.godot/imported/box_019.png-86bb2b2552a540186dfe64da8a30778f.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/box_019.png" +dest_files=["res://.godot/imported/box_019.png-86bb2b2552a540186dfe64da8a30778f.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/box_020.png b/thumbs/box_020.png new file mode 100644 index 0000000000000000000000000000000000000000..aae9193c29127931936211b9540a8ea3941c36e0 GIT binary patch literal 2203 zcmchZ`8O2&7so%d7&97XBKtCu9&3$nvXwm=OU1}O9{X2XDI=3@7D9=L)RTNsmXdwX zI`c%4CB#_D7>^?)W{@r0SO3KG!@chx?(3X;&->hS?!9M!fgmg-BLn~twzjfx*jL)` zKqB_@J7b@&eSw5H5X?bouiP8}NGEFxGe^qvh3B>*Bx~^xdjva@nnvmgdqm<$g&$P* z_79q6oce7v9~Dp(5NGrkPwS0Ow${afRB^}qtYRs39|)<1sZSqKP1mdROg(1XQ0MmZ z`gr`}&^s;m^{kaQm8-KY4z@GHg*X?{sP%{m7wpI*x7)DTX(gx@0q&iQWXc_+87P4e z3-B!gbRUE~J@PLU(nz;q8LUo0o^rBDUr)nsXWvg%jb>Fj)$1V=ll*Y-aI z)0g+QlSFS_y&8sp$$=D-*BPHE`5SRu z{oY5Ug2PHFQ@)hwWMbp|CCvj?bs$&IVP>e`68AFE7$}l7b6nNU{;M7AA^BZqf}#XX zl0!!rJ!oitx;AFkAb>phTo7wY3o&4BP6LqAGec}5LZ>UG8q{yU+Q?Q^gh9_9L34g` zDbkl;L}mD-0<&~HBWw~KUmsYr+T$V7?tmIKS2&Z;J>`-{Pe_5}AYk%j{ED(p=UGj0 zrgtSY36G@77|ez>0PxY@zKLkw;>yG_J8l*r5))El82gQ-&c!tJ?EW-!58XX3n=At~Fbi z)%`Su$$f!&5@^G}WR$o^wYlq9HBcBMp6)5*X@Kn%EE;tR5HDanmSE>)>b4M zs@i-~`S1D}vHo;UbaPMRjR6g&QqXpjEN?2rDt8oT+CRGEWE}2as5U3A$gt6GH*e4i z_WSh`{(&mAM>0&vKp0tFQK7FJ@5y$b?4Gc55u>sOVhtA`tI6Ye*HW|L1woQ3M(ie5 z>t4HwL?nOy=#Vs*GegCBnfw~X6bw4jl}#(8Src^+zrYo{~vYg7R6nYJ2$Lb$UZO)5Ag~Ap}#hH+^(WfqzCqlV@%+S^ZiR`CgbB-f9f60I|Z|N zJy_dcjGMY#0j@a`-@c^_;vf3XtG^1?3JsQy^jKs8i;u>IR4m3e_T zF&Nhj2(5E&%$2byT~2H-xg`zWi#F{nBX@1gEurV_^9nve&>Urc&a%Yv&T;QMTw!Na z-w!fTE$G}=uh$E+x9s3!ul~t!;f->P7389%zwb;|(GOXdogxF{ZuvZJpaWgsFwbjP6*kp?okxtu>SJ`LHY)!CP`P>K8_nnIP zAslDC-E8_8`NF(*%!F~tk>Q6yB=-t+7zh`oI8*ORXe~|?i%4JeBckL!B0lk`fEKnF$=sbIsDgpluU{4vZTAnah9O7J$Uyrp7%#|!f(LkqmzHtUpM&% z0-W+nDENF7R3n>PcE@qa`=rM{>D8R+%3h75DLWf%05J&7AN2_Cy2_Mw4iMK$^xFMZ z7cx988c8D}kfPm)el$~U16+gvFX$0a$CMpGLx_ws&|xm@fi^A2Cldls`WFsvFBP&V XcR2I3cocE}+W^*<7c5H6y&3-pCehv# literal 0 HcmV?d00001 diff --git a/thumbs/box_020.png.import b/thumbs/box_020.png.import new file mode 100644 index 0000000..098c4c2 --- /dev/null +++ b/thumbs/box_020.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cq1agqq8wtxyl" +path="res://.godot/imported/box_020.png-7aa5369e6ab82b79cd7588a38d89e8c5.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/box_020.png" +dest_files=["res://.godot/imported/box_020.png-7aa5369e6ab82b79cd7588a38d89e8c5.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/box_021.png b/thumbs/box_021.png new file mode 100644 index 0000000000000000000000000000000000000000..ffaa67a319ac7e8bbf09366f5d481e4b302104b4 GIT binary patch literal 4154 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 literal 0 HcmV?d00001 diff --git a/thumbs/box_021.png.import b/thumbs/box_021.png.import new file mode 100644 index 0000000..8e5c264 --- /dev/null +++ b/thumbs/box_021.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://yu780r8avr2w" +path="res://.godot/imported/box_021.png-5556164202d4f6eb4d033be1d31b7da9.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/box_021.png" +dest_files=["res://.godot/imported/box_021.png-5556164202d4f6eb4d033be1d31b7da9.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/box_022.png b/thumbs/box_022.png new file mode 100644 index 0000000000000000000000000000000000000000..699a27815e8233901b45ff73349d8369e7b76b9c GIT binary patch literal 4430 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 i4DIESJN3T&sLVY{I|!Jt$=W literal 0 HcmV?d00001 diff --git a/thumbs/box_023.png.import b/thumbs/box_023.png.import new file mode 100644 index 0000000..b26727e --- /dev/null +++ b/thumbs/box_023.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bnn6kx5wjwfvs" +path="res://.godot/imported/box_023.png-0021a13a259c0bdb73af1c8901f7de5a.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/box_023.png" +dest_files=["res://.godot/imported/box_023.png-0021a13a259c0bdb73af1c8901f7de5a.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/box_024.png b/thumbs/box_024.png new file mode 100644 index 0000000000000000000000000000000000000000..ccbb693c282f54fca826748c8433a8488aa43ef7 GIT binary patch literal 2532 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 H;1m7_gfPwE literal 0 HcmV?d00001 diff --git a/thumbs/box_025.png.import b/thumbs/box_025.png.import new file mode 100644 index 0000000..5294902 --- /dev/null +++ b/thumbs/box_025.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bnj3ti10yhqbg" +path="res://.godot/imported/box_025.png-69300549c2c18173259955c959cf24e1.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/box_025.png" +dest_files=["res://.godot/imported/box_025.png-69300549c2c18173259955c959cf24e1.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/box_026.png b/thumbs/box_026.png new file mode 100644 index 0000000000000000000000000000000000000000..fa5ea108b2b9e8b638dd7cb9933864e6ad765730 GIT binary patch literal 3757 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 NOpPoJDd-z<{{w}}=hgrK literal 0 HcmV?d00001 diff --git a/thumbs/box_026.png.import b/thumbs/box_026.png.import new file mode 100644 index 0000000..b78413c --- /dev/null +++ b/thumbs/box_026.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://jmp0uq7uyhjs" +path="res://.godot/imported/box_026.png-7b995186153400c99ebb3ea51ab9d44f.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/box_026.png" +dest_files=["res://.godot/imported/box_026.png-7b995186153400c99ebb3ea51ab9d44f.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/box_027.png b/thumbs/box_027.png new file mode 100644 index 0000000000000000000000000000000000000000..09e9c225438be2de32726a6fb998938e6a4f26f4 GIT binary patch literal 4463 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 P6u@J3J+&$o+sOX{E&f%% literal 0 HcmV?d00001 diff --git a/thumbs/box_027.png.import b/thumbs/box_027.png.import new file mode 100644 index 0000000..4a99ed2 --- /dev/null +++ b/thumbs/box_027.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cxgmxncmhneob" +path="res://.godot/imported/box_027.png-bb2e33ef6bbe6c959bd58186b10ce601.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/box_027.png" +dest_files=["res://.godot/imported/box_027.png-bb2e33ef6bbe6c959bd58186b10ce601.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/box_028.png b/thumbs/box_028.png new file mode 100644 index 0000000000000000000000000000000000000000..5d8b2025f3a1d30b1eda566cfdc48ea907cb7398 GIT binary patch literal 3825 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 NG}Uxf8=y83{{bxY!UF&R literal 0 HcmV?d00001 diff --git a/thumbs/box_029.png.import b/thumbs/box_029.png.import new file mode 100644 index 0000000..e19804f --- /dev/null +++ b/thumbs/box_029.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://eqotu2qidpun" +path="res://.godot/imported/box_029.png-c0b93d34fc6a9dd21f96f38847103314.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/box_029.png" +dest_files=["res://.godot/imported/box_029.png-c0b93d34fc6a9dd21f96f38847103314.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/box_030.png b/thumbs/box_030.png new file mode 100644 index 0000000000000000000000000000000000000000..cd2721ccd94f4569f965fb849952a396e9a578f9 GIT binary patch literal 2365 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 literal 0 HcmV?d00001 diff --git a/thumbs/box_031.png.import b/thumbs/box_031.png.import new file mode 100644 index 0000000..39245d6 --- /dev/null +++ b/thumbs/box_031.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c56xlvkv4hmdq" +path="res://.godot/imported/box_031.png-e9b8a6c272dd4339adff75dad2ad4f83.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/box_031.png" +dest_files=["res://.godot/imported/box_031.png-e9b8a6c272dd4339adff75dad2ad4f83.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/building_001.png b/thumbs/building_001.png new file mode 100644 index 0000000000000000000000000000000000000000..9afbb787b28118678a5bc385688f3b9e6beab9c4 GIT binary patch literal 2316 zcmc(hXH%1n5{93EfzYH_AOccClV*TdigXAa=~W?y5|pA;0|Jr|TIkY32SJ*OG)1Hc zgsw;*K&mJuR4FPg5DxF0|8UNS-Fs*D%kEq|b8oDfi5?5%HAVmcSPb+L7UzolHz0K9 zxl_%l|6D-+7J6Dh)gaFr06=;S5Sms&d0Y98W>#bQ0`QjG35KeeMbM0?7P8Z4*RbSM6Q*kS>JYO0 z@ZL;uPtN+FnZs()@h4079Ba2!a~hu6=CnD=#jj2I0-YIy$cbwE&TTanoq?I^S3Dwi zNZ{Q&Rr}!FDxb5YU@ZujPKnd)|KO6-w9Mm){}4?Hnjxf7wV`u zeU+ZuVW+14+qM9E6vNOEn*q9Ni>YY=Qn;W_8NFZ)Dsd?|$}W|m1u6j5>ctSFgqS}s z{9L6Jmi?0%;GzWjs)#uRwj5Oxoaw!S@{Gb8;}<+VjGv;NP=5raSmt+j{RLg&J@cR0 z1U7$l{JdWp!cohk9Ey7a?w|Tlo7Ho#;f7e>V)B#BsTN-r(GBT6YfsMm^_blWCgnr# zhU8}6N0Lxzm;J|{0BmcSu1!#!-H#h_Avewavk5VaFN5UO<2x;lH`J*~upQhiT4^c$ zk&C+~yYL{xhsc>Ug=);iQ~m613?$m&r3r;h{8SWK+L( zbMpd~e$5>cG4o{-l~X5M=@DMh_G4TIMiB}stPiGayyUsz`Mi}xD6u4j#_dn?vjGAY zVmfGHb0>CZ7G>szCRSUb;R02H~H7lYS z?{f%dOBfj*7~b9;4o3iDe$9P_I+0O|8)>Dbr2ZgyA3gb|>b^_2v%xt;-;%iK4+Ryq zcdA+x836G;e~w@M&x`sTfv%e{zDaxU=<|W@InIUpQNNom1=YGH0MEs^FG~_2F8iCJ zmgPOcwd~au`q7LjJ)@8MN;)%HvR_OP3oNxjtm0 zBeQK;fXutfoz?LUmdgU4W2~KbZz<4pfz{`rs1XPXCDP$10$5xvYONRb;Dal$yD_Sj z+{YzIgWRkpgKrG^?`cg#p@`{6hNr#*4vF6v0PiX%f(QB1D zt;5)3@vLkRI`YnplnSwh6Mp}-r*@{J%R3STGkvQ4qi%;^kef?TLk#u}-n+^!*iUQ8 z(d7od?+!`Lf$|frWNF}@_P{r_40h=T%qW=;!h-ySxG2QjYHb&wsv(#_<=^*`M{qUI z48>)Yy3~2yoM9st4XL-kMe_9~x5zB+w}ow3Z<1=$lj@%n#6WIB;!JFY z2kDxDR%cwck?wf2D9&t0IkW-l!oXK}HW?b0_!K5ii?DFqSUy~1N+;{k|Kri!4)bF` zM^??xm*5Kti+b}AdUf7F>Q}ZATA|{m38R4`LzL|LQ3U&Dg7IH^6uDHYw5SxHxK=I4 z2FVKCpF4=QZ;;J=BGI4SH)s$-3&EfB9Ir>d_8c-VAQM8oFDNgD1DP|o*RJstge`QP zc*wH6RrRH;wkjAOd~&Ly9Pc7M=}~WC;hLswSNQSk)Bcudl0#%JwaA^F!^t()V6{oX zIA&XZiz@I%{!xja5rg%1!3$AT;)D?xPU@qRiyhwP(-+f1>o5S05uE|YkAI)W`O%R0 zg$FBrU=O4Iu;Oh&pDp}Xb*@ojd~W|l!)=(Os%R$2WSZgOiOz!2`X39)&b=x5clf!C zXH?G+c6+Sam59@EjJ)?+<(c0@u+~P#&h|85uecwjaeA z8HO7~>*-2CLx-(3My)0bXtkgM`|iu^n?;;dP`gQ5HJ=y8FwfrDbbU{GMJP zul{TwefZbwRFj{pq^>yfOB}~^Q-~7g%L%LFTl_xo`^Cy|{N<2Yb5jZKzym{DMM=I; zGtkw@zPj^El@mF9A&k-_d?KXZAkkkzk>ELqHyDas(SPk*KD=Xu`F~>Jd1tiYS7M@@ STqytkI)H(W38G31h5rwBXe(C$ literal 0 HcmV?d00001 diff --git a/thumbs/building_001.png.import b/thumbs/building_001.png.import new file mode 100644 index 0000000..877b110 --- /dev/null +++ b/thumbs/building_001.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://biq11fg873opn" +path="res://.godot/imported/building_001.png-eede809ed875d37c26152dca5e9f0bdf.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/building_001.png" +dest_files=["res://.godot/imported/building_001.png-eede809ed875d37c26152dca5e9f0bdf.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/bush_002.png b/thumbs/bush_002.png new file mode 100644 index 0000000000000000000000000000000000000000..69b48c7b2e661457e0c82248deeac2b5ca75ad5b GIT binary patch literal 2523 zcmd6pYd8}O8^>p@8FDHynmLy_gxJGmVXbV=$yrE9BFbr`7>377IfR^+N+Viw8mTpt zLhWg*mQyqnnwnENOpnv+x!&*Z*Z2K!-~SKy{o%g;*LDA|UyiG@owTHiBme-A#^bPV zJ4*bgAmE+eb1aCpBVw^`b{Ie-8}=OlkSM`pZQT>A=Ex3Ie-CA1*UE5m^>wuut{0N9 z%rgEXdA05|lPg47Y*Rs5*)R@=)pY&ZpR-F`#ZJcQ8mW*3kyjHl?8Tl7xr>#CYVUzU zXtY7Xe4PfD89Y|!q33FVMiU+zjdYrui^ixgwxXY`Y;S*lvwxv;zUL0Mtv^Xt z-6XIGPj>aSl*bRHCV3(gNc zwze={xJM@3KO+V%?@h|@o22)7I~0a){LS!7TAr^Ipy^BY#XyM06}Hv`um)fl=F-1Z zPZuV`()ab|-Gu_3l8{10cz%T1Q0IF!L zo#=-%18&SVR=VneEIF}}qeKxzqX45x!Q$})ZC1a>q{22101q zb3*4_c7F8}Kg&aZ&TY8V$jpwjni}2|V3@vPRpTb?yo5A2n3d9+m7F(d8dGMnT z>uFTyW|~xB`XwEvR^XPIerQ@zP&nAt?Zb*K`-oGiQt>0D4+Hz1(A{yWWD^a9!e7S- zQ)^(a*)uf;F(GP~5!x8U12-Jy%HTPtY?@+N-Cj_61=|&ANU&Oap5**S*wTbzrfnww zlc6X<$ zPPXI{NL$2s?+IP^G}nr2;pLG{BoTa+=IUiJu1>F>RydslU~K=+k6F-4EgQ9Z0hiKY zPKxGEymx6lTS|Y&SjCS#Y(T|qfXFmx1Y!wB(eC@hy#7bU^ngUfQ6n9F`>NKpaMOO@ zl;58MJ0~_5YX6FT%g|h8bK9kz%ujkCd1_j$BXOn2s~x+}q^ARBdm!6<0oiw}T7PPkvjy6G@mrfU#vZK?Il3*p}OgZnEdC1lZE$2j$t`idB0 z^;nYDVA6wS96}zG4gsob_d*^0ximxnA@+|X0lK%-C&7qfgC8Mm|E<1?di@=<^Ncam z^Zto8-}h+j=MA0ReYxR63;RP{t?b%Y&}Q7>wN|2dRF{|#mQ;)Q1tT%{9S&A?I&G?a z1Db!*u|dMaU-TyM!mpjM7|q%X)HxA|dZ?bEaPLtavV2g%r`PS&<*6AHDiWemXfL9r z%CW_EEVQT}f!_H2?Z(i%bdRDbczrzkVZ}}K0$q{3AEy!i%*4(m(zrq8Wc<6QQ79AG zyXf>Sm&1u-^Hl zLAU}RFy?)NDo-?!MV!75;AeJq_3ytu4>}ubF*WV=hq5QqgX>24mTt5XkSi4cAg02{ z`9Hqgo2UsX;4d@1oLEo8XY!<3NnLFRgiudphNEe}sd~sFd=W>#tb4B?%z|=*$h%%j z@+CsgmkS`40Tyv2+H}$Fn{dHQFTUb1)gZTck(`q$#~0>X_YkZ_@};@g5>lcc2Y`4wtQnWp8EXev$^4It~Dc* zkg(;06Juv}2;~=^{jlc|2Bv3q9ZJP_JDlJ}D_u>9fdc2&J(nKszHs#Tmw5L}eM9hd z7Cl;6)okp?ten2L z0`c)IzPr8!S8|3ULw~j6m%h-kTd>}7{qNxMIjkA5%6XujT0K@_xS}8WGjP=Ap>dUH z!auDZ!Van;FYq}grz98OF9~NyTPs&?9iNfS04FJ?KPjUX_-`NSH?wWyH8W6E|Jei7 z;hBp3pA0M_r}^d}^fUWxZF1KVY+NN~o0}~_&&E2p0Uecxr28PD;}=m(-@b>9sJPiz zvxIhsp#{gt^<&JDrfAOmCDmEe!X3Df+R7|=<>&B!fE53oY}j35bV954_(tQQ9a;n6 MPdH;6F=x~N4RP0^@c;k- literal 0 HcmV?d00001 diff --git a/thumbs/bush_002.png.import b/thumbs/bush_002.png.import new file mode 100644 index 0000000..b127ff1 --- /dev/null +++ b/thumbs/bush_002.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bvwgcwf1tqtyi" +path="res://.godot/imported/bush_002.png-b49ef48e6bea3168514ff01c63e5211b.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/bush_002.png" +dest_files=["res://.godot/imported/bush_002.png-b49ef48e6bea3168514ff01c63e5211b.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/bush_006.png b/thumbs/bush_006.png new file mode 100644 index 0000000000000000000000000000000000000000..c45ca708dcb241177b680de972037e7f92292796 GIT binary patch literal 2402 zcmc&$X*|>m8~qPs8#72^vV;_BlCdkYU2B#pSqf>$Rv{51nlaX_kuqdYh}TYbMx!gc z;c_uyOmPie!^}l?bM^iG{JtNa=X^Nl{C>};=bVHaHfAu0I0OIyn1#8q?J?qi4KMfc z{;cOVcnqK*TQeh|dPH&s0Qe*=j1BEVa~ZjJK1HZ`FX7g_8l){W@0Lh7=fuTj zO@crAocZ|9sNw{cMd6u0CkPsQ;Vvx>E{TUkDZ+MWNxVk(6NTt9;dnU0`a0~<*E#EY zN~&+j`kc--byr(&h<+Gf*G9={r5~XCW+|-=K|k3!?A-!2H5CD=E0@OI#Jd^BY2OAcF@}VB!ABuMj_d09|PZpgYGThY|$v z@2Wu~c~=u_FJ)JW5`^HuD(jD8RWh5; zF}KOAzlj-DNQXDCO)B!fe(ch6WIzs1gXRG>CXvn7ocaqn zq}_Y`l#Nu6X37X{Fo0FO=-`*++^8gZ0eRg%Mu=DTXhB86tfGIfIW8auDPlq+6E`oR zY0csmv_lzyPj&U5JLNjS>VIAe9mxy>-B#zBoL%&tYH4)RyEX^mxMF*5c))$^$$3HM zA#h>5vVgk_Vh)Kt3q;zlUP(t<$53{?-%_vb$)IqBP!sM?=8ld(VCQZ$DqZX`s=o%s zC0h|iZkt#&{~6R*3C0OQ{Y2r3qQk?=s#;xrRqYxwP~6b#ipC{glG5G`_|{2qu%+#re}^oB>OzQ%%hvPIpCB z;8P9ZT#zMVHUUDk=@v;l7d7N@!wV5bQlPT-$0w1gQ_66f>q-NMM*>wwxMBW1y zKT5Wwcu8FaKgf@`wm%^*AeVu}iuvlyW-)}JLfv5KS6+y!jtCT!9G-yS*Lr2E+Wg#m zUqTHCEC4|Zoi2jh%JOs1(AONYxxVI4(VZy|k=Z=U7oq!y`N#6l!Jlbj8=Z15bkoB@ zPWioaRZ2fmHnkCfQR#klPLH25&X;SoHAg;3Tpn1j6q>;vU3zRnlGY5I=Q0TWM))F+ zM8=0NNl3s#Fpi8ddw;Leh?3;6Fgb$E>h?^Q2yYR&TqX&lc~#Yl+8@lV9sb>*9v37l z2_axmtmy@w{k3}-@hq>9HGL%k9mMYe32LOr>?6%zjwtrwYo2FYx1_05ZW!K$e^f1o zoczN^GQ4y>qphXGineb)Z^o^s$_u}6s*C{P9W;s$tvk{EJu{PPMU;?UmrK>-z-xfj zqFen*p(Ud#>0K&pf3lt_S+u3KjnF!MzA-L(f$MI`yTz@fOu(nr6~*+lLlQSxg8r!c z+{XS~zmEMwL*lOGP_KZr`{9|x;Ip9O@^cLxI95%6UBTPDZ#22^bQnw%+n(A1DZQ!?I1n~T6NU7Y8ibTp0rP$@-M(1l($Gn%W$RZ9t9oT6cb7>GU*dL}V z*%1&dfRCD^tUj`=uyAC}e(QbBcv2cqKb6?j^HlxRtaa-fa<$Ah2i#z0tE_#+o~Vw2 zO>LZ3!dz#yF1(0j!esFC>;IjbCj@ zenBq7!&xXr+x>*EY#K3j%71J*s6bYEv5CL$=P;veK>2o5Q$gwd8DXp$P-PxvtpLR} zPVAfCE^#3}5$|t^OuxaQ7S_-w97S+*@52X@)}E!QD=*sOeVGjtIZBdRorgLO7ruq* znN)03*w!Cn-LmWwL+0=IoQjnO^Nw5TSzb_4-Fl&3bhg%&eJ@)zAh4X#Sn}sfvLE^H z@Od`Mk-oEZuiK)q=3dK42i$Y~fvF>IQzQ+ViL)DU6Ql7M_Bxxg4#v&pgDNNgp}-ac z4A>Mz(AmBu zG+Z1+RldWQ7(3!$=p;olrryHC-Lic(oG(>ZZ{!UQVz-}7_j`)fO6BhUwrBUaqP;YY zW*I-&+k#kL`eT+Osp4Qz+0m!9-YGO&*SKgRukZ5_E0oJ(Ic VQ7?COGmc9WU}0ioTy2Do`WH*+aO?m8 literal 0 HcmV?d00001 diff --git a/thumbs/bush_006.png.import b/thumbs/bush_006.png.import new file mode 100644 index 0000000..6e05c0d --- /dev/null +++ b/thumbs/bush_006.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cfoy6lnosuawr" +path="res://.godot/imported/bush_006.png-cb51347701436de4d864aecaa0296c50.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/bush_006.png" +dest_files=["res://.godot/imported/bush_006.png-cb51347701436de4d864aecaa0296c50.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/bush_007.png b/thumbs/bush_007.png new file mode 100644 index 0000000000000000000000000000000000000000..60354a4db35ed8e44be5266307845571b304542b GIT binary patch literal 2141 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 literal 0 HcmV?d00001 diff --git a/thumbs/cactus_003.png.import b/thumbs/cactus_003.png.import new file mode 100644 index 0000000..9f444a9 --- /dev/null +++ b/thumbs/cactus_003.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c8x2ac0df6ge7" +path="res://.godot/imported/cactus_003.png-6c139d54c0012263761e734012076a12.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/cactus_003.png" +dest_files=["res://.godot/imported/cactus_003.png-6c139d54c0012263761e734012076a12.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/cactus_004.png b/thumbs/cactus_004.png new file mode 100644 index 0000000000000000000000000000000000000000..de0ac2e3d936e1b14160e61a6131d1032c84c98a GIT binary patch literal 2089 zcmchY`#;l<9>+f$%Z!+5LR;H%nOq`rOJwd2hRUVfR((+?V(#Y7G)ive5{g4g^%0?f!Y|oc01aa(4giQP+FKE>#FVW)9nC@6B72i2OuJ0@OHNV2 z+QeQmLZc7%^amS|uOt+17a&$+;KS^ z4^RH4r?=1d^JN|8ZV)I4iuIkwpd-*@-W3kOtD{gvXaV=HS^*F#4uE60T@U?)Ie`-#PZsmUFJZLYyuCaV+FyTlw7T`8OREyGT;|g|CwbT7UDn z5uCpJ3{F*Eqw^1u^g}Jl(cFHy$8G(wv<$2nJf5_t=VLo%N^byGo?RWh_Fz{ELxo$+ zNkCKJU{(F(AGGS-PO!WP5tX9K`OLX%U1QUH{No+afH>RKSM;_`LN2H7f_j%!b2ueI zJkWc0l>zE!3+bmr%$!amly2nu5`BbF+MV(f!*%0>g zTW{>$Lso{y0;Rb1omSga+stUx-t3fL;LX@4FCWYwUIQRtZ_0t?Ywh|xq=K8j%!-WP z2N8Dz597CCg?bKLc|@7#&iw@4(yghY!=!8>1NUKI6@W)k#;<1D;t|?Pcbndeq=`P zy^ly=SpUJJVG^UlP-TF;j(M{OtGg-;nXa+P=EC6L+Qt z-b32@ySRl27#D^kG>u(Uav-@}l`hBH*_Bp6F5c!jZB@>no{bHswWtloX z>Xs5I7lN+xsv2XPIZ;f+Zk-Oc|NEs2KNEl>zXypaOkz9(yY&KoepmO;C)F>REF=_- z)@vPXyR+i7eR>NE-}WTDWg3#DIds77Dmfq$&HcXpK(ByAj!Y@wyUUm0V)M6%uDNU9 zH=4R~F0Z3HhETi@#-{xaS;N;Bo9~HH=lzcoW@7F>EPQ@M(zf`09AO?5N zsdDFJsE@})# z<#3&_;_b6vG;*eI-@p%r_;1v!NqHCr1=xqYjuf~btkl2(7VDaQPq}P2X%N}7ogv#@ zXI+e5VvB~D_VC)raqg5S@h-|hZ=bV7_If~B?5(u0E2rF5Wi5-{fz8wr?ttuSFpn^V zA{Bm$9O=8v_ul_(IlI4h5zu*s^Krx_YrJrl;)JukK8phz(=RbALSk&J?kIIf3G`DN zS0Gx7h=pZqVA?fcnDIQWt?K4y==R8!xnRh-0 z3zBjl!$4z+*B>gMy<&a&2Yy#<^6h=+TX(U+r51`VI3T!Ru#I!Y=VMecFNUV_lF;GF zQ3DQ2gsu~wN#VTfHrc?D{mX)j$mf;djF9{V)##m==^);_Av$n$gn$Mcz3QUq)NkXp z1(D-k#^BL+O23kfyx*%-tnr1W``pmO(0Y(PYqvO8Hg;C+$nnJd@ZQ?0V^v zVVYk&UEw(d2{sqdPMI0)js9YoN-gud_`ANJp}BKr4Rz*BUiy#~De9{j9(Abeo;;5W zk(?2XoVhf?-(RakZ?Z-GC{iIOqtM@8Ro*~;%%AtXnPWQUJ=?4N!fcc22=xgViq_Mw zW>`<$Woa%yGUkjY|ArG%e?q0l+6_{y(%tMB2gX_l@(7<$Sl)UjSPc)WC{s%gs|1Gs b&n5}fLSRC2R1iVJ-w)VZ6RjF7NU47Us+GG0 literal 0 HcmV?d00001 diff --git a/thumbs/cactus_004.png.import b/thumbs/cactus_004.png.import new file mode 100644 index 0000000..062d99a --- /dev/null +++ b/thumbs/cactus_004.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cga1nrd847sbx" +path="res://.godot/imported/cactus_004.png-5533e8ff52546a669f4eeb90b902d0b2.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/cactus_004.png" +dest_files=["res://.godot/imported/cactus_004.png-5533e8ff52546a669f4eeb90b902d0b2.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/cactus_005.png b/thumbs/cactus_005.png new file mode 100644 index 0000000000000000000000000000000000000000..ffec7298396a17c563b9c2118f48d847ba4ce28e GIT binary patch literal 2362 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 O!@%D+kRkDo`SCr;7HGc! literal 0 HcmV?d00001 diff --git a/thumbs/cactus_007.png.import b/thumbs/cactus_007.png.import new file mode 100644 index 0000000..b70068a --- /dev/null +++ b/thumbs/cactus_007.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://lh3s5sksx31v" +path="res://.godot/imported/cactus_007.png-f2be442d19a53747f19ca104a4708390.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/cactus_007.png" +dest_files=["res://.godot/imported/cactus_007.png-f2be442d19a53747f19ca104a4708390.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/cactus_008.png b/thumbs/cactus_008.png new file mode 100644 index 0000000000000000000000000000000000000000..2a86b7fa1a6a574093663a05fc491bb05fefe3cb GIT binary patch literal 1883 zcmcJQYdF-20>=OIM;Ky=kO?!aOH_(>FfKD=7^F3eA=k-br4(n`W>fIcHGBElsaT5w_HYQn!%!7F*jz``Fy^f^WnWb&-?j(ez%F=5Dr3*Kmh2pSec8+7C#wKLH0ckHJ>}Kv~xtj}4@jua_?*!h>}OXm%YvGOr4scrj7M z+h=)5i>-+vm+9#QB0?YN;5|tA6;r?6uwGKNb|c0o-r6jbRI96LQfl7D89o*tjf&j- zV`M%}Q`4?vahvd!(Q@0SBTG5$u|Zgz3(HYBpEjQGL##NSO+5Q91@P>+2aKMA{1OdX zjwllIRIA{JFplQ*AAAAc|73Vvr$BwXyEE)mKfZf!at{ldg2n$a4GpAA<2zde}pkV1{R^aoVJ$a6dj6`NFHQonX z`db$-IumjQaS#9*d$5)IUcI8U2*X+_$W!+@P0uz%cnx%6If$cH)q23FIsnT=L9S`l z0w>*Q`CL{zK(|HEDOA)Y+x8m5FJR{&XT#?6{8O|^rk6<;Xbc}?07du^MJJ1xknFD6 zlw%6iP0Qp#dsbTf(EP6B)ddN^$_>wcx&(r(~#Vx>EMc6P@>!35Sjf@bn})7I7! zu4WASTA+6?7@GS)fbdgQoYF_9F&Mzuc}#j^T$4RpTG^>V(D2!ZYcL_)CzTDFB(N$RuBfxoD{sa8_&r4KVt-S?o8Q zSHdX(z&c~UTrnV6V`#Pm(i2D=t-ubh)IFzke}PLgIFG|*@=JfU&W6W#;H@#0=%1Dm zV7km>EJ<*^ljK{mwW=nhr@nH4;fTy={q?y$4!7T($@nMcBqf1wq!kr=!+=f>Cr8VM zJR-Z=R0D5SQ-2Q(Uh{ea0!@qSrUSe?ezy7!W0j@G#>uX>f<)wlCM_5u3sb!&896@C zBkv9j5~&2Yl$SYuDqjjW)_Ng@U=vhw?p{hQ@l83fqkO#F5P^&danaS$j2^ew^-NWyp-;C8C<#7HqX%l@Yj;Jm82BVam({w%PWot~$zaw9FE=w4{{5S2Awo zaV3&XCl~L++s(_O95OJ&n6@rg6A?Fb7DKE{a-TIPpM@+hnC7&bUW7hMTO|M z0JMO_9E=PuZ2#54e|a2;h0X|P(&YWG^$gupyDZMVXAkG}p?YHJ(dW8ehxIM;MM2D} z1!w{0TWbHGPiI%S`Qdbt9WaS|19`eMDmh)Er`Oq?@>A{eB8=lUV^;w&G-tJch9U~> z?pNV*_DDcBi$%>&tv;VGFG8h@V}4dmN|+s6bHzl}6-}&|Ia99unC|Rd8V@_a6P}4ufe}yddSYIfFJbC*LkS#j$b=!>6R}&diwg>$B9Gj` zs(QgR1ZMf*8L+A8sS;oT#?WIprzLsi01DevBec!Qu%e=nHxvB$_5aGI7tcl9J*-FFTdzNov+?=cVo247bnYd9ZW+aGzO?w> zKplBPN_pT%Cqk3 zgiLJlDJNSek1q9@o@-PmMhG?CA}@X2>F!wz5M5m}gq(AQ56hv$y^C^EgDx<7W!bED ze*2Kds!{%tNf4NrGT~9P-s-@Op)9tLC!NX&%lWa4Rh*cAKMP8@dDVB zxh!s+%5dJQx-BZ$^)C|nS{x{-=6vt0sL~Lo2=c%up|MK$0xz?Tn*^bXpjWev+hadz z#Jp(Y7%hD*ofBoBxle{kcX|}q@PEO?e-md+4)EW2U4(RxI_%RD@b>ry-;BGE`8TYx BUGM+^ literal 0 HcmV?d00001 diff --git a/thumbs/cactus_008.png.import b/thumbs/cactus_008.png.import new file mode 100644 index 0000000..2b1d2b8 --- /dev/null +++ b/thumbs/cactus_008.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://brdj5ti0abs86" +path="res://.godot/imported/cactus_008.png-a590d884b399127c9a945f5264db79bb.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/cactus_008.png" +dest_files=["res://.godot/imported/cactus_008.png-a590d884b399127c9a945f5264db79bb.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/cactus_009.png b/thumbs/cactus_009.png new file mode 100644 index 0000000000000000000000000000000000000000..7ef022783e13ff03bbbcabe0525f2d23c7e5d014 GIT binary patch literal 1444 zcmchX|3A}t0LR~-*@jnIR@g`i2uzjnKnLT4%lt9m5u{qV~4@peaRZ`K9?peY`% zzG|}mwbll8w(JY(R0E3jbteN+x49euL=eT*`RJu0Me)IG^J7NorLpDA#v(%NGm4&( z?XA=-GYg##@T&s8#{44A*K6aiNmz}SZWy=?9?6Gs`yNF4lqU36lG>SZ=(AANN< zt@1JuuLOkBt21c$2Zs)5LEu1ZXif9P65F>Lr3KmPQ?F8p%`U)Ec+Dff&3@|7rIXzO zNQiX?6DMlF>vP_UWh9^BT#iY;=w*$dZ-egOiJWIKi5%w5%OJpS59;*mu5X{afW2Lu zC%=VzrkR9Iy@*XLs6PG{VR{VnU71On{gJHKL%Nf&CrZV3&zKu|BN&$7TH1XuAlO?Q zrAn#qdz-FaWP+7qf-C5nP-u8o;>7nBV5?8Z2$8{sy)w+D;xD@+6>JZWaEl+pF$b3^e~3 zY;gZ1cRE<`IH0QjaSe7Si5QN5Y)@jymXk(;hb4I*mnWQJDe37IAhgIE1Us%5Zd%^4 zyn$KHs{p)^MG8Om^~Aw^UVmS+Nbd{+9~nFXkM7=s^}p5rl6pexA*{;~TkAsdA3&@{ zlRY!@bmXnwtC4{k4=ZKH0(+5lTvc zpaUP)v+LBD1sF`8HYgZxM2Y7+>pLBIhc_gZ@+*M%hz6K`T4-`&{&cIX6qAdQSt%uc z>$SW%7%CP4I$)rVVJ+^U@tv9FgQNl$7Asc1x%k&3_Yzf4H*`MJLgr6f@^2|;R*BuO zzT=L)T7KczqpgSh;5B*o!}Qq5qDcB_W6~b8z|GLyl(o7kXN4I_6sGj>A=c*y!Gx8Z zDw>e1O}yQIeW>{ydO+F2H**d$532!+jh%FEQ`_PpwMt7PHBSc1A#>G4z6Xg#_<#jd&D_|i0QShPY5WwEx&pgk%d9BT zypW?AcTSa1QW=L)Uc1iDt=o{bjR4Qh&j6bF zp(&|tR^nbVHAYJ>bOmM;*j`>`ZgVc2%cEm{4_R>`T{N{14E5@jCF;fidLidi->in zO(hN0BU`>k?dJcomf@sn7cwhYG;d-Q3^j8iED7WCbq6-|oQBTT2h=aqnhmPeG)p1( z2ave#rhDCjnmI40l9aNvhXBIbupG|<4+esU@O$qs)MRQ2&I8?J}@A2sdNsj;&|D=BqReY=3- L=ItsXQ&ax|sq17( literal 0 HcmV?d00001 diff --git a/thumbs/cactus_009.png.import b/thumbs/cactus_009.png.import new file mode 100644 index 0000000..e4b85c7 --- /dev/null +++ b/thumbs/cactus_009.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c2lg8rvrhc70n" +path="res://.godot/imported/cactus_009.png-0475d5327c6d61d97845c24b518ca20a.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/cactus_009.png" +dest_files=["res://.godot/imported/cactus_009.png-0475d5327c6d61d97845c24b518ca20a.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/cactus_010.png b/thumbs/cactus_010.png new file mode 100644 index 0000000000000000000000000000000000000000..a709ad9f4eb28de1d6a9d0504f41e1a9ee237760 GIT binary patch literal 1819 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 DNRL%F literal 0 HcmV?d00001 diff --git a/thumbs/cactus_013.png.import b/thumbs/cactus_013.png.import new file mode 100644 index 0000000..7210472 --- /dev/null +++ b/thumbs/cactus_013.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dp6fb8u33pyit" +path="res://.godot/imported/cactus_013.png-44f3666210a7d2950e2645c830dd1348.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/cactus_013.png" +dest_files=["res://.godot/imported/cactus_013.png-44f3666210a7d2950e2645c830dd1348.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/cactus_014.png b/thumbs/cactus_014.png new file mode 100644 index 0000000000000000000000000000000000000000..45abb170dbbea00439439f2dd07970bae143aac5 GIT binary patch literal 1715 zcmchY`#aMM9LK-k<+^NUBnLCM9CA6i#?#6$4SQOWDAbb6=-7nZZzFRl&s0QmX{(dV zNu!QNifz>r$)Q6ytW7xNP}AlNhjyI*;XLPgUZ2nFdEU?S`StTI@h9S8P<05D%4 zT)?(z|Bjl<_I`0F{LQw&qyW4pz#cUG1OO@&Uz|r^TJ3V(WW3G^!(J{qCHhPE@t{!C zHOMh-ZTmxflIbxL>=iCTtqhWQt>$VPA;jc-fy6jpJ--B(ZDyX`f}IPZ5I)f>IZuVl zpTn|lQlCx^zTeyCH7J*-haWgty$P3AC*{l!#5XR|t4LDgp>qW&8p6&LaQpA!Vde)9 zzkr+QEGWCCx?H|(*Fullvmzi9$EQb78Q{i7v_wuadp&<8jdK@MJ2KIr*C3s!3I{@ujK$7zJ1Q-eBfFwTAd(x_e7;B_xs@r*j1!Ouy)oK1+?>?2VG4F69cMI}B z`6Ntm=gP?u-l_q=EDtrwUFh!C9#OPv)_FbB>)YBJPgrrb<2N$0x-clkIe_|NRkfGEyRi|A5U||8ZYz59tgk@TF z#vV7I%_RfE)8Dw2yN0_CV?)7Lhv)rmx?+4n^SE-1rosM=bM5VRBwI_%wEFyT%byI| zYpuW-8?5QW&e(`aJBA^fy=iqLth6-J-lftzHy7RDP=0Yle{ zSD9ak;ai0|?_#x$bQnf zyZ^@vTN_R`zwx#Y8k*1Eg8JEhNx@LXAL;OxQ{_08*wmODBu#3N=jiBCF^wiPAUiLv*!3J7HKGnBd)j~dG%iH{F+38FNg_$5wxx;>x4})NgKuC*vS>bt@SKyP$z) z*gale^u-+n%=iBXAVQK-wnlrD*b(~Vv(>P z_)1^I9kt@>wmo8F@iBPXy;8=2ZPo|w7|Eof99zdi8Y7Q2jjs#p4!Cu)izYh~Pb@oB zzkCEWIn6?z%}ZD3#8JE~X5zoL+&-#QhW=%DKYxQda8{0gtc^o4k;e7K%!l@zrM1cj zIZ={ep^-~VylO>$)ORsMoqFvWH-KCjdsBDl@$wNpbZ#+j>iG?8%{B$IN5G6~QgY2` z0qs zYTIeIezBNOGOmCCS4bM+ML_@`uVlPUQ2_8R>j#7%_}5bCnYpB^;wXfNe-9davLI0j gp{oVH{(o3kt!aMtIpe0a<#r1JzTQL}+w*MxKki%ffB*mh literal 0 HcmV?d00001 diff --git a/thumbs/cactus_014.png.import b/thumbs/cactus_014.png.import new file mode 100644 index 0000000..5bc7c1f --- /dev/null +++ b/thumbs/cactus_014.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cgkcadtfplqkl" +path="res://.godot/imported/cactus_014.png-4228d4a531ff0b68ee692366307eda30.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/cactus_014.png" +dest_files=["res://.godot/imported/cactus_014.png-4228d4a531ff0b68ee692366307eda30.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/cactus_015.png b/thumbs/cactus_015.png new file mode 100644 index 0000000000000000000000000000000000000000..2abe90835c22c9830b2e09fec09f35d6ba2af4ad GIT binary patch literal 2671 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 literal 0 HcmV?d00001 diff --git a/thumbs/cactus_015.png.import b/thumbs/cactus_015.png.import new file mode 100644 index 0000000..a532459 --- /dev/null +++ b/thumbs/cactus_015.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b6myrk0su04vp" +path="res://.godot/imported/cactus_015.png-23df9f1d71ead0d346933735de944ed0.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/cactus_015.png" +dest_files=["res://.godot/imported/cactus_015.png-23df9f1d71ead0d346933735de944ed0.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/cart_001.png b/thumbs/cart_001.png new file mode 100644 index 0000000000000000000000000000000000000000..7d9023a66eb5f6bd50c9ed71f218ad01cd5d5400 GIT binary patch literal 1316 zcmc(f`8(Tp0LMS^I8q{xwN(*BDN0dl#?lC(uBQ!J%9=8182ZFHM@q;yb+&VDt_@Y4 zVpoH$Qg>WI>wK!{Q%6J0Q6$0AL@Bd>V*TO$e!YHp|NOq^MRZkGL@5FQl-=E&uO1Ql zFL3#z?zJZm9Rc?3RaXLFjiT28kezpTcJ!fDY|f2&&Lp7ww~U6|NKW2SIBKy!Q_ky{ zSwyS*WWpS|?7f1Jz3zjId*kvNUd4XwV}Oi7m#Ma=@p=1q`{El$cG?Y8<$@X9l?aA= z_N!O7&4mtODQaRFgByxag$$++44wtC|F_PTdRt&3x7UZ7o0}a*{`9hys)}Q4i7;vV z>|l@emG+c9WI{RLwc4zTKe=P{%XLq0TdBhZx&sV=$|pFNk>ALnhsN(}W^Ls_P)v;4 z`TA~rlx4F#i5YU`#V}st}B&Cdl+L)si^mefDaRmDuXEs2=vvg7!F+@u28WNwFG;HS&-B_Wp@s-pX> zpwLd{jNaFOXIidDNGLJrsO_`IQ__Sw!b&Edtwc5x_HzxPp-0$;>ed$>Cu~bglNiHa@|Xv&+^+HJKi8rr}>sTx>~RD!U>G5XDsqQd#* ztlfh(6BIjlac?_R*YtKH-EjQ7E`A0;aI|vbn}jC@7#q_A3^C)`_uM;exzmgTt&Jed z&xQch4Tri_SsiaAbid@T1q-utn8N2lf`b$vlMw%s431=80qc+8+5p}MxXUq$2o#V= zPU5GEGm%}^rcxS;!&zal{1pHqAFQU2OKO-OaXb+xNvfLr*M%aF8vjExJfcwroYIEz z>^1Nh9#408gpBX=lRx8ldYerWIA>*yQ*Dy<;pgeX(u)&|DEop2jf^C{9P0(qiZX?_ zg)4WSh3#j~DVL2HS|w&u<@ARWb#Q1MzuthGGH1-enD0!F@lIz}E~?Yio78oF_hG6W zu&$>)ZwhY;x?y%SY>Qg-=&Od-_oX`)VU?dZeB6t|kzjiV_IV^V=xthyrgEyxy|*$S u!li{R@vy<*y)~Tfdjo)9}xh^$!u| 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 J*IW80{s-Z+8F2sr literal 0 HcmV?d00001 diff --git a/thumbs/cistern_001.png.import b/thumbs/cistern_001.png.import new file mode 100644 index 0000000..6a95882 --- /dev/null +++ b/thumbs/cistern_001.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dn2k5xiv5c5n8" +path="res://.godot/imported/cistern_001.png-65f1f2b3074a18f2ab17db41b79ba065.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/cistern_001.png" +dest_files=["res://.godot/imported/cistern_001.png-65f1f2b3074a18f2ab17db41b79ba065.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/cistern_002.png b/thumbs/cistern_002.png new file mode 100644 index 0000000000000000000000000000000000000000..6c8741cdec6b7106538971f1b5fe93693a3680b4 GIT binary patch literal 2203 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 V|I+#amFe#RIBaZWZ$!rV{{sz-Is*Uz literal 0 HcmV?d00001 diff --git a/thumbs/cistern_003.png.import b/thumbs/cistern_003.png.import new file mode 100644 index 0000000..c7dc1e5 --- /dev/null +++ b/thumbs/cistern_003.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bdii624lhc7on" +path="res://.godot/imported/cistern_003.png-324a04044fa30e03cfc90b02fd620e35.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/cistern_003.png" +dest_files=["res://.godot/imported/cistern_003.png-324a04044fa30e03cfc90b02fd620e35.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/cistern_004.png b/thumbs/cistern_004.png new file mode 100644 index 0000000000000000000000000000000000000000..9689bf647ed666b62457250585a620aba63fc4de GIT binary patch literal 2213 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 a_E7;`?S$=+FGFuiDt>UB7wV8bSVFR6aXI2pO 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 Ltpm2!+AHpFBIu`+ literal 0 HcmV?d00001 diff --git a/thumbs/concrete_wall_destroyed_004.png.import b/thumbs/concrete_wall_destroyed_004.png.import new file mode 100644 index 0000000..f11f6fa --- /dev/null +++ b/thumbs/concrete_wall_destroyed_004.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://tua01wiox5nv" +path="res://.godot/imported/concrete_wall_destroyed_004.png-9305dddb356201bc9e244c9fbd0f369f.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/concrete_wall_destroyed_004.png" +dest_files=["res://.godot/imported/concrete_wall_destroyed_004.png-9305dddb356201bc9e244c9fbd0f369f.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/conditioner_001.png b/thumbs/conditioner_001.png new file mode 100644 index 0000000000000000000000000000000000000000..dd61a9e058ea169dfab6e9a4fa48ad9de2c5bbac GIT binary patch literal 2860 zcmd6p_ct4i7sg}MNQ_qPYNM3eTc!5iTT)6>YSe5MEir1V)l#qZirN*M#z-VaY(+~n zRaHVztJL1}>-%54=iKK$&pG#;`{Q#yiI(OD%s^fs003Y%GSs!c^vM5A z)C?)?nlC;Aq6M#9$Ss{+O_V#3JF3-l9Omli zf^>_i52gad?@XIygJWDxoqSl>pSWWRSOXvQb%%ZI;70&?v-RjGI3zSQr=WnI;UMC; z`=om(Klm}rwJJ|MKr@fl8?8*qq|?}2<0<4_8;g+7VFH0bryupHBf%!uw2{gn%gvbk zxo|qC0RHI82L{69uev+xP;5WT^3`;N(-~vbH8dh%M1y{5Mf_0#(B6v|k_{K&9bGZU zl8M1pF>o!qvtxxe1_^d1;1$8;vv66ZY`C*jOJnW9jhh7a=QUl4g7LZJSnqFaJp7qS z^2*_fP_Y!xiP@ci>@dcAzJH39w;jJOBLYiuo2AV8?!T?9@TeS2O$jF#pbIw}NYaWe zp0~{$=@DyDUn8YE7u#7D>+k=GhBvg}Pk zS=YNI7*B*U!(cIHMfO{VHe&^Z&3NW#-TkF2JcW`RcO7K_(G(qp;&HcVV8DbMuy@;_ zy&!K!TLR@Wd9NjCChfe7;MZAQUG8=rp zh_7kb|M8NlBbyR869MSJ-kOG8I5*9Q-Jx+ay7Gd*L`4{9NX5XQA z-*yGA7S>^DB1@`bB52;GrlNx<10^P%$7|sp$Tz4852U{8trE$cLP5XC1b_DuBy&e% z|E)X4tIPP5TJLfsZ>?z{1}pz+OQ3dj4#I-@>*R0`<@N;mRA&LDF|q z_!jAB!V(hJ2?W#w8Vlk)d}IM5>A=Ht1enB}A$u?~gKpcsb7oCNR*gMZ0pXm8!>Y;g z%)+x|?|BFd5Lh0*aRBA$g>@~tB(Xh>+fdzg3*YG{%n+Bt7S{9DCK~8ru$;V{zHS$T z3w}kcK$qY2POA)g6`8`(i1tBpztJkPv+q}WrfR=|svv{4#@aKw+f~RmrD=z`Q)TR%$<2vRB$tv(%Pubj1K;@fPHb z70OcX^Abox;_+-#+JwcNb!{>V1o)I8?jMLq4BZcm6MvnPADGm6UKf5M=i7$;9Mz_# zsTX++eX+lGXTUWHq52^AjOJ7{XB7|0U#cTsqg8`wKNQm1dv!&Rl%Ojx>ug>+ZX3M; zVaaj}2;P!I-YT*btN-9I3-)aviBA^45irWDYf?=EJ=`<7J{w+o&oc6EL74wonr$kL zuIP3_FDEOxzF^-@;H|6F= zO9w6lJFx1(s8<;G)bvnQ-Q=!YNP=F8V%1A!oAm3utW3p~V}tG6Tnr)Yga?i)1@x(D zX&@hRNa%YbRl;Bp*{NDdl!s29WYc;-I9O2Hq}#KC$4~7etG7p3` zqQt);>;oC>zRsua&d;(ka`f3=xk>5O7`L6G4|*;{$`i)Ej5|N4g2MDj-;tqvW1;(% z#Xmlt9lMdYwq)`0ZJo_v(;d@vd0+TX;zrx(lpM9@o^6l!nXuC>(TqEr+wMs=}GZ@(8y4*<$4 zzb<<@QLm&tib)f`DSk46d)QZ2Hi0fFh#;u_YL+HZPx(^=n0!|Ctl0ZdKQ0_Pk{AFh z!z^rxkbDOM-uB_7<74~Zd*~mh6z=+YCA>$4?p@r&;S4c literal 0 HcmV?d00001 diff --git a/thumbs/conditioner_001.png.import b/thumbs/conditioner_001.png.import new file mode 100644 index 0000000..39a5285 --- /dev/null +++ b/thumbs/conditioner_001.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bjwonhrlw4nsu" +path="res://.godot/imported/conditioner_001.png-0d9e1d8c07affcf7432163ab68dd8561.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/conditioner_001.png" +dest_files=["res://.godot/imported/conditioner_001.png-0d9e1d8c07affcf7432163ab68dd8561.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/conditioner_002.png b/thumbs/conditioner_002.png new file mode 100644 index 0000000000000000000000000000000000000000..6fdc2f8bb79947a4603df3dc6ec53adf3e98d306 GIT binary patch literal 2881 zcmd5;`#;l*AO2vNyO2q46^Epz8p1-_&RiOEi^32sV!1QSJxW563bk@M>y%u_#9R}j z#&R}PLJMu~*W;4QzP|s(`Qdp#KfHf?F0a>c;Gr2hjfvVS|x zd_L`yK)55y5~%D~nFavyZEM5@XTr1j=k7r&u7{G^&QjJFOj;{~11QopdFNbn6<-(Y zfW>6N#kqBIf4exn#5~YFh;Y*QSu9vwB0g|5O;i?gA;1ND)#Z_>ZvE7dr3-t_QrYPh zEL)XM%Lvr2p=>m+>Qg8*YIp;!h_q^5`fq=KKj}H&l*?xpXA$-Y$SnmuQ29^2v>g{kJamuc%$LWsPW9iJW#?{)mJIL% z*gd}6?fOTQ(|+OZc4>qwUUl!NZKrmG0$QC@pF;#0iyX)YA;c2+r5KgCRjhSuaQjKq zFmNnqL877m;DM+y%D4=!dcOIFx#{9pX0S9PMKni^u}T|0I~T(X;47h%Wb@^l)GqrN z!e9N|VMl@pdnm86#D5JqtIx+buk_7A`PUYI2D1f&J&lOt42EP&OACX+0B$F$$EUp1R5o=myiFf!8OIvPEEs6Bti(s zP9`1oXStcRaN_A1ET|tB#=wQGZFtFd>lhd#Z>~&Ue;!QmgMBB?sBgB!MGe!$xMfEi zElOJQIS(D=<|`DW&VD&zDfZjdi`GNa^`$TM48&9on)7~$Vp#?e=!rP5T|rAQC`H|T z#jmAE(QzX(Nqc=%a8qt=qe?SBw!shzvWI&|y41YW=UoTc?``W8l6}7_k^@4y+Elhm z=t!qMbQI!tJ8omnaySBpmY{}-i??QSm-EKW>)+zvxy_gfM$|Wi{gEfMlq&PVw@<+q z*B2`I^x3m(r;5z!1v^+iT}U2LdOBzXH_?rLWFyj+u&z-+B*nkr^TOh#fQ6QL$TVBi zX&RP2Tbr{A$Ww0uFosj{59oo0*p7sLt;OV3|D&I`3$lI_v30K>KZsPppNKJ56E!n z)-Sx#@~SrJ3f0h4PwI$8ZK9SwbTjiqybrEw?vT3rMB$!{e%x<`!-hfa;pY>RF&27? zNEQfsA9DQheJ%XvXeSj326%d$lwi?$ilU`XmdmzFSH5^&e=Ww~M?(;V} zZsq8U=92ZXore{3qm-iH#A(ICqkCJC=yH%bZ@H2iHvdMmv~o=}H1XZf`z(Z`3_78q3zP2nofj&@X6Mum&Qf>{+sv;0;uo#jrtyCwI1icyD}f zy6OqLn@RM)+gD^%8lbGrIu3^qNxrRUJm}EBO5&z<#v^jPh4HXUd5*6Ut(fLACic|Y zSbnei5Jez|KOq~PxGwT-#JvWc`Snt^6~b$>=cCK1g3Em;plU=>dK7PFK}5h33`3)2 zVqeK#eJXuh7O@6yA`dhiegCFkF&q7&#oKgo-}(6Xc+TB_3alRR=1TmPRLrC9BTCBO z^n{11BvMrGxHYE@3>F+K_(rIMkB7FzfiOA1>hqgw=e$YX#&Gu(dXS8ZgquvBy6!M99s1F zyR_u`z=7N8pFxG-m1gh?@rSQ1%qH%JHi`SQ>B3T~$0De4Odl;bdfu=0%C9q5u)h~K z4|+BHRk9#hW`8N~Ql+F8!2i}=(wC1c#-w!N^-msV)h;ci?6{jT%&Er8T8f!IsH0EQ zI}*nTSyp8k_z@~6M$N(K9)4u5#W(sKQeM!G?D+PO${Hjj1^FyQW2Ie!9Oan-^7Tbc zd+iE%(7QragGM^)^dwn+Gl)VfSpRC3DwaA+Xk>c=NfEKi8VVf8 zZWVFVBx=d2s;w`o+7L@>%@8(d&pMp96X=)wm;nFoy8aR_8l7r-uS%UD%&L9oL%)+c zruY8a%UBjHnH&%i5taK1H_hWo#==|OobSQukr`bRm+VwZjTK9s&-6fSC&Oawo)=8D z^QK0J2~hvL0Y3;g)9n-aG8WfiyoG5=ukp4-ehm4p*|9q^XARD$`V=aW+dx5ArushU z+bD<&o6zDme^BQMBrfD$Q}$&_&}{HvXF>^0n>Vjk>E1sto$Xn`Dk39$VZ9J>zg1%# z_ZMMd@BsFFF1A&o0R+1ZT>mJS1hq`8l}XxOpfSf|NO5qP(Uu}pb1KQ{2JSRko&`It zC(o+YKPmC4ju5yhyWb-5G4kV?I%9 z^iC+vWGdKdo%yPA_7!vKeNid*R*;axM$rZCPiRL~T5hkIW5?e>k|>4StPYGAO4V+- zGXEK7q3aq8$X2(ls?l~TzTP1fk4boQ)B z<5-!S?n68DO81B9>&?2h_7}5&L5989Zu!mtAdo>lD3Lu*4UkRZG|;!c(T&bT&7Er` zsvT338rvElnUqM=KtAQ@_!K)n zo?xbqeAMcE>94e}#7fuEM$6<&r|3PL&Sv!)?Ag z*7mL`jPH6vLaF|R>6L*J_smXO3FrH?MO}#|67N@%#xxd1S#Z{5S}N-CvOCn=H4DHz z^fshai<}$Jfe+Pf+kToIswl;GiC?R6(@8d~TB(w5f-tn~NmhBiQ@m-j!wN4g)>rV+k;AV=~UR>;q=EQ4-z#+*c=0)yrt$zl4 zU9^FA??k92xciS+P~wuYPA2ex=dZ1n!)dH9kDIFBrG(!gM9!_4mp^RO6?VJ%<~s1c ztH@y9ME=k#HFPW!BWPuJ(O&4_r=0)VmV3q*a_%wh;2_JG`A4%`PE&$r$oG zR#?5c-V@3-Knj>RZ&Uc{_;UsF`u)Jrd@g0E_UjO#=&(-JsIKC&Xg5XMJFh37Uwg?p zeQTEiErfnIaD&bm-{&*woRIXJUhP{|UNxZ9?tfYMIzB$Gb(>oJqeW}WZ*==DHbFDR z$d!71nZrK+lpOAx0!Y>zF0Eq)^jrm75QGfF^MQwdK^{o_e@33F+o1fr28Ybkz|*JH z_6CpG#!mBVuI`VHf@Z$Ubx;%c>jMsN=Olh+?PUz`cS?O7M zR!=d39@M=!1du|sywq~h*hn;ho9#x`=+X&0(N3dB|Fj-OeK&L}o8hU7zt`p`eTpc>g4=(!??FM?zE>y zSQ?OPkxzGO@Bpo+b>MD5EM8OUVX|EKIsqv7Ot(W zH4_?KPMiwn7s6+YTm-LZJYQy2Qi%e;+4#6s1Du!5$cyT(3CaE|y1?fBc`vbBSGo z;Oy9h<|K;N!XR9%@{CElAmHle24e4XCex>Tond;h7Ccl6<>|+WJbF$(lps)IpT(l;Ohzz*Q2OYtqC}dK4)%cM`0W8-`D&ZwV6qISHEIHf1h1{5&%CxEGuKISE6tO`c zl8M+rp^8Nk`d+qcfLAX_i!<4xD9JveQ6H>%s#y%uR~rVFF|z5uJhJ!bV$5*8Ufiba zU@I%D?_#g_`LmR4PJZ%F9nwdc)y3;`Hci%T5`r^XXOn=*Oo7&TB#uN&9@;yWG z3tINWXN2m~3hA7-_xWNqf*^x0N2^*X<;HOuRkYVs|QpZs5)BQMA_R{t%v$?a1MU zUfr#qM3qNJiIrX@NMRYB*Um1+Q8*P^D;Nr(a~dnfjP;iIy_Lc?>AaDxxVOLm`djy1 z`Js=$jyv6~VGUQ$SdYO27Cp&$1SX<=Y;-sr*~f7k#Ctm>SCqUZj> z+KFaEnLOH&ivn&v{+!Yg8;xfsG+=7)Kk0F$as415cZAL18}G=EY2S2iG0FP1yM09e zlf}V34;)!`Bo(2$sKf)8Tf-mEOk8%? zzi5&gnvf6p=;4S)Jl1pyQ%Tf$|Me@Wd2$>faTZsC4due&25(<%iPks#-uVo;sKrdqm>F|Axrv6)J($^lWDnr^tcX+GXt(s`E-8=o4k@0tIz zM)XNm%Iv@ZzkM^Kt#KwbRSB0%ZS%efZkQwuj%Z!DAjGR$Ft{TT(l^LHOAcxjgmfXM zSBh2sZaFLqPCD}n8|vao=$_r%Bwo{VZ%oiw*vXa=Q}pYJxx==X7co@-%GB7HoE{n< ze_<_M(e`LpZL{TZa-%jy0-SRm?Ze5nXg{1s>H}JUj7s!RAE8IZL~%?MwNvqS zarY1+_8^E6IC1zr{s=n!yga@}T-wiA4v!F##XWMVu|{jS%K>p&Uc8cZ8@)QQmrWx< zW@eZ41A~ILN8ga+f~8H~LsxEiD$W?=op6G7%UOj<)#i_-iv#TgSen|JR2g~Q{SOhk&Y1uJ literal 0 HcmV?d00001 diff --git a/thumbs/construction_001.png.import b/thumbs/construction_001.png.import new file mode 100644 index 0000000..6a0e79c --- /dev/null +++ b/thumbs/construction_001.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bw11b0cqn1ju7" +path="res://.godot/imported/construction_001.png-1658dd738fc09e0abb76d6f1990cee0d.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/construction_001.png" +dest_files=["res://.godot/imported/construction_001.png-1658dd738fc09e0abb76d6f1990cee0d.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/construction_002.png b/thumbs/construction_002.png new file mode 100644 index 0000000000000000000000000000000000000000..4af02ed1dc3843404cbd62e7bd41ee0830399986 GIT binary patch literal 3105 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 Jc&m?z{Xc|%wLky> literal 0 HcmV?d00001 diff --git a/thumbs/construction_002.png.import b/thumbs/construction_002.png.import new file mode 100644 index 0000000..9fc66f2 --- /dev/null +++ b/thumbs/construction_002.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dbly31kixa54d" +path="res://.godot/imported/construction_002.png-19b8319ce5986c60d6a5bcc5e0035092.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/construction_002.png" +dest_files=["res://.godot/imported/construction_002.png-19b8319ce5986c60d6a5bcc5e0035092.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/container_001.png b/thumbs/container_001.png new file mode 100644 index 0000000000000000000000000000000000000000..a30b6e0ed5397e9b3ff455dcfac9e342cff589a5 GIT binary patch literal 3642 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 literal 0 HcmV?d00001 diff --git a/thumbs/container_001.png.import b/thumbs/container_001.png.import new file mode 100644 index 0000000..aa0a2a9 --- /dev/null +++ b/thumbs/container_001.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cfk3n0s55m3ik" +path="res://.godot/imported/container_001.png-07e0f052cdfc610dbf637e3ccef75399.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/container_001.png" +dest_files=["res://.godot/imported/container_001.png-07e0f052cdfc610dbf637e3ccef75399.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/container_001_offen1.png b/thumbs/container_001_offen1.png new file mode 100644 index 0000000000000000000000000000000000000000..0a62d422e5455c8b7d751ce96ff30099b461ed46 GIT binary patch literal 3014 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 literal 0 HcmV?d00001 diff --git a/thumbs/container_001_offen2.png.import b/thumbs/container_001_offen2.png.import new file mode 100644 index 0000000..3a0ecd8 --- /dev/null +++ b/thumbs/container_001_offen2.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bngbmgxfh4ft7" +path="res://.godot/imported/container_001_offen2.png-23f7fba7b090b984ce879d8f7e8e7326.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/container_001_offen2.png" +dest_files=["res://.godot/imported/container_001_offen2.png-23f7fba7b090b984ce879d8f7e8e7326.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/container_001_ohne.png b/thumbs/container_001_ohne.png new file mode 100644 index 0000000000000000000000000000000000000000..b41182d824148f5971c80838b18ed47e9ce3ca3a GIT binary patch literal 2961 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 literal 0 HcmV?d00001 diff --git a/thumbs/container_002_offen2.png.import b/thumbs/container_002_offen2.png.import new file mode 100644 index 0000000..09c7998 --- /dev/null +++ b/thumbs/container_002_offen2.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dw56ic7fws26" +path="res://.godot/imported/container_002_offen2.png-d7b9fe96a10c3a4e692911bfd40e7240.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/container_002_offen2.png" +dest_files=["res://.godot/imported/container_002_offen2.png-d7b9fe96a10c3a4e692911bfd40e7240.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/container_002_ohne.png b/thumbs/container_002_ohne.png new file mode 100644 index 0000000000000000000000000000000000000000..4a8ef89b43168b430e8a43d545f60fefd499a7fa GIT binary patch literal 2806 zcmc&$_dDB*8~r3kVvo{Vr9-$zgHpr{tyQ%ZmkLTzdyB+~QKL0FwA>a++q8;4hn=ljF^o*&-xyw7vabAC7()|MtboMM~+0PvWZUa>t!+e1S)zYmH>eBo!J!wdvw8SflGkh?&%JFS?N$)_*uvE53T>=;}@)c zk~>b+wSTqZ5-o5=tX%E(011-+-2z*3wZ>tb)n2Sz2AwaDeqs7ZJ!{oNJl*njle^+DG})Q70jSrlzqHYcmPiy@>47+8JLFJxt~UMSLeyLh9h)53{GOW9TVq?Hb|! zlXGMZB-+A|RNkb0Sc>6{^un`Ea?xS#1R(#@# z`Xm|kU#S#cmA9Z!1@v+>#k%;CWRC2A%>LR)1z?=_WU5d<$9--cy(MU{!y;xv1Q4?| zg!qr{7b-^x`y1F2MQ|y5=~BA?5La6lV&e4g-5Ql**(%aym44e?+}@g*IypPa9rwnQ z#P7X$xiFRgXMJJ&R+;ghSZky|W51Ap2}J9&Ln^#@@!i2lr?sjKI2ZDk0HS6hwIv>< zx0TQAPxAjhGkOmcF)3C#%`sD^=|C7atRx#kpzLeu>QC9d5PNSye7CEWd z9cA}De|Eh~>{-}WFD&hOf^&=a8W~a))mZ*3tx~HDd1MKVPIQoOKd;ML7ksa|52=v! zt$S}9oAMI5v~1Kc>| zQpjJu{X5mQeGBgIOoV)}^;tAhAZ)N5?#F%ZTW@Qegi!{-`SbM$W07+o^N_R{fv9V; z?`kCX8-)r-xG`^9N@rD08?HJ*!f#_puI$wo=Rgn2hQgjJ%zoTL;6`;D{KDI*Eq$T# z4wXV3V98cH@CXZEK!T*VjQbc=j1XEms2STPR%E%fowb7sP7xWX&Wi~ll}xj>=vw=2 zMX0^k>aN9!J&TaI=#-ujf28N(d3F4KlUMv4yow0kir;u0ZW!|l9luXS$FpX+!RXG_ zB7AO%ww@=7BNv(d&O_Xy1@m!Q-d}0Ho?IAb{OJ#7L@qjr|L_2xHR$J%lVg$8B-%73 zyR#a3L9W3~A%BCU*nVpo?eTI>qc#yD9;;AHl+m3hwPxMnQzqzE&e4oZMZdNgKP32v*F|X*kr&t2uW0^4HOinrtB_&OWw|hC#J0#km zdp+fT`7e#GzHy2sO?A9xZ0w(4JC@jU=q_salJVZ-XP`{U;8V>la_}VBkrsLya;l`X zRA!&5=`&2DOvbC|On7Ek?^Z#FxkseG2i>_b?02VNY^W~?V(qPSB}PN)r}3V`RV2P( zaxN>dt8g@{p`!aCo-JR>bZbUrp`wyTFM4do@o*3*&=ql)_bw+kO=@k2Z$;E8-}8#f@HX$q%ACU0*>y9k$4g2%Do5M(= zqfQqt4mRuY5SdP$hNt?wyvJZfj~}^Mkxvt^=O!_Pwn`>6#^8po=9a5!XKohoNN6s1 z+ac-HNWd9Rm%(bzk{PI z2=FL;`tXWAoWr_-l=L7ir@u#gl#y~7>j35`h90?Tia#m0;PqBq|MbzSH$iY_(WyO# z?LJn}QK6agTJul^JkJvYt^iOHZFa>%`m z@lk6$d)(cgqGunQ;wvP*{EHvdZ!F|Yl53PQwP^jWl+A+>%Ni@`yy~>IO8QJC9oFGO z4sfFGhs)k-V0a&@%ze&jf_1N8+`x{kBhf!}Hdj*V<7*A9%^ksk3v*DgS2UkrxS_Y=PZZ6`%&vZ2pHH?* zP{9iD&Fu4C=2h=rKz&5?7q}UK2%8(zCmEO>hoz^Fb5&pGrTfi$+|c3r;yHXHX@BML zu0|(U_SE`To0N8iBkoTsIqGrfvIa(*IsVYY^AM9TH2<`$h+j0vz$}K6!UuQ2#hLVM z*5MmwhdRZ5MN=32^5Xq^%g^#k9Qf<0`G^Bu99U>kUfqncN6ZiYnZ!&Kw& z!IZ`Awp(nXdT3f5?r^Q~RLmU{mL|z>@h*;Le^Yia+7%9fYLW)|!f!`ahWtuy)#k>X znEJ5gkSJ%rOcWoRlwPeX=;!*V)MS$Y|E}<-WOkSyCWtqT=0qCk_)Hn(q%YSkRFe>& z5>A-x2A>oal1pDj`gI&>?i3L!r4u5z2Pv+5Qy~z& z|3NKqwpBY=@sIlViZX#|HE>`@I3nwYUM;-2kO4i<6!#9!;NL-(YA0as{A A{r~^~ literal 0 HcmV?d00001 diff --git a/thumbs/container_002_ohne.png.import b/thumbs/container_002_ohne.png.import new file mode 100644 index 0000000..f9372fb --- /dev/null +++ b/thumbs/container_002_ohne.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dwc0jmnhnch4k" +path="res://.godot/imported/container_002_ohne.png-5fa21dd48f1897875695b301f7ccb2f5.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/container_002_ohne.png" +dest_files=["res://.godot/imported/container_002_ohne.png-5fa21dd48f1897875695b301f7ccb2f5.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/container_003.png b/thumbs/container_003.png new file mode 100644 index 0000000000000000000000000000000000000000..6a0794e2151520f0528a90b289722d4d5f95d33d GIT binary patch literal 3642 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 KHs-EN)PDdAt>A3{ literal 0 HcmV?d00001 diff --git a/thumbs/container_003.png.import b/thumbs/container_003.png.import new file mode 100644 index 0000000..68b218c --- /dev/null +++ b/thumbs/container_003.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dupngc2xv7it8" +path="res://.godot/imported/container_003.png-6602135b960e178eb163aba029d7287b.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/container_003.png" +dest_files=["res://.godot/imported/container_003.png-6602135b960e178eb163aba029d7287b.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/container_003_offen1.png b/thumbs/container_003_offen1.png new file mode 100644 index 0000000000000000000000000000000000000000..12b3fc5f3ba301a87a79d04f1ffdde78dd8fd742 GIT binary patch literal 3065 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 literal 0 HcmV?d00001 diff --git a/thumbs/container_003_offen1.png.import b/thumbs/container_003_offen1.png.import new file mode 100644 index 0000000..0930784 --- /dev/null +++ b/thumbs/container_003_offen1.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dprnj64lwdete" +path="res://.godot/imported/container_003_offen1.png-bc54f3aa06c7683aa41a6f9d4f45a896.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/container_003_offen1.png" +dest_files=["res://.godot/imported/container_003_offen1.png-bc54f3aa06c7683aa41a6f9d4f45a896.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/container_003_offen2.png b/thumbs/container_003_offen2.png new file mode 100644 index 0000000000000000000000000000000000000000..6a3b777ad04ee0ce3e59b2331047c98b8384dfa6 GIT binary patch literal 3169 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 S*He#w2EbU~T(42rE%Cp>3-{Cj literal 0 HcmV?d00001 diff --git a/thumbs/container_003_offen2.png.import b/thumbs/container_003_offen2.png.import new file mode 100644 index 0000000..2f77253 --- /dev/null +++ b/thumbs/container_003_offen2.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c2kpdcvfpfapd" +path="res://.godot/imported/container_003_offen2.png-4089b96be64c84fcdd6fdf336cd0694d.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/container_003_offen2.png" +dest_files=["res://.godot/imported/container_003_offen2.png-4089b96be64c84fcdd6fdf336cd0694d.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/container_003_ohne.png b/thumbs/container_003_ohne.png new file mode 100644 index 0000000000000000000000000000000000000000..c4fb6124b6e1cf4cd9e2e809f8fd0524809f0790 GIT binary patch literal 2978 zcmc&$`8U*!7yb-kY%^p_WKBdO%gi84Gi1xymuw^1-t4C0@zWBum*t z)+{At-`AKimXT$AegBB>`JQv1`~2{nd(XM|JU={17HC6mj`JJ<0B{={>06yL;lBX0 zp7vIqJ3Xfa3biss0_A<8s{p|1Y^;C7CMtU)yDLy+jjPpM3Sh*)-gu>Fov*R1wDL;tEPX)jn$_ryyFIC;QbWj% z4-vkzDkw8(pcjJQSaBHnoq`2gP<=sOos{L{sjQA`?d?4k8b1HX*sSsm*a#{T=6pc> zhMf5bN1%O>N$#njUhqfYQ2~pE=>JE0W|F6;NZoQWD=n(5-*XqzJ>JPO$?J=i+NpRT z6tX@E56U)!sb1bRSK7Mw<1f5RKs?_-B(r5%=A?~fSXzU=ft^m`|R)v>Lgfs z-@y=W7oyyBHGMmsFC{H%Hii!f#2@6fUf*CwX@DA|=;1-4#24)mt$c)Ezv8tuX9Cm5 zd)a&=oWG!T!fL`s>MGQ=K9irvGvq-G9O!K2nP zc%REBF+(iwi`W~oCG=Ogg5=~@0WW*#r)RNo%W<(;Iob=UExSxw-iImf7t%dU`zx-3 zwTB1IBBW+@8{sf!qy*ucAFJrUYmT}@Q7oh~r&QCx+LNNh@ZHWuy_wZEX1vDmPw5`o z3IX%^2P$?qCw&1aL5&e0y}U4)NIrSS`2f_3zUZ++;9-(P>gW1iYE)~F5k!*jve9y( znVDy2w%=7SlT6E)snfH;<@LLKAqB_8FDl@kK7ogmmpz-;r&(l15@NHRXrWy5s~~` zG(At(Ky#2&uXO!GjHR1|_hN{rV+4*U?u@DZmM@NpE{5_DZ}AZhyM*CRAfy{V(Y5nv zj8!&8{I0frj<&xoI|&+-EMAq}PX3M?AVGhDlHCTX6%B$=*Cu(M3?|^DKmN`ZdDAw1 zX|w`02piUqvp{?~UQh!E7AvtupkdZWmzbXDG^%ygAGRf&pf^`55%N!M2>7GYI_gZv zI`DonHQ?W2jlK9D=f5`3NWj0R@Uk<9q5V8u`uip?V`>rN*n7>eN83 z+4`WuJZ|tje)JAAAutecdrp(7quWg_(z5Bw;hs;Zz2$ly#(XxzVk4*d83)PP;f{=q z(>Dbn&7(B2r^K#W>9rxc%EDcjboMIaJ1|4G#G4Cmz5F#)`qLR=NPnTlh^~a#4GyOm zKhsW$)~-=l#w#6Uk(Lps$b@)ST2H|Kvt`F(Ozzd&b2Vo%neJkV)nP5)FM>;|k6L*- zsU5RiO)+BU=VU=qp9%y-5@C_?xhN_8`%rm; zR1h%TSXCG=i^{JO3Gl6{_b=q~@`k>)4OmX*cE3pr{J|mO@Eir~u%hUWhra}QIt4K| z3Ew?k_;pM64*GfV7mn7IWPOTLD(f3(@i411Y`#*GY|j2ly!Y-W`CLQ}CC(5|(oJ?! zLr{>MCZm;lE{%KoF~WKz;Wg>`>Zrkk*Ibjw>t^UdEtna_0cSxk6>cGa82`BMa_Mpc zdljk9yuF+$Z3Mo*WCN#o+&q_&!Ir=A=?BBlai|Pjq@|Tkrd5XIo*|cu5fx&e#~2MM zA3>Xn3-5QG>5f_Od+h9xf%_6E$-%g6;L_`HxAN$~By<5zoY-HsXqoTtjnGjY2c65w z@eZ@=Cgm8N7LO+7k(<8q6C~zG5*zN9P?-?9raFwS^m5>788%@_#D8;acU^FJA#8`u zHkuu5s|KAhrlP&t(wi&5vvM~>WzjUrBHkMkMoxmj>}YUlQoW4|6$#t8GFSxp4Lt-r|Vr`a#O-~Z1f4HrAl z-?N?uO+3n7vbSc@Dlf$88W|`wXFWcS2`#Bx`QxSzoXaJFYH}Yj55U#gdU;iPUyno| zM<34%FO8I9^9nGuc-0sM>)v$Zm^+G#t`IbnP524a7H3@y*8vM#GSsr~_-$RoT8AEa zz6s(OCM$}L&$W!+z{FF^UG8JC^>7ZfmYe(di8#iMFe+97@1Y$_0*1bZR;gbm>m8Pnep z%bZ-!Dq8FyM7=f1zDHxnTGE*$rA<1Oj~nqaQ&GyY(vJl9>ZApS;Rs&#?d6t5?B;gR z+n2zU;qKC0bM^RzOY}`v%7o(9#w1MV_nXr}<0LSpMgVH_E~(pv#m3<8iDTp5io)(v zUIXZc;k>Q(AHFwn_8@aFz3YN33kmg2t!W5chBb{fdOSE*J?(=A^5JdOSrm&x^R5#+ z?&RyXfabwwt5Sn;@H;%Bu9pq-6HOHp$YJwAe5$dGriKK`+O0u-2({coZRa0nh)TH+ zd+b{nOtXkyUCfGntG@MORT0}LH--IQ6rOMP`-zWHi=tz8YcIVwpcnEtT0{6G25FMRxpy(Rr6r5;*gu^J^NK&RfN}p#ld*aSL=|liZw7EZgbq@w#H%uqp(9<<=}2PQSNr)87^OvvcwcGeRyY|4!20i z{kkbE)cg2M!WGTlUt-kC8mmzrD@U=G1Q{pNVW~AY%h;H2i8!OCDHHC~4nILoV>L>n z5QUe6n-d5>yD*;1UoUt%JUzb9?s<9yaej5l<;iv+5{dNc%ET$Yj_MQ2X9XQZ_7Cmt z=`)s|OqSE@>k^C|t8KN61{|M)5NHXbp#OJpF)x1r%f#j=%KfB!Cda>tFs41_4-KoES8vc+F z>RB|#35>&CmGhJp8K5PAL;a-{k@5H^5FcP@{oc0lY85a{r?r`$O$q#-ZMyvTL^^3~ zWB2n)SQt}%T2a)fCAuPCKkK!bpfDH`dRdzZ;zqIP%DQhQP58OR@}l7-m#X0{e++<& zo@9cu^T?W6giuDFI^k#8nqo0L|5Mp5-RyIKEoZ$y+NjiBZH2RWNV=Ia54pt?@6!bS zA*>JMf!)J+lAj+Nm`~7VJjHmE?Zmlcem}){k^LSXRDDskEWj`{;sXYrUK&lo1rR1b zrs??}d6;RTqt^YZPaN>cTB`OJ@ULGUq0ZB2bp4nLml-v`iYWs5SG z%rV*p71{*?U}HXroXANH-yJt@lBa*y7X37}TtLBa`^3CpUtTU(^RU)prc=?-RXn~? zHdKmyr88xBI(gf1q#9N)?X;p;H>Ogeld`funD_%#6CRC^$*5nx^hCkX#-Pa#>+nau z+fbVwUcFojVezY&EPD5$uZVaRnwIHXZ%n-Izd zG)M^VFBRR`0--|~CYrM1Q1qA@H{n^=8KS9VqCHh&f3p$p{2p}GOyAG$QtV;bx^V}L zsgoTaDReNh-37U3N3rnK2w_DH-Y{*LDZ!T6FFpuWlY`OPpqqaTs#KU&F8=)+LdvSm zZ+wp7BK%q0z?3qB==lPk%xvvEc!|41NZS;QW|qike*6V+ViTqZPAv;_8sTCWb-WPct4}wOvbL7`J^27AMlt?Q_}v z+FZwym_a^1M=KpYGpa0)f`+B(Eru8=BHahGa4|!}I+tBF?=12!D{FRT%egd&;XNjX z1Va<#a*kf>xpt4vA2kJGaYUEbHlqu{g}J7oOJLV(jgIYZ-;gF+&O=|H`x=(1-wgDI z8L5jJtesHotxT)BgUzvd3E#$(w7O4vSUwu$4g9x3w67)W4Hw*34mX$#h++R4ANWrN zq_jSt(%mokerZ)h!#-4pCE|kw7oS<-rEzRuz8;s;w6`35b`Gb0ugM=wQGMi3B3T>U zR89ATva8E-M?pausk54|VNf)n-DLKVF77hm$4Wk^;I#0||BQ4!h}{(VWXjIa0*&Ss z5D=K+-$co)S7w-=rFw#~t~DaC>uq1mdkkhAj`NML)D%~CMY2x*BRK&us^(c@CImB7R$QM!ZV*}TI3eD z>I}i>r?0)bn+$w%aC6r&Y0fyT8?~!cKvVkS@Lm;`ayzfXnqD(3nsTN|W(;NZ?ijRI zNxA-*5ud`d3-DZ(OV2SudmQHaEbS9U$d4G6! zc+2)|=Z(`d-T+pTx%Z=0>7Hgk>ZCAVzAr3(3-P(UVPry!82PZXQzhNWyvjZEZrI%M z>7Wr(d{m6_!g<|K17BeHck2+xM%_ut{skpG^~6%7?+Z}bITUJ_mIz|?%u!&$$O%94 ziJb$Nbwp3bSLA z2;x%KH0rJ919L&cMxAQ#c9qNPTl(~4!eTQ|uD-nnZ41lAg@4?M6GnJIT5=5*$4Qa|R3zh0+1zP91u=f8 zpkO+&p>j9&tm4l)_h%TP8m5@A;|&7K5+$GAyH=;MX)kjujXKh-S(^B>@MBZK+qd1( zyN`H<^5ac**s%>;|G2|6U^Q6;QZ#!wptH7eX#9j+zop;cXLod^mG7L_Z{psPhbi#i9AJWA?L!IRxIY(BIG7aZlI*$G5OH1IR?pjHl<*if1{E8 zt5!tXah!+m!ka^Br*Fcg@EI-VwhvWA8TRAqXl5~eE`m`Z7V?MB{L*Z3y`zM2^T-MY zhe-K($L8S>QMs9+pw+DL30m{g#=n2JWuLr~A8j)?>|l)F&BZsZgY56QS0%ZL%ba>$ z04ZogFGac0JQ5ND=s6uY*Jk2kN&)W5?}h3p;qaA-bC*lS;_DH=1D^|23CrcGh263_ zeMABd_w+j3_1*c&TB0Rin@aZe`rZ2N6cypS?RDxpT%S|xd)pJwep1-@NZxD1OBwd~ zY_rXa$@|tq@UrJ-E73b?jgdKf`YZWPO)rr~h!6EC!o5sJ&8ZpKI%}X${G*Z%*UK+U z@fGAXsOy`L;QQxPTpGW1Wyo)t$zB*A5mSe-C6XnSCLeoSMq@gF@kLM)8pKH-|k4xq|zhR+czm_GC7h*V)ToI=OSz4;Eup%si4D zfmGHqT2mr|Cy>ZS6F1rO+VBqXSsw)KPtOaDF$zpHGv@?&5{iwH`RBbG(RomQ9oq|t zJNd1@c>f;!=QaF6FP)$%J`XGlHbDyiR&R^ecCYAsDWJP~ik?Wio;0l=V-;NBa%}aL zAQbqq_x-^4Y4v`d#L5rdeUxA$%AF^T&Jm{}n*)(;i zV`WklW+>}380jm?J@}xB1>tZw`bXiDzsVJ^wxXsO8LTM7{kHJvy$)oRMWIGISFh+0fN1uXw%DRJLI?MTYoe^+4pW{J4N3gQ8eFSuy@q z=T2dvy?OZ*=^0S6y}a$;?>IM5oY|rmy`Y!sf*x&d!u&TQlGoalxR@6`!e*qHfzrQJEXu$s?0)J&WoVb{*O;5>8&)l*Hw zR0hb`;*RDI!)tL6n_CCJ15XN}GCKeF*b^#w36tom_d2-$ivbqrtxd~~UGM!58|IwK literal 0 HcmV?d00001 diff --git a/thumbs/container_004.png.import b/thumbs/container_004.png.import new file mode 100644 index 0000000..e04afbf --- /dev/null +++ b/thumbs/container_004.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dx6067mlj6jdc" +path="res://.godot/imported/container_004.png-fa22b914a672c1f97f7809fc3a8a7845.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/container_004.png" +dest_files=["res://.godot/imported/container_004.png-fa22b914a672c1f97f7809fc3a8a7845.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/container_004_offen1.png b/thumbs/container_004_offen1.png new file mode 100644 index 0000000000000000000000000000000000000000..eb88c8c4415ef05032474f42d965795642cfbb1e GIT binary patch literal 2975 zcmc&$`8(7L7yr(fG}g(Q$}&l~#xfau8rd${vy2pDWbA7pyBUeDl$3oNk|o)4Whdhz zWtp+dHrBBVDPb(H`~DH{`#k5I&kyIE=X16nPOO=U9tZ11RsaAvZt3fopCa*Jg)*Po zHncL2IWjJ-K-%%Q;D{kE*qPxa$x|~z=!_CnQ*m(=(ZZm6vswnNScxEtbq4;fx6s&`+1gXZ7{E=lrqk z$!;@@WvZAaD9Qzn6&r%YBYqP7CN_V85{4B4Z;ogXQZl;Cqk*SRNGS=dffa8X(Z7yU zNroxnk#N#2QFf4k;PnHMs#vyj;2+W8OWF=Gy8Z6kxmO20*{z@DUPT2Rm6U()z2m%U zPP~pKq{6`aC zlA>ustSEE-1FfM=Qj5+MbZcG&-9{yBn|J)(Gj-_LB>X zBd#{XMX%v-dnN2A6J5GQPnXYb3N6OyB!MUE91e2m`c+{Hv()b%ZGUCO;Tcf3Gyb?D z{HhHX2phbgs($c^N>aJS|8We7lJ>2+LCP6`!kraQH%Ho%dV)4 zG~!ZvqLs{7;l`J!m71K1_D|_qSK~bJsQnd;lpt0|jaXc0XmhASD3HZwGFbZ>zkFDF ztM$aM5E_*xhwoC8hU_f2l0A0{+-n!PF>%x9SWyN6R`&eh#rGk<-#d#|9B-@&6Vgwq z*EM`USnkKQ&XfFHYoHkcR+RG|63QwD@dK*CnejJ?{oQFD))v?SW{%r)Y-Y70(BQEg zP%{}JGZs7=il6kwf7_*WE->rW?=+vN&EKsgVx;@HptiFq(&&XBUvo)aJyp&}X0>4T zY&%<=DSBTF$W#unhB2oeNKdNssB0!8NKIJ3;gCGU1q&qO7G!p{>;ykwF3d#@^;;3L-NbdY%$+WJBpd$JE2XjjR~Q?RXU#a z7%6pd$3cjNGs!g}nd4Tn?o(CA%U{PgXv=l8QngO|^^5;@?c2YGR+?>Xj41Qd5adLm z(cdi(hse$$A=PrH`<-5e(ehHd=^CAzLEYwJOW*NDSS_` zpP7|bc*U7(OQUY2pr`qjsNzcJJ|tIf0y zcBVYHn%rcEY%z|+?%zI*PTxa%|DG&*UID%K+b*a3g_3{#GVL=bt?>JQXK@HhQ&pyj zuX*NBmrC9RrIsvI0?)`_ESW3QP?3rVnyt#5lv>*r3k#EBd()xtvmeGj7H7uZNn$CX zQ*VWCpokLj*=Y;{zY2XhAYEuNgiYjPE)$T2*7$R$LBOqKb?Qd4%ruf+jY*Tj2*;ad z7rI&bl|8jl01MbpJrhui8l~qQsj<_XJJiT@BS>b$$g51FURA6luYSAeo|epB_e(G& z=w4JZBF=_T!c1O!_)0`gn?ZxQPBU8bYOA=4Cpd9z505A8^Z$5Ie7^^MVdw&~EjuIQ zeHzavTXh3{8>8;%QB3lgELZAOsa1cVS zuK}LN&vJS59SSP+$mR+%_CyTqx5p#)i~)78%Q_#E!!%t&zNi;k&r*%GS$rK$iU!rV zCHdnhS!A8Q?UCE$!-Ov`(;6)Aw$A6hfw*FM=&u9B5_+B8#)jz6g(e@#nW;VSU+}9P zqEr7KzQmz?R^P^oFx^Se%t5xCJ2;)i=|cQQDzBPJ8?~|E5?he1KHewt)RT2x?EJEU zk4f8rStD`%`}FmvfkHk)cIlf;wk`@u06-e{@^1=AdirTU08{pUQv~M@$v-H*qpQd< i3gR`4`yYRl$1pfWnpnJzX+QnAfm^yJI^|lp$NvGfMtw&B literal 0 HcmV?d00001 diff --git a/thumbs/container_004_offen1.png.import b/thumbs/container_004_offen1.png.import new file mode 100644 index 0000000..65092fe --- /dev/null +++ b/thumbs/container_004_offen1.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://ij0up66wkdei" +path="res://.godot/imported/container_004_offen1.png-639d1fdc12e40ae2fd8e7c6d7665e7fd.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/container_004_offen1.png" +dest_files=["res://.godot/imported/container_004_offen1.png-639d1fdc12e40ae2fd8e7c6d7665e7fd.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/container_004_offen2.png b/thumbs/container_004_offen2.png new file mode 100644 index 0000000000000000000000000000000000000000..2ba16d10ab6d68b71bf72699c758078add448f20 GIT binary patch literal 3080 zcmc&$`9IT-AAehFb7jaXXUUb&6qRFIGa=>3eKa)W3b}I*;e!zRXwKyuNr|ak$>tg# zxtnY5Ma;3>OJctJ{1uh&2rR0_nQ>Kxwu`6pJ&RW_QZ+=BY0Yf^Qle{(S`!Y>HIik+l4o1Cf z2V6;LMJosca&$lbgr$6|qL8m;;3QA`3DO%Vm_`0tyAtA9pLz|fb72biL%wMd7Lb!L zO*K78tijXxf&9F@OE-`2V0!CdKH1LGVKVt4XbZ#BesSh00hqda@NZu57{wM1>1OOYVq3Ll}dnP&ni> zz9AR+V6Q2u0DH;Y4W9MKEj`~@n=z`p!32Sm6bSsPKM~%`$uZ=EdrogL9APqx2>+m{ zmwhhYWmHm1T&3W$ba+)!iK%H;NRh=H%WRGX7fs8AfnE^fo#OLP_1!l|x?eh~dr{IJ zid*9Q11r$5I*;6Ixo6uWI5|P9*|YrnRT;0_ z-|__TPZ?1C04JTAH)dmbD2LGWWrd96X5?# zLU!i^Q$>=8`}b1k;+EPlHRFK;rHLYEiC!s++_#xL*!shlVQ_e|^d{c`-)@0M!}?<` z_=8lamwWsOF!m}Axa95`RTSCZ?|NHTOk4kbXDXjU(Bi4HFPn7z#|Mms`lSDn57uGZ zYkfM?;Fz9sF(xxeE2?9yGvLE2XmV?AN>-SMMOwdAtPF(=>@oyt?Aj)m05e&&G^3|2 zA|X)@7ckw)T`MX&e#Mx3jGg;z_>6XD$;ce#uMW7PL}KZ0wQMa;9mb^NR6C%r5T^Xn ziQs(5KDa$1tJ$|9M+lU&4dIIZ)A(Tb$B|z-+$6sl-P(Sw4)Hgg>hd&%k6>9p+=iRa z0ymo3qTY)d3yf&$?kWqFNft^IUG6DB1Xb}}ffJuJH0hL1C>A~KGPc3=@9thh3kEz` zHKRm>aBi^KeC^63FB=;hW!D=fH5cgToi;Wig>(}}AJ1sV3nX9&YD~JM;_2@Xs8SH< z^7)8U0( z9B{5njnqXNR*wZI2s&+H7u@lTG?f5WfHL&6q6#4b9W_tgUJ{9PsB-xbcO8UEPzEh- zKA!<5-Bwc1wZa#kBAze4zRNNV-N+h060(-6trvN(b2-o__u%su3rJZ(0#aAvCcDpM zfceMSW)0F@F1ZFc@|VvsMx6&iN&t;=)xH@<4+QIS&!)sk)$$ci7ZK+A3%^VFY2_p3 zAPXu|Yx%VXd81Wd=sGp@R`Y5L98gqAuqUbtClj%q$EWur!E4h&qCgVqQ*v-%o8~JU z2e0#T2;F>jUJ7TbOA;ug3x01Hy#$)&{0TExIz%{`+qW+NXWh(^m#ULbeyCn|D=6B$ zicaN2DeP>nApe(pBIn~U|9aEJnpV;k6+zJpxH_zcJGlv$f|l`_`uul<$rpn|hN5%z zy&h8;-ST+r7`m7oY+n?p%WO?MqaVyoD7$|YpB{4;PvC??LG}y`)WX3){q&Y#k4V{i z?UfhTyX@d+7S?zw1g}5?dz~!WpWK5H)FFrET8aA&%74V1%lTRw%Rr6+Gk`sY>w|W6mxtF@XI0?e<{vGcw{8j|dbK6-N^t?N4LSz? zFbBv#qp57y+3LkTg*;Vy_4BAQ|Mhl5I%+&n^}E2hOulAWOIJj>y=w#_9=<&G*Dd z=KofF{h01lDHjFvLQ}J2y1Q10hnul%-|69v_rK;i#uQ}_1JvoF!9D{1@TI&&>q-DtO8he; zuK%M9NICfIZuaeG8nHko5?4I}uc@hFeDwXfd%*tajl*vR#xC!c+*lYp(|gjTig1Tg z#ns`!yy(3=cxpOrG-v3CA2>p6b?N(4(hNp^KhGahY&y9Ao!s}S+{%c;_w3ef=OQt1 z^A9CSqK=ecCa%N7SfpV?-})f6XM>{0yl9cgx}V%JF^g0-aZyG1he#rvv1 zG?R3eBsNWCpQ-V1^)v$1e8AQS3J!L$gM|u^x_ewxG#KWo#@nfeF zw_6tN9&zQghI#*$?C})5d``kda)D-Cr4MO&C@nGD(roW#zp}9q&~y9sX*fT6fE|Vp zEk-QLsIIEGibkFnZ4^?^x4aL+87N?VW_)7`w`&EDLwP(t)zrA4!T11J%HvHs!OQbg z1VU*);Z2H=GmH3h>vvfF8gzUQf<;6 z%Q2w}r!86*7QuY)I;XG>spF02v80>;Sc_~!WZQ>|Eaq(C+MxjM-Hc>&LDy#PB0C)^ z@XNSVi5oh`*RnAJrP&=i@-?$BP8$C4Ui0^#fC1B_@K?Nt{BKguJ1-~O;Okv308Yki zQFr%d=EBv7FJQGvHq0ojT)u6MB?V#@2jy&uXAD!aXzxJUxHd`jfyppr_8||~GfmB} zTQ6ct%`kUnn%|?}-UM*0(P?_@9whJe`ydNdG3$K{?!H_3TOs5l_J8oHvIQ}<*o?Bc S=yc9&4;bm2pes?%asLM?iN6>C literal 0 HcmV?d00001 diff --git a/thumbs/container_004_offen2.png.import b/thumbs/container_004_offen2.png.import new file mode 100644 index 0000000..088c09d --- /dev/null +++ b/thumbs/container_004_offen2.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://6so0720te2wu" +path="res://.godot/imported/container_004_offen2.png-65a2ff4c43475c590e8c260411766967.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/container_004_offen2.png" +dest_files=["res://.godot/imported/container_004_offen2.png-65a2ff4c43475c590e8c260411766967.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/container_004_ohne.png b/thumbs/container_004_ohne.png new file mode 100644 index 0000000000000000000000000000000000000000..08f658df49e04f63d20b3d45360a891c0fb326a1 GIT binary patch literal 2876 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 Q?l53tU~#cQ-}UCd0ZQvXsQ>@~ literal 0 HcmV?d00001 diff --git a/thumbs/container_004_ohne.png.import b/thumbs/container_004_ohne.png.import new file mode 100644 index 0000000..45cc6de --- /dev/null +++ b/thumbs/container_004_ohne.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://0g2gmbbh2ltg" +path="res://.godot/imported/container_004_ohne.png-ba921267ce01e62ae18dbdb4634a10e0.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/container_004_ohne.png" +dest_files=["res://.godot/imported/container_004_ohne.png-ba921267ce01e62ae18dbdb4634a10e0.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/container_005.png b/thumbs/container_005.png new file mode 100644 index 0000000000000000000000000000000000000000..ac22293bda2094703224d9dbfae04f1a5d689893 GIT binary patch literal 3535 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 P8sL$Ju6m`KZNz^7iI2d{ literal 0 HcmV?d00001 diff --git a/thumbs/container_005.png.import b/thumbs/container_005.png.import new file mode 100644 index 0000000..b0c67df --- /dev/null +++ b/thumbs/container_005.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bf57o5pnj355e" +path="res://.godot/imported/container_005.png-44dac20b33a2377df4629488ec050e8c.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/container_005.png" +dest_files=["res://.godot/imported/container_005.png-44dac20b33a2377df4629488ec050e8c.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/container_005_offen1.png b/thumbs/container_005_offen1.png new file mode 100644 index 0000000000000000000000000000000000000000..9ae7891520cec5550b1c4a11eac9f641aa9a8be2 GIT binary patch literal 3019 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 literal 0 HcmV?d00001 diff --git a/thumbs/container_005_offen1.png.import b/thumbs/container_005_offen1.png.import new file mode 100644 index 0000000..08d6522 --- /dev/null +++ b/thumbs/container_005_offen1.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b05yavnc71m3q" +path="res://.godot/imported/container_005_offen1.png-abe9a419aaa7261b44ea2c423c1c2fed.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/container_005_offen1.png" +dest_files=["res://.godot/imported/container_005_offen1.png-abe9a419aaa7261b44ea2c423c1c2fed.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/container_005_offen2.png b/thumbs/container_005_offen2.png new file mode 100644 index 0000000000000000000000000000000000000000..857abc222e7896a45e92849308a547ca1915d574 GIT binary patch literal 3136 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 literal 0 HcmV?d00001 diff --git a/thumbs/container_005_offen2.png.import b/thumbs/container_005_offen2.png.import new file mode 100644 index 0000000..a3b5717 --- /dev/null +++ b/thumbs/container_005_offen2.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b7sjub4cbkxvg" +path="res://.godot/imported/container_005_offen2.png-b9a4568f12f6f8709ddfe53c8915cbac.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/container_005_offen2.png" +dest_files=["res://.godot/imported/container_005_offen2.png-b9a4568f12f6f8709ddfe53c8915cbac.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/container_005_ohne.png b/thumbs/container_005_ohne.png new file mode 100644 index 0000000000000000000000000000000000000000..9058d0946d797a2f3b596f67d32ae374489172bc GIT binary patch literal 2887 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 XZ1iA5fXnnjG6pQoZOlqca1Z|jr`b%d literal 0 HcmV?d00001 diff --git a/thumbs/container_005_ohne.png.import b/thumbs/container_005_ohne.png.import new file mode 100644 index 0000000..77a9c13 --- /dev/null +++ b/thumbs/container_005_ohne.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bnsu2xyjabygv" +path="res://.godot/imported/container_005_ohne.png-21d69026ac64e40efa15ffe31cd6e52e.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/container_005_ohne.png" +dest_files=["res://.godot/imported/container_005_ohne.png-21d69026ac64e40efa15ffe31cd6e52e.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/container_006.png b/thumbs/container_006.png new file mode 100644 index 0000000000000000000000000000000000000000..2d3fdbaa1e249d5671392c0db4c18298a4b16978 GIT binary patch literal 3545 zcmd6q`8O1P)W>IxtfR3MlW#_nEEN-zeGl;^YuU*@WXYPbj3sJFL?zk7cSvQOY-5|G zBpSP+v1S>A326+&c+Ppw`P}>Z<(_-)d7pdlxu0}v%NqiG;(P!AK)}q@$d=8d z|1};iw*RE-Ilu-m!uEzCpq6-+$_{#NW@K;+RYWTy-;*Yx`}B~HqWeD>)}V4s|8)V? zj(N0L0>unE<`AZ;ibbd7ZBMO*z?{#8Cygrw++j}s6-v1J+ZuG0>7}mUGKY%x4xpi$ z-n5(DADiM84K4piW-hYY!lonbdLtx4s=B>n^w~^=E&wYv6uJuTo}b@xUCsWvODPR3 z&lasApSF$^^9A(VaAlwUe+P9ArT8V`q0Z1U@`U$1k;i-~^(ka5~D zr2O-+61DXxeL(%Qfj?OJ{}6dS}XL}Pm@u3Yko1a@-9T5(EA~m zKwptAecB@FjUDizSx89fpB3#>w$O#&%NG!3_*vnz{vvMHb^lBmX36de&ieCem89W{ z`hO{kWIuVT;alJbQ@W;iqsD$iV`uRy4K($@;q7ffK>fHLLV*mqR$J-2Iu;QYaniB7nG_DJS4!MjN!*Im0JR#zTv{{xwZBRK6!ar zN+?ZlUjV?9Z!Q%Z#ARR}TIdrGPKs3J)^ENU36SC}5ClUoUwtC>LBMsLyAQeoITWod zy&O=BkWv6#H9-_E(mEpAmNx4Jg3@0?+rJqj@!WQyEaidc{%M&`N zR9VEZy0C;uUWt6ia`(T)ZR$+za@+ol^#y3d)Bx3OPJ$djp0cour_MhQq}`dhtUV~B zXB$fdG%rMSAE);AIw|Bnw%fxh>1_p7{m=?E3C0Y^8FhNXyIYsFC9Rxkv6_L?#vagX zqINatXX)zGuCS+M;W^8l0svwZW2nU&p)4C3KMVKZcVXWtx*E@F=;JoM4pb8>VI*9_CDa3AAD zNEHq|cdob9_H(bE0DFzV3$c7n&NWNUUO6w%aI!v1s}Y#%d@Hv7F|`|->FKyuSH-Fd zUw)k&3t>r#6X$%5annT7D=VkN3&OqLHiT2tE6Pg!aPTU*Jf`D2m}+s!jr2sEzgnil z-RhlNi)}}YE>6Ya@@+X$K32u1P|PxyDQiy`N&I`&inH{BaE5_Mc@Es1`a!1Twco3p zYsfQ;LCOYRh`W1(Do(D7Dl&y8{^l%u%*nm9eVxJVe#*`o4CfwPPCm~3ku{FC*f}hV zW_=aN-tQ5U&-?d?mXY`|g&Xqq_KAE~m|L_^MyeTBrS(d3u=EF8Cei=i8DRb3xmTvW z>3!u{0Lxx}9E-TTyLxp`kYypqso&sQ<`}o1#yAAMg$xt9)e^sa7VAzPqDU88;_OxQ z7DEvx7xO-01AEVVz8rPx<0C%ZNvsFFWLMFn{4k4ZHpEqxaYt^V=1Ef|;rEFI}WFKcyM> zw7ZipO^7vri|hCi7a6Rh-{kB&EZ6vKVEbryXpE;oGN_mT;QjRC!0JuuDUSA;5Z9Lk z5Alx)fG1zh`xoes5jJ+%LwZe;A7_a;JOVx`XlO@cyp1}hTF_$L+8f6BXTZuj)(bz8 zg2_H852s_lFEqUuwKt74s~XGV?HPIH%_%G0I-5jz6AW6Q$M!pmT-|f*l&G+m6+Z*) zZ74_U@nMx+f}iWql3Pw zgRYd?@0|FV5XHpZjgBz7re0TUadTz9K?TnzPlR>Doqrmw$K=If6Z)PnooYC#Ht-7Qg#cB2*7c4eVWwH5Pg1;CjQHA5b8 z|5QUHR8oyJ*BP^q5 z^Y5r1-gCIrI;%Jn(xNh_mxd8yI?|4Gr>jQZsE8)~mbx3pjAX?D*_tP72-jm0U{5jr z>V_2~08V^VO5YNl7JFKCh!m*=!->SjS8gRN*gGU{8_o z-Wi!n-HsbQ_+l4@+_cYL%MpIh7wYn=`O#0WYJi&|49lv=631G6@5S6g#4b&*bcsmf zgOaE%bvq+BB!y05t`0+Cu#4j9+pF{d6O+M)M69ipAe_RpZis}VLaP)+tzeD`9lV4T z#<-5|+X-crEz5|*S*o;TQ{Gyv?DkAs#B#WXeS{Mi7uTB#p-dyqmyczHdF{i`u%GHA zY1_&7UEs!~P1fAJb>Zt3$)v;S9|ucOoRDc3!a6=b3?{Zy z#tnWQz#+wHCpkw66jKbP5G7tWg;pd#>RSrv^n?^=osYa+qFx{0?Y*X}H$iXeQ&=Zc zV+MvYTOSG`92Y~t5| zAi&Y`Z0YW}ofS~9`O6XihKp-k_z5`9Kq528^hw$9Hg9p%aTv>5E_I-0DV#cJG3({G zKFM2*W30uBgzhNa;ap(Fbz|MtpwN9glk+x_;_*j2eMe-y&YqqgjtXFAWc9}{O!4bw zp5Io8*P{0r+xL~Xjq1JWS>F?W*45TX_cFb&#A>+>0kj@&$9``DM3o7Fx$=vPS0-y* zh&;e^xEDXruf0nH)bQpvk`OQS#8)@#HGR=J@W zh3LtF0wN+JDtS{69`Y9^ON@PFY|U<<5{5VL_)Tvv&*oU53QOPs!ZIY`>$|$nlZb;| zFnD`Cu+FZI zRLm=NbBw+9;lo9ekEZ%P(J6b8b-ij-Gf@0-ZX(wLYlC#K=gq*y`9%Qa(y!^uEi%d| z0t-7R6upUbux_qY7SJv-*(IX65m?{#rI^aFY2jjzaO^+-_U+R9Ly9&zpEQRu}Xkf;uWQ zhmQrd^j(j;{|$vS&rm?; z0)LprFAkmExlyV?qOJeAf(}fAgv|ABNqT4;%Xja4RFWsCF3e_L>mo3^5O_*9MLB6% i4rH43e-7d?=y$%JkIGfbBlcenU}kJ-RBPz*;C}#7$;^rX literal 0 HcmV?d00001 diff --git a/thumbs/container_006.png.import b/thumbs/container_006.png.import new file mode 100644 index 0000000..0dcaf4f --- /dev/null +++ b/thumbs/container_006.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://gub8lvdvu8ig" +path="res://.godot/imported/container_006.png-6bbad0f31b1f9733dd0fbfe92452c03b.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/container_006.png" +dest_files=["res://.godot/imported/container_006.png-6bbad0f31b1f9733dd0fbfe92452c03b.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/container_006_offen1.png b/thumbs/container_006_offen1.png new file mode 100644 index 0000000000000000000000000000000000000000..dd2945236e3a51d4277d92b9566402dc334d02e3 GIT binary patch literal 3039 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 literal 0 HcmV?d00001 diff --git a/thumbs/container_006_offen2.png.import b/thumbs/container_006_offen2.png.import new file mode 100644 index 0000000..c3f49c6 --- /dev/null +++ b/thumbs/container_006_offen2.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c4e8fd4t7r7m6" +path="res://.godot/imported/container_006_offen2.png-1e7ceda4157caf471ff2302bf78778ea.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/container_006_offen2.png" +dest_files=["res://.godot/imported/container_006_offen2.png-1e7ceda4157caf471ff2302bf78778ea.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/container_006_ohne.png b/thumbs/container_006_ohne.png new file mode 100644 index 0000000000000000000000000000000000000000..332cd4c83041b2af19e7fab42efaf7de095c6be9 GIT binary patch literal 2907 zcmc&$={wX78~x1^vX?AnD~~Y<*~!F2gtAoD${MmqwxPicSyGCWM%lB4FkbsIHB3Z` zN@7CBk})x3?86vd&mZw#?{%GXpAYB$a6X;uq+PKw7vMd?3jlzCrG@FW1I7MJ9Kcse4>`7#`e*9^t^!($5Ce{!PN2{2=`OO;EdtcTsoaDQjl1)RWc{f^t(64t3ynVfkUyw*sDLV@Z^Xj@Gu;Rm@610}VJ7B68ko!8QBNt3A56rtvoc>65wF&3Sx%Q#?J!H~Sor=`q}`ch?jO2sS=^ zCmt)%?D6f=n&h__1lPCS7pUicq%x6C3>Kuyg@5VYKKS|26L28K_liLK5Kfi^=*C)UvFOJ63$01*)b zfc#k`6iqTN9zpnVn!6P%imrj=iRFz5Q*I(fqGwrz3c2H-g9*0`~O!aso&abP=wqs-|U8(so zdF=BxxePp;NZl~sXCW9?g96h0BzYP4qUI^0I{ynX@s28t%P(YJ1CULxt6W}&Fek<9 zcCu^zUttC}Ol&Hy$-lsXCc--z1+xOaE?KxqwPhDFe=>hE2aIuqYn%8_? zr^R}=8BiNbMFSti#dpJ7rnx#94?|(ua&4V+OGL(7?-J^g%#B&7M~;G|p||4m0jt(7 z-_b(W2xI6}`V$HlOekKDDUrIk7%qBpd-ZfYx1uO7_KQjEOOwha#}4bk{Gu4S#umu3b>+>xWlKKb~{c72`1P`xyOfDJAkuPx$Np}Eo_q}Sla zEQO8Q|D60toLucNX`a+!A7H1L?Q&#B{>ALVD+W~jO*YdwAM`(^= z=?^IV_|8TPMHQapyuyhck+7GM2SBb@_Gy=U%Cya(H3S`Gz5Sd(=qBZrQX? zDUnJ2{r$B%(SAbR+A1@TaG<+00n27MJrjI~lkCPYQe7T&yX0!X$c>@ks~wgO`it|% zM}F$*{^~U=mt&}o3lT)Ln4UJ06`^;gBufH0#{6{<9z{m(hl&oNQ)2=^^TcJs*zP$X z1|>j5P`TIga>EA~(HrIAlkrxa#MwuDuG})6KNh{~9DQQ$cDX|&{;VO>SvV8Ic0z67 zoDtf}2b~)m^{i%Se>P*q2+*{y4uLb_Sl^_ERruIOk3{PH@L*vv^ zbhlg0LnDo@XBecxrbZt3g+j>lO5#*191Ei}NKf zxNu9<_0p`@1xZn5n%^HGjZ=PtK4`2JhP}Ul=UD$)fAR-QABm%~Q||YsrSaJ23PiZd z<}y7WNPEyXrQJB&xfS?|czD9>ARV2t;6@L`Fc)XUgnqwAJs6czO)=ok$$u>4AIl75 z66>E<7G%iQtnkZ77v#Jqzb&Eta!wHr+a`lhWm zevUF=6Ax1t369LNHQHM!O@%;V0i!3+9WN$_I_~xw#!5tS>w|ZEwh(dS?x-NzhEnYN z;QRU>Z<$r`i)}o=z25wrGavGC0Vi^RIbE$EjQwKY3C?T8-^!vX*5&$~eV<{fQmn+Z zV3E5`=6E0RcFN_KwyhDpb)#o?>7Vp~b1rO3dWMHSzblr!kleidjolUE-P*X)pD
  • 1Xzx(W*9dA$OyMZSFh!Y|`+hGQGybmid|M{cl$mHDZ$kLZ z){0qfdBCM1Ng%p4{R+?3)v<1vQPDJ9o+f2d0Ssr@m48<0h0hV*WW35Ev1$~Fe&9s7 z?*z$+*O2(x{e1PTOl{mrGnP6Smq50a4PW`r#{)fGscl!sndf)&!Smy8X>`AmQhood zcnDPBJ@C0~pZokl?FB*Y>Rc;UTE;8Zc{!wg+G5C+u}>gTqfWRJQ|7`l0A$FV^QLbG zS9MJ7;35xxm-mwr4ym>?HY6EI8I9AV2RxK%3p_->*o@2aYqCfaGh}N%**X1UTp?a; zo`jaQkTy!s0Vpbh4k%RY5y8`4LD~j*4HfvcASdOjzX*x5prR&|X#2xl)7Go@BQ084 zU?R)o6tyyvI+eN267cqn4V zS`guTZwl%NA>FV@#+deA1VUk~s0w<>3V30-LHjQnE7Hlk&rHt-C>D6TO4bzkUciZ< zx0pk3s*r+SaO_8$vP91lbIAQOMcqg>FC`+U1H~C1aKiMJu!T~iwP(LL^8%`e?OAZI pAT@}nFKH|a=%E$;&llo0QrSEaG2PuJeXy1ROEVkOS`&}N{{r@9b|e4* literal 0 HcmV?d00001 diff --git a/thumbs/container_006_ohne.png.import b/thumbs/container_006_ohne.png.import new file mode 100644 index 0000000..c0d028f --- /dev/null +++ b/thumbs/container_006_ohne.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dhrrb85snu41i" +path="res://.godot/imported/container_006_ohne.png-532692f0dfce5ee060e28dbac5d17469.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/container_006_ohne.png" +dest_files=["res://.godot/imported/container_006_ohne.png-532692f0dfce5ee060e28dbac5d17469.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/container_007.png b/thumbs/container_007.png new file mode 100644 index 0000000000000000000000000000000000000000..97ab265bf8808393a44441767ac92849e8e9623b GIT binary patch literal 3480 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 literal 0 HcmV?d00001 diff --git a/thumbs/container_007_offen1.png.import b/thumbs/container_007_offen1.png.import new file mode 100644 index 0000000..ea1b205 --- /dev/null +++ b/thumbs/container_007_offen1.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://denqy1bllro0l" +path="res://.godot/imported/container_007_offen1.png-3331b42973d503316069c3bfd56728ea.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/container_007_offen1.png" +dest_files=["res://.godot/imported/container_007_offen1.png-3331b42973d503316069c3bfd56728ea.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/container_007_offen2.png b/thumbs/container_007_offen2.png new file mode 100644 index 0000000000000000000000000000000000000000..a3c473306dbd9b9cb47709ad5c634c3815ddd6a5 GIT binary patch literal 2982 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 literal 0 HcmV?d00001 diff --git a/thumbs/container_007_offen2.png.import b/thumbs/container_007_offen2.png.import new file mode 100644 index 0000000..7ecab66 --- /dev/null +++ b/thumbs/container_007_offen2.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bqkr34vaxvy5c" +path="res://.godot/imported/container_007_offen2.png-1f3964f3eeed540daff6df248b5c78bc.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/container_007_offen2.png" +dest_files=["res://.godot/imported/container_007_offen2.png-1f3964f3eeed540daff6df248b5c78bc.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/container_007_ohne.png b/thumbs/container_007_ohne.png new file mode 100644 index 0000000000000000000000000000000000000000..1d87d857f9c5e413533107091bee7ffc4e9bda78 GIT binary patch literal 2872 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 K+O)#hBlbVALsX&w literal 0 HcmV?d00001 diff --git a/thumbs/container_007_ohne.png.import b/thumbs/container_007_ohne.png.import new file mode 100644 index 0000000..3531720 --- /dev/null +++ b/thumbs/container_007_ohne.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bqm02u41bb737" +path="res://.godot/imported/container_007_ohne.png-eccd26afa9b16068d6d18f951b4b4e6e.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/container_007_ohne.png" +dest_files=["res://.godot/imported/container_007_ohne.png-eccd26afa9b16068d6d18f951b4b4e6e.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/container_008.png b/thumbs/container_008.png new file mode 100644 index 0000000000000000000000000000000000000000..489e5d051cc56f18a9f544b954fa09691b863456 GIT binary patch literal 3347 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 literal 0 HcmV?d00001 diff --git a/thumbs/container_008_ohne.png.import b/thumbs/container_008_ohne.png.import new file mode 100644 index 0000000..711f9de --- /dev/null +++ b/thumbs/container_008_ohne.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://yrbfa8pcdvlh" +path="res://.godot/imported/container_008_ohne.png-fc59b39356dd3dcd19f1894441dfc381.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/container_008_ohne.png" +dest_files=["res://.godot/imported/container_008_ohne.png-fc59b39356dd3dcd19f1894441dfc381.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/deadwood_001.png b/thumbs/deadwood_001.png new file mode 100644 index 0000000000000000000000000000000000000000..dc27646a593cfe86a00cf6cc9dce7238e70458c4 GIT binary patch literal 1797 zcmd5-`!~}I0ROH+NvTu9@~YH2g*zpiM|oUYBjX|p+tkwXoYx{-qr7XBE0&g)t5&WE zi6KVAlsq!cV=VH@+dPJ0yY7F{IiJVRpYu8A^GS9>A$BQ(6#)R)g}h+nyy-FjbG!Ve za?V|C-ZW5{Gr}4uY}FVC0C_gj#>zGF*>wLZA)TmED~jkU`P551h`WbFWI-E`4Os3! zVg3T? zATUi3uaGeoXGw*W=7rG;F-I?-AFw^Q{tI#maP{*AKK*V;Rvbw4r@f5Y?u&2*W?^X7 zRN(BJuk3qAklI%cT5@_jSPa5RPw4B7k=~L8#tAdFO3_+dYWJdeB7VJ{5`tPg&FNX? zelIbO5xsR2JX=nC#l@Znw9CRBtH@)O_v02|G_z~GLEW9ff`oMK%itynFoVYIrwc!X z*nT1kCDnl)AGwpwJrS*roTp9IHvaAeXNEhw@9dft(}}Mz*Yjhec)V+O_LhNhPq!9U zzgfx{(0!*gwjf9qV$ho|F<&^<_{8pty5*vgxinf9`A+*L$lGOn{iS$01)rqgmZAHh zFkeT6XXaBC2XZPKkOgCg&j6)W1k(%8CHk!Q8G>Q6gOv^Dq{)f6NoA~tkKlfm@=Oxp zc%C8iL8+p*eSGYi{{e>zavK)yVn7Nfu6x#~&h#|3WrKiQoiwgKNzyp7O$pa=E;KYW za)gW9u`K(*<(7<`aiLILY30$4#15o~+#H(D5NrJ*V8V%8r!LQ;;Ie9*DvRJ{&ek;1 zpi|a5mewouCjqscsU`SNo^=qu`<$@2)t9?Gud0CK5nDflKvV2J*AaJmO4pE(%<%OE zQIG(7>6LwVm+>0nUqSOcoRmX%@b|lYx~_lYG<`yCQTz=CuV0={v#%${UzMsA0ZwBY zxTO+BVfNvK1Y*XNw3^5tvUBJE-C&QkThciOhK8A#sa?kpsxFI0TkH-jyN!HDxAWDs zbj4YaLvB2J`ccR8#9_kN{7yxDUyx%M?5LbUl>8lXdtVCzB7sMU!>3|MN)V>+{4XOz z&`RPFd>r@?nW07bu>~2Zs6=wHkHBreXgrSs*Iu>#hFek@_9%$6#yvTd zo@N;%cgqZKdKgCC%-Uk03SG#39*CLA*qE24Q5AJ2xb_ND4;zoHhf|COO*bo*OEv#; zKwlSrqv(6KBOYr}VSG@TkFjlst_;6~1<@l84iUiRuJB-${UU$DapSg2u1ckjCS_(P zvO7C556b-|ko)0jX&{>v`NnRq8Sft^vX?$uoMeH;MP$x{dt`;zsOO*;t>{*T7M?8h z_(YYl#Y26i`j*qyIdPLSm3d&&^YqN277cj#qee=z9^1k1dN{xqC$MTFAn@JtM0$dg)sGK`J{O@)RV!698M6V>&8~>T!{tVNNsp>2aSF)bMGvu@G%q` zE$qXzU+2{&>X~lUJtA3oBRx8y^x_x~i2FUUra;x~aAt`Ro3{o4NL!Rmp|$tD{{RQP Ba#R2S literal 0 HcmV?d00001 diff --git a/thumbs/deadwood_001.png.import b/thumbs/deadwood_001.png.import new file mode 100644 index 0000000..6f2967b --- /dev/null +++ b/thumbs/deadwood_001.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://brb6m7wgu8dts" +path="res://.godot/imported/deadwood_001.png-5f57701ccdcad85386aff399fa67c0ff.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/deadwood_001.png" +dest_files=["res://.godot/imported/deadwood_001.png-5f57701ccdcad85386aff399fa67c0ff.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/deadwood_002.png b/thumbs/deadwood_002.png new file mode 100644 index 0000000000000000000000000000000000000000..fb3a0e78b87201e271b7a2fe65cd2395ee83d8bc GIT binary patch literal 1502 zcmb`H`#;lr9LGQ3vD}Z^2`dVvi4IDRlH0Z;Mrhg|&JLPTE*;B=VVdoMx#d#il7ntm z;xrx8DxES-ILBq~RRDm7 zE6(YZJXzmHd5e4t9Rk|q0bM-hf(6`8y-5Jz#jZ{mVqEF$+YW+mj9$xv=mL$WtE{~J zr@Fc@r7BBdbYJGN-e1a0vV3f(I7$}um^I$2X5an8<#y3CjV{eQ9%xsFenN+}1sNI* zb_6qbW2?%r2y2{mgGd(BF0^Q{lFkrl_Yct$v6wDPUwf$A2LWtUSfz?+Pndx*bR{3O zx`GczAnJQ#7cId=zRn&;8Sk+O0uDBg(WKrCcois|+uXJCluuCrnV2{^V)Hd6y=vD} z^}qIy&_BHX$9@oi?U}DygPOdCm8cB*D2{CGzX$;g-XZU`ttmwxeTQ2nUqUg!F+dH%bwhAzxpUj zP_y;93&{qn%Um@;8XU>AbM_0{hTfa-aXe~qJ=VA%0?H-Gz1%wGo5YD>Mr7-&@Wu?g z#4kvexaqvnH|)oK&b~p*_sDK|L>OeXCnOTanyzX?DOF2MdLYu7Fjh06T8w;HGL(~k zzzjBj0wT{2Iwqy;Sf{**;vLu}bewZHz$TfVsxl!X1-bzJEmCRI+8m!k=x>1ZPp%*Yf)kyZyB&y-zgG zCR^1q?Ovu~SR3!k|7|q5Lz5OAK8?GlcgcoFcjATHn-zi0n2Q%QUNbviy4TNN(l0tG zW&A1Wp(@oA%=^dE7OAQJhPY>y*TS04eKB-cz?oqphz*b+2 zA>^D?s8Jh{sO15`Je8urot9)32wQ>_;+~6|PTcd9q&<`Q*gq<~r7E!UAQfhJ=O@2; zGt^A_s5sXi62@Pa-JT^2$cVccGd-5qP90_Zt>4RI2B5?vlYz52=T*+^b1&VgCzu+r z#&YnBUu;{XH!ESl)KPt(nOZ}q1>Rz{y3!lMJXPnse5>Xfj+Xkc7ZwBVB zH$^q>?>D`v=MBRR(Fh@`(@yGp;PVwWq3G#@x;6vgh+)5g#fg|mMLv1 zNl9TPxFKzFb>txxwJN!NR9Rj&;)cWHe7d!ni;my{2L=RgMiLYyD>hQ9(gmkZo>fJu zBU7Ok{*^je!|inFG{~Ve)*=qZihc+b@2W_UZIX>igGgMTjfZ<|wDd*&W({#%(GWgo z57h&8A$lC^&pt?eh!`0L#0EIggtOHYUPJ6zs+Br>!RI@v<24Mno8kVVQ6-20h}A6L z%LR^0#C5MvOA4A|`vF;x)ERFE0m<}AhxbWC@5(~(KK^^#>Ho~P0p&@lCZO?#vHWGg M^|+@K7keh@KNM1#YXATM literal 0 HcmV?d00001 diff --git a/thumbs/deadwood_002.png.import b/thumbs/deadwood_002.png.import new file mode 100644 index 0000000..b8aec05 --- /dev/null +++ b/thumbs/deadwood_002.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c3sqh234ydke8" +path="res://.godot/imported/deadwood_002.png-3979048ae050bb6eac02d14d423930dd.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/deadwood_002.png" +dest_files=["res://.godot/imported/deadwood_002.png-3979048ae050bb6eac02d14d423930dd.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/deadwood_003.png b/thumbs/deadwood_003.png new file mode 100644 index 0000000000000000000000000000000000000000..1acd41a698bfb57673093590d2916c2f782e43fd GIT binary patch literal 1480 zcmcgs`!^GM0RN5_X-Ou;E;p6uyi(+qapvH9k4k76*CUpw(em1gNK$UMlxoeqI+Dln z$SaTCM5VELOl%rwBzZKJ#~!%uulEn=oX_jG&*!I4wvU&~9t8~r0KgtMS2SkZ$^TJ) z=eE8*iR;}q$Q6u>6R7G#%mM(t;f8kfCq7%CjQeSxQqLkq!j~ZjGnAAC>5$C6_fbJM z7BmPM~_l56zLAu^_)Q8KxJ6yT8w89}u zZYs57J)hfH8qq2N9ThHCHNIoUKh8g~9A8}&nWrSrV1q*Il*bhE`p;C&J9-NV zCZOpzMHTnqbb1`~dWD*<;KP8S>erPZeCQ=?sjazxI9?JXCYIw$$^J!lYSOq(<;|v! zJ6SAG?(O`)(W0)Ur2DZ>L6BO#02sy)VzgDor_B1Mq%F9=qVFy|IxR6(z7UqdMsb2V z8#?#_j}cw(Xv_MfkIftc6;qzUqB-KbLz8pQGxDlig_{vkMgXKNjacrqYa<>B$)foW ziZgK`v;F&tp4~8ulM{n-tQY$tTv&ksG_~JHSNC4$B~m=+H2$FD8Yk;`jW0j)o-OlZ zHx7iJDQ*Kmz!+2fhpu%eUqesw5EEdW54WGp+YRCpA`n(THkOCN=2gZNWn!B5GjQBk zISnLSpQrn=F6%F*nW_}p^}4YoiSA;dpF~c5O)b%gb+GezUoxm4J{SdiVWHzk%F>(nH;2WS%8Whfy`b_D*SiW2PBm-to_zi2+`^7r8Ya`eHD9^q{7R15d7+ zliiTpBgc_Q#5F3Ho*x^4KDjV~yWEU~LGj(n$rV|>SGFt`k)dvFE*lNZ6#!~9#+`H? zo~$LL=p4Jld0J`j&0O$NP%=+3gC$JuMb9F6{HX^rVA_Dn@hw zx0HJSATf#0At z9K4_jajHB-cRP>54qqKu7wro7^4M{rFVK;)5AvWWpNs{iDzJBw&)S8kN`|f6_I{c?Su>ED1^uMAlSvc8X-OLf*zJ1NW M&DjfG~QD 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 NV2^gPZnX4I`!Du)5CH%H literal 0 HcmV?d00001 diff --git a/thumbs/deadwood_005.png.import b/thumbs/deadwood_005.png.import new file mode 100644 index 0000000..a0b4146 --- /dev/null +++ b/thumbs/deadwood_005.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://coiwt4gpm0y3m" +path="res://.godot/imported/deadwood_005.png-cae213d4f55340af24486a42cbe391df.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/deadwood_005.png" +dest_files=["res://.godot/imported/deadwood_005.png-cae213d4f55340af24486a42cbe391df.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/deadwood_006.png b/thumbs/deadwood_006.png new file mode 100644 index 0000000000000000000000000000000000000000..031293ba9a3cddff2f99169b22caafe4e58183fe GIT binary patch literal 2182 zcmchZ>p#;C1IB-I=$Xl;!aQ105prk_X^71s+6Yk$TR9YR${{4f9;HcIxl<9tkmR(w z&6#aQtgx|AOH7DriIO3w+w(^}&x`B2KHtyhdUL(IZo0WRDnQgA001apPuRO}CHcPs zZ`<+?YyY0D0L8jH+5)va#8&_SW3cu%r>_*u(nc;Rz1u@(#|8x*HtRI=3k2JsKu6qg zX>wi(&XTyh?)le z)HMNI;iB*Jb=eBO35&6r&03gVR$YZzHHMCiF!nxiuUcqKl6N(3GvGJCIdMeEoN&>t zD0%5SihV^KR~}r|>+Bl+lkiA3MbZcN4sX!y^E_%iXz+Tg46MI;X_qV+&z@=iGtf;~ zalP%{?EEp&K4=7%d&#uPZ1iIjrcsACKlUV5DAr(s8*y=6u-kv@UCJ%+Wdowk7hwce zOuCm#(Zn(fbnu7kq&f630#W{X)!F5~&e6$}S){OMvnBur(Y+m}P}{mWdekL)Y0Szn z*}^FzlKP()L_!O3UuIw$vV_$?epTyzXGSA5Pmu$&JNAy4z>Xoj8Dgd|`uK0rNbc5B zZR}398kLhGQMFqmB2Tec7+OkR(1z6rmw3YHphI9MnXmjT{2bk3;6H2^8 zxK*pI=WWTNWaHyKFmB>r(aNv4Rg&X3>8z%!)fy1#m}W$Z;yC5grt{`p>ZWqa#&j3~ z6&r3BFn2^e(-+a@T;Ij5wTYJ~Cx)$grzFjK7#5h{Fp~3UwnW3VjSgawUH#Bul?_*R zbXt39si_LQ*@QSTJvG|fu*3KO=krZ-)*0^GbNb^UeRtRrEeA)3irzkYz0aah6Pr<@ z7`S}^Vm@ZMv{Sk@-lK*WJvnUv z6^Pu1t2?u%p?Q;r)B+B4V10PVidWpO5NBPI-f{j$mGm~ z+SBx`vH~VL6}yZKL{Db_r6c%0j>@xA*nHR<1f0-{q9w+|tdEZ^==AaE_xIy=#uVNX zhvc}c9$5HB*&a+b+|;R`zjhayDfn^jukmJRI*Gawkj+6aI>;6_>;QkW!@)63&n&*n2C_9D(0SIp!7tJGG@CTg|Dpr->Y zi6mNWiIP1NM#0{3{vyd-(gaA%RxR7hBRF_!v^5P8=6drKNjiX;5>M7E`K0=wW(IRg0~YH{M067 zyADn9y8j{R{_s`Jo1bhhJYb`_l3ks~x}0zgf^HC8gPcpSD{7Yud=21S=9cJ`iF%IirrA^@D!6GZb4C<{?gQW z95oVwG4iOorAy*g0DyYV2+56A7dj$;K$c3~Q^vqMJ4z{ESwSSPTV6EV&HP~PHHRLX zgN1w9|CVYY;UgFF*<&wZQZJDl)oa7hWXt%w{LjlB2Ht2D&`X&wzxX5f^!3faq@v={ zavxof?@3H`8W%FM5&iQ{M|%sOk`RnS;W2?oY?inMv3t+>hq7vY4R^9(k@J~mGw%Qj zL@4w+9}<%BoGzt4TJzh2dD4yv5Dy0JW{Q;|wH>h(SRDhbE-IRh!{^%uC4ug|S;TP` z-<;$P%_IiRMKL;rrh@~!o_rpIU&t29KhqDCRir9oP@cdiJm~uW7I>*3xPLzgKP*?e Qbu0kvaTohqTfek_0QE}m+yDRo literal 0 HcmV?d00001 diff --git a/thumbs/deadwood_006.png.import b/thumbs/deadwood_006.png.import new file mode 100644 index 0000000..d82cca0 --- /dev/null +++ b/thumbs/deadwood_006.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dbl117rcr4wtl" +path="res://.godot/imported/deadwood_006.png-f7332dc02cae7eb7eec49bb04cf5ea58.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/deadwood_006.png" +dest_files=["res://.godot/imported/deadwood_006.png-f7332dc02cae7eb7eec49bb04cf5ea58.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/deadwood_007.png b/thumbs/deadwood_007.png new file mode 100644 index 0000000000000000000000000000000000000000..b3cfb4bd88fcb4e7a22fe65ea452af23704c1a84 GIT binary patch literal 1966 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 literal 0 HcmV?d00001 diff --git a/thumbs/deadwood_008.png.import b/thumbs/deadwood_008.png.import new file mode 100644 index 0000000..7d0e6f9 --- /dev/null +++ b/thumbs/deadwood_008.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://h16yvecq54xv" +path="res://.godot/imported/deadwood_008.png-42710d1c92f9f0ef74976e4fbdd3bd4c.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/deadwood_008.png" +dest_files=["res://.godot/imported/deadwood_008.png-42710d1c92f9f0ef74976e4fbdd3bd4c.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/deadwood_009.png b/thumbs/deadwood_009.png new file mode 100644 index 0000000000000000000000000000000000000000..a7160c1936774fb327f407c4cec4dc3a5e656c42 GIT binary patch literal 1993 zcmcJQ`8U*y8^=HMiNRd^O@_)6H4+y|S;jhICfSOpEF-rZ-?3gsc4G@QvXyL;B{3P9 z8nTalxivK;A&xDV$yi2)rYtjG_m8+gJn#2;KkxJW_B!XuaB{GffGNTN0Fc0-t*;z7 z;olL39%!$b597cfVOMOefI8-}WdIOK##mdrM3$_P7{MNH3S9}aMm*-v!c(tNN*4ZC zr471s(0RhDu3sLhR9;HI?@1|J*W4^s{jrLLh~9TEgI#leo@D3cJE%0JAI6%Ak$kXQ z@Oni{Q?Zm8%R*#oO^rY0y#GbwAXyIsJUSOM$o(mjDzf<+gug0)cNw4t0#;V?--c0G zh+y4*eU>g~Oq?Ujb;Y1-C63#KjKZ))6`R2CH%B|b0r=(IjhVG^RGREzIyfPucSPom z4y4ST(7z~0`4t2%ui1D6mXa!VL1xYZxK$knx!gQiBP z`7TS*KNomfJ!SIG#kabQi7zYMCxR_hn!J!J7;bWU0N$u%>Qf>wUQeVaqxgFq`f#~0 zDih#L&y?kzLaqkpWrjhY$+YdJ#cmZcJ31{tXq9Q$0nlee{ybsOWC(sop?HPVm6Lig z6L=mLV7jcQnDu4aysPD>o>&>0FuS(~SwQ*~-2Nw(X(YgqWdN0Y?Hyh9#=n%Q9b9x#MIKY2jKCCS5Awk(N#ffz3!}Z{5@E2z-Po`wM zQzA6UHUP`h^_PAB(NFQgFUzMg!1o5vxq%NZT){)^ZC(v*jJ&(@O**;kj`&#>*yFQ=}Kt^N0 z51atHMx~e>sHGE5iRu)^j|6ihuvO~1jXBm*VcwH>XPb>N`@>c7zT#Gog^Q*wGZnDw zc5So`T-BbA*{HiAg08(^IdPT;o}22lAn{-D0CA>CJ2#S(9i4E1PJ7sX zv8At>{n8DdH$Cd*G(XUmKMecm(!uR0QarJ3>1>KfS-M8x1qV082|}$eKmM`uj`wtj zT%eLWj9~yWX+A-10B%hzEIzBc6$PJJSQ*^Hk13AyZ8Eo?pycOW3hW^3(=F$(Z&UOM zJSA4_&5w0K`^??eV%;^)mEuuEDyy_*6|5TCg9O@%u*ZTzZYT1Td|EdtolRpkMyHW? z73OA0IQN`J{I0KeKRlaFNT=RRsJ{S=M9BEx`qiK5hLUHc>boh-?JEa58ILo$bm~rQ z>?dAvV+8_qIn=*o{DN9PMxz-Df{&4k#Wxtm)ExPfb1O3Oq#e)Cn+K~OT?-|}t6~-= z8UZ{Q+qFB&TpP(%nDd(zK&Q`i0d$A(zeaosOJLvLf89~rW$X(^ODVpoUe z>4P_VvpVBcEyNtt3grN7Q|A!&k#qiHPNLU#2!7E`&f~a{Ui$092WLmt3~t8+p1gED zKkz&xa&fbt@I3bQ`vCckP-?UZ?^H|x=UP*gNn2~rSF0xDJyob99^MC^_do;=0=@I( z4ugO<8_6Qy*&*UqcMlbzs&h6_3;qshh~Ox6RTUTT)Q1Kf;?sqY9BjS!OJvJ{K(MV`-8vEPb6c z%72m%7l*D&-AfnUO`gw5Twrg0_xFAiwe{9ds-+>~DaGxN*V~nYOFLmt{h)<*5QkgU zokNeQo^x2k%7l==Z#6L%NPf0;%WGzWhviv~cj5BF@As=AFCa z37wVcJ{U33!urvSw literal 0 HcmV?d00001 diff --git a/thumbs/deadwood_009.png.import b/thumbs/deadwood_009.png.import new file mode 100644 index 0000000..a09e7fc --- /dev/null +++ b/thumbs/deadwood_009.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bvh8c71joh4kt" +path="res://.godot/imported/deadwood_009.png-fa781055081084858eca43f617417669.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/deadwood_009.png" +dest_files=["res://.godot/imported/deadwood_009.png-fa781055081084858eca43f617417669.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/deadwood_010.png b/thumbs/deadwood_010.png new file mode 100644 index 0000000000000000000000000000000000000000..fd49f52378b7a5af46cb8f76b4838b5b9e112fa1 GIT binary patch literal 2114 zcmcgu`#;l*8~<#fQ8bs@*mOuPMXsywRKgGnhn=P@&8@RIb1US0Lz|KrvC3R3#aBt0 ziQE+kio!Z$fU+LsGyrVhbak{p^Jm`NBYuRovt~2dsxl`E*>P2C za^{|+;+_zU*1-P#A*qhIJHcrsr{t0#C^H=>_^xdt8N5i5Q_C^jYquNYySEOarMSD_ zsHh6-m5G9-TsXE`pFjL)G=PVo_Vqob@jgdfzbA|uoI#M;R#qF`J$Rd?sQ{|8Ny7|q z{G&h~ngO#z6M)e_K}lo(bEi;FBsSc2MLbA9tKD9LVE{eWRTemEMF~`&5~C6Z_CWrH zi!ovhVt`dAiu=LaFl3$y3U%P)5@!NQunNouA{gzQtZba>Zb7z+4 zc@R+6-90$>Gg8IFrXnXHQ+1L^9YNwrRb1q!t(LX;<3$>$NT$-bi4!LqU*#%4eAaX! z2D+BEW7($WB|>*6_^tUx-u7oxW?iqsIK&$|cE(Nxhe^>N*6aDPvwjlMll?yJZv)e4 z6<&M!75DW9cP+0}Y(oxLXXOys)<7?gP&_5ReguxHLO{P3y8F z(kWNROdb)I`=yR%qB$^o)g?0t#p!%?`>VgpYkm>`m&ll_Dh1v&KfydxcNg@Msp*e1 zdPGb*7}@}hJQq~IvMQhK`oY{4zEgbwrSED*oOl`Zi23_KjvfY}kfM0BR&#Qp2AW!( zvEJq+ZcUQ-cmDJ~@%m+)EaN2Q_zSC0{u@>KVAk~NM%SULbKj$#^b@QDDn@L84+$t0bvP^%8xF7#~ru?8o9)O>X z_bL|k>Ki1FEU&ke?>O%Aj<_*M)fi(M3Y z%qV%=of5mb?M;~-S109lV#Wl!Zec>?Rgk6&suw5N60iwQlHDME17)!1BkKY;VGpF@ z9sb$g(rCgWhnjH9TkDc`Prc=ONA0g?V8Kp9cnU0I;Q)6tO$%V01!CfCUI{cJr#IN) zpPV_^Ib;Yf6PnH+I&b--(9gp3?DQ!D?8u>2Cpc#JC z;+Ze<9%fDseK{D`V|@?B*3<~jdo@*9`J2WtnW*UC0EN5VF(ij@MDK%MufM;~GY;!G z<;Bz;so&ze4sKp8uQ|6;!QDeYgr-^~ci}yux$$&Le}ib1RA>|!8m(+dpDSyyHpZ}O zsM0mza5}nB)hQ`aSIL1(r(3wG4Rj5pV6-l~Jt!&-Il|GkBi*dlJi?K6t!Ol#zWuUKH|rZ3FS6IB0>$Fvj%5*P#2`5NFe{%@$~*w9dlG+ z?!wl5R_gf`iK<@nj*d0xEszxtCL8a$aJpY!9D<_0J=W5qX4OD3Pqy4rsAFNGs=9!h~FZ;Qr|uPZr?-hx4Nh)GwF5Bx~`~=+C{xa`DU4dMg_VWwn28t_aCrS1a>vs?z%J8rX`)n8q3xehv{R$AqUl)_y#(<;6{~ qk!F<0KX8zxFV_FB+xK5QQczN0?2t`Y161}D0Ip6Rj%67C8-D}(zU2`B literal 0 HcmV?d00001 diff --git a/thumbs/deadwood_010.png.import b/thumbs/deadwood_010.png.import new file mode 100644 index 0000000..766e31b --- /dev/null +++ b/thumbs/deadwood_010.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://d3dd8hmm48f2u" +path="res://.godot/imported/deadwood_010.png-72c23938bc1a2081a750e7063b1757e2.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/deadwood_010.png" +dest_files=["res://.godot/imported/deadwood_010.png-72c23938bc1a2081a750e7063b1757e2.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/deadwood_011.png b/thumbs/deadwood_011.png new file mode 100644 index 0000000000000000000000000000000000000000..cf795975ec38052758020be6e10e56af103966c1 GIT binary patch literal 2131 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 literal 0 HcmV?d00001 diff --git a/thumbs/deadwood_012.png.import b/thumbs/deadwood_012.png.import new file mode 100644 index 0000000..ae4d501 --- /dev/null +++ b/thumbs/deadwood_012.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dfj3l6ryvbifx" +path="res://.godot/imported/deadwood_012.png-1cbdbfc502eba2800bdc64dbf7b63ea8.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/deadwood_012.png" +dest_files=["res://.godot/imported/deadwood_012.png-1cbdbfc502eba2800bdc64dbf7b63ea8.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/deadwood_013.png b/thumbs/deadwood_013.png new file mode 100644 index 0000000000000000000000000000000000000000..501cfbeeb1f4fbdf55686e6bd83622ed0bb6a3f5 GIT binary patch literal 1792 zcmd6o>pv5E0LFh=7#R{FatU#&9XgR#IBq+L+@@S}Ns5FC&D|m-hE!B;QDM2|GK_3P zYs%Cl)-3mg(5SHC*xC6n`h1?tyXVdK#gpM^Zv_+ICk_CB*;rdT3mW^sp(29pG4bmY z)Q$*eD|1lyPI(>xk#-wPGneS1rBS}a9*i<=g~0ADzCu;SajB#3~^; z+_*NlK7p)C222M|9r1GgI>K7I1{wAqdxxMoe2Q`*6QY*=yU7L22)j3o2~*YOC=Xw6 zGZRB&Zmht*XI#^~3hoz1Y$YDg+_SsZp?0`eWs{dizttjlMofwFM%1`zyuke!V}8J@ znH2B`zL929`XDRNbKu^K9dy@GBU#?*{9BFbl361f}Ro3_k10VSKNi8^zqcD?RzEg;%5J?{|N7G*|56b+gc9KK&J1jTe+Ck42zwUgj{5cOUdmQj3N%f*MFLWvs-PK?#4*k5`IXZ%{@2!|UtVFMLa;CW&C^5i$_EIWNKvDlN)Ck}K7 zPp9oxiL4pzg%Tk^8grEZ=#C1fe*+mDqED#1+?xGl4nb;#giyrtCDa)=;(N*$oMe!~ z02GWY>AaClU@kF{k{?z)`*r#aACo$jw2;HXIec`j^wjpf94hO{p?Ee*)0PnoV{uqLkdXF;nGVJnzvv>m5ii zs~(`t7rmbBPQ9Et-RiOI;CZUfxcJq8yejNxV|xQ`-PGaRUnQsR^dml%lyzss zEj4=gG_y5=y=tgbeRQQ0?p}b0*StdM`Ad7XyT``hy1m^KRr~wyMmdTJ8Rgx4xrIBC zv~u92aqI)CSj|zz6|42B*3g_KI_-U{XSmup_R+b*nuI!?zb0K0>T4Prp7tIyeawc0 z3MOg!F=1OFN=N)kF%=D}hx4_k-)8aZNub))6@wU!uo;Z(b36hpWvf6&m z`P95O;1z$jg^PFvHtjH$1g0~?M$kO@Jm#((=B`RMP7@~rv507r>a-VC+q!D$68wVw zl#27d{6%*wN!E48%ShsAb|(VQ-Ci8Z^%qCIv>sf@&96yePj`8s_B!8Pol_+|p+6F< z*H3wLjt`0X!I31Fu7A~3Kh}415Eg-1bC!4r+RZ~T{*5>DYN=?Vm-N}Ue|NnO0Kkzw zEkNc0O~#JMb0&BKu6hnIf1GaB+Fw4c37XsvKHBfN zv#Y|&VvziIrr|`%nb=i%IY_t?09!nI#^^!#Se$LnI3$#!+-v9?>6N)F{7* zgrfwcW5wmICAb#3c)X3vl2`h|`ZwP<2I?Bd`)yqgW#L%i8yhLNd{E8QC;-q;m>GFT zU~99_Ca%#GPQ&NXF)yRJPy09*q*TV~et3_aYDrTX&}4q{L&fM$@2gE7dJxKdBC zr7+ISX|MdCDdNY+yA16h_2({CN-&d4)n?eine4gs)n_~rsI*$YHMch83xWAWHatlr z8sAe3G3T30fyc}%WxJ8SMsy0YZB)hUN=_-6D`v$jz=!3kK^a#L6qag#=n|EglTf3r pmf+nu$y2!}Aum!-fT`b8+mLE{2ve(Lm>bF literal 0 HcmV?d00001 diff --git a/thumbs/deadwood_013.png.import b/thumbs/deadwood_013.png.import new file mode 100644 index 0000000..e03e80b --- /dev/null +++ b/thumbs/deadwood_013.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b7efle2j6s4ap" +path="res://.godot/imported/deadwood_013.png-07bf7879adaad44641ee6cfc3dc156ab.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/deadwood_013.png" +dest_files=["res://.godot/imported/deadwood_013.png-07bf7879adaad44641ee6cfc3dc156ab.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/deadwood_016.png b/thumbs/deadwood_016.png new file mode 100644 index 0000000000000000000000000000000000000000..bcf35580bc44e239c089e45fa5bfb1d2dd7476f2 GIT binary patch literal 1436 zcmcgs?LX5A0RPR-EY0KbF=tqk$CmAsXpCm19huZ8%R|gcip`o1hxCg@+o3yLw_QkG zcOEK*tI2k=S?1&<$zvGNXv{+?cJ<+Q_eb>N`}pSj?#m4e4KgzP$`AkmBk}=KxK6?U z0Eg*VPM~$^1dcDg@M7V^Z-xK!{qb8oEW)7@Z_E>6#)t^do-lb3|n;w=lR&4o!ns(a&orD7>ksu2Z z;0;5gpr*wTcn83t18twJ#tu)a&fE^7nnAI{7;9mqUmFhzc6uc+8#6hUIH1&Mb%XXE z?j8>~iEuurb*^zaR`Hj@R!X8QKI&4N9c>3fcJ9fM|L+h>vrjd&q+MEp_YI?C*dhW# z3g|}(Id>V|>_{v(M;EQHwOyb0z<=D%C;3X+UzNe7YQ7tuwll7+_1LO#m?Sc*T~-%@-nmWs_NS)&60!TY1UrC6l4-y9`soi3(! zaNS``_nec`W(le_N<`bh!`EMfoRv4}f3_@KxG%Fk8*}iWXMA}x4VWvt7GZk!JdH+> zREP&0;o9+?fg^S(Fb3w9+r9>#($1mD%Il?)d-UBr_!gM%qoGD1G6?r@s*n#<&B z2s43UXFnQh$*krve0JQbb9>$wexv5h(0TX9-ErrVU*x*d<+gE_zxczu?H@--_O2Ks z^Z=q60g^l(lUHAJI~h* zQ<&N`a3h;tYo)O>^6;l7to?Mblb^p)?^-)L{VJf2koaPeaM;=B5V= z(gE9Xh;Q^UFk)3B!*_V(kIe+cxDw$qW>erH3zScV@4b(~+!4stxh3O?I^~r?yVIn( z5|4a4-E8NZ)6q6I9S`QF;2|3uoyv8!!%(u9yJFX+npL0|RpY*IzheIo!z)BzFA={O zC1%8aN3dwWC>TbECI%+fV)oYEtm>YMnl$^;07|{|vi9a5SbLrvg63Fc8Rn*@u6<&^ zido~5R)VFGiR);Evy;^Z3~gaZ%Vs}$Ra+>x4JdFMgf*87r%t4^vta+TjH?+Yc>6XSCK1?4kyi2wiq literal 0 HcmV?d00001 diff --git a/thumbs/deadwood_016.png.import b/thumbs/deadwood_016.png.import new file mode 100644 index 0000000..557cec2 --- /dev/null +++ b/thumbs/deadwood_016.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://db4vsy75vwufd" +path="res://.godot/imported/deadwood_016.png-33fdc1dc42e562482ef59569b7b2bafb.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/deadwood_016.png" +dest_files=["res://.godot/imported/deadwood_016.png-33fdc1dc42e562482ef59569b7b2bafb.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/deadwood_023.png b/thumbs/deadwood_023.png new file mode 100644 index 0000000000000000000000000000000000000000..6a462f9af40b952031066244c3440c632ed5af67 GIT binary patch literal 1432 zcmcJP`#;lr0LDLGYm~`|w$x~+3!Ow0F{~w**wNXv6f&|G%F87ya>-=E>Ee`FwiZd0 zj+Vo0i+k^W*Spd_lVC#dbiOalO?lDzi>rj^c(hEmK^*L2A~83}z+!Nv_` zv5|Z`T3W^Hs@O(S$$Ukki2Is5kbk|=I@Z%9p{DBLFv_&|sbNFIRP;kMqIj!qM6Xfb zC-oRZ088g+KW5oD>Q3#Y+)SiLHPew1PotspLeLokCbxkTC>9>!Q3}WQ>6sk+Z)cWq zZMX#@BiADsSQ46&+-FVo=urGyT6;&okIk&Zw{naBV(B32UdDJIqq;8c={Kt%;|RySZXmnH4r(%XG}U@p4|>&5pF^0gCyDBP=EIA- zl>6;^Vh$@dVjCcW%#jcR#XONqxhY5|4jwl!x1lU`R zYmW9GeU@x2QSmY#{w~#RtafAj6J2!n?Q>}hd!t}YvUxZ_8>c4Sd!(>x_n+#jc1dab zdh>jc`V^P{>FA-^Fvp z$Dz9W9ERmNua+zX!UiIZiK9bWU%kF!y{S?o}39&aSX z%4I?;)RJ!>Vg;=pbUm%n+^Y9;xDk0Gns?-on47I`{#;qHFqzZsDk`BZL>Bs=qk>LC zt15>HKv-Fq-#zjU6e8oQCj1RDw8dWYJ5AkS+9O9pX^sk~w;y#2l7XXceZ#hI4nH2z<*!;D-XBCC$r zE7K;XV^>T_Q|07NKI;XW`NK(@GV5=)sc;Yr=T)Nsa9^<2D(tT}umEMW6`55fmi zbc;d#9u=?7zmvegY^h1eVk{%ofy!xpL9kK30{^jfVI4v8OETaE76m?T_1R`MNHe+v z^Xq&Ur7>Vwrivwq^M=!Q^u0_t4#gt;PpJ7W#&lr08E!sdP8`34T0rt4d)InKoc$M_ C@`Z8$ literal 0 HcmV?d00001 diff --git a/thumbs/deadwood_023.png.import b/thumbs/deadwood_023.png.import new file mode 100644 index 0000000..0db8945 --- /dev/null +++ b/thumbs/deadwood_023.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://ee1xpayr4wed" +path="res://.godot/imported/deadwood_023.png-6e382e9b2f5daa1d46d7d80382677ccb.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/deadwood_023.png" +dest_files=["res://.godot/imported/deadwood_023.png-6e382e9b2f5daa1d46d7d80382677ccb.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/decal_001.png b/thumbs/decal_001.png new file mode 100644 index 0000000000000000000000000000000000000000..4d75b55ac8474e217e8c0529db497466683c3467 GIT binary patch literal 868 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-HD>V3zZAaSW-L z^Y-r9(pwH94iDYC986QhZY~v2NIiC;x2i#H4y&9i$KP9S9(St4WjqhgF_!n2GQ0Wb z&)46!Jh%JP>lv!^m>Sd>Dh8O?9>wrDr-}P%1Pg{-et=L62ae`Campg4fd+Xop8&)m* zlCSPe7R;=#UuTo2{8pd;XHRz4Md1Z&f4QuXfBma$dF}U|9V?bGZ@tQRB2>UmY? z&ny}9ynmm*E25ATq1zB6_da&9oqpZtI~Q~tni9V<6qR!9-1l;Vy2JI2J&S9qb2;>x z6|T1!upWF6QsKz6`ZlZ2T0RA(MK#(=vbV~4u7AGm(O$^$YhARrKEFb_F{hfsi>lcD zW=VS`3>aQb&6k(ptJL~Z|2qGFu6f_<>UG>qLJsTfINSEUynL_RRwC}5Vu9Cx@%Qy?m8xXZUvZ%-O(f!{F)a=d#Wzp$PyD&{rG) literal 0 HcmV?d00001 diff --git a/thumbs/decal_001.png.import b/thumbs/decal_001.png.import new file mode 100644 index 0000000..18f0e3e --- /dev/null +++ b/thumbs/decal_001.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c7lew1osrqr5r" +path="res://.godot/imported/decal_001.png-6162f15b97ebbaca81cb7f1dd267744d.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/decal_001.png" +dest_files=["res://.godot/imported/decal_001.png-6162f15b97ebbaca81cb7f1dd267744d.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/decal_002.png b/thumbs/decal_002.png new file mode 100644 index 0000000000000000000000000000000000000000..68a4b05f3b8e09cc2c9c77c44356045015f786f2 GIT binary patch literal 1062 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-HD>V1D4~;uumf z=j~lzzuOKBM?bpHEjIDJab%iMm@OM?Sj*%Ia~Lcd3EoO@5Zecem$#VKcdU(;Kw*2nBj>CgXO?89XN|`7wqMp z8px1;CYSlyw#McZ`I8T`|J`uh^uFT!KCw~;_LKkaEKqM>|0Da~)BW*xw%rfkelxNE z?SI}a;U$F&%q#ouPY-5r`1HC|{r6KYSB7V5hi*PN9@hNt=V$W*vkayidOG4+(hmB0 z%na}3=4sX6y*PEQY}(X)-_){%8`i7eYqQujt7>a}*agNJuQ?bl$eU>Izhs`6ckkQx zJM;hY>NQ+o+uO6V^Md{PYdq`v6+0Ntl(zgk&@a4=SHA!7ZH5|~$l0HMM(p8Ih&PD! zn<(>hdqPxr;e%RRwdagiaxbh6=sWGnVCUa?o9pcjE$#(7s@M-%SiUxx%<(tT_&(p$ zA6nJv%9gVZ`Yfv1Exx_k(sTaC<0i~qnLjbhu{oPlkM|Qe$=^f^K{X##tBD-cT}YQ zJmj-zskYsh#_fB4xJ;PK`)1dH=^Rys(tCHvK6zCa8ppzLX8w(T8(#jImY^nh$>i+* zR|a>de^g^g_?ge#9h@(^Ywoo>+4t=29{>Be^HS}KN#TqPkt}**9e4e>@A_%q_Sn4M zihs}3ScYl63+!{0d@sK_CG)<{%-}Icn#{xVN4@_=6d5@e1?_*iuV*_W!_Axt%Wj@u z`G(=GQB&UX*2@pS*X(|GxmNP|d$x6_dKND|c$_pS@P0SYBB zGfcbAdf@lewZH#lHAON{+4#EYkxzlumD)O4$MXzfH+>jhbj7>sGHvMUwvGL|n)8>~ p29M@_cI)efG~)f~mpOL+@86Yqn*ZZx4`9Y;@O1TaS?83{1OS9%$)ErL literal 0 HcmV?d00001 diff --git a/thumbs/decal_002.png.import b/thumbs/decal_002.png.import new file mode 100644 index 0000000..840f2c9 --- /dev/null +++ b/thumbs/decal_002.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://xqi68v0ratl5" +path="res://.godot/imported/decal_002.png-b96fc226722ef0bdd1963fa42a78e2c5.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/decal_002.png" +dest_files=["res://.godot/imported/decal_002.png-b96fc226722ef0bdd1963fa42a78e2c5.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/decal_003.png b/thumbs/decal_003.png new file mode 100644 index 0000000000000000000000000000000000000000..54f96827b6a401f0981e84544ace500cd2295228 GIT binary patch literal 517 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-D%z_j|fHhE&XX zd&k!6NPvXHMHjZ1?%ui865)@dVtTVT7j+r@n!q#T)yn7dv|PK`??0Vrzsb(Vu2v`U z?%6npXIcy~j1RaN!Wnij9S~($$56o9piOzQuX5NdtZ{I&Z{+;@|lzE|lqkmZZ znJC62d0_3s{wV@GvK!{}{6A4yFDu$$bVYdvgVaAewT3rvra+4;d?=k`4cuX>YNrkXv$Km tzJPg$l=FoN`#VlfFQa}4;0oYahA??0P3yqAR$#m`c)I$ztaD0e0swjHsi^<} literal 0 HcmV?d00001 diff --git a/thumbs/decal_003.png.import b/thumbs/decal_003.png.import new file mode 100644 index 0000000..c0d2a8b --- /dev/null +++ b/thumbs/decal_003.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://pecgxgai7fs1" +path="res://.godot/imported/decal_003.png-20e90f039ee23ad30ea27b780e1a5b84.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/decal_003.png" +dest_files=["res://.godot/imported/decal_003.png-20e90f039ee23ad30ea27b780e1a5b84.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/decal_004.png b/thumbs/decal_004.png new file mode 100644 index 0000000000000000000000000000000000000000..5ac3a01a25acf807a994f60ed0f33ef688fa7a7c GIT binary patch literal 623 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-HD>VAAw-aSW-L z^Y)H)o>ZVj!$t3u&aF#4pW7bDis%kc&ObXf_=bu@&iMyQ5#MX(yD*w}m>R?x_Aor4iO{{fYt0|jfBo^{&-vothrh8! zf7*NN%)j!F?|J_jNglewaE<4`iJ;SS2K89(v^J)Ki;oW*vnn#kFHztCxlDoqsONlg z?xDnlSEmmw-Q~`(mf^kW?}Fl|Ttl7e0p^ITXAk=u znImrfPM7~DVbRdUxaIqPH>Qjq^^X}${(RP8Fus4`XV&F<-9ImLUu4^Ty7KLx;R4Zw z%^!AI{4rEuNY+snSjU^4M^aSW-L z^Y)H+p0J~c!^QNLBT+L9lKD4CU7K{ZWo@bmTc7Ib%=!%hJ+JN?yLLt{#|+`AME@>?8CEb0b#)m?(^oy?GWHfXclo~oU_m+fMLhe{>Etk@2B4F za}|ETq$py<@b%38R-S}s-#EhNGvzQC`!-2xG+ZtJw0D|4tBiKj_ZgfMa#;(GzBA@$2a~nm2K{Kka)X2>Yvz$+8rLSb6uW zeP#O7PDhpkE7o_N385|w#;yf?!UxX$JVB++2aSW-L z^Y-q>T%|w}hl~BfSvOORzc;L2C>H)W_v}Pjg)MAs8#rw)*?&(t=T`N7|3@B=oPU36 z|4Ag;uB~N^3}<}6#SqT0gXw@M!#ain)&^~c7#a!n@jrO`wRX?med}u_S3hL72y(u0 z!d{{<`+@%NxB77>t8OubYe+ZpKG=PDt}T;UgUkfRGj*%#n|Kud7c!Ro@-Jk3A|iS~ zd3pV}?~EY~JCCqj*jq0tcwp&5{o&G9boog{P2R|-&ds*d=KvZZk+zN?AL$c z8^;e6d-u0)=C9|eVXje~^G%htz^!{hG{ZVx8U`m?Z27a)2RW}SwwDH`5C%_IKbLh* G2~7Z*Ti#Lt literal 0 HcmV?d00001 diff --git a/thumbs/decal_006.png.import b/thumbs/decal_006.png.import new file mode 100644 index 0000000..2e27048 --- /dev/null +++ b/thumbs/decal_006.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b5vb3tdhktjcs" +path="res://.godot/imported/decal_006.png-14c41b129eb81c7a8b621c0fe9925278.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/decal_006.png" +dest_files=["res://.godot/imported/decal_006.png-14c41b129eb81c7a8b621c0fe9925278.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/decal_007.png b/thumbs/decal_007.png new file mode 100644 index 0000000000000000000000000000000000000000..1d2c6bdc2ef22d11c29b98e1e19851a977412c34 GIT binary patch literal 618 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-HD>U{djPaSW-L z^Y)JKIw401hl~8lhoa_K6!UMAy7nlmB)e}Ovs~MU??#( zfAW8GWVY?RXxg5F}E=aNT2iPaabtl8egM>|>hIIKA#-rM<|#{Xn?i|X)wGkwBiP|V>x_nZGlMwyq29~fm;3W^-yG;DgxT=6B%zdPY) z=z*Q?Y!MNf1&lI(GdWhfZ}_A7K&HBwn%*g_2ls|aN z+f}Jy=KlVKrw8XZGR@f8^FVhs|398T1}}CvSG+#W-E7ayK7sj_&;)NJpV2C;(V}uc ZgJyBW<^Fi?7GUCG@O1TaS?83{1ONwe?PLG| literal 0 HcmV?d00001 diff --git a/thumbs/decal_007.png.import b/thumbs/decal_007.png.import new file mode 100644 index 0000000..ab9fa1f --- /dev/null +++ b/thumbs/decal_007.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bcjttf21fewn1" +path="res://.godot/imported/decal_007.png-af55afefddea6b5521a4c369f42af69a.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/decal_007.png" +dest_files=["res://.godot/imported/decal_007.png-af55afefddea6b5521a4c369f42af69a.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/decal_008.png b/thumbs/decal_008.png new file mode 100644 index 0000000000000000000000000000000000000000..534e068837cfec149b964c18dbc883ce9c59af5b GIT binary patch literal 607 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-HD>V3PE7aSW-L z^Y*S`-XRAG)`!nEgwj1H>y>->9gZxTHAgozD1ar5Ejc)%()hAtYUcjGTg?=fO~1Z< zzQnfWd-V@|^JVzJ!r)I=;(g_N?i-8OpMT$dUH;PjS*rNI3x2MfdcZ=Mg<##-NdZT|kl z(m4zdZU0#Evp=|%q_3DUS7wxF|DJSTNYh?OP+oP`G6MTB!!zaQ=i@ zmFo+qh`Ck0!0oOHp8qpJgDTcw*)z4*}Q$iB}H$Bo; literal 0 HcmV?d00001 diff --git a/thumbs/decal_008.png.import b/thumbs/decal_008.png.import new file mode 100644 index 0000000..9e43199 --- /dev/null +++ b/thumbs/decal_008.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://kl1dc8qqllob" +path="res://.godot/imported/decal_008.png-fe6b54c54a37c254357269c55e6b00f1.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/decal_008.png" +dest_files=["res://.godot/imported/decal_008.png-fe6b54c54a37c254357269c55e6b00f1.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/decal_009.png b/thumbs/decal_009.png new file mode 100644 index 0000000000000000000000000000000000000000..6394f5c8d052d3855ce07e3779d918c5d63461d7 GIT binary patch literal 628 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-HD>VAAt+aSW-L z^Y*Tz-=P2zw}< zj48C4b1J`Y;iLFtG15`*xery_9It=Cw!?Ah*#rjh5Xn6L7=|SeziCJw@PBu4i-Q;2 z2kBLN1WXz@Z@u(iz$n0ew~5Cgo$W*GF3}B)0ql0|ya`=0&5Q@8{&5SK#N#>5?y1uJ zKZ04zA(fw>>Y6uz69b-5O%m@T5>MB+#xQI>hRsw*aHhc81IywgQYQf44J5DU>pQ zcy@nj4#Vy5zT0{)-?4hSxJj?sW{YYq%K1a^&*-2BsN{`D*y24~ST@ zl`uRx*nfdh#jSzA;T(gWLM|(F#*Me;9RfTFj$Z|M7F?Ea+$!Pq&!OelPR0j34Cff= bLfA3#cDYNOV_stmOhyczu6{1-oD!MV9xP$aSW-L z^Y-rTJfT2_)`wd=^^g$gS_I8OTV z@bdI|eJ_e~n15`JdZQ=N7ndS>pzQ08-2zJw^LzJPy1MoH3)h?M1rmQ1JREoJ`giN} zM;_m4j5*=lqIr+28!t+y2p%xIJAXQhXJGjC`+Bt&i-nH;+T6T-|LW!6e&z1Vs&eKD zUCgy0v&6HjYu3G*^|k+YKK=e(@X+T^j*~<#ZSK3XWhHjzCMfF z(W;&&^T(^pXC)S=$@cxd!zKxIQH0g}<6jE@@6=mtzB7fR_waG&UCk2lQUMGvUq*w*C{fU#=vOnC4e)+km zZb!cU%Zl);?cHnvGJ6UuJU4Uq+~&<~nZxSMl{^M6%g=G;9y6$MVvyaV)?(PJpZY22!_C%Ti+`@#$U9%)0O#zdhcA9S zZUt1Jd+jv4Z(LkcmdUq|s!S^)?a!)uKK#&ByhhYuOS*2pBSUp&#ma|U=luP8GuQ60 z`Zq?A_UTIm%HAulI8|74(xTzjhajnVuY9$MpJeSe@;vzQ!+IzG{0P(vl;qdm;Rt?)8E?psT>c7^x!WzxX41K)%D^2#j{@@wLI7ccjkZbbYAMXyU-(-b q(f`CJo`!duY?v2V(U`q3JaSW-L z^Y*T<-(dp*hlh-XGgA)sDSs?p;`IKh47*sulxdUHM3U6r*UnxLwp8r%tB4H`R_)$f z&6^mzJ+9%F5rYMDgYiHTw@VmO?YG1o+F$;3e{Zt)eEAE^Ij%4F8ifA9SM{q7g< zcQ+q5iND35w2yC3{R^qJD(kN>UTN%iE)b7U`>MEM4-dQG4rZO{Rt>K#S~&9Ai|=lU zJD_^%^TQ3NKUZ^nEu1_37mtA8Mf<+C{~t^DzS?tz(c;DFrF;o{u1X(1zl8h1!vE_` z7;EHynAv^V%D*9#NkabHwyc^7v8UDQ_&>~kC2(!u)h!ZrE}s}q<#qg9c~*Df8@I-o z4Q*k~>x0+>bU72(W@IS@zrR}bL$LE4L+~@6k}QQ(bD5e&{qdhCzy49{XB%Jkwq1VX zM22I1?3T|b->@&eZ&$C?v+{lMJF9ft>{~~4A57VQ@742pjIXTz-F~q8Nl0N*}05cdKeE#GRzqu;*RvIhZ~Rg=L-h{lOKbptDnm{r-UW|P;vz~ literal 0 HcmV?d00001 diff --git a/thumbs/decal_011.png.import b/thumbs/decal_011.png.import new file mode 100644 index 0000000..59d0df4 --- /dev/null +++ b/thumbs/decal_011.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://vx21uyfes5b5" +path="res://.godot/imported/decal_011.png-70022216753cd8167957d8ff9a091d58.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/decal_011.png" +dest_files=["res://.godot/imported/decal_011.png-70022216753cd8167957d8ff9a091d58.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/decal_012.png b/thumbs/decal_012.png new file mode 100644 index 0000000000000000000000000000000000000000..11012bf19b0fe0f0935aed575107bc002052639d GIT binary patch literal 561 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-D%zUwgVZhE&XX zd)K;1%2CAO;>56IL5<7Pa&$Q}6PwGD-EXi=`6}sXTzsChbJwf8d2)i~{Qds>)i=F! zmv7j}BB0)2!FYsI!H=PksYBRd4#Ok53yIB$=U?2vVFts#2Npl>o^L;>9_hy*Us82@ zyTK1-#y!d2+yBn7u9v&}jMc($|C;)hzjYXW{

    z4dJRzxqv#bMAe6^q{|paZ3Jg z%V`I8`0i&oy7b*$PGd*=5)$xj3?wXq+F ua4v5sj%SaVF0SzISsiOZEM3FwFXJ?OuP@WhMYDiufWgz%&t;ucLK6U8g3R~; literal 0 HcmV?d00001 diff --git a/thumbs/decal_012.png.import b/thumbs/decal_012.png.import new file mode 100644 index 0000000..73c18ee --- /dev/null +++ b/thumbs/decal_012.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dut423cqtpll6" +path="res://.godot/imported/decal_012.png-69b42c3efe2a8b1f7c51f880f0fbbaaa.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/decal_012.png" +dest_files=["res://.godot/imported/decal_012.png-69b42c3efe2a8b1f7c51f880f0fbbaaa.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/decal_013.png b/thumbs/decal_013.png new file mode 100644 index 0000000000000000000000000000000000000000..50f7f10d785bce0bfd8256543f75cc410ef9c22f GIT binary patch literal 540 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-D%zuX(yShE&XX zdv~Mn;Q$ebz{4ggtg_0DMnWxnd2TzjPFdn`L&Wc&ZF-ab-qp{q|IGXTHV8M8VQ^Aj+kf}r1VGdn{c9bxD{(bzK|BV>EhRX}z&o7tW_rxlN>4)T= zh4ZED7@Ggzoh$FYjdv&Gv&E0!t#9K_u&eX=E&lr7`ZlfuAEp;GAK~4~7?Ib(@XXx( zev}qzyHDQN4XW1Y8{%@bxuw(XphClrbkJ>mA>Pp$yn7S~mdCt)zoyPowXH7Ct z^Jd0nC&eO?S1^2QpUWX8rPYurbTA00?V%aNX%2mdKI;Vst0F*VrlmGw# literal 0 HcmV?d00001 diff --git a/thumbs/decal_013.png.import b/thumbs/decal_013.png.import new file mode 100644 index 0000000..5b81eff --- /dev/null +++ b/thumbs/decal_013.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://l8a5euv86nnp" +path="res://.godot/imported/decal_013.png-6aafbb5ecdd96f653be3cab886f866e9.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/decal_013.png" +dest_files=["res://.godot/imported/decal_013.png-6aafbb5ecdd96f653be3cab886f866e9.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/decal_014.png b/thumbs/decal_014.png new file mode 100644 index 0000000000000000000000000000000000000000..2326e96766e85c4bbc1a5e0024708d610ca8cfd9 GIT binary patch literal 725 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-HD>VCwgDaSW-L z^Y*TzU$cXR!^4#yjW!fKpPJJj@-?nN=I#_DCAX;TpY`{C3oTacP~J0BG4GD4|9N@W z2>xt-hu2077R(LC15Vs7VYplUfBp0PgL&EiEjCrZ_Wph8&&xgUa(NO@ZZ*0c!;l>% z6|XY;9@CfICfWx!=%mk1yx7XG@M)9P_jLl5dx{_BGcLE;ef?wF_4xHGYcsum{`mFb z^?6B~b+!#lZ~c9##$NfOx$OR&<00q&yxVHuZ@I~Yaf;CQWq!v)`i)=BVE?$i!RXwt z6{`>AEA^YZGJNHcN(*^1+v+J-f%4ZPsh`XKiDVqfxXdC@t3Ovt>Bpx@5(R%2{^y(U zcH#NXf7UI03Y%Z>*9qitzv%n;?PPXJ#gC;dJPT}1%)1v@e|z3veL~{B+V+NbH>Q8P zpko#0^|Ne_${j9)(vxdu&9nZ#_v^-Q7tXA+n7&3vGQC!}hQWJVOO@LHl6R9LR&7nZ7JN_q5^I6}-{^dAx!kE6(}3xe!PC{xWt~$(698+K62<@k literal 0 HcmV?d00001 diff --git a/thumbs/decal_014.png.import b/thumbs/decal_014.png.import new file mode 100644 index 0000000..f5b374e --- /dev/null +++ b/thumbs/decal_014.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c28q30s5tbmpy" +path="res://.godot/imported/decal_014.png-333e47df5bfe4bf93289f00a529f89fc.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/decal_014.png" +dest_files=["res://.godot/imported/decal_014.png-333e47df5bfe4bf93289f00a529f89fc.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/door_001.png b/thumbs/door_001.png new file mode 100644 index 0000000000000000000000000000000000000000..0e5bf19191e3174849707180f14c8b2211335625 GIT binary patch literal 1216 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-HD>V5#zSaSW-L z^Y-rkY~e(i;~&p=-tcr;>y*1>ZSxBy3yYG1iw7MS{+q#aaOMA2zhCh$f&}M8>4XG2 zvdg{-DO}xj>(UqYCwi@A0)-vUwR+R5=RLV(WE zjaz(Qsu@@9=VYj4a+t?3L7m~rU|`C=`OZ{z^+~Vc^S}Pj>b_Q})`^OI-QQdN?MGTo zb=5m%h6hg`2@6}t}p8ox;=gNuWLSKt=!)I(jks%hh?2i^KriD@BMvK9^L-i#=tP&u0HqI zjmvWqK73<$Oe~d7-1>9s&r?+`Q@?VUE?BR17ER*5dV1n(gfMx`sEBhdK{(<>V3=f zMRv0%rhn*_*u)lpZv_*>J)Il!ioXN%7#YqAGW70dWau$%G}yz=!T9E3I}L2m|G2i{?t6w6OWNlDW0)Xg^Wgl4#wG>>Nse!fS7ijeu5E63Ca^E^`OgDV zdsbiV<;WCbx^VOk$E*5NO$G)9Cw}g_m{yd*s5RBAJCsEu-{pV)PwScm4GccQ*SHNb3m zL5lG~+lJeh#H$?n+W03h7`%1JsM}H9n!qn#vH8J&aYqJ8hRa8OY@F7=omyzc&EN)b9mer5VziH|Et>Bn-9)@!8qfV zrLIWs4~CbT2STr9F6=nW-tn(6!&;K%++79JKYRG^Es;HN@lDOvr+ooa9x^jsFcNQ4 x;+4PPs!)52@q{qLCzb{qMg@NcdN6;pzx&X$Eh_ME4X{XJ@O1TaS?83{1OQBo4+;PP literal 0 HcmV?d00001 diff --git a/thumbs/door_001.png.import b/thumbs/door_001.png.import new file mode 100644 index 0000000..0d87297 --- /dev/null +++ b/thumbs/door_001.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://tr06b7hh5j2y" +path="res://.godot/imported/door_001.png-b40a1a9e719ddeeeea831462319e52bd.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/door_001.png" +dest_files=["res://.godot/imported/door_001.png-b40a1a9e719ddeeeea831462319e52bd.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/door_002.png b/thumbs/door_002.png new file mode 100644 index 0000000000000000000000000000000000000000..73df013f5da5083f90617a0e39d5652ae7dac0c1 GIT binary patch literal 1217 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-HD>V5#GTn+R?c7s66NN2&J---I zwumrTvO4%NP6%drG8mYAeZLsmp8h?&`rL2*do^}Xls|f_t^J>S=QsP@#{4PU85owU z`#(6meEq`b_bNV>WgLGxJA^fX|8DByJ+1Ti|9|x7X7JnJJ_2h5Rje9zG=6{mNO#{` zg+j(Xx1TR`pQ+xd7|6(z{lhV{@8D~OCT9I9+YO8>nH>6^@0|{x+*yC>&syxX1%gk)tf zF#i=zT^w}SZK>F<|Bs&w+12Si{P^i<-M%{$KmKzH*cf%ZB-`|apUHonsQVS43(Fj| zokCcQg_AWR1poZ{%+Fv@p2nq}y|hv0v_i#BR)({=3)WtgY2iGeVRf&unQLLZcDAaH zeVy^E!yQlGiWR)QcluoKwS7@*t^}?r+1C2zNJPeiqh4nv+jdm$X1X!&ZfwSSCfVL~ z58ZidMYIo{isCFzUv_J|{@riiTMPsl8P0M@EmY3E_t2Z;+r51DgwMKdM_3YU_HGu~ zvAp=l%|h*#EEkT)zh#`*7Ea#B(-7mr(5A1bqQ|gU*y;O2e|EM#l7dbjDtB+(C1-bg z{%l?zyMn^Z(!D$k5mjHR&d;y6uc#K1NdLIc((}zfzWlK4YZs(v$l2ffXL#xFp1ZM} z9DMfX)~$Emg#5UAjra2`*_Z;ESx43}Y+GKw&c#kl=3m;8qpIO5de3BYPM`JLW>?g2 z_J8S>uRHYL*D0tnN;LB<{Qh9^)BQ89r{3BhAI{KxS({10u0^?>-!lID+v8=|-|l$$ z{QBueR>jA6KQxN4CA=|f*}+iuWnDSX{pG3mr`=-csoTcN@Z($U?T(38+J<(oGYT?7}Dw#hRUUDULNAotk6HP4L`)1Fb%~Klo|1Mw1 zf8fT+Z4rWXhK4*pr}uV8zaeGBWC pC%42dnbbIFGuW=Bceeb;yfU_NN$-i7OMzt)gQu&X%Q~loCICW83gQ3& literal 0 HcmV?d00001 diff --git a/thumbs/door_002.png.import b/thumbs/door_002.png.import new file mode 100644 index 0000000..4177627 --- /dev/null +++ b/thumbs/door_002.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bwud8kkshrkff" +path="res://.godot/imported/door_002.png-902a396b8b34fb733dfd1ed0ecbce24f.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/door_002.png" +dest_files=["res://.godot/imported/door_002.png-902a396b8b34fb733dfd1ed0ecbce24f.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/door_003.png b/thumbs/door_003.png new file mode 100644 index 0000000000000000000000000000000000000000..6b0ca0e0fac63c38cdeec78b22a7dea844176d55 GIT binary patch literal 1323 zcmd5+`!^eQ6#s_2=9QrJYF0sKTM3St_aaEEu_M%~PS+BvXOJ+oSdb8^l%q4oHeFC^ zY~@s|V;sk9Sa=*fIjIA zF;t_hcSOQ9QGowyR3nh|&;UQsK89Hb0J=gV`ku?Glg$fL#4%uKi*mBbs%gvmgjrZ; zpbXa84-0x~*jR@~cpgH@{#7MvEie~wGc55g0Zb1_x50lgE>`2Yp3zBZ<@03)Y zAiv=pi2GDE(pJ`=2sQ&8hko8u;~IIX^hVL)+0O+FdEVUv36VJI(V}WVZ+B?GtCxq< z)Qgu@-MrLIWYR`3qFlL@+IQP$V0GH-i!8xNysR9{Y(X$vY7TZ34*LoRxX*s0Pc+Yd z>7r;mPh}ucPzZcWM()c<)4Pm_oZZdc=)CROI2;RW?3+tB-suslX2cA+m?09g^vue` zB>-fJKhxmBX6D2n(!s%SDTeI&IOw<53)x5jFV2q{5fo&fLE?$gi?dYv<0l?cW_k6v zjQ@L-Oi%u{tNh#85rLnJ%^QI~cSgc?6Ph<%zTl-@+bo2G5DwEiXT#@`i|zbcS;yD- z_|vtM(}hd)#erF}io3fwzs{Y2o`eDHF$lVN!MwQ0mwk4uC}gTO1e0l(ldR=*U*Dgq zSzEuXG1jACKfszB!Gh~!uGUBIQXZZzi-90JVSeiX8hhMC4@x**7*FQvjW=j!2g>Guv6Iq^0>ZqnxW@^!S3&Q>Q3!7REIl=aRa zVC)p}pNKFM!Xx2y^F;5qIT9?4e=^?E{(N0P(Up$AN8T=r;K3OPODq7(Hek{U)8%Y{ zCum_4aM@iqRm(#~3$-f mLGcKuzDs^Xh5yHA|BAUGD19n=y@%I)KR`M~Cbs)U75oeA3O*YE literal 0 HcmV?d00001 diff --git a/thumbs/door_003.png.import b/thumbs/door_003.png.import new file mode 100644 index 0000000..1632acd --- /dev/null +++ b/thumbs/door_003.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cqk4exg0hksc1" +path="res://.godot/imported/door_003.png-ae12d8e770739b27b6e7a23b1174af61.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/door_003.png" +dest_files=["res://.godot/imported/door_003.png-ae12d8e770739b27b6e7a23b1174af61.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/dune_010.png b/thumbs/dune_010.png new file mode 100644 index 0000000000000000000000000000000000000000..7e09184dc6fdf44ddda6d37b697cc9928d663b7f GIT binary patch literal 2769 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 E7kRkVX8-^I literal 0 HcmV?d00001 diff --git a/thumbs/fence_002.png.import b/thumbs/fence_002.png.import new file mode 100644 index 0000000..56edb13 --- /dev/null +++ b/thumbs/fence_002.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://42jlkxottfgg" +path="res://.godot/imported/fence_002.png-a432336c73af686d500561f6cb63f8bb.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/fence_002.png" +dest_files=["res://.godot/imported/fence_002.png-a432336c73af686d500561f6cb63f8bb.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/fighter_jet_001.png b/thumbs/fighter_jet_001.png new file mode 100644 index 0000000000000000000000000000000000000000..af43bd5e3979351d13f0e72de2cfd3add5788e45 GIT binary patch literal 1369 zcmc(f2~!ei0ERyf4No-5qfj9n^H>92GmkPzOKlu9Ty1k_FmqQl+M=|yBqO!M3!TcP z91E*4wn)^}z``UL#k^ft#mq&+qs9t60zA-lXZAld^IkvTohLt<9A;s<)f50=5fL6r z*=W{(Mi_6TEI6@qqabONu>C;LgZ>17kxfJ>>8H$!FJmpIxBZ5e&-IRt1P8g3Z?pb# zW2q?luCX|hk>eGJiLt`LDrASE;AJhLwssDWdDHTyDEh~Th;rv|dF9URTmEfruV?Nj zF+MAL)V@!?tT3sRSfOB2zVw9aGftV+^xXM7pB#0?3~knq=`qP&%~3xL?_ zvMj!7w|iARUjDv2O6ZK=a$o4I!^9c6r?feWFHVOQ0HIKM3Mv84^vf=ON71)*}q$ zPUZGcMdtiAv^>CH7lx448kkueTFJ;12hFS@A+dfC=KNHM%Pn_BU*+K%9Ac}&u#f>* zjaVrm&%0YmUmqk4c`wFU5f^TH-_!OVm4pXgnm6O(Zj;y;TL@FDp%*VuLq=~0ed`A(W&U>-HdqqS6Nwl z+Kk>ak3?vIbWJ@jjdUHqU?LKj(Y=aHtl*CW^nDm#Y^1$Z7Xw(*O@=N#?j6R;3_Nf^?$v^%*jVae`Q zP|%-od_+#=UVU-3*Xn9#O?z^E=ITf5j9oZpe{5XIqG z`$FNaEE99T!dAh8oY4+5c)Wb$!dL-FxCgi=@cQu~?laj)}- zf+^$Y*)Z?DXA|x|Fc}{}I#tH;CrWk{0v2V^$>Ad2V*O;uInz?U-O9SP3-5cw;C~>k ZZL)QHTE8Q-O0~gC5OIJUD%gK4=U*pPQnvsA literal 0 HcmV?d00001 diff --git a/thumbs/fighter_jet_001.png.import b/thumbs/fighter_jet_001.png.import new file mode 100644 index 0000000..a386533 --- /dev/null +++ b/thumbs/fighter_jet_001.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c1chndfgaoj8o" +path="res://.godot/imported/fighter_jet_001.png-9e81f8cdafc349e9361101c7f8b80f44.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/fighter_jet_001.png" +dest_files=["res://.godot/imported/fighter_jet_001.png-9e81f8cdafc349e9361101c7f8b80f44.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/fighter_jet_002.png b/thumbs/fighter_jet_002.png new file mode 100644 index 0000000000000000000000000000000000000000..9a520dfc9fae2d6c10deaff887abc5078fa1014b GIT binary patch literal 1416 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 U&705l_KpPL=-_JKWQR=uAKl6DL;wH) literal 0 HcmV?d00001 diff --git a/thumbs/fighter_jet_004.png.import b/thumbs/fighter_jet_004.png.import new file mode 100644 index 0000000..14d50d9 --- /dev/null +++ b/thumbs/fighter_jet_004.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dj2kl8dhnogl" +path="res://.godot/imported/fighter_jet_004.png-aa28fed20712e015ec9f061d039a82e2.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/fighter_jet_004.png" +dest_files=["res://.godot/imported/fighter_jet_004.png-aa28fed20712e015ec9f061d039a82e2.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/flashlight_001.png b/thumbs/flashlight_001.png new file mode 100644 index 0000000000000000000000000000000000000000..49ec57f07dfd211fd3fbdc215a91671103fff923 GIT binary patch literal 998 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-HD>U|!(q;uumf z=j~l@f8juewuj}*Bs`Lvq!%yi&=l$Vn+we-YTZv3p{zbF;hBZ-%zblAD^_zrXR{b%f2J_P5y1 z&O)uJT>a0UEB{`#Rm*?AeYefG$G@buW=;LgFMq`JNrZ}7!=W=e3`^ff|Ka$pWPj6q zU2I}@vGFGT`SX*qKTDS{e_v9&rqC;gfuXqg`>oqYlQzn-I&8@QuP@K;q08KO>h@v( z`Dgxp{JnUw^4qslr<&W;{P_~k|8oBY;qMH)QWGnu-nntqR(;#n{P^?2ar^4H|JY7b z@%$pRA$nuPpQro&m3+yRklg8#7n3YGfiuBk_QDXo_mTI-r-fUV|6|&)Sx77`&3eC& zNhiav%bG=#r>_iIZIf~D+1KU4b0nl5L_AYiAGfE&=3j-`;YXK(WSrkxbuyTF-DbG6 zr*3QQ*ZJrD4J{4*cE+e(o!nHV-1YMI_8(jJxor*WEfEXZK8?CZJPd#~vxZVgi7 zaeDQpWzu>7K)tDtB+{;*WMQyY-?7xd__SN*Yy+N5-Ct`x_SOBp^!DLVC#{D2oQD_e z-5YponSrr%yW5gMfum$T+g;`N7b~CNIPuFnr)iU^(&USH3uVLpp=-GX{oumRUON4eJ?sLh_kp9Gc&WJYWc@6FmS_ z?Z?39FqfHO%5nzwhEFfc8F&w|S^$#_L%=@45{5@I440-e06B4tG7jA@ewH)5l4-DD zzp!j42T0L^lllDSo_q^@i@6GbY8@u8XY`rGoN;*$6G)Z9ImV93{0|(WersN^t6H#q zyZ$@HBVKk5221~nWXRi2;0ivgdv-t16n=-FlMfwa6ws)*;ox)l^*HeWMol$Jjg09ld{e761(_2HFEPnN3waF0__ib_tkq89ZJ6T-G@yGywoB CKc!Cq literal 0 HcmV?d00001 diff --git a/thumbs/flashlight_001.png.import b/thumbs/flashlight_001.png.import new file mode 100644 index 0000000..3f0542e --- /dev/null +++ b/thumbs/flashlight_001.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dfw2apb7qh6df" +path="res://.godot/imported/flashlight_001.png-9b3c3f286242326d5eddce8c7777380d.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/flashlight_001.png" +dest_files=["res://.godot/imported/flashlight_001.png-9b3c3f286242326d5eddce8c7777380d.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/flashlight_002.png b/thumbs/flashlight_002.png new file mode 100644 index 0000000000000000000000000000000000000000..94f8f26d9ebde792a6810ff057794c2a6f77ea28 GIT binary patch literal 1258 zcmbVM`#0Nn82)_o4Z%t?dPr4O#}?}a#Vix4tZ1Y}QJdDKlwvKBW7I7!-_|bbRD@!3 zC_40_qs{cR+B5_SEh?7wxHYMgQkrHV>RM#!f3WR`_j%6qKIgpWJU_h8MSnkvp@F#p z0Kkyy?HQ z`Nu*<4}XwU^s!S)hGNy#@+dp*VX4S^gA`#)d-l|1;0@``&S~S}QQ3|=r+q}0f`Up2 zD+c*-K@8mTiSu*c>y}E6-F|j`WmIANglrD5+TMS5tIPmQsf}y0)d!A}LcuHLu^I_q zW9j;*zLJ-EK2Pr9;TCS|Z};07I$f@CiX$Yc>nhwke@X3v^k4HIc`iAwo&z~ ztaKEOEL-k!L-$Ct^i>|pB0RMu{~068Z(i21`rLqck5MQ88-6!BEaF+;<}#LD2599` zMN2jK43pzal@Ai9Dln%!Vjgh>LkDXvR;e_hsPJAyHgfN=m^N`AF7 z64VQDV7?wAm@zM`T!bAU2}t+^i-{y6u3!t|42UQpG_rOJzGF?^fzY8zkgy?wA}Lze zN2@=c(rO%(0m_{L6K88wn}e37&0Kw)EcCG;lVnZg9b~$!EW*snuy*q_8^Z4Q&yK!3 zw-yf{_X$Q^kTJaV$fs6UoIv9_z9ULN$NN#LZB9x6c*rUgTJAop2G4mD?w`LKf16!* z#doaO?%D*uY((x!&BP4y7ejr_0h#@Q{YddlH&U#V58t@X+Z+SZ@y+jj&B-JpsxYY5AwV=f9z3={HJ%MvGVtTt~!nnO**GXnZ z1si+=FcB5gLzr>2)xMgZ0KWaq?ChC!zf)HihoM1@G${I1Xh;aSAzgKCCF`9Rk7vHO zCn81=hY4zv&cwBx`0;@SjYjJa2v<#qnW`33!IxlB3=`5{bGw(@(jOFJQLEEi+ES<7 z=hho+7ewCEdcaCBXrg%f0f-+hU?{AC!?-<(fkeTECOwAOV4WM@+`A8QG1>(d1 f-|zm50@y_7;?4FJHBlJa@&Z&ZKhNevkr(~}|1>eg literal 0 HcmV?d00001 diff --git a/thumbs/flashlight_002.png.import b/thumbs/flashlight_002.png.import new file mode 100644 index 0000000..97e944c --- /dev/null +++ b/thumbs/flashlight_002.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://csf16sblar7h2" +path="res://.godot/imported/flashlight_002.png-ca4be632b113a37f341a7c269f1e5694.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/flashlight_002.png" +dest_files=["res://.godot/imported/flashlight_002.png-ca4be632b113a37f341a7c269f1e5694.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/generator_001.png b/thumbs/generator_001.png new file mode 100644 index 0000000000000000000000000000000000000000..454c4c349b0f46e3d41e600edc2f17dbb67ebc15 GIT binary patch literal 1585 zcmd6o`8yPN0LH(gam*}_2{D9mMG=#n8P*+U#N=2!vyAC^$USmS7;_+GYs(`ICF$9a zUB{%%W*vjdwu4j{v5uiIOyj;XvG%XneV)(zetvp?ehcwF9tv;`H~>Jw%hS#8(DZ*J zCv(_6-;;QUf+YKSxPXQMO(6i%OI~iy0hIe+D#m^F12ua)Yf6gDesShTjf7$?6D(gN zo4-d~@ZP%3l8fAop!UQ)Qrv6!D2sCYrkM2+C;zo2_NNg3jwsLS+KJ-@u>gR@;T_{-$ji`L=^1m1n45Tfu#QnbYpeY z@h*O4`{z`P#hb-6B>U}7jXwPgr>f+sDTdR&BCzQls(bB%=I)FZ%sw~v8I!(qpbCX8 zKy8r}lF+l)ADCr*A|91O(;X7^iBqnD8*4pqbBlZ2d7_VYOl72wDD{X&*UqS?Zd}h9 z1iXw?=b9I@tR~*;?=yt+vgJ{71)#F+pl&u*ugv(RP2%FJU0Y7G=Rn^8U%={j)`6b% zh|>*JgH>Oi4_)F;u?-$*Q|jhsGu^|b@uSNecAg5*iBYa9?+PCq`B22^Ok39uqrIr9 zwzfXPI0h220IcQ(I5TG~h$hp~ch?f?|43U8s~{{mFjT=wG((FsUH|P%S0!eg5Ihil zKy;E012!|ex}+u2h=jqTB(~Rb#&bAPuv1ewgdD_-w#s9eKrpWYx$H*;OD8fi@vvMl zjQ5iY;Exv-ZdLx)e(?er{=mgv-k%@X`a#}tjP~A2@-wVsDt0ZQe)@Mk}~JaXV--qgmlRu42W=eGf51SgTh0QwiEe0)CTDkn_)85 z8%tg=cfvqR;GI7{k)^jZgg#3Zw=OsK_3}bCQIpi!HyM`A0%(m?38uf1iFN4EFU}d+ zZLI=a`d^(yL1}Wgrj*#o&x8D@xw0lC=FG!#Tx+7OJeNKYE&6OJ(t9}*xuT_259sr6 zS-pFyt-F;PGM<37$*(=Ac%eKoM>?kBVrm*ij%JK#oU1oacg$-{FjZ}#E=z>1oiu$| zDRAm{bvD;Jst`X~Q~b&3ZmtXK9w8-H5dN$29oOm{EGPCJm>yD|C~(tbmEGVAK2UPd`Jj0lBi&?S zA2l#+0X9n2RYk6J2Z|1=<2$t}u}5U45yFU0SCp<*>8KENX$Qf8e{Q{Z%i?s-^+sq@ zH|O^Z%*9JMBl4UH^Pb$zB;Nuww2A54SgyP2FcKJ?zL_>dM?P-ynFiq&j;LE!l%i@! z*l9KK*Yh&-#HD0tCUUe#HcN-QwrH5K?l8HyixZ|s)nA#poyMmoNJO25>S6CTq>wUA z9WN9fgL(y#SR9f*dt$+EaKnb#u^0b*!3fUDrqNM`e1~Y?!If8D4+m|_JEY`pxI=Y3 c{yXMr(%iPfo%dy@4?h5Sx%;>^xP&wR0fs81Jpcdz literal 0 HcmV?d00001 diff --git a/thumbs/generator_001.png.import b/thumbs/generator_001.png.import new file mode 100644 index 0000000..d2d558a --- /dev/null +++ b/thumbs/generator_001.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bhguehdkjm71i" +path="res://.godot/imported/generator_001.png-83c7d2c2e14c3d733653086ee836f133.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/generator_001.png" +dest_files=["res://.godot/imported/generator_001.png-83c7d2c2e14c3d733653086ee836f133.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/generator_002.png b/thumbs/generator_002.png new file mode 100644 index 0000000000000000000000000000000000000000..a2e449983f4b04bb7bf4f146ae988d081ba7411d GIT binary patch literal 1474 zcmc(f=~I#k0LEXygQ+-D(^3?etV~NSo4i<3V~5N$b*#-yH`g>RkHP|!B-rstQ#aS# z0yQIdt-LxE%`>GmLoqE;6pzSVO{f=d7KC;GiQNy+^P72Qp0B^`Kz}k~lldk901)2C zNI@H9{u{W#Mt2c^e76C}l_0VgP}7f@0|5OrZ<1#Sm8+2UC7PsQx|ORYm7($2+yf6u z0zs?s)X^WZ{g3~4t_;2`*s0=)zeFG6@^p?5Y+P?cywWZG1$*2am);KFIu$f@ z7lm^Tx*9@8wB9TakYR5$0mluj1_}~c$;fgA%w`KgW6MeU)9KD{GTyh+M2)fY4{1Zy zcv?g6iME^7t!JaMn>rOPNUX$~Sr*V&G~Q0LQ>Owg3kyyaNdJUY{Fdmw`%J5)$)DN5#UK!y)oXBU7SG z`>7=2eVOAO4;&)d;jBr4DP zRoG`klw&gEF}S8G!tiu;z^xOcLn0Tr+PG!U2z#ATw9 zI0Dti^7_ceMQE@0w6XVO{)m3vAlUWbDy%2Nah{%nY72jD%Ur-dJJU#Ms;Pal&8uE9 zar=~B0XEIH2ztN0y&ZhIx!7L3KIAM;*~~XHH3gd4qOql7Ry;zS5{{Hx+U}6Yox&0Y zI3~p{eB|XKS<5y=fsC@6nwrNES5$GAyN1oKafnPDJSp6)I~inPMRui4@dNYxIS0LP zKi^Qo3V8whrdAsJDozrx&mUSrJG_p>_5E)eT1VM&y7Auym3eMR8SwtzpH$-&$@&M@ C3b8=| literal 0 HcmV?d00001 diff --git a/thumbs/generator_002.png.import b/thumbs/generator_002.png.import new file mode 100644 index 0000000..a5ec8bb --- /dev/null +++ b/thumbs/generator_002.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cc0fl2o0fwa1i" +path="res://.godot/imported/generator_002.png-284d38dfce3e6000fe10b79796703113.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/generator_002.png" +dest_files=["res://.godot/imported/generator_002.png-284d38dfce3e6000fe10b79796703113.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/generator_003.png b/thumbs/generator_003.png new file mode 100644 index 0000000000000000000000000000000000000000..c5788a4cbded7ba199c65f481859bb0c0808f735 GIT binary patch literal 1378 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 literal 0 HcmV?d00001 diff --git a/thumbs/grass_004.png.import b/thumbs/grass_004.png.import new file mode 100644 index 0000000..268c80a --- /dev/null +++ b/thumbs/grass_004.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dhxqqpaqt8wkl" +path="res://.godot/imported/grass_004.png-1838e0b0f4ccc06ef1191e3d49e84327.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/grass_004.png" +dest_files=["res://.godot/imported/grass_004.png-1838e0b0f4ccc06ef1191e3d49e84327.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/grass_005.png b/thumbs/grass_005.png new file mode 100644 index 0000000000000000000000000000000000000000..8231384dbffe383ed00cd123428ad3f98b94818e GIT binary patch literal 1716 zcmd5-`#;kQ0R3()LT$DrVr`3}rg8a@<U)ou*c(zu6hTi+=quFrEjz zGY4e{fQ`HV1EUlnxEsxYHfkh6Pk`;QB88vB1a4Y)t=UI4vpJK?Xo0fqDG3-A2jEu& z?~cj4m!8@sC7>aBH`pyD5||Ar5z|HytIU`6(WlGXiqlUPG`l9z(GcVJ12;!m4jiyu zm$KjefXNJSkExTr&Z#1HO^E@hHSC zT+w_s8zc&+3tqDtmq#rkvc`iZr~G&5fc9A5+szxoOQL4XEA+8-`(sYCRqG@>q2kL7 z`e_xL#0?Ld2gnIgFFl(E{MmE7$JbI8-oUnTjxa)oX^N8Hzr8iH0jM$0I?DbV@>MEn zA!W`99W6P-g_A0o0P!Z0f^9rSC>_S}Q|ov#;~!g>|-) z7T=Bj3RTE1fIj8Lr{#oZSZ>--*T086)s|zq9Q17&(|iinPrkNgtQ5fna;gr6L$yVE zvdPIGCgG9?$N1Esy+w_$GMnQUv#gG4!4JZ5*FzGKR7dV-zxtD+uPk+E%|#Sg3vfoX z9aoNctK|7^GCV^q*bGz`|xy!4qMv}!Qg;v6r zLWT0YPfQ3`b(VsJ`(G%n-)#^H3kq|%G(FTAGSR#ZdH^Ckt`5hDm-iOsIxY3}*no|^ zt1PMDV+BtjX@k$k&>qgYZ!1JZ1Ob6M%nbN03~@6g!ui*>b6yXy-9kb6$Gk z3DT~eR5uWTWh*0Zqh4I)2cwiTz9+Bj-5x_eNUsxD%cVY2H%;)hOG3FV6|-~4J(la`e54xuJo+7vMG6aMbt#CZ9O6RB8Gba zH>)F0tr8dWZSN}ViH&7hhC=J~9qw9o*YWNhtJ_^l+mnEOZHIP!mB4Pz$Ih)jK9VR_ zt`JAse(|hQX+&8>Vn$y{X-ft85ulaNmYsa=6E-IMd7oNcq; zzKs*aLxxu^Z5;qdiU(I8m96{P1JVpUw=XL7f3vXv&b!E+BQWYXaYag8yCHyh(95mT HFumKee&2$a6R(8Lck09m#SY7I}WS6bVyIii8xY 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 Hu*rV|R_K)> literal 0 HcmV?d00001 diff --git a/thumbs/grass_007.png.import b/thumbs/grass_007.png.import new file mode 100644 index 0000000..5ae7eba --- /dev/null +++ b/thumbs/grass_007.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dqsb1237co8jt" +path="res://.godot/imported/grass_007.png-ee8303a8e0ab4f7ece24904942fc4757.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/grass_007.png" +dest_files=["res://.godot/imported/grass_007.png-ee8303a8e0ab4f7ece24904942fc4757.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/grass_008.png b/thumbs/grass_008.png new file mode 100644 index 0000000000000000000000000000000000000000..607a0b35a7cbf8d0992dd7326697252c7826102b GIT binary patch literal 2273 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 literal 0 HcmV?d00001 diff --git a/thumbs/ground_002.png.import b/thumbs/ground_002.png.import new file mode 100644 index 0000000..8ef2675 --- /dev/null +++ b/thumbs/ground_002.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cqrbrema1q5ip" +path="res://.godot/imported/ground_002.png-fed7b7cfb80eab63aa06512485d36475.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/ground_002.png" +dest_files=["res://.godot/imported/ground_002.png-fed7b7cfb80eab63aa06512485d36475.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/ground_003.png b/thumbs/ground_003.png new file mode 100644 index 0000000000000000000000000000000000000000..a20115d8e95d84ff9b6981e54ef67d86e2b95ac6 GIT binary patch literal 1536 zcmd6n|2xwO0LMRLXzLJ_WWze6Z`k=Zt&YvNF$qx*b~43HzVFi1mS(<;>xAZ6aVN%u z@}RAj;tW&7l2A*&#w5pz%$JEXbMCLW`{Dh5Jq zoOaH?bX<|E#9AEBp7LWbre_|X>}lPa5-+WQzc^{P8Mfty(woN5^Q(qVfVw5S+u|Ng zO3&)nT_#j4qVlkt)8vDWE~~Bpwp(imp9vpS8Pc%LgU7hG&Kn9%Q(I%Q6^=$9%wF<} z%V(_?7nq`MS1z(A*Hk}x6qNweGKjxneY-F^%hBGfJr#y|j~?b2DKU*B+%6aw+oW3C zeF3e;i8{!1P<853zoIpaHCI2NiIJ=WJ_2i1O^l&Be1e+~etcEOzqABkX@oa}4=+|h z7G6kq?TZCsh2~vFlP}6s%Px~L7~mbYMU=ehj4Py$pGEo>DBQX{?8>sFH9x+vrT2s_ zA3Qj2dZ0Tql5>A!xTpRQIT*VSVzJ#m`D1%sQv9QVFToiJk$mdKF^e21CPEKk%~Cjc z>W#>vhU~v*9eUG<$ah(nwiG5sgdrph{aL^=&bE8%wGN9*Xcx#B{3->Kd|yA#d#g9z zz~TV}D%o41rQtt7IpqV9kOfh}jBhIXOatwMnpTcVoX5UUUk#gm9d?GYsX*gFqgE}= zTw~M&Jp&fDR9&T9EqTDZ66E8k_D(yzJ=Z5O!R9T`^Ipbbw}i?rlY;v<*k%NbZ1HXM zMZVa+y4ENaOH1CQ&EJwify_Prkw=$5qw0=6Po_FCn#)6Q3;pU7x+`R3LUq2Zizu=l z?Hg;=2(^BM>6P=M+M!-L` zvKmC|Q(F@^3&r)ZOiqoaj(~m4zHu}guU>(EEr}q(tEkMR&G>6w-gzNsU39Xir}bBx zh!L(mABD`NNvDa2PivKj-8LVH{Xrt(vXq~YRaVH~7m*Mu+JNK`Z@$g$j&V22c33~-{ohpi{g zri5GQA*z(B3~OiyhQ1(7mm}qJv50r)<+vNhOsH%M^8-bDVMVheED!2pbHhdnDs}X4 z;=Q&x@UI+f%2118_n+CG1fw5tfl>K+dI4@0FOFn>lOuHj3RQ+Rn@<5KIs=ym=nf6N zT4YO{_xhBldaO2O?T-cN8bzGN=SY&n-0FBu!{F`VX8f+(_2LWUB&(ptFlXW&X`QejEy`(IgwiwnE4n`Lb3{ ozf)QO@Wv)5y6h_LKYy?pl6fc{fzZaAY+pJ+@bGo#xrV3z1E0*X$N&HU literal 0 HcmV?d00001 diff --git a/thumbs/ground_003.png.import b/thumbs/ground_003.png.import new file mode 100644 index 0000000..a197223 --- /dev/null +++ b/thumbs/ground_003.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cafdetlj1g1q2" +path="res://.godot/imported/ground_003.png-2d516bf69e020009859cb4fede05df1e.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/ground_003.png" +dest_files=["res://.godot/imported/ground_003.png-2d516bf69e020009859cb4fede05df1e.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/ground_004.png b/thumbs/ground_004.png new file mode 100644 index 0000000000000000000000000000000000000000..80a8ab49efa10a4996fafcf39da56b81a8b736c2 GIT binary patch literal 1998 zcmd6o**hEf0)~G{6H9DWgpwwiLv2NhV<%OIAyZXS9W|vAPnFIvjj_}kG1{6sw&&=C z+NY&jTG5e5)EY}TwN(j45VZwSLy2f&InIAE7vJ|@d{^Jq`^ekNT?wI$001ZvJY0## zr2Ri~GRNJ8C-)x%5=C@(0kuP@RRCmvBe-7ljVu0K@;-Z^M>RcVP+xQ}*5JRL23;zo zGfDkde#ADzMbYBs-o5@}sjqH1*w z!`3h&s=t#oH8okW3t9ZH*J%Hs&rfKUqck;~ZH;LZU-0P#==6cye+HFvho8(wU{Qaw zp~`U=j!F}4^PxS%55*sM8KnopQpQSLLHZ8Hz4mCgi1`WStyOMFtFDN79z&qz%6p^q zTrmJfEAuATNw!({B3IoPI^^mO=kGD+|Ku4F$P_h^x?3oRz_&v*b9epO@VfqAMn5=^kaL= z>WUWLtRGvG)0X&J9FHlUHl+Q^=U~yW7GW4q$`wnU8B+TU(n_4*PLPjYs=kK2Wr=qW z1wCQoJo7wc*a|x?51wCJd+7CB-a8-^{KcWuHSXe@qkraHRv4)A$<`wMG#VN4SZ|ub zYhf76K0CpBO}{WsI9n4gn8IXj!e8Yh=g zVt>|YvUovegQJlpH)U;hrf%kHzYNhHhp5)g{9{`>jEgmYHo%q!w#d+*GS64K@nYFY zGJCX?lrI}TWt06DYw@(UF{!P(<#dX!#yv2Ql(CAE<7t!m?13t0|KP*LmVDUdeB-09 zk8gfO#r*4asZqrK&_th|4ux){0N^F{e>z`-^pxA*0K7BB+XY8o_Ona-gdxn+q=U&s z(Ae0IuvUI5R`)>OB6bwx$Y|Wln7a*f`F`xN>>p3usQA96CN(h2+lCvm*ujDis@bL_ zKb}iAHnY=#uy0?Q@ig(YY1ZDDM+kAV?W3VP_F5rIxkPIC*7T{Gj9FpmR&Xk7ruV=+ z*HMp&+}nZ{d>>}*;9L3NN$BsbRptkCNp{H>FvN~KiZQwYes#JrMHcj1Wuhw?bg|ke2}Ri2kNrMJFOfh2Nbim zw&k_4msd9JS+kS>)EVKVOvUa^`kO3D6uC-b+37vCU$S}YE5x^@hKN^qw4i(V_!4#5 zCSDNs?y3cA!)&A8?K^2eUA#&_#LJqA&k!9xqx#eQ{M#hd&r=qrj0Bvn68?NJ1dv4Q z&16h54)0xOw;AYppx=D9R&9vRUT|j@-Tm-OLknJGAW9nlqu>J+=V)LaG))ccVbhTf zOiFrJpQ^=(k8`l-o2)-R2B8%z8&3|brogH}H)%}C`}$mF=&~Z^5H``~(QY`~qjzL= zUg37&sCb&IvA#wfqwluIYWCh{TCp$hoGM7`UYe#fo8+O=>*GDGsy^2IduMhBJC|k< zg#}SsbDlKwD(Z3tj5MBdbRe?vhoYt82YhIl(02#IzJ)JdQUJS?*INq}#iH)40DvW& zOiMwehI$dfZER-*6tI&BjQX>6Jd)PLx-8}@7{n*nR?DOVuoj*|&6s;58MR?VV|o`W z;G_iA;zR<3mI|BI9mFH=v_3Lz?K`Yqai)!>AH_M@MCzgM13Mw((D@uo9t7miSwo;B z2|N%2=SuTb5{A;$u%QPcS*Ar0bd=+bpwoJ#@pZDNV6RH4R29EO6q*SJBtjKhP>Z<< zEDK_d%Vq73jSAeGIv2ii0ZXypI;p*wcKX}+Xj{!eaS-K?8!DmusyH>DT`O Dvc`*o literal 0 HcmV?d00001 diff --git a/thumbs/ground_004.png.import b/thumbs/ground_004.png.import new file mode 100644 index 0000000..0af8d0b --- /dev/null +++ b/thumbs/ground_004.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b01gbyck4hmt" +path="res://.godot/imported/ground_004.png-14ea2eab0481f1bc094c09c11bb65eda.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/ground_004.png" +dest_files=["res://.godot/imported/ground_004.png-14ea2eab0481f1bc094c09c11bb65eda.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/ground_005.png b/thumbs/ground_005.png new file mode 100644 index 0000000000000000000000000000000000000000..c1edc9988500803931173ac9001a7b3ccc75ea30 GIT binary patch literal 2257 zcmd6p`#;kS8^^yJW0*6y4nlFGrW>(jvN>-~@#K^oqmjt!uE}B5q;e`m>b@6QEGd~| z4lx^waww;^k=pVkv9UQ6Hiz5&S3J)TpX>d@=a=jCx~|vj^U3r+hEbH?B@Y0AqAS+v z_%=!Z3M#WbyHKb4wgI|$9OD4c-fPbQ05sdx$=)}yXs*~jTbr%fv$f*yhjy{u<$53G zgxsr;o<~4k&%7MjC#?qkc5`pw>%79+`u^8yuX!pCp^2y7_Ud->5(7*0RNm>wj9Sdj z(543_CxTY|3Av|x9?i_6re&Skt(CLuvl9W1m3X40RR$ciTyAQ|G1&)PbOOF-0R5_< zzx2Uo80qjFC{tUNWc~kS7=2lW1RtKEx7x+on#Ss7rj|jB4 zJs+`JUz%D$`gYW$PX4C>y2$9uI3@=>}Vf&#A<8d z_xbY{%b}!YIy)duYL%RVrCuR{+}2Lz-3Hy(G!7PK$uXnT%_>dme)0oMvrrB3qQ$@UU&#r$Qb(LVx>IE!S7y1k&0_v-w!>wucn#Ka9e8i+p#})2Z985#>bdL)HOBu znUA52DZr!w%NJ(H{Z+m~3FuuV{~DqUTVz9mD_JM!E|CLJFiSbCu1Xy`YH zp_O43IVAy!3E6!cA7TUw_Ng%$lJ0+!P-Uvr7Wo-*V^L9dIR>VJG4?v9%575u{@Psi z3KPi%AEeJh-Gp4{0++H3ovRhmp$+i!7j78mq#ATf1K$;jOfL#PqW}PgpO^eMZr9##o;X8!5J=IA1kDWXoh_weo5zpB@(c`aKFsH!C!T}5^~oO; zr31R~Y2@0&X^-V$4L1eLVV)f|z07u5cf zuMFad#{{q`f#8j7p=KV=7xr2e2gOOGCNsd>&+sXPZ5F6hFlGGcAhLr2ME)Ssj8sHp zvdq=+;V71q1jG& zhhmuGU0`c)x7NczAc;<;2Hu>(Q-N`<3mx#Yw12(RM zO0oJaxY(g`C31T5OZU~dVi@WRG!NNR3j73Ajp7fQ5O@cJXNY{0+6TU(fEw(AsVt7QR*OT??tk)`41#B`v*a-w z0eSkoO{F_eV;~m=)W4;;6q|g#mC7an1ar8BPSwH>My^@y6(#=bc`14yu-BCFQ#Idy znEdY|Mo+84gfFOHYoc_2!7b+!T94>-nk=y%(=s^`A!Oxe1HH>4bcsarBSw_^NC61P zISpizaJQCvEJ`*jUm>6c#l;d5#@;9wzANrwh-bHk$bLd+p#BO}F+@%farH0;71nUr zmMGc*c>7fzOlu$F@1wYjC5~jdLyK#~OnQy$Z>+ipf1m4IV*#X(IpiZ}wf1Tul+##_ zSCRO0yEw@Z9t0o>8A}T{S4LzT-2kTB;Qss%)9!$1pFtyL@WOOX2^uBi()CL&IH4jI zh@u0u$!Cag(o`2_(B8H~j(45A!nA2T24Ipear$jQ+9|T?Hq4Q=0cP>1Mh1{@hNGjE z0~#fW;Ck$QsLoy12~^^!7-iJ?ZfuPu{iXIL_y!e|&i@^X*#yL=dK9e=MH7Pu$aUi{ z0tYQogPH(Eo`1Mb9ef0JCH++(Jm`^7mXLlOZip z8NUG{!A{S5A1)R4jOfC7$&<1ngB(yv5>0_HEVdd}Z`V{sv+=x5iA`EtD=3z0i=2i) zU2{X16w;`+DBekh5Rl18$>!8BEw-RWjh94SnIFE*ve_*lY)A0eJ2#5x&Hp-xm(W?i Ww({n}9E-O*3gGH|%!%d@e*GUSdJl~N literal 0 HcmV?d00001 diff --git a/thumbs/ground_005.png.import b/thumbs/ground_005.png.import new file mode 100644 index 0000000..b15bf3e --- /dev/null +++ b/thumbs/ground_005.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dlctx83x50wq3" +path="res://.godot/imported/ground_005.png-c367b726e031a0344deeb5ee10e5748e.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/ground_005.png" +dest_files=["res://.godot/imported/ground_005.png-c367b726e031a0344deeb5ee10e5748e.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/ground_006.png b/thumbs/ground_006.png new file mode 100644 index 0000000000000000000000000000000000000000..6e4cdb0af1616091876837caaa23c44859debc2e GIT binary patch literal 1088 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-HD>VE*Ol;uumf z=k46sqRR#%ZtHDw*la%>%ggwwIf2jTCXcScQirxi-Av1lc8_ygb&eOtTo2m+{)|Ph zZuGv5ed|(|8you1xBc#vka>--VGTDcLpxK0Gvk4U3=aYr3N#ojL>Oea82AQ<@ErAQ z_6;oWe(CIy{^5IO;`~!v!t39e&YNVo^?%Wd-ImjHx~l{Yg|$DwJ-tAs-?uM|wIKdn z|NWicIsJc}h?AWx6SrC9DyPB9hst#YsdceccdIwf|95Wn|HhSG4StWME%)m7pX2zY z!tVECE648dTRQ@J8Q#4^<4NS1YK!njVdpn9 z?(PY%zuIlLJ(3vWqo`LNyNuWtEL#eQ59*G*8YDKA!A8n}nyThZX0Cc0`{2pK9z%X(oeZCvk9WT|S-$nL z{O+xN9A8r!HlEzlDfHuS%Z1fC6T>Ea``4JVQQ!O6f;kCq-|U|s`KJ9-)qW3ENsx(k zvKm)ycLi!%n9RC&??r8?zHi#h!uxLT7x#EnSE$cp4S;vNMP`E^>bP0l+XkK>5;;q literal 0 HcmV?d00001 diff --git a/thumbs/ground_006.png.import b/thumbs/ground_006.png.import new file mode 100644 index 0000000..e525edc --- /dev/null +++ b/thumbs/ground_006.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dbxb1j8iwbfp3" +path="res://.godot/imported/ground_006.png-296a5752b59f8b2798876b0c1c84008d.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/ground_006.png" +dest_files=["res://.godot/imported/ground_006.png-296a5752b59f8b2798876b0c1c84008d.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/ground_007.png b/thumbs/ground_007.png new file mode 100644 index 0000000000000000000000000000000000000000..e0f77af71c9f8b4106d1737e65b219c592eaebfd GIT binary patch literal 1247 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 DQm71& literal 0 HcmV?d00001 diff --git a/thumbs/ground_009.png.import b/thumbs/ground_009.png.import new file mode 100644 index 0000000..8308ffe --- /dev/null +++ b/thumbs/ground_009.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cqxjluesevpgd" +path="res://.godot/imported/ground_009.png-1676c589e2c36b544a562c97fb536e07.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/ground_009.png" +dest_files=["res://.godot/imported/ground_009.png-1676c589e2c36b544a562c97fb536e07.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/gsm_001.png b/thumbs/gsm_001.png new file mode 100644 index 0000000000000000000000000000000000000000..467f9d3177f075a455676b9de21fb420831f986f GIT binary patch literal 2113 zcmcJRi96KY7r?(WStl|EWt%YQeJjbXc|$WIYhx{96jRoa3B!w+WEmv;G8tQ587a+> zLCV%hqpXcrgtF9R-!jsO-}L(ze$VfD&b{Y3_dMr$&b{|@&pj#j7z=TTJOls$aVtwR zN4_Th9wI{g`IU*+TfPE?I$D?lwS9_n03gh>GDAB@QkIJ2Y}p)m_m%Eq=L0%P)>hYs z_0!OvQ8z1d-uh`E>|2S2`)G1FSIkpC;fZm56bXL1Yg$ZYS#0`Kn@(k!41dCYgS62KV4dB$%a4j~+8GcsO4QO8?=xS@D7nCqH_h8|+ z*>10P*@S#9m$1IEajD)%T#lir$=H)578%~Ci`oo;!C-~O#b1WwVO{-CG0Yw6)6{RT;Gy zD-#)#RJ(Vh0@%4^Cvz%da%y|0U`_x2@-{Z!i{d=~m z;cXHqN>^uz3&i=gQ#=(CGB>0yub=?(3;U2Rv3KpF5ODSu2D9_irRTr#z_x2~j3tLn0s3_ceTZ~*#MAtU+0f+0zpEZY>3!C!x;jras1%K)aY+6Q+} z0@QxG!{VY7#Zp|SK{)AkcY60mY+I*VfaFosER1H-{aR&2`Hv-Xs#7)kAK-T73RoUa zcwyrkrwp~1vyww_fR_^mEW)fY*Ucu>`0~?&&TJk1a%q)1aKf3L^|Qi2$R^hN)AcTh zRP|YQVwq)MX^>9suTql}H+21E@!*)Dv3E>n!rD}$-bnpQ1FnzF+7{A+;lV&*uh0DT zxVK5-3N*JT6dn~sY;Hz&u^wc+L89<;k}xSLIXJwssw$aGmg6p;bcEZ8A_TuJwZ5DD zWxhCZC7}yf-t?WcES7D?Q0;dGN$2Md4q@$*PFUcN>64^^G8!$@X;=oh=HoLx-~8xQ zmb@9nKK2_hde3O+%&**9kNzC5w;j9V7l-M&$~R?bwKe;Rtm)|ila7APq0Az4ES55T zZLpg{$&SK?ll>F)P>7fn2OW`$c=*uo<_B^~X_bm$8nQGaV?0># z`p6^9p>XB}fXLg}kPd5c6%*jgpP}OGIaQ?w2FaGD6rkqu#n#3cWbw%*&kHd|m)lDF z3J9wxdy5dYX@NrQ7;O3H{P7CNPSDNl-RLdX;4DK#suWPh^70MwcUhgP^vQh8cFxPn zRdFP;nvntBD^C9IH@*v48u8Fn;Lgm99&#~vYvRF&QHus+r@*VEQ%f$Fp0MwIsv?Yc zRnJ5CcbG0-4s!ub3s^?)-IAY-$x%9@KE?ZS^)a0eI0sq#y5BMu`FKbf12lf@?N~4* z+82aGZWpX`KOzhhNk#hNOEiF&QoUpII-|rt!dV%rQTSXhbMY7Rb9`Owglt_U}wxK(#BAtYVfG5SvT6JHn}m znmc@Z&d!9j%1r2qbg-ZR%|VB#W4XbU%`9xMon)iF?Kl)DPcMT@7NaIwBEYoGHe0c_ z1(Nh<>s=_SC45*vi7oQdy{QSp-+5dO1lZ}+ zw@f#d%89oQgcjLo;Zzv=3&pTXgI-v1SnEi literal 0 HcmV?d00001 diff --git a/thumbs/gsm_001.png.import b/thumbs/gsm_001.png.import new file mode 100644 index 0000000..a95182b --- /dev/null +++ b/thumbs/gsm_001.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://js75fxtglx73" +path="res://.godot/imported/gsm_001.png-992352df17ac337ad1b53ec3a6b03556.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/gsm_001.png" +dest_files=["res://.godot/imported/gsm_001.png-992352df17ac337ad1b53ec3a6b03556.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/hangar_001.png b/thumbs/hangar_001.png new file mode 100644 index 0000000000000000000000000000000000000000..3aa1b78ae8976ba23434d7b382bea037d90d28ef GIT binary patch literal 2261 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 literal 0 HcmV?d00001 diff --git a/thumbs/hangar_002.png.import b/thumbs/hangar_002.png.import new file mode 100644 index 0000000..deee225 --- /dev/null +++ b/thumbs/hangar_002.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bhmgksiexoq4n" +path="res://.godot/imported/hangar_002.png-37f8a9365073a4a37192eafdcda29ceb.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/hangar_002.png" +dest_files=["res://.godot/imported/hangar_002.png-37f8a9365073a4a37192eafdcda29ceb.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/hangar_003.png b/thumbs/hangar_003.png new file mode 100644 index 0000000000000000000000000000000000000000..6d330e8d1542494c1254373f67e19f2df7baa370 GIT binary patch literal 2698 zcmd5;={MU86aHCZU$0)Z)>c{?*H(9ct6a{dFDK4&Uxm{%$W=aJ4-=6DLw!I1g)*$j;9g( zukmo5`VYqF!PCHY-_a5VRFBB4001A{8g6zo`qlcMfgxwelGq|iG454aO3qExH4Zj& zXVnyy-jO%YrTlEwoNwf0zQy<#3U|a8o4hu8eK z`e`a+=hJ~qCH9NiJjHtdf1omOpSP0Bca+FxT5-?f^Wcw5l%roA%KMtMXByJj4{7+y znZri0^;^eQ-~QR`kI)v!DKk>*}&UUe(00oj~wajY0LXp^qJ3S#zfq)CYiiGuljg#@FI zw>C9*`09EJM5((gWCn$Ptx~gDBa3yLAMAQXkD3CzLs*A*yr=jA5>UpvLxuR!In~TZ zN)QeIf$ushFdq=ZU9UT0AQN7Sd>3XJ5^}M@4#rn>?gP*2!K*l$I)KAt2Gugk_Vmog zbOeVfPA%1C{(9LsSM@sIebd@ej*JbZIIpYN@84aL$)pk#bPo#D*Vm6@W|I8XBqPd^ zzLAl6tj^A>76l+9LEQ%BkhzX;T;78p!(N9xEn7p5)ewA9QN8IcR@_1u-(1fod=o!o zA_O!1Q#LBjR!G<9GggkFk#U5vtszU78|muunB`s2BS zT1Y6ECzkl8-+ZEl?)Z0Vdk=kO^4>+r0?6bUn<*p*+^I&A^2Eyf@up6T^ zU-(U3YKTo*wbOpvrJ}!raX3j4g+g{yMG^Ey#|aw{xiRy*`_ownQ|B@=YnMAXBeo=* z1ev}pVsbUBBhcYz@0SHLG6Wj&XMxKVXZ5-`6abm|1EvD1UFU-eNw>{cfgh5+)m2~v zbvR=qVi{TM;`FdPGn_!@+Z)3iFPw)1P$*QZtuse&6gP)R5WRHdisjH7a{fAyC+N{S zQLvC|C^E{mMS%@p-$K?FdgJaAT6!nXz0uaBZa9-4tlAk#peI%zKx&R>8UyJ+v%jZw z{&FvhS$m9%Y4rNESf1qJp&unfO&FdQzaOdJ$ck1Nwbf)9-?kgsY=`YGh6iVsZ%r1K zS=)pA|MF<(xs}r8$N-TdjLuw3i|ydb##OKN7!TdeMYy<#9Q&l~6AJQ+7qSX}B{l|F z+M2za*-cyl7i+WJ{~1}h{sWCXdHI)cJCt~{+Pm>VQ2$6Hs_W5N73_ijq zSr6=-$F3CD4;$t28l1rlx9++Se3j`yb`NO8gluzTNCH>o@ztzCzUZg(EJcSB;&$IaP71~ zKY65+9RBXP%4PQBg)d!GomF^2>B-VHDP0<^RqK%Tq}g7qN8 z6O1u-BZV#N2)yOz&v3umAGWM5Fgb^5zw>3PF7>n*Oby+kK){TVDCSs!}tB~Rt`wE z7&6}%xgp6mPp#R2&L}Dx>6#QFaaIA`b4@=!ZaRJP>W5-4mwyZfdXP1_S8hzutL|Ba z&QF&sJ(y>|_Q(U}6~4!X%^8mYP!`F;j70)XY4CLT<&dl~_wA#7;KG4+kn8SZ+gRhW zJH)#{)zT)=QYbZkmLDVWxP|?lZ2YHCt^-3WADqJJ%JTX>3o?Mb#xJcue%QnPLbLx% z!mFhaPjtjHVU_;EY7#bsutWbAB}c7{J>u@;WbkIyzT|XrDl@RPdY93&Snz)N;tQ32 zF@H=r-Eg1Yt{IWSW#1JVuK$9d=+(r3U>LJKwPQxsLQ3$qrEDOCJjmbt5wDcFOsw4) zY;XA=|2k$EU$1W=X5ChJHUyxbOv~plF=+tFztV{H^>WWzR>|aSrfU7C3eu+f_j@jX z35;+y;kVxN$*2?VYKhU16Vr`Qa{6yq`n<~%K8F= zhrPPV`;kxS>&wpE)iK{ZTFSN%?tj`ozT`Jn(1x;>$F!CtU=h^usyX>?<< zW!Sy&w3d9brWs-C=(~X6zDs8{qP4CJCmb&QlDb%d?p_yv?Ezcx8Qnc6;IZ~E_xaQE zhd4sd(r_W}z&?LTLo`}Wk`oMz#zw3CeXOV0{hR*wR7r7M%X1O7GnO0dXDm4#WJFEF j;6R_~Y2tqkUY&4=?^@c)nItuwK9_*Cg&n*ahD!b~)m#*& literal 0 HcmV?d00001 diff --git a/thumbs/hangar_003.png.import b/thumbs/hangar_003.png.import new file mode 100644 index 0000000..cd037a8 --- /dev/null +++ b/thumbs/hangar_003.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bytr0yfoa1ff2" +path="res://.godot/imported/hangar_003.png-bb79f7b35e8ce29cadce98717c9e7293.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/hangar_003.png" +dest_files=["res://.godot/imported/hangar_003.png-bb79f7b35e8ce29cadce98717c9e7293.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/hangar_004.png b/thumbs/hangar_004.png new file mode 100644 index 0000000000000000000000000000000000000000..bd1ad6ea9be0d5e3006410004a7444702f5d8bd1 GIT binary patch literal 2263 zcmc&$`8(8$7ycj&VvMCE6XR>SxtOtp8;wlL79&}|7!)c?M#|1imQYzrmdP??CnFjo zj1g{@Ypd&O21DZ(60(jN>s3g!Wc4*&0>v<6 z*g>RHl(n^(_}+AurG^8@UeG8hvphwu;$p3exv~T7L;_j0q}K6OaJiC`hf*+2rqtZ3 z2z>dNqhW2e5!vpA{OZWEtMbgmEW&t+Fg-Cmx!xDa<5}FJ>TQm+>m6R$j9;n~aIIkdH@23XMo#u)nr?c+|vT=cvE@Y@^ z)RV>M={|CD7b_fmJaM>=r+gQ&?U$>buI{m$U^&*w7A--Ze+;5!>rnV?^_K!fN@7VF zmxhLgsQxAS;z`T#<|%{YRO{piadDqs0UjosLjJwqHo?I^Chw}`@KZzoZjck-s|*$v zSc^-Y{~3kRqJEqD#o)g1`lhJu-WQWF{xSU>W}bnd@l!?vNgC$Fzkk^8^XSSI1b*?k z^xoH#8&QubP!SWt^K1p9W2Kyv(bAcohkK`HUgmpGfx~ql8h2w5eWIxeeQZjBdS z<*8%_?`Z=QXP(T?LV(K3DmVI<^IJD;b1UEAYh5Zj8yF&HCae?N~lNa zrX2T>Netd}=?u>^wt?430j!C}L^gdkxqh)xPX0_r&aVb!$*#_>Q{w?Shp4bk2}Jz1 zO68p^sE`y$;5A*s@%U!>DUx#>qGZ`9HWr(eURGDD#^VP+N3y>FjI? zj`N?=l(^^~sOR|@DZPTZhw!JAptJHKeG)?JB{d-~I{167L%UskO2`6NE#>lPSU)8g z{}L2dGty?Ty1%5z>UmlCLH*Gqz8k|Eb8o8>FmZX6%4burBy$ZuQ;9~&y?yNQK&mFT34 zp=)FT?>-VyH8(9S3(KA;{P0Me(;P?iwpFsMo++pEFEwi_L{uiS+^@MuU=^Aw(-wxu z#|m2HY@dN@qyZMV6WL!B5Xgu6p-g_47&LODr$4UI;;rkwU$*|s@N1dLOf-Xq%)Zku zK6w)M`*&ZKeVMOuKAV+@R119RXafIiZPFBFvyh_=sgVJ^dDk=F@(5qT9kBRv@#I~C@|B#xT8nY+5X-6VonIb1Q2;tDrKF9z58N@( z-xCUjc+mZ@teYz7R=Ms;Bq`v0pg2AsL~_qCUAJ8ls}~W@I=WKwGBdzSZ(xQ7&yM{=fd*`w^Nfqa<_=diFNIVfCe^7Et=LyodfS+bjFbiMmkfYw z&}X&8#`Hr6{Qx0h;cgA-`;VzGq>Fap*Q%K92lt5_Yq}^F`vr|3F~4o2RsU+mo(wf< zK*5MT`oqzwI*@=l8%m<5hK>>S7uTZmj?=l~hC-3{fL(3mzmd`Ejc<63Kb8qgIX`RX9% zQ+Tx_HJW!uGL_ZlC%WSi98DK_2tu2#8=VR{fr#`SECW0WxagDzOk+<&@na0$Hwgv0 z-|~)Wc&y!@TRI-bsoHDi1OACSw57J!t47@4NSMN<)v{mt(JR5GIi6SB9PlwdNadj< zvGdUQ-xVsHxF!7M2`Z58%PM_ET|eATn=(p|<-yalYleD7Ed;r%EAA#?+~j1BjfC%Q zI`3~h)4u`|PP3i8^v3@q*E3OwgfSZR%Ah@$JN)E=@ed&M2+Oia`j4~p-BUlI60q^O zTj3NMT!AeRG`WT7^q5~WYsW`PugG^dnkhfihEd*SuWi9^5x=BTfX(u+pWlN&Z{nzW zx>~kwN5(Wot!(~qffx5}`S0w04pA$<-e2#zz6P7~67>vbzKc&k*J?7>qUIiNDp}HS zOKXZ~iOI#>B@4RxVq&)qwK6-xmt7?fNmY64k0;CcHFbFf9b+4dyqO3}g+{DB--)7- zpabUvb|9{}VBU6`N@!a%>jP{u`K}wP?~I!u^IYx7g8Awe642XG%V>Cq+|&%!&!+Zh zMDLkc90zk3O{4#Po614Q{OdJU;O6LN*D$B`!cP34?)8>G6_M3|*!)6D@z?i^uvl#1 zbMU!+Sr;2_2~ki}ey^C>wf?n1?{GB2dDme+`6!H6`2U9iJi_Bk_4S!IPFrj``cwd` L%Xa1@ly|~EeG(~g literal 0 HcmV?d00001 diff --git a/thumbs/hangar_004.png.import b/thumbs/hangar_004.png.import new file mode 100644 index 0000000..d788de7 --- /dev/null +++ b/thumbs/hangar_004.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://crfn6k8kq7skr" +path="res://.godot/imported/hangar_004.png-80f63e15d6ab45e7f48be06e5f8f3810.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/hangar_004.png" +dest_files=["res://.godot/imported/hangar_004.png-80f63e15d6ab45e7f48be06e5f8f3810.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/hangar_005.png b/thumbs/hangar_005.png new file mode 100644 index 0000000000000000000000000000000000000000..e2054793ce0b3848d3d45614b3baa0692f0ee753 GIT binary patch literal 2218 zcmc(h`#%$W8^^y`GsoFt6xABaSt;k!oKIO25+M@O9Lp)gLXPz~c47>7WZ9Z-IrijG zu~K7BtwMIML`IF|wCL6!@w}cNuIux|`?`L)UZ29Hhi|ivs|poE&Z4x0U#( zV9@RU+#>Mxwg_Evcd!Nz2b8`701I}qwem9()Fpw&4p65>>P~A1GygE<2*{qs}&Tc1j&E2Y78u}<6W(fCa4|Vm! zDmaX%lbe&QtNf93gCmuPrH_2N)Ol@jB587Q{abs%^-TWC$~{PymcIWf;vxz~G|~bw z-hkT(UIYr|JQtS9-hq~uz$*RUz<@YiQ|2g+Y$OR}!XcnL!E$2dZxh`c*!46?v|*QndAf5XNb`@L7w0-3~r$$I*QQFZa;-d7BMg&lWXrPIB@WQ z)*uA|!Gcma8{(AtU?*0pEpH>5-rIsU-Lh@^i~mm5x83b22I3F&IUU(*#az#cdn;xJ zm{Et_EM$R5I?*G%`|;Eu2I5XU$$$$LvTjXKGzTqG^5#p@v<8bnX1`d69O}<_VGd)z znjjrxjfNP-{ZeKyoU?TGtB0);N;u;miiv1!ib9Wy z`3G!ThqE)s&ddAH@i(&6kc({uJOa_z*Vh=iuzQ@hW(ApoMbF)d(=0GB5C+!OGJO%l z$%|WOSeu_pTUvrGD&QX;2h(5~l&e^2l=)8VzG%veLgsaW6)72kkvgHmWrAheM50); z@5_878e!%uo;owR%IAFa%Qr{P@p#SUNu=eO700r)OoD95tBRJCxJY;ZgE@wV%9P7? zlu;tiOQ@T3);X<4U7 zHJ$EkR&H6jby^R_v$Vj zv;%IZOTBW;VBD> ziyb-u^|HLFC^l-`F``q=7p+}7=oHI=m-Po|X#u{?S_+0Jw}PBaGq{fgv9IGtRAsr} zal*}GJeG&x<tcH8r zTvj-WT{kw=*%Bm?ANzjUL;7w}(Rm74k?_N!yY><}X!^m}Z0GVd-X;1^LZpsIM zK;I6WW4_Jo8#?zi)9I-9z0~HgD;n7i>`0G$INki2UD)YoH>3FT7h0&72IDIXBZ5po`rJych zAI>TF!Fw%{mIb>*V%xEheN`BulyB=o_xuFDsGIjle5xw4_dX&io*U(uni)b|NM_f?e&o%uwaB3JeYZeNKm ztUw_8K!H+-P$(tniiRk-DrJGy7im*~ds7;nPLD~%ay)0x136J%+t^+LF&x@ho5;`j zIOS_)C<5wMm*?Gn=ZQj|bhV~CLZe$@Ri4!!+&d9S;Zo_YxH)=XX;h}I{2_hg>ZE;) zoVcXsI)bu_9zeUW-o4AYR;xOGZnQQ2f$_8=rNb~iFJ`gn_%Y<0fqq?ro1_Ky7{J~F zV6K$?JS21mO~myZS_es1O>=Kg34^+W2Onw3TKmZzUnF65MC$ABo{dbc4CZ*g6z_gn i$P-pD{~zV>56e3;oj!}MIi&69131~?Y#&;mP5&2@#_zfS literal 0 HcmV?d00001 diff --git a/thumbs/hangar_005.png.import b/thumbs/hangar_005.png.import new file mode 100644 index 0000000..fa34950 --- /dev/null +++ b/thumbs/hangar_005.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bn2gr2b7332vh" +path="res://.godot/imported/hangar_005.png-71cd601620672c7569500ba92449d507.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/hangar_005.png" +dest_files=["res://.godot/imported/hangar_005.png-71cd601620672c7569500ba92449d507.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/hangar_006.png b/thumbs/hangar_006.png new file mode 100644 index 0000000000000000000000000000000000000000..982760212ad43798203ff540ebde8e6c61573b4e GIT binary patch literal 1621 zcmd5-`#TeQ82`@L)?7AGiHUT5ZE{Z!p~r2Qb(G6-Ytp1yXPrOdJm+~n@B4Y5=Y5~&^ZDg{-&|jB4^^Z#5&)oj z{Fv)$IWxWo0w&LGj^Vv>g3wQUxBzY+W*z_->bR@3U+V3pNuRi)^BDd|>b5vKmW9>o zgjt;5(ai3ClV`{-Kjvouk20X4SxAv0HYe3tSKIQC7aM-0c6Y47!A`{%hLxg$Lf+WD zE9~&m(PTb5nbJ9|yC7N``mDP$PWffMe?@Y#bKH^o&9pztM<`j^9-?#DQHP)*s0`r& zT%$1%{Xc>0TURdesaOsgl@FX``mI z+Ijwah({tKA|_fcv)gKf?`N!co=Zbb|NMngFdKG8i9fdrk`;Pl<>F*Nl5f*%1W`bx@FaP1o`l+xO8wyO{GEs-|A)+n?v!=%%Ajc+GSzBh9ENx8; z`CscOFs*0nfP>X&L8Bi?>gXOn z1}TDl1n642^yYYaGu{kRtr?O_?a1G|0x8j6c)l1HbK==a6vrYMBPypsNl@_3 zpQ!jgliPp4wxW8yCN&Fp=AfPn`43J*`EoA}acGu;R3Z!jfY^9wXT7PO zV8)oC^yo=4x>h7xpTT|$#=h$roxXm+3zBJF1s6i~9Vlm_<%Vtv8U+nJB7zi-fDu$a ztxsQwhln*?PAQn*=ORdO^rh%DX#+m@W1N#YvnaHbr{q(yZZo4{a-1(W9F!uzHF%2%eEr8NvP|7jEig~U6;MsBN)Aa zX7WM;RVqP=f-J_Hjj5gd4XGdGPeWaga{_;2o93FO#eX$HENmUxKUQS+zM^wH_k&tA zxXmIMm6>~}s-N)p8*9Lob;|@$r;|(WS*`d6t9(LR+gnO{4$4vXgGqm(@e{d?Z`%5u z^Q|dYUIVYOoP>oD;)B>xmhvt`Z)y8A-edCnCsqe!{Vy-Ew>GrlskC()K5I59ni>n$ z-<}IrC)UiSxsTq(6s*lE(W@mVb|tCa(&&HTTZBUD7e0Pc@%*crcwuwJDjt8CLqa7GDc+c&5q6C~u4;ig^-BiwP7=l+9@qC$=tBo0H zJ2z-JLuxRZtPCFA%^hi= z({PM@SMJW&umtRaf-bYOye+*C31VkRPxOEcc=Ahp^Li+3+kD9Y*OnTO@qa6Xu^s`;No2A{d3aN}Z0)F=6$0LR_DUAZo# GtbYKEZQ42j literal 0 HcmV?d00001 diff --git a/thumbs/hangar_006.png.import b/thumbs/hangar_006.png.import new file mode 100644 index 0000000..ab5344f --- /dev/null +++ b/thumbs/hangar_006.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://de7pl4g7cdwan" +path="res://.godot/imported/hangar_006.png-8c6572fc592ceee43a4df696e634fabc.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/hangar_006.png" +dest_files=["res://.godot/imported/hangar_006.png-8c6572fc592ceee43a4df696e634fabc.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/hangar_007.png b/thumbs/hangar_007.png new file mode 100644 index 0000000000000000000000000000000000000000..8b1c2c80b548b2214099ca77c7c8a0a1b2e3759f GIT binary patch literal 2078 zcmc(g`#%%DF6W6foS8t zpY;EZq{O~+vHoxN19HXPo&cWpsV)F;V8p=&?{VYdmjb6y6j`ZzuY~Y*gIMu^+Qv(or0Zcy!o&VQ`m)z#Tw|^G22ryRq#jd(aiwe5a$vRf! zg&2PF--poQd*ru$<1MO-ysIB?glBOSZL`UH6QV)$h6{2k5C%ihk(#&4caf+*gMVsH z#L&IxaS_6xfzmMPy1Lmv@4X%megq=?1aXGtN2rfceprrTOe2iG5CZ=yoxobc=%NED zHReP#Ze%hA)Vm9}9$bf#czZcRYtOoWK?PZnA;1>W8d{McrI`TmoP3x52A(41ypxJQ zx3=w;aC`M!)+|fH{mm`)#n)46f*3N|9kR=4D$GQGE512~;zvl3CVKwpOc{=Rz?oN} zl_4URnmv+U>$CMS$7gbb7eS`VsS|d>#<~ruiP|)#A*Ut7Q5)P{0FvXlOdqr7D}K#i zv@|Y5z~t+xw1}xS1s=JuuB!0Smec^1cPnXr6t%rH(s;LpC-$7YNYtV$ zO5jN;{qROj@QT`-wE$^NCs==dh&{qEdf9TQS}^(2#iIl(X?UUB z*@2vbwgc5=ZU~<}ub)c-Zra%f4;QhAD}HvTsalR)=hgB>3p!b|Wr~YM*hZ8!>E)-F z?Rn1cs60=t-Kz@&gTBu4$=Y(s(0whx;~T5JQHL2(By#WHbF_njhgMNW!l+6nO3bIt zIK)!$YQ_n${Ycf3O^E((hwu+}RbJms!<`(J7ULP!^#LfSG?oZrbz_Hj{_4%QyC-1h zdzBC~*+#1$8U!&Us%AO?nEczJ?LH;%x5Gsni3eqW{J1g@xH9QRRjZjx!bzKb<_ZM` zdVf_?yvjX8oXGDQ817R7h8QrMO&b{qZ}_974Zrth6+Y9vK)gN-CNEBQ)@|l~E5`Mz-?e8l*{x z&ReodcL$t7l1@$Oa&yQTNqg+dp{AOmiFA#7Lb9re{z(kX>S+=gQyC|+W@)~sC$`{f zZg891llJJ|N2JjMtt!?W6Io+AU0YoufxP=THrHf(cr44!pzN-?-R4>QD=;OqNLBDW ztlK+vhFM@?U9K+?H%#_Lmyq1(sb5QWh!?h{{Omm9IRm{c3RvVa=b zd3DpX`_X~Z_{as>ifBPXrkw=3WJ_u`L_CDDOrT$~2pqpB1nutJFfS~(&9LCP@ zyN-buCXc4XJCD(G8@FWY8?NUJHG4ATPj`n>tH#n=0X4T54U6Be(J0}ZNJwpjZA7I)v(V~sNN6DCr)`@jbdw$3)s2!4$J0MNa#TmS$7 literal 0 HcmV?d00001 diff --git a/thumbs/hangar_007.png.import b/thumbs/hangar_007.png.import new file mode 100644 index 0000000..33d441d --- /dev/null +++ b/thumbs/hangar_007.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://30hgrq6alxw4" +path="res://.godot/imported/hangar_007.png-e15e2c777eb2524586f0558b331bf5f8.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/hangar_007.png" +dest_files=["res://.godot/imported/hangar_007.png-e15e2c777eb2524586f0558b331bf5f8.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/hangar_008.png b/thumbs/hangar_008.png new file mode 100644 index 0000000000000000000000000000000000000000..3cc281eeb99d69930054dddf3861e35a28d5863c GIT binary patch literal 2097 zcmc&$={p4vkzw5ZaBGL{4}`cK^Z;hguw`#$HxIp=xLNp?PO50g@s0sz3U4z@1) zNcj;GV*9zr%5P{NAW<&%XF%iQY1UGyy z=-zX!iwj&V^;EBAcndPV;qW3~`#P)9I4B5B|n>tt(jFjjZsmcnEhV~>25X5;TNlmN-y@%eJ|(cE`DtGn;`9S z8Y0EevWTp`fZ^#Inq>zaJ#jZ2*PY^o6 zzXL&T%hHX-j}(yyBqRABJa0XICXjoljB3Q|mY419h9M(VMrAbzBqI4uQ5-h$=+6U3 zeFIws>?j5?I=XEpx9a8Hk~ph12wTqo0HE}UZ}_d1om*0>tA^&!vv9c2trWj4ZdVt7 z_I|&4Nd}xZ&=9*b_5kqw39jFdqa!Ad7L`^WY`LoE&`OLZK5DWkl~D&(KHRjqp1Xk3 zRBkO~&z2mM5}sTcXb=p44nx(jmI+@kwMXlP!*)~gXRT?SB$Z=>xfa=)S zwbAS;65qPAWdWEetMl)&+>~U3a8>{z7TnTBW!TD&*T$;hUinE!gnM;~)q^$MR6}f5 z{#Ew^GX*UWs}w%fmRBj0CL`wi0%wc+dxug6_~I%JbzRGBKY0~6@SVfTAe30M{pk>Z`bLtcTTU%{%6__%ZuK7&rE^qd z$pv*tlWdnUk%`47zG$+off{awSm>X6!)$cAuw}rnu$h+97^F-5egHKXr{i2Cf%f&3 zfIZICTqOo(^Zkj|{CAB`GdeaoL9{N#O+kA@)LVna z`#T5K2b$O-Nq_hR=Q9WljXXy_RpC-jW#KyI$n9`f(%!U0)!Vv}FQ203U#^FY-jhIP zD#|m-o(sp;QkZrHjl&mOPdhBgpCjSo(QW?Z5A+~!2!JbM7&Wi6Nlcizb0RIZW0UWX{H%@PTQpWHRU*_TDc((Amt(7YPn3cl9cF7UG9 z%BJm~1Ckm(QGCTA}2|KwfuhU!=EfnW19TF3SjBAbzrg}U>3?<uCO6M z9z3GWEuFFk;6>o1)584CATAPCMT}7x=+phmH+i`-HNls_>6%3 zK}RFbOgYTw9&BgwzaE_TBAQk*+;+`0hWEm2(^$!9fnd`VQh6=t>) zqwrJdMao96sy`ZXCpJvsQkm&U`|^z0hEA-riBXQEb^Ta*DZ=W|YAS6_-P9cQ>IlhD zC`(nV|L6jn^F)cGY8UAz#|(%sF(*hipIWJbIti*<6npPwx(!*h!n6Psgs)IJ*6@Fb zQ`fx&kIbXI6!2huJ|U_GzczHa53$s)TF;8AG`+_DF=jw%*--Ne9?hZEoq~8!LzOx^ zc4(G~!{6TcJQ@!@6UR3EKsJlh(1L<^$rkr#YYw~xA>BGEHp4ZfxO-m&F*GB|K7fN2 zT>Vr1;v8mr=TOY|W!2vGxHvYUcXP6+xj{kd!M2kxo-E6mynmCt*-c3};dUJ`g9P3- zoZE$&nVG{O=A>UQJkh5x@sfaM;$Ar0-)y#%cL)ms9#H;S#BS>Zbo+kl1)7j&W3Xwg z@du9Lv|o;!rqa)Utt-+(#SFdmkQSDXc)XZ-f66-XrcOQ|>!}gaCV} zCSVKx)~wsN?iHopC8||VeNpZc_^7dZ<0I+uFZEMf? GQvU_~0Jy0D literal 0 HcmV?d00001 diff --git a/thumbs/hangar_008.png.import b/thumbs/hangar_008.png.import new file mode 100644 index 0000000..879ad8f --- /dev/null +++ b/thumbs/hangar_008.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://ccrcd7yexl8h5" +path="res://.godot/imported/hangar_008.png-a557315a61a04a2c79315d091959d139.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/hangar_008.png" +dest_files=["res://.godot/imported/hangar_008.png-a557315a61a04a2c79315d091959d139.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/hangar_door_001.png b/thumbs/hangar_door_001.png new file mode 100644 index 0000000000000000000000000000000000000000..a01a4f4995d1d48846af029300264b73ab17566c GIT binary patch literal 1360 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 K#%W{OrT+oc$s>mV literal 0 HcmV?d00001 diff --git a/thumbs/hangar_door_002.png.import b/thumbs/hangar_door_002.png.import new file mode 100644 index 0000000..96da55b --- /dev/null +++ b/thumbs/hangar_door_002.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://0f782ov24am3" +path="res://.godot/imported/hangar_door_002.png-24fd067cedcacb5419145f7fb65d81e4.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/hangar_door_002.png" +dest_files=["res://.godot/imported/hangar_door_002.png-24fd067cedcacb5419145f7fb65d81e4.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/hangar_door_003.png b/thumbs/hangar_door_003.png new file mode 100644 index 0000000000000000000000000000000000000000..4d2a9112a2a7128179637e23adbf6e3b49a26be6 GIT binary patch literal 2084 zcmcJQ=U3DD62`wNgiuxz)PxctL=eIT1VlO!Vj}fYEEt+Z7uYD52sRL9`AIK=6a^N+ z1hNQ;JYfRu3L?Mnv~-nt!4y{`x~GL0FJ0zkY*(faqFIv~=m=5`ZcjrJPf3 z(M6@Hr zy)!1!JdAVPLRo)7rb_C=CGP0AsonD*lDN7nRNbZ@1Qwau^>XgTajS`wTLy!s8P)?6 zWjZg`XB*vv_T{u*gt@wE0Ukan5y9uj9Z`f;=jy5(e-cS|@y=@iVc#*!#hL~^`i%RUQw}j#J&||R%*wm(%)>_8QoOu-8 z?}#9YVuS9qOJxslExFoxP$kL85rzI1Y^@YVh3EU*sLH*rEXz|Bs&nv<@9QNPkO@C0 zn6FHDH~m0^>qmb8{z(sJ7Za3*UOeJTM#a6k2GTJfR$g0D3{Y}s4poj|Fy3{&3o&cwYUE1=s;MV zE9zlr-kY^@DAH8R&k>>4gUq+IGaeOlPxMcg;C&X8vf9tz*cKtNwP~(d?skNob8|s~ z7ms61BGyh>w3hn^M_B3IR%6L`#OMriF( zt$whdUl6fP6{^Qnp;8{(oatYAuea=-CiAHhlJ0E6TsSy9{dBm z8n!gh@y)KdpRqhoxL&7o-S3Lc$@B2_&i<^qteoQclnH#bRmEV`nnH8l=>w9pICea^ zsXjX`X-B$(`RWzH2xa3U{|&)F=*xz_C8vdxU#!9V@fuR)F~9*W9i4 zjpe1D#ePUuy`n%Hvg<`coipR)-$}qZ@e~OpD(1R(?%Ln@zD+t8b2oB)`Lznn%skMz zTwTIG(qK$t9$44!@K{VCt1=-qW{834PtH4BrpYw^jbU@H^ro#_JeKQ|t&QHumu?Ct-p!r9xWFBUj#PuJFWe^T=5_Us!*=4_t$ zLvuPY^#xiu833KOnGPpm7t;((1{q;w7*b6~^!%LjI6b*#Z7iS-XMg{xKf&+dB_*p0 zik<&|ycsio1+uR8@%8X3S&XF-`VaP10C_1Smy9O#=w$l0@KcG8DOW_K`Kw%QJr_T<2N@X?0b{%(BAHSHRT$6?=!)iGx)Ay`fJaPI(20$TAI>;;g3a{~1 zyeoi&B233wt5=2^yFKJ#@oDgL&#)oC5 zWNOc0zck$H#=4`b;NUqMbFzmQdOc$g_Vrp5DK=y;fSv$(TeWFr@B_f5O zwopXq)Xj>ciH^l*&5t8|&9d|Cvc#nrGfwu2$jv-jV z_Y63lf#XJ z8QjsUk=JT#ErDogNH=oztHDV9YUL!~TB8s_h}#?<8c3yviUTylWpE#m?b^n)jd`JD ozol6rQaNeo|A&45X6fY8=G?`{;^@i02Z#> zv=Nfm;6B#S7O5NeYF-_TZ_TdF@7}t($x%M(8uaeOE2>U|p0V&~`n_h%FR$?i%k)YpOk+MM7uAeW7L5Vuy;t#< zL~+enA%Dv;&$9rnVGKWEx6pTUkbYr+{l<#Gfb}7~(We68tzRrriH0xo#4^{usU&ff zxL#UZ;rU7O6;6$Q@sV@i$Y%Kdl#ac_69B0@H6apHThmo4#I!wnCzVdPB<+UhY{P20 zFz*rIx+F1^<;lmL3ANOjXDZPyFKY*8m=cnXGA+q_EjMjFG{D~}v|*_Go-%({$H10A zkf)ZHH8WcI$a?nrv(eHs^OsinNG#;?!8uqdEE`Dwh*BDa!9z~yym8-GuTGL$&xRI& zl0BxIc&U&9h^Ulw>Wj9T6xU-(Xl57PuqXnVYv~ zLh~#%O9xm~#lo5%u!SNO#E4s0oQ8CXHL*;=7|!9OxWU&<5)f z8RCtW$RyIkx+Pf)J=FDqHqoVI_j^ZEY6rTMd{coDwXepL!gZ{yZ0Cuu;r6_8hVfwC z7RKOso+`I;?}iBu3Qsqmj+U=Lu#3CBznG_^aF%w4kUnx<$I z1Yk(8X+Ro!ij1PW9&+S-Fa2bLQa%S!gXE=4A&Lk8A zka`@g1v>W^W>F%iH{_hvd2uc&)#IMp!U_o-y17O;J%^?OUF?4XA&nB-Tg%eU=4qZb N2;3L!U*|_+{0kMvz6$^V literal 0 HcmV?d00001 diff --git a/thumbs/hedgehog_001.png.import b/thumbs/hedgehog_001.png.import new file mode 100644 index 0000000..947570a --- /dev/null +++ b/thumbs/hedgehog_001.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cqn1wnj0csnx" +path="res://.godot/imported/hedgehog_001.png-3ca856ffb8102c1e40ef57c2ab1f9a5a.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/hedgehog_001.png" +dest_files=["res://.godot/imported/hedgehog_001.png-3ca856ffb8102c1e40ef57c2ab1f9a5a.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/helicopter_001.png b/thumbs/helicopter_001.png new file mode 100644 index 0000000000000000000000000000000000000000..782028d3b3912caf1277dd074db5275902463ae9 GIT binary patch literal 1953 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 Kz*V^frF{n#n5>ro literal 0 HcmV?d00001 diff --git a/thumbs/helicopter_platform_001.png.import b/thumbs/helicopter_platform_001.png.import new file mode 100644 index 0000000..06e9c01 --- /dev/null +++ b/thumbs/helicopter_platform_001.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b7ujf1j8tds8i" +path="res://.godot/imported/helicopter_platform_001.png-401551cbfe51fa1ce5357b21d39af14c.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/helicopter_platform_001.png" +dest_files=["res://.godot/imported/helicopter_platform_001.png-401551cbfe51fa1ce5357b21d39af14c.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/hummer_001.png b/thumbs/hummer_001.png new file mode 100644 index 0000000000000000000000000000000000000000..b6bc8000aea250f96145b3893d7ab1db9e0df683 GIT binary patch literal 2986 zcmd5;=Tp;*68$Cg(2LTmGzF=V-t?jri6Bi7fgpl{+|Y~E1R{z^Q&37UMlclVNEZwQ zh!oAmAiWzvN(iEaj*t8PiT6J2o)0^-yJzR@%t^7kX2A^+g8%@)ZDnb0e}c$=gPrvx z6HUAZP5=~YZ*d8z`XaFc0GxNM%r81dVQ7W-100q`ky!fJSh}}iN~r8vR58v@ZGNKS zMl>$0z@^DwC8x2WboF@M*3j=jli}?!340D{+a|q7*c-w$?1l`+oZrKWN>$z}&>-^Y zV(zmXAb~Cg9;*O05<~y4X}Wrg9$!`CUWY}U5OyF^jsB~BHb%|4yX&o|#&yfo7c@z` zJHiS`sxnC4fbK$D8SyT2K0{SRqT$lt@w2t1ikcrypNtnt!>SsZ?f~w?yI1KH%nqITevU)NcCOemw5aAhm z&|>BRv2&a6L100IS_%{J;dj>s)?2sYv+hKQv?T&FyEk?k{x(dd`f&55l7^t-S(eP2 z2A`HZO-LO?*pyEF?y7iUx%gB5qG&|xQGQ+i@H*RuYd_=TA7SJlC`)y`be)-pFMuqO zs(>r&bxl~%m&g{kDyl!So5k1)15T7|FEPo4{v0&l;MqcBL~?G;RHR4jfq!EV<D0%xkkbr+zwgtxSq0`~SsHBqoY z=vJCN_M0(kd;5&g-qa!D&#qtxJpr2-qu}P|Ugk$09tGJg?fmqTQyDB*wJLcqZNoAQ zrL1`9a$)cH{aHfSAR;U~g3d{yZ!oD&n#=7a^5`TJ6zw+*d3}@*`2SBbQ2WJ-fJJDH9GRU zxUXPar$@kz4X2AcNDBthZxS;|;Q^Yufla1X_IX9czb$NQqmI|RF~OYp{#pVuJk)ocFEeGCK6;{tZVfJpWTj~e zDxA}Ts5Ck?2Ti2Kv^vb*t`%utPOhQ`1sdqP|MwD(HKeTFnTX#)C^O`aI1^wL zHXFhxr*KJ2DSN*iI1%}Kc48<0dhkv&!S+t)l>f-kbIo0GU1{KTgtMsG7dGh-M`T~S zNy@haw~SZRAIsC(3g9;HK=n1LS3L)5&YHUJ{IMRo)fe!j^-$DRHdP}5TzhEj+yR+Q zSw&r3x3aA%;U+1MlRC_|xr8sNFtu6J^4C(dn6MRKXSR3PXG?r;4k)Xg#p&9Ao>D!fI}>9C97xY#i-faZV-dkH4L& zA3K-X7#Q8(`ZLjKZahFt$1Qp%{XKTBx^2dmC4n^KK{&VjEI}zLAztRw*M}F@r&Iy}2n3_dzB3fE0tI{$`lkTFe3Kb6c4o?UvM>GVfC+?p`Qa}8;iF5RE*=u>W8*^ZH?DT8Km!QEp2?)!|-6#lyLCJqmfd1jM^Vn&)%8v zj?2FT>lKb%m3*ijfDsjuGYUgZ(|Lv>>XMdq5B=Rx%!&Vmo&RJb8#EXcQuDSD z|ANQ*P+{2lCDRIUSM7K2X;jmdO<6W(;9hQ|_)!uu49lz8^nuTz-a&(yTvD2=ZoH7E z+L@~?-us*067wNmq6(}5o0)9-QwPF6Nh{#>7}{#FxyBA?eEj;TsWkUqP-YE}XY3gH zQ5sPwI!^W7Blk9*pQ{72u<9Tdfo!M2##bXN!3^4;sQyJGgfOnVa=NTJCy`e_>`dwR zL5*LaN1s_;$YkkeGU>Qi=DY=Dh^FmlIMlf?(bw*D^@DJx6>~M2Y#AjY%bbRVdWJ}+ zV}IaE0%g3fG=BqQ=^byhcE5%8Pd}@XzIP6B#UdUKEW5 z&FFo&FAKUz_S};J#Y%Ow8D(7r55lLU^mP(xlnF*&Jt}x~|K!7|NyNBO+E_>yMikuZ z9kOXD{tHn(Zx+fwZDsHMM^nLv!LwfFK^E(g|>OW2d$H%F{xseAF z68TrUg(@D@i6|qT%tncR65c9aoM=u@YJB>g;2c+H7H_l zGM48}t#YgH_e*+_379O{mNl|9gx7sp@M1?4NW;&?J_9!{!ofqCd3iveTNHbs%?zx} zF$uYlXL%(IVfXHBZket+-jTNmWQIKlzay;a6?lH^BP(p3V^Xd%{a<^@L+Mn0=YrFZ ToFAN+Z@}vEHS?-V@WlTBcbt#E literal 0 HcmV?d00001 diff --git a/thumbs/hummer_001.png.import b/thumbs/hummer_001.png.import new file mode 100644 index 0000000..fcb331a --- /dev/null +++ b/thumbs/hummer_001.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c2uartd0dn3iu" +path="res://.godot/imported/hummer_001.png-be9ca8e497ec57595d0c647cabaadf68.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/hummer_001.png" +dest_files=["res://.godot/imported/hummer_001.png-be9ca8e497ec57595d0c647cabaadf68.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/hummer_002.png b/thumbs/hummer_002.png new file mode 100644 index 0000000000000000000000000000000000000000..6789ed2cfe7c56299f03333d5dcbb614151b8a2c GIT binary patch literal 4143 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 JmMfcm`adt<=uH3s literal 0 HcmV?d00001 diff --git a/thumbs/hummer_002.png.import b/thumbs/hummer_002.png.import new file mode 100644 index 0000000..6015533 --- /dev/null +++ b/thumbs/hummer_002.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bur6cisexpp2k" +path="res://.godot/imported/hummer_002.png-a4841a7fee62dc784b4b9fa231c9201f.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/hummer_002.png" +dest_files=["res://.godot/imported/hummer_002.png-a4841a7fee62dc784b4b9fa231c9201f.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/hummer_003.png b/thumbs/hummer_003.png new file mode 100644 index 0000000000000000000000000000000000000000..ded36692a81d6598180b2f1930a963d53914f204 GIT binary patch literal 2915 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 AAOHXW literal 0 HcmV?d00001 diff --git a/thumbs/hummer_003.png.import b/thumbs/hummer_003.png.import new file mode 100644 index 0000000..a06785b --- /dev/null +++ b/thumbs/hummer_003.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dx5g2bynue8ks" +path="res://.godot/imported/hummer_003.png-d545e6d04af3c132a995e7ca1bfee24c.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/hummer_003.png" +dest_files=["res://.godot/imported/hummer_003.png-d545e6d04af3c132a995e7ca1bfee24c.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/hummer_004.png b/thumbs/hummer_004.png new file mode 100644 index 0000000000000000000000000000000000000000..37979fce33da0a0395acd3ade95896397c0986bd GIT binary patch literal 3952 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 V$+QHl@V^NS80%Z;)#|v#{|`!rQ!D@g literal 0 HcmV?d00001 diff --git a/thumbs/hummer_004.png.import b/thumbs/hummer_004.png.import new file mode 100644 index 0000000..5110f4d --- /dev/null +++ b/thumbs/hummer_004.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://d3w8lpx2muutn" +path="res://.godot/imported/hummer_004.png-11471605f359a4f101e78ff34b5e7f10.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/hummer_004.png" +dest_files=["res://.godot/imported/hummer_004.png-11471605f359a4f101e78ff34b5e7f10.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/ladder_001.png b/thumbs/ladder_001.png new file mode 100644 index 0000000000000000000000000000000000000000..75a22d497fce716b45075373fe4925666f8b4640 GIT binary patch literal 2934 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 literal 0 HcmV?d00001 diff --git a/thumbs/ladder_001.png.import b/thumbs/ladder_001.png.import new file mode 100644 index 0000000..6ed5265 --- /dev/null +++ b/thumbs/ladder_001.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bnyw2hcwnplu1" +path="res://.godot/imported/ladder_001.png-3cb6cf8bf32c42476432c3538826b9a5.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/ladder_001.png" +dest_files=["res://.godot/imported/ladder_001.png-3cb6cf8bf32c42476432c3538826b9a5.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/ladder_002.png b/thumbs/ladder_002.png new file mode 100644 index 0000000000000000000000000000000000000000..293bbbad4ab14914810803c31d1254ef884cc49b GIT binary patch literal 2985 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 kQ9gO_@!`z>e9vU>Q~i3DY literal 0 HcmV?d00001 diff --git a/thumbs/ladder_002.png.import b/thumbs/ladder_002.png.import new file mode 100644 index 0000000..8ad723d --- /dev/null +++ b/thumbs/ladder_002.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bnntdaecyuisd" +path="res://.godot/imported/ladder_002.png-824513e0f517c632d1b3283c1469eb90.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/ladder_002.png" +dest_files=["res://.godot/imported/ladder_002.png-824513e0f517c632d1b3283c1469eb90.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/ladder_003.png b/thumbs/ladder_003.png new file mode 100644 index 0000000000000000000000000000000000000000..4162fd9cc0bc2d80ebdca2eda66e47cd2629552f GIT binary patch literal 2959 zcmcgui96KW8~-AWkTqL`l07?R$;@QQ)=y+ZB0B&8=gmxw?lWxc zzmx4OW9$fV{-sXHr?>AMXhS!b1{@9(1$gdGX42l<^^Tmi*hybi26uxHuX@B9oURYrKY?0+BBb z9F;}MXXW~Yq+@@|FeS08t|DUgT zUy5)RmU;C9DUUuFPhzAiLI{lxpQ0wI)VUQVqaCI{o;+cSfS*+0&#U-7nku;opq=%F z98n_p=fWI>77o)vbD>&PYc>fsBgMQO*4jI8I$7^2uTtNt-Sehu1-Qs?reGV2%BB{1 zWt9|TwT@z1amm@TRx9WBw= zLKYh-1fJiE>6;EQ|eF>WQDn<1qK6Fbc6+G-&jW%Gh6j8ChFr z)BFpSpiK&Gp-v&Edo$rofmDN?V6F#AF_%)P>Ra8e8LRMAXkzwZ!_zDwocq(iShJf_;gst5X42 z@lE8MFCaJn;{(P(C%?CzyDI~hT_+V)oKW>0^@2=i*aJ!W&Hufkl=38BrlF&}{0xj3 zs4ez$*?46i27?vqhO#H-Af(nZ>6tRj)l~{N_UTsDP9qS=N3)1c^wQqow{KEBY&|1_ zXe*R5cx8Ec*YWn|Ik%6S5{XT&1pQPY##@B(Aivw@=H_xGw^NUqZi;hDOG_shTyAM? zeW(9CY&LSRfuy~&Vc#TlWeZ!tY;cjSuI8gy?S$S>Yi-O|W4R_#s8h10II32k`N+quK ztc4K9#yV?K&8d`mP|x`9%ZLRblRmcjVPOvorjLqt3wsAf)LPd@b^qz#D?-?vXFp^& zagFDJ3ZgvqMfZ<{iMgD6@{4(o7jn}l?*oc6VaL4`m#V;CRvjL;h5aabW#zuL5OtsL zVtkjoJ4X|@&eVCI5(^}(B4!zM#68A3Rls>RHoAYPGHN(9Ej$t4=&~`mO7@Z@SpM_Z zrn`5C{t@7Gt}bl9n-&cg<9bCaJ8$I|*%dOJc4I!Tjn5Y;*g$hw=*wU?e)C z!*}q87?;MQp$kN{zRmCp7x306(k@*pz1U(wZha;3sN4y5-szz*!rv5W9W8vlfh9~j ztmpa$@Wc+1N+REY9fh^KBX|v~0_%74QZR*#nte?NqpZAQuJWm+aZ?sHrbq&*k8u0= z0IQVTK@D%bEtcQp7H{@^i*yU;(to3c%+g`SIg&QAaKNInUj-qtU$}u4n>c8;KY{6&QNRco;dIYYxo z_v{zUxp@knH!fyFP{x4@E9RxQLv3vZF&GR!?OnP>TXwzAS4Ag>`ZrL?%wKV%eV%&* zBO?MxD2%vs5be=1vn6>Q1S|^amjUfM;UX>ip+V7(SI^qpx|FONR(k=k2s3pd}y2 zEZJCwtggNWob}72yRk4;OTneC(9Whh)Y>8Axk zYG`caFLdXYX#*Sz=8oH!!L%@!O%Zk{_COn|m!Puq zfWdSRc6Qde?V(B>w3G6A;&VsKE*CMGUjASiY%lwkMpUD@Asu3K*6h54ymw=k-bS}S ztff7j^YQxASE2_5sX&`w`;C^uRske^9+wnS#8Yvnqu##!?zPzx31B2Km@&wG{(6Q_zV;+ zWfDyyv?PpdmetjbQA~=`+VX#b#Nk2>IE_ITNs&4i*3ZvQkzT+Y>7W;@gt7SZ_z;@_ z@4&fvjUWV$#{T33ykPl81^vAlT(uu+YcuBOA3FNS@ZXJ_sBZ^&vH_1P zUa(~4-QyjJW;IpS&dyF?<$DnewDmYyEnvy0Hw@WnbZ6#Nl1PQH<$+%Li3>4M@$&Xg zUQiq^e*x&)p8IuTZ59&)@%dgT(r*iUN?^1<9%MFra6YXiXe|IkIAg7lmYY@`iG?HC<4U}kJ-RAb;4{~sJ# BxgP)k literal 0 HcmV?d00001 diff --git a/thumbs/ladder_003.png.import b/thumbs/ladder_003.png.import new file mode 100644 index 0000000..0014ea1 --- /dev/null +++ b/thumbs/ladder_003.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dpmrqkuydjhd6" +path="res://.godot/imported/ladder_003.png-004147375948a2ea52f05ea572f1e28c.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/ladder_003.png" +dest_files=["res://.godot/imported/ladder_003.png-004147375948a2ea52f05ea572f1e28c.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/lamp_001.png b/thumbs/lamp_001.png new file mode 100644 index 0000000000000000000000000000000000000000..1356f8e2e4324287421e6fa603a14c73e942144c GIT binary patch literal 1335 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-HD>VEO3j;uumf z=k1-dLAS$X+8=&TINf$bS3t(YwxwiO)~*-p!YAHyyq%l3LFcmTN7A|X|IcJxFxd9o;Q7^wDF@!2{BB>-vu5fl_Jmcbj2)X9jzls% z(qSkRYp~#Un8T`Yj!7V$V&QdhUm5J$&!utiInKEE;EGod?_@f%eR%fub<+9AHYK}b z&rRNP$?$Hd<2I~Ool)N6fsaN4$NuiWabCih?c{Pv)3w)nsw_o2KApX@}HJkF@Iue-|?cD}}&Odj9ey9g>5x=|qw!LF&6Gwu{x1M7^r&K@x!0rD3XTpKi z;q{;1+}zxn{-poxC7$`Bzax)r_uqF|Q}$m2_t(dd-kZw)s8O|$pYzoGcYxoAW6#w7 z*3JJ>#KHG!tJG`$GHsbc)23?WjJ$nHIkgv4a-Sp&!pLH-jp%^czss7tW56FofggsOE+_|N6uZq{Gw(j7oSbu%d`uR zGjiWeSgP#idFbg;*17M@r}l34a%7)yzRK|D(Vh31m;bf9a*ZKl+jbyYSK0W1wNSiZ z?^Ern{>A$ZeyTlSuzGz|#X3Ci@8o&D|Ja*&A3U+qoL)QU@e`f4UFW22%tgPL9_ak* z`k|hyjMczgS=M1fe&av?ON5k!f=O4Vo8WhIGl}?lA+~c)d9XcLZWw6$=*t%U zdSwmqhWW>S`d!i5KfOo2r~Pl2TZryX28I~JpS%z2IcHDiT43{Q`aVwSxq2tBMihxo z;8f67yRWPBw|MP|%@<$Z`!?Yn%S;BD`Sbp`cCBu3VW_iuvMc`2oVjzS$!jj%!NnpE zH2uLr*SFHPac?&>HSsgNFYJA-zW?IAN&nUsTwwgs`R(=|bHOr(59{6kFRK3f<}=^3 zJ}#?iT?kmner-u@2dUuXm^69Od8W&ycER4pQq0~l8P+_Ar$ X*|uu$iy!-eB_V^StDnm{r-UW|uCrwZ literal 0 HcmV?d00001 diff --git a/thumbs/lamp_001.png.import b/thumbs/lamp_001.png.import new file mode 100644 index 0000000..d373744 --- /dev/null +++ b/thumbs/lamp_001.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bpkh0ald131kr" +path="res://.godot/imported/lamp_001.png-7f97d6e134f3cb6e9a7021e0cbe3f125.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/lamp_001.png" +dest_files=["res://.godot/imported/lamp_001.png-7f97d6e134f3cb6e9a7021e0cbe3f125.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/log_001.png b/thumbs/log_001.png new file mode 100644 index 0000000000000000000000000000000000000000..7ead406a103b97fa97f8b7a354077f7cace16875 GIT binary patch literal 3325 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 Rvi(;8CtOdt)HnsE{tf3S2POaj literal 0 HcmV?d00001 diff --git a/thumbs/machine_gun_001.png.import b/thumbs/machine_gun_001.png.import new file mode 100644 index 0000000..4f6eaa8 --- /dev/null +++ b/thumbs/machine_gun_001.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://xh1oboycufg3" +path="res://.godot/imported/machine_gun_001.png-3ce29604df13beff873ead3da78037d8.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/machine_gun_001.png" +dest_files=["res://.godot/imported/machine_gun_001.png-3ce29604df13beff873ead3da78037d8.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/machine_gun_002.png b/thumbs/machine_gun_002.png new file mode 100644 index 0000000000000000000000000000000000000000..8631c3b157243c22a85edbe5d03ca1b61b973472 GIT binary patch literal 1219 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 literal 0 HcmV?d00001 diff --git a/thumbs/machine_gun_004.png.import b/thumbs/machine_gun_004.png.import new file mode 100644 index 0000000..9c5ff19 --- /dev/null +++ b/thumbs/machine_gun_004.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cc7gunrt8jror" +path="res://.godot/imported/machine_gun_004.png-3f688f149e9c692a0c743a6d07ee1b53.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/machine_gun_004.png" +dest_files=["res://.godot/imported/machine_gun_004.png-3f688f149e9c692a0c743a6d07ee1b53.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/machine_gun_005.png b/thumbs/machine_gun_005.png new file mode 100644 index 0000000000000000000000000000000000000000..3de1977990f6140a66bac9ea72ffddc470db9715 GIT binary patch literal 1246 zcmcgs`BxHl0RM6*p2KsJFrz(Nng_bov!)s1fk$b0%{ENUO`R8bqiND8(Rzt(&paD! zKBvCTyL`5%=)faiUN2J$MOa$kEs2UEG4@aN!{>PK^ZDuX!>8;@Fwxk++5iAx9N_O0 zs#W^`(9_j2-!tyHRv=lSL;`4=#H;`SuMY6>3a8a?2nQ(W9L$JZT2EW2C!MymY{@Y5 z&AsGt7V6ruZFSpj5LgD;embP<9d^}BE0y(c<% z*_^#)#fUebPxMM{N)+$(eW59BZCB)r1y$Ym6^bW-;9$B7wf)wBUJu1KfoJw0^W$6D zw0oF+--XJ%1;?Vpz-P3)0%+N9@b|+~60R|YPr^z1Qq_;61|HS)i)L?3d_M{SXjU-- zD7h>VFAEjjpHf_!2Ig680A7Tdzbc@?YLMLXGi!-m@q;aiW45CG@4QwDYf zawfPaKMhvq1ARJT093`R4G`c9ntJLJxarx$+(f*G(DvoGzSZVDXKiEy(^T zN8XOdQHMew3}zLLiwo#((!gHz=zbJN<@lzONWsFYgPTm?kdl%TiRxyNtS2p=LP3I# zzZENE$M9>f#SQMCENZ?y2ox-|A9~W)mm^Rmq>DTTmM+cToyr=`xMF9a9gz*+-ioaY z`OsZs(KE;Od)Gjb%gPzUm6LN8Rp$6u0DZNv;Nx7y*ivnKAlue{Cp#}mBphq6ndvEC z59h->t193}BxYo1zjUE-c9SR>nM$;a$?Z$jq90Bi<+$49R&zC9(`dcI<{xW2_E>SM zv0wgWi}on)KxlLkh_-J*^du`^8HTX0CfXdXze$!YJ&Z^#q-SrREjo_Jp*Fa)Cu|Ch zeZh-seJ~dSB{GMqkQ%B)fBk_QcBkh)-W8bYP`eOGO5;*!k_vV_IUM5uXB1+(zzKf? z-yMYjpxcd))5~#8Fdp^<9HuF1@F=v9s}J{wg2}j3rTVqN783zPn^0Gk65#>{5V9xx z++H!YSe;%c)~Vnaa$c`sQSlt4)?YS g6=7ic^ejgFT#WXPfu$`CUx4hiX$iov&@zi_n7Say z-iUH-+p7OvJOU-6t(%q%+KRLvfqG%wYUM(QK}d~TB*zeM6|7Ev-Rq&AY-w$6`y;S^ zeC#ja-nV9!>?=P!14p|JB5r(TMJyN?fXigEC7G-=0N#%q#kI&u)0JJ}(XfAlAhj`7 z=I$>?5I4R>%b_sAaOx~#&z&80CrNrSn2On=1qWvn>@%f22$DFM1Xwt`di*|{dEL6V z?LHGIW@X?8<&{BpS0If$_=KJ@ETH$)Jma5!cDYELT~F50@=0EXQr08SuSm*8ouemC z8Gc^z6fU`T`}jW=8KkUDr_(0*FFxQD()c6i3-j~8b9$C@yrr9%^m@_^sJ-1%CZ(KN zwG~Km&#UDZ{0hhct#(Pt_&O%DQjxEqQi=CDJNE`ACOSMx;op1EawW`X<9ko_ik_Ez zXkcHVOMA7yU?n48tMVMR6RYC=RNU@*V!`jPFxJ%4^0JB7w!6Jy!!`MO;H~dpv8U}^cQr0Zg zH8fBT*!y_a)SrB1y?F$dw$)eY9y&kWsZS8ubv3`qsoBP`;NHwhBp2UuJ+YZo-kas_ z?*4gx!Ut}&2^S5s9eML|bkwMLhEWY#;Ds6_4BNr)55qK-Wj;u#zJE}s)Nnm#F8eF! z>T9oyc;3gW3dK`+S>U3=W1qn_(<^tcdyiAe4GqRm)5T634hFk~k!?b#VBKCG@^a4zTV8r z>h78}&75Yg5L%?1n#xTnqw5MByi|sR^0RIV4<@!an`z0IDM`1iB33IDnWx?>=fAJv zw<3Zx6MKzS=HmBEJxxwd-ejy>I-DR~*Da&n=4HA;^65;&B_)Jw1oMI8Tz3Bw>{-)y z#%fduP8W0cNd8u3nz%aQCSOf0OEH&w?%GYn#8y^RWC-R%AJFH(z$3NLdcn!5xk;>A zS?ydE*=%>aH5W+$HAa|jFM-fM!IwknbDcV)1N>)n{k{0=|I=Nc%mJ*!dDHfY39{x7 O0)hKOd>P(x7ykwAw_bz* literal 0 HcmV?d00001 diff --git a/thumbs/military_transport_aircraft_001.png.import b/thumbs/military_transport_aircraft_001.png.import new file mode 100644 index 0000000..a00b873 --- /dev/null +++ b/thumbs/military_transport_aircraft_001.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cdsdyfdep87dm" +path="res://.godot/imported/military_transport_aircraft_001.png-87744eba4d595c5b08a6fabcbf7f2c29.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/military_transport_aircraft_001.png" +dest_files=["res://.godot/imported/military_transport_aircraft_001.png-87744eba4d595c5b08a6fabcbf7f2c29.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/mortar_001.png b/thumbs/mortar_001.png new file mode 100644 index 0000000000000000000000000000000000000000..6f84f924574a8d49349d93296e844b9b1e19d5ee GIT binary patch literal 2162 zcmc(h`#;l*AICqNYfHtNB+IBRlSwW|Vxf^;%55Q%To!S3A+>Ueb@3HOoYq%I(V8Y5 zO}SrU7q^jI%aM@F=5ChDLdbFciu1$!{rchgc)WjjzaFp0`<>|Ggx?0)0|5YF8#Y4-HU$(x#^Zp3Huxj}C}W8B$K7r{lROQ*y0cf4_PlZ#>KkxP_x}AW zReToM2ZDojKxB5^Nu<8m*JbNj?%rG6-EH_~>?xK{k*%5w;grr6r1E>2C*;CoAkUBl|1lZh4cJzr2Rwlrvio9O@`83Qzd0 zi0-EF1d|&MSL(Sz9M?-HvlzAR0~K~!UJfLneZhsKmS=YG3r;`&oiMLw+MD9fdQ`>k5RlH)md#b@Oo0?ngK4TsCD2RQrFWNuyXE$rL^P;RxtRQM zjNbw~5Coc#MJem5;=;s>mirh4HJLn6<8p2GQ`Mv#)p%ark8gW-&Ta{qpu)R82;9>m z4By23ZzsM{q!NxM+ADlurxFX%)^J6D4}Z$#NytN zen!fm#C4ib`@05DDV5@HrK{IwGcMp%R@9|Fw%_uua4fyqQVh{Ip@dx00^1-}Gr|Fmos>iMw^L5FgXB*;rxr<@+j6}Rstj(8%(1mP|>gow+guexm*L2qgt9-6%u zh-qP!4S$-$6&=+$5-7^OOx90047(*sV;W4vLv>;K2I>Gt=TYhI7Iu?{2`rgHM>Lrl zy8}#aC+lp;ojvQJdWB$>3HLVF{OjR9`MlnKt}%YoHS)n~DxrM8vRvW>(c_FcfsIO6 zy!|HY;UlGFwEF1z7t70!9$Pp~XQkf)kzd1{rHDFej!E2V)Mweo{7v(WII1GR>&p?z z%1~&V0tuWSwen!sr(zV0Mus(-4hlo6k3fxR(+)>0cW^z2rg@0oU+47&9{IHo+wq~G z8kdeM@yoGhD9lFr&ktg$CGga!I{mo<)PT>dw%M2b(`YI8%D2FX&Q z${Wn1YTprM7={3_Ut63_Gg-p~Tz3ufP}5;?#i)!*SvY)RfDCux-;#v=N)4QdgI z$jXjvRl|5Z_b6Y|41{`v6d%$GSxWZNjSom0TqmA0QZW5CX6w&xxm{P`k*!jPd-WbP zrSe^@p2p~;7T(u>Q}aB4JWD9bxaw@p7Yi`wtzr_?gmwW67LkRg{IQ!+I9dFy*EE-b z%xHh{GOA9DcO3GoU$WYCwLvRq!_2r441CTvoL?c%WVFryM3B(zCiS9{Ov$hERjc(Z zDe=O*?hEiU?i#~me|?$ZS&m~8dxSfPIriqqD^T#?eQzxwGfux6lR4-Wju?r6qWQw- zZ#rc1n=abv-{Q`sx59_&S8Ajn>-Bb55A7pO8m8jp5PKu0>*db8?X#MOwM@I+*T3J} z-tfoCXam2wg@1=oHNqyREK41Ufvs}3#D+VQu-8o)6Dk3Ev+_@=-tV_8~{c}QN`y~_jwTn>9B%Tpq2~~3^N9e6C!FjHaDI3H0ebxFBme*a literal 0 HcmV?d00001 diff --git a/thumbs/mortar_001.png.import b/thumbs/mortar_001.png.import new file mode 100644 index 0000000..f3bdc44 --- /dev/null +++ b/thumbs/mortar_001.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://v84fuy7v5cs" +path="res://.godot/imported/mortar_001.png-75f4699e57c777c8fbc44a1ccff17099.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/mortar_001.png" +dest_files=["res://.godot/imported/mortar_001.png-75f4699e57c777c8fbc44a1ccff17099.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/observation_tower_001.png b/thumbs/observation_tower_001.png new file mode 100644 index 0000000000000000000000000000000000000000..05a70668e658919d5f7566a712a533311a4cd9ec GIT binary patch literal 2252 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 vn?a-yvkO6ThVCnI6aSW-L z^Y*Tzk4z}Tv5)pi0+;km?jCGiBJOKaWhi&+%8@1N)eFUw_k6qHGWk-sX|MT)dsCBb zO+Q}X;?1o(JZnaU!N-Iw8;PwRf?ibu(Nf~m?nZ9tV7EH_#;JAD8-w4q`-QE!Pbz;t zU!9-Ue&N$6ZTB$4NdKj_4Bpe31)eh;v1BOZbC@#-m@&_oEG~byQt#hC?VG`@W0y1e z6P7RHsM__p#>Qsar;JV7lNsN`-a$)5>0(( zUaQxBeEmycR&H1U1LwuREjtTlI+f2$S{d}Y&iL2^1|c{0Upp=9X74Q6`Rqs7>|;)L z{##AXw{FZYukHD7&d$)oH;3)P^p)1L?`8Gnh&knl_jySe?f)Zi;@%ns`2!cM^8;6f znB@q)R!!DmsqE^`KJC0Nwbd&kweIJ7Ui-pP?LboLv! zH#afgSolQt*v^8=!=D&tAK!32jg|d_JkYXd&wiwwU1qq`#^u|mH4hldG;Uekn>Fv@ zpXcTcYt4H<{E*<2ee>k6NS=NAr_Kc?uIh3Ru3h1I-kyJCy}k5rwg`U3sv=EG?Kkgj z7}m63xIJ}ol%8Rz-rIi<%pWq$yKwhrHN%|U6@NG050*b9U(EmL`=UriF2=C3#3{F* zt1fW-_jYspt4l(UFB|XqohC1ATrRoe%8vF>8HeVp_3s!8_Wzo&FFZc$$4Pef3A0`l zvo`?MwldGt@-zaKhE#_%M|tt z2^UkJ#991&z##SR&e7M^&z>}|XL?e}M*qC|mwD&EI-X5jvt9!WDF#nhKbLh*2~7ac CA0Qt9 literal 0 HcmV?d00001 diff --git a/thumbs/obstacle_001.png.import b/thumbs/obstacle_001.png.import new file mode 100644 index 0000000..aa2d4e8 --- /dev/null +++ b/thumbs/obstacle_001.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b6d6aiegl1n0g" +path="res://.godot/imported/obstacle_001.png-003f01cd7547dd99ce5ff0586a20df6a.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/obstacle_001.png" +dest_files=["res://.godot/imported/obstacle_001.png-003f01cd7547dd99ce5ff0586a20df6a.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/obstacle_002.png b/thumbs/obstacle_002.png new file mode 100644 index 0000000000000000000000000000000000000000..7cd7be65aea76c1d14095d471e03ca0a2db183c0 GIT binary patch literal 1583 zcmd6ojXTo`0LOofS&LzdjaDJfdyA8o7>?yFX3--Jk!$QcUZ&+;{G4|p;_{NW6)kmE zb2oDl6Pl2h=tcB2shCJ}UWVb^Uvc+5pU?O6Cwy~BL}vxKIvfB11y>h>*IvPYg+ceW z+xFtXUZm(=&JF-;2rC2tS)nW8r?c@@i`Dq>gA@!u^;jdyf_*4VH&!XY9;T^{(VGW@ z!qATydASG|`9Jq-j5lQ>-cxlAdcbjpPLp168c7>Uswh%&Nj}i{%b1h$eD=$J(VJf4 z)bY1*9rW)7yw7LK@|3l<60(j{( z>W4@-O7`@q^9FVK)}sO8eyt~Ko_7!(o5;)t^2{iFf^G8ryWL!)8joUGEF)kqSdNu3 zCptsXfOT!kjW{AP>pXdQwB$z+l^_FlG0M64!;R5&h5&E7y*(W8un8@Et`_tcnWCZI z&^!ltC}*MW0Hw=TYfBTo@FEYURZ6VE?_L&oygrYn<*MHa*#A)dk=S8x8UDB zzn0iUnUOOt`FafRJKk*UR1<<|J(0@nII61C;?*sB0cXKTQOXv{rd4P1fkYAj=6N6a zwBY-W%YiEUvV1T(h{Q#yO5szkR6yBWzB0y9zto{bh&I1 zxU$B{Q@TFhI_*bvNag0#s0t*-5I_>Msy-5~*wiF75AnNM<#EJ9uQ>|?*Zyzc@q;EeG+~h(0D=TCLbDw1E z=tS^KT`aty;!2)B+ug95+%q$YYDYgcxUGwW;@yeutLi{m2dL#Qh(FJvhn&w6X=fiJ$+efhTs^j(`Nixwv{hz-z`W^&FbDHJieD&Y*m zMJ@_VFHPxW$*Si;pCnyv-pTLzj|!5;v$7ytOWZ_IpdZHcn!W@}SKPe7du(|krr6sX z?aIFmoK>ynZOa|aJrkIJk1My%?@e{DKOMvEPKNs8B59JXcSdjMI$)tym)+4;WOxB0 zQTm1T>G%4N6_7!P#B#gc!#J6>4aiLV$zBIGwp_tq?dE+IDy*n5V$o?Lq8L!jX$zxT zh?V@UrXv49Qma)|4ON~JG->G~IVaz%hq_b*pJ!`7ul`&c%P}Xxrf5^VxtHn~hOHRj zuPrTxMbxR)eHDjhTrujuIc9+g`#e7VV9s;tE7|B;U))uu>M$)!NSF|M@1lR4h3_iJ4>dB}(tMM$6{{_3! YMo{C?!=0?=y$1kXPZ0?$hoE2o0SX7p9smFU literal 0 HcmV?d00001 diff --git a/thumbs/obstacle_002.png.import b/thumbs/obstacle_002.png.import new file mode 100644 index 0000000..d4cf172 --- /dev/null +++ b/thumbs/obstacle_002.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bkg1ju0lxdf5g" +path="res://.godot/imported/obstacle_002.png-9829e66fb755cc762438d224507438e3.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/obstacle_002.png" +dest_files=["res://.godot/imported/obstacle_002.png-9829e66fb755cc762438d224507438e3.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/obstacle_003.png b/thumbs/obstacle_003.png new file mode 100644 index 0000000000000000000000000000000000000000..6438a66a77dcac4b6d6a68876729fe62b927ec4d GIT binary patch literal 1891 zcmc(g={MU6AH{zOsWhz;B*adJX;o?MO0!Kewj_+ID%#L0p|&p8SdtJ#sWFaLEmKPs zLnEr%F`>2^jIAAQHKamI(}g7FG1Ss0kNGE_d2zq@#XaA1KIgu)qmt470cqYewGMLnTLCGtRd&__~JE}IaDSDOhUPM%k8o69x~JXttD=nqjNoZ!ym<+PHA zImnnl@0tsQV^Z^qzmIN@Pb^c*i7Qld*;nIl1e=Lv3)|xi8AF^+G)&nEL69s3Yz)XO zzzewFk^iL&dGuq|E~r!Ss2#+`1fCafQ=$o*V4Oe6Ayiu62gi7 z>(&>j*rc)@&-(RW{@9FrqPCXSPi-`1*0|gTSN|BaIM~+!nqA0J!#-_}7y`St%i*3N zPtx@XUKtvUGxc4_6*nYbmaCtdXMdkV+0Fb%FHU}*;OPKwM(hBNh>Zp}?oUELY-YZ^ zB81oYJ#-ZdN+N$NiCmY>dMi5}OU~P%rLZ)!a@oh<#CUx$#cfD+F1>V+B$zy=E7Y%R zH2d?TG_EBMez_X{iVJg$2nV@p(8HiLfKSg3u8{qWJ*rG2wZK0 zbBEAdKwAvkohobozSn{{Y>DRSDlrPB(RNUf@70npXaKK1lk;D4j*8U#ubEtJ*;h`q z65)(enPBb(=yB|%bJ7m2gC9pwM0Gy(>|9KHw2S@RwPvN^)gCMo#VaL*u277r@u&>jT`9tDTEVN% z;Z<$TXDdQYX!JnC^4jM_j^N0l&{Fr6hTEMf5%zE-ieLmHQ-Ha(5Z|oZVM(gMv+1dU zs-2%~=g85fz9zJoOR$YXPTlseqc=(Qhou#!A&gP=RFFe|-aHSqwVisqyfQut*jSA9 zQ+CMzkxMcFiCPYS=dD(EC)x;=*ahU+4i#;^0;K2p=oya!7&0b|!3Y?(c6s;DZ)K%i zza2gE5y~f5Xd-ll6E=D3Av@zIeK<7U%UeavR_F*_Fy$rJQ_<5d#FgMO?%2C_#Hl&T z7Qw}#Lt3nif};IO^3fLw;-$LBAuWi6L9+(v*sD*<8&34OlkrKql>D;J6S6J|a(Fi9 zT$nLJGAVTS9Nan<$jyVsJCX~5!fs^+hQ+XKq1lD&<&*i>`#5HCe(pqzfQ}I?4 z>Kyca7qACSxL{p#Y-1b2(n~m?hgC{I6##fLrV*f28XjL3+yUlBVl04ksdRjJw}duN zvxy9N0Z=1S?b6<5w8hwv9ZDBPONVjklA{J<)p?=%Bc;|=Af}~Z=Haq4 zW7}HA_s_d&vnoQ@>MyuH6A!gc-%Gi)d{~l>?i;B=kBtc-Rh^@sOQNvZ56(&WotIww zIK5K-zAj|t*^Ll#;3_c&}; z+vAM&UHRI^@(~q8^->wz8u595+F$rvtRqWP#i76S5}D3Da6~n!;K{Z9OfEL|=#@|g x8AFHBQLUM4&W>^8vCShYXCZlR=>Pv7NQ`*f2m0lg72w^~1UyJoB99Ql{vWn+L*xJe literal 0 HcmV?d00001 diff --git a/thumbs/obstacle_003.png.import b/thumbs/obstacle_003.png.import new file mode 100644 index 0000000..053a12f --- /dev/null +++ b/thumbs/obstacle_003.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b7tdyurwsi0uq" +path="res://.godot/imported/obstacle_003.png-207110653c8cd83481863f857de8ef63.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/obstacle_003.png" +dest_files=["res://.godot/imported/obstacle_003.png-207110653c8cd83481863f857de8ef63.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/obstacle_004.png b/thumbs/obstacle_004.png new file mode 100644 index 0000000000000000000000000000000000000000..7b58aa87eff1bc243d3c45bcaceb17fef35ba7c6 GIT binary patch literal 1879 zcmd5-`8ON*7XKz=X@gozDukl;Ej0F)Mo}6{s$&#Gq-qapnIJ~0_NARxYiVq6GUYrW zYJa85ASt6mtF;8NgcnUQ)GlL|^skut;of`BT|Rd?_nw>Q>ER*;Q-%Qmq+G9D#t9|m z3!M-X@_~!^5ut#@<6JO+F{;7`KwQ@K@+EIl#YQFny0R-gC;c+cTEwxQTWh#%{18pb zZ~@XU(QNnVi9Z|t+MhJ&kbpjtG#HO&beFK1-b}Y(EoZj$Bv!2KOfE#6w6H4wcJs~o zU2{&%cMqO1e&OY2oEEtB?9D^j_e21e3b4ZX|t^e2i5$AJSY;mQ6v%gcnh-gLEl z$aHLZ&rHU_=E6Xf1>qL?CQZ3k{5ObJoAm~Ft#92-(WjHiGO^%b0z=J#L(>!?b#tMN z)#>B6b-n5L2!jf-D+hqVQic~fOFnQPF8QwQJVxl05UkDHVRgCa>gqa}w$+k|ophww zJxF>XwzhqgpZyc4Y;=e3j4{cRbKVlPcX0ELt8pKEe!gXfA3{(X>s78s+QxQ&LRqVJ zLZx z{WUzMR+JaK0<$dYRC`nzWn*dP1;NYq8{t>2h#>?elWd(>GP!WOWpiufy>W9x7dI8i z>}17SRg`Q#(%bd`;RNCaGB+S4H1axT{piS=Y+k@sRW^YF^5NE{&o>Pa-P1?E+aF(C zbV~d60icYJ=<_%}^$c70=M8vs;#D9LN8_~DIZ%>`lS z+hw=sds0D7nd2=3YaNGXzG4^W)NY~$Z8|}Ma)&m;dABzE*CKOE1T2nL+P1uo78b)! z)spiHSdr}#&}f?M?c!p2CZY9ig04c0JsFpAf5A}>sj1`SwYHiwmw3Co-g|cJd~$DMmL1tsvVaM# z^vLnl%@l&v=Xra1Jq#|7oqJzpAz3I;Shg#^1e6NwwToTbzsFRW+MtS`>uH4$!yUgs z@Gek>Z}o3YE9@T};5%n;5D;s~rH>!KB>tqYrq7Zp6g;}W0Zh@I83O~3AM6B>j{5B~ zGyIHhfc+H<{}qj=66#vl=zghiBo)UAtqzpxghVDWkD5drlltR1xEAOMRs(q$Plh=Bqd zVU18ABY*MklcE60l;ak;!Pml#3JUrl9_pCrHa-}?!~3=AqIUILEZ~3G_>I%ug1U#a zkGk=Hl!T32v$+HvzI*s?b_tUj?>N5x>cxK*!J@P=WQY?!*ZE^Ppi-$^IMEcYuv{{k z6wKoePfoh9>QJb53YQzqz7y(*rWA;H!X#pu3a3vC56Yo)_U_tL6P=Zk)*3ujZTR)# z;-Wh5WcBNPH{dzHVYq#s-2fhrda;^q{d`BS2pQA3noiBVH; z|F*#3SkR!#^%hZX^_zzlmW`vj+lO^l4b2yH4 z4c5a>@msv{&wRdK(t&h4!)^ZI=~T$DDO_^y@Qj9z$dwS-kpKM(8HZ@t5E)_pd87rD zYwCROTQwRY)GofSyLQv(Y|QXU2(Q#qeqX9=_Xl|>$UT|`+G#6=0DC*=A9xafeI?2= V$@j}T?ht-T;OgXYnSlw)_#3&oNW=gD literal 0 HcmV?d00001 diff --git a/thumbs/obstacle_004.png.import b/thumbs/obstacle_004.png.import new file mode 100644 index 0000000..59506a9 --- /dev/null +++ b/thumbs/obstacle_004.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b7vmv3keroksj" +path="res://.godot/imported/obstacle_004.png-4f979e09a2d428d6379508c24c5aa18f.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/obstacle_004.png" +dest_files=["res://.godot/imported/obstacle_004.png-4f979e09a2d428d6379508c24c5aa18f.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/obstacle_005.png b/thumbs/obstacle_005.png new file mode 100644 index 0000000000000000000000000000000000000000..3c5f4aa7c9e77f958385dfa4756d5197dffc1428 GIT binary patch literal 1525 zcmcgsX;4#l5dXhO%wfPlV?=Hc1;qmq3&aTF2`FdN)M|vF9Evd@1}sOAoS@Xyp<_kV66#446sLawyX0__d$?u)8z6zddK?m&o)uq)OBx0svH< z4?D0>i+mRRT2xDIeLGMCU0@x8f#jLa3;@_lX9xQuk-|CAaIm%`rG0g8;C_9l=);A4 z2#;lQOPq{03@{0s`{=M>?XF0~7S=B;R9dnR+HVUL1XM^!7(B=zWlVZpTSOc|n z3>_+By#s`NjX-EA&fNWNOhk#Ib~H#f_u{0yC3d00YI$U1PRbjhB5rw$w0uS;1Pj5# znzX6;U`s$SqQZl0CiAjbk@dmBk-Rd-v+P79#%JI`1#eJtI=9g|1oLTO; z#qulw7%HJKqX{lT&OcnzC@U+Q{)xu5)Iu*(EwJabnYUmMZwm2L z54CyD+gIU0zSgO&H&@5>^v<6m|4>w%J;%;mV@mJr&5s8D#{`_~>DXOCP(Q&y>~^yu zwOnUB^h&bBzDq$02xJq;j^E#7G0zly$D?{vB<}#|P+^J-B`UI9dnD%%z8DACTNz{( zGVBu@dqN)Vh5h0}h%-%zc}beiHkT7wUGsDk4MwX4#Cu;xhPjF%+R6I_h;tSLWfKa! zREM_v8Bdb7qBW{OW}z1`*iNw4u#-hG90)#6GnwC$fsQwKX7*&hB}s z7G8w*Hbr})n1tyH)Nj903y#^w+V#ralfp1}^57?a>QFgV!Lv^(9H(XZYr)*x3|5-6}iL1&%Z^@eu_*B*O9NVj9&; z`@8leB&@&O8E1Iv--T7lO$2#@A@wixxom20Z?7JH)WB5^JuO+MEi;gWK~OSwakbYr zIXStdPcI=c!44;A7&bp}CoKAjRj(DW%iSM|r7=R`()#(3 z3nZF&Y-LbJatgJnj(Rzr760cc_D+!gHqFU=rh0iOwfOf&lOT?i2lc$7_?=KK&uqnc n?JrH>&%B;={E9U7|5UgN0xvxdRnnmml*fUyqlbe8_KE)wR@#X; literal 0 HcmV?d00001 diff --git a/thumbs/obstacle_005.png.import b/thumbs/obstacle_005.png.import new file mode 100644 index 0000000..36ee0d2 --- /dev/null +++ b/thumbs/obstacle_005.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c2nq5302is5nq" +path="res://.godot/imported/obstacle_005.png-efbbf9e7ecf79b200ff9c284af663b44.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/obstacle_005.png" +dest_files=["res://.godot/imported/obstacle_005.png-efbbf9e7ecf79b200ff9c284af663b44.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/obstacle_006.png b/thumbs/obstacle_006.png new file mode 100644 index 0000000000000000000000000000000000000000..e0081572e785465c23bd7deda3b295db265d3a14 GIT binary patch literal 1179 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-HD>U&=_3AHUnN`S;(NxaoHy%c~Raowwm%oV)T{ zU$Z60+EPz`he=BrPG~X|aW%|gQdmw`=JhFG7#c#ADKNvjs z=kb4&|9uMQl2;K>H$W}Jqym>Qd#lW~S&AGBcGB6x`qO*ckDAT@+|RH6RXxc`z+n$p^Ni>Sp8}PS0StD!-upkt*XQ1v@xUX?d3zJL z$h?~GH|ozwu?jT1#r|jf%;<8TVcM*hkAsa1d6(%)@+(Nap8m7w49kV@4?K^queJH5 z_hHA^oBR@73#8Po`9)-l)$5(3tJk&%2Y+GQqVspvi_&85?$h>RKCN}xv5WZ^+>z9= z{w@9Ii1ii5DYO3aWbb#DcDS+h{;yl_1K0xIJ#nA=*DZ`8nbE~YJASqqBZFN3KK`0{ zso$8F*z**HH%y-U`}1+F*zdpP?YdKaJU5oIu5hZ(HfC6NlV5=CLG1tk>m_}x|2r*X z;@B-K^ZnfYLv9yB7#J>?i^w?2Sl4&^|NgPUdMa;*83Se2VP1`F$P$%Je&D` zMl@5?mOs7aZ|DEN{9`}Qs{j^-r8D^xHvBGlP*z)$_4E4f$m?~-OBkB(wojIGx@#=k zF!|@V!=G=Q{nxnBr*3gX=WO0OX$b|+gzMMNrp|vaEwxgs#VyUOA!vHN`EU2<*Trp* zOEleNXxcGZzD<*5GGj~bzqo%r-|Tn~P~;{AT+ZGZ~f`sWEBn{CxeE{3#cPAWLD!7^%A05}(cXQo@W32L(MW zg1<91JpFs%M@g8my;3pbiB~fsnU)w)KO=tU|6m{`_44t96Ts4j!PC{xWt~$(69BLV B0&D;P literal 0 HcmV?d00001 diff --git a/thumbs/obstacle_006.png.import b/thumbs/obstacle_006.png.import new file mode 100644 index 0000000..764e82d --- /dev/null +++ b/thumbs/obstacle_006.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://daxxt4wxe0gdd" +path="res://.godot/imported/obstacle_006.png-1027d2a99d4c96df0caf0b63408456c0.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/obstacle_006.png" +dest_files=["res://.godot/imported/obstacle_006.png-1027d2a99d4c96df0caf0b63408456c0.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/obstacle_007.png b/thumbs/obstacle_007.png new file mode 100644 index 0000000000000000000000000000000000000000..5231bdcf6363484fcead8083ff93665c7d9ceed0 GIT binary patch literal 1688 zcmc(g{Ug(P0LMSym2#7ZNWzSfJax!JQ?X1WJ&;Xdh_KwLJmk`1Y?+5vZh74GAQGJt zI}ahz#!aI%6L*uRJ*3QYL>`NC|HR!7@AvD6_xtDfn|{*WRS~WQ2LLF#9dX93llrgZ zH?2DtbGCgQPz=u139vd4qX2BexjAFKNO_a@`|;Yu9cj8sTof_K$;{AmKW<+NGTO9n z=ArPZsP?m?^w7)AFHUx(`N+E*(JE9QMa=}iuIe2I zHmHWHVp(`~b;E3mIQt6cGap6_SWz}Q*@8PW0U5t?kyBy7^$_ZgcBa%QFCcvk{`7>B zi(vAu|673foq+7<9*kI6XH|8km4p_VXg)=)1?qZ=6uv9f3k5K{v8Xq5fxO}`LexP{ z04F51fPqtWlB3$g(1x|qB2v7~0_Qg4=KWIS2NWW| zR(wf?2T4CXF(5l2PxPX7{eEXf(67WRf0!XHO2;gKKYLF~&p44tOerlb4c>ybxUL~t zZx6=?#W6*M=jRTbyA+4K)ynmtp}|Om_*a3n>MkLPxEb!}(ZajtJ`LcYkoM(L*9 zEqYh;#!@vec&FW~j%C8w*x2p7e2ce^bzl$7zfE=dw+-3Du>$t|Gnv4A_q%%8DcF?~ ze!^@ekw7s0V&7Hnk_^Hau~yY8uX^4GO;x8x7-qIL8sBi%NA&gc=H_e?IR)9GaFB2R z^C#g?#vGbR-&sB*bXRcBjFQ;gJa0g*$yL01_tNpb&~QjQd45%CM~ z#L$$hdOnAp2gXB*%p2Ksq4Ecd)Ko%kvEil#LH4 zg&u5mdrqMG7y7w%K$rHY=D{9NDwCR}16YC_@K?t?_o9YQ*E?C*tk!Nn7Zw(yI}+q? z;%KMJ?f3C$5csqg)Ruqht`xz8%1vq9-dp8mWuchbM%MU#b#M6e-~hap4oNPS$-ezy z@T}YW(#;I|N82M!BvL|l>zkwAtBbg(PX{cSgmOe==`Mt?dg0j^{oBpiTHiWDJUU|9 z+XvTh*2rH79 z6%*N*^M{N~k^*2u1fCyKS#W1%vi)T!t>mxhxgYiL)8LR@2cB5P;o!T zNaVh67dDB$yZIP58WyTBxJ>^%IqDwIu6c^qw%s4cSNsaJ;h6rqq({ji8+{Zo*iO}L z7a|f0Or73d7(cq!(r;1yIrTCzpl2YtAHwu10$|X4K&R!+EF!IlEygw+Y#(eji{w-f3f(vYObU zx>Sm-R!M2;n+b&J`E3EfCsz+T(T_IA)=DgT^A~j4I^^a|CX%57_L?`x(LBBkuPP;S zY?*19%t<~YEVvykrQ^auWP6NxGV2GJ9 zv11pvM>0z*k^_g5UJ-}t8?0;=$wP}_cQKrB`<$8Y6IH2!05N+xYH#Z4@Fy&WM*I## z`j8pe!6AEkN~aFCNWA<}j`m1z2%c;f0rhb$5Uj`GsPyE2Hm@>@p#FGOZrX9y`qcn8 L7k6itQ&7@B%_ICf literal 0 HcmV?d00001 diff --git a/thumbs/obstacle_007.png.import b/thumbs/obstacle_007.png.import new file mode 100644 index 0000000..2983009 --- /dev/null +++ b/thumbs/obstacle_007.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://fbb2wc4ueccy" +path="res://.godot/imported/obstacle_007.png-ddbceea5697f2664db0ba0d1e27ed39e.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/obstacle_007.png" +dest_files=["res://.godot/imported/obstacle_007.png-ddbceea5697f2664db0ba0d1e27ed39e.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/obstacle_008.png b/thumbs/obstacle_008.png new file mode 100644 index 0000000000000000000000000000000000000000..facc3db33878db75598d9f6046a86ff3c7c3615b GIT binary patch literal 1254 zcmchX`8(SO9LGP2FNrwvU0vy<6&^!9_Q+$@Mn%Nkx*tz5M_qleGFFDV5=o=0Dyv{gN?^A zSs#R#IrdIkQ2#M7u^#pe;17})0gw_$8!OMmyDP$W4<&bUw?wJeE<=^f$uKqw2@%VA ze|5Q1fvfnX+YDaORq&8&ro3HKo9<#>{f|YxyIWRS<87qK`?_%X>s6h?=FqiPafuM6}4Pt@(7PA_Xrn$v$5R+(Y14=gUu zu;-aIPkahs{BYPI)&G|Y>|cj{bKgKCr!tV_uaJy!ScYJE;~Wp zf^TLwIeu@ra!%NOf}l>v4JW-fv&oMN+X|a?q(?nqo{uyTIko!XDf+a-Jk3f|{$w=y zAkGIb#e8>&bEY^6CGxi8N)#Ve#-R4|mF^5RSfSpfoDUZwvZ``s^`+hD{4gwo;ldDxBaN}jg8}(!!P4V=Q=%O6c zH>xVC)o^~(Z*K)h(uF`1>BqX!j!5NLjdI(C%iXd-$`r)C{zqpBHV(g6d4*@k}a zsT8p`GDbKwqGpw>(bzvu&&Mth03V0d+ha>ny=sE^0iCp1=o|0AQ!- zJFoKcDvXV~r>iUR^&`nr(9WJcU)(Et?{!ZE_ zD{3ZdS4TXr90`)9j7kAj5x%%ZOHN3n<^4KC#60*jVJDu-PvH7J!-4|_{1IE>>Pl=q zl#Xi-No5AxQXq>|o(?2^0(+^D#RB=N=MgirDnJ2ixr15?{KO?#L9TZ=9tph8D3a+A zq8@hF5@c+>Fnk_hi+~$iBttWxmB_j!4jYHBY0UgKmqWxusu}WMZu&q<*6xB*s@j>l PV6pUcaSW-L z^Y+eZKjA`&V-L5x3MVP4a0uq|aPSir%}7qsg_ zS+l0fvK73oOCBup;Xk~^=k`mU`+MH!yYf%*+_(JyOusfYF|q0E7G!w4?Pb)u#nNEI zsNm0VLYUzb9hmQ2_c9*d_UV%*Lqc7d)X6VSuNzqc^yL^B?(O+2a&*~Djl{pJlVlm* z8EwAIaG{gwK&q$4t!`b0^+x^jj0}?`#k-Q^!WpJr{}B+t_+eG&p{+qz)`xdJ-Fn`6 z@4wi7xrW^(;sOrY-v!l0m>w+t(zE$>!T+@^dh7X3rr*EmqR7BJW!}uJe|KUuh1MSb zZnq}+>*@0owr6cPQ_pke*{6ld8gu{T-L=Tv^LcgpbB}YWRtgaw>P<~&ZhT;5T;R{( zHgVxp2L`tbuiAQ<9UK^#-hWyl@m1~1R0ft1qp6)$!faj)Oe?C&?(Is<_|MPba6odl z9ZQ29By1ZFY})>xJ&8$S_G$OMoM(0BvM?nvIq=S7V7c*BKl**01H+4M!G;%nhbFE3 zdE(!<4M#Z`1X!E;E+1g)mSnh^Z^)AH`Ey0cQKkc{#m~on=V-itCQkH?+^@91iqnq$ z+je&{gTOn{_t*TG7}*%_)ND7`ntr;1|3T?1$J=`q6%6*>n8937Rn>L!`Nm!8bIySbqukimhu@&2Zr&1M|R z5vy|7{bS%^mRKUzlAsp0*3^$#dY-*F!*T_|h<+i42W!|4$9qoMQMP5*$K)5+yOfIO zGc}!a6gX1Ovt|C0sQ*7oUtH%_{(N6RDCMuxifiW#r_FNzyQ1U$_vNq)8sJeFk!&=^Zp2rz%SA}S;2+^9?e>Cw&1H+F~y$X7V*|%_i znA`l|(W6C`^S?f1j$*9Zwm164uLv2Sn+~kaeJ_^h&~X}=lz@s9{0_6TELdOlR%neH o!xK)1N+ySS3=`C;#Qe_~r>7Em?C;92z!HVQ)78&qol`;+05C-AX#fBK literal 0 HcmV?d00001 diff --git a/thumbs/obstacle_009.png.import b/thumbs/obstacle_009.png.import new file mode 100644 index 0000000..8b8195a --- /dev/null +++ b/thumbs/obstacle_009.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bxhmucxkqh10m" +path="res://.godot/imported/obstacle_009.png-a837064651bc36e09af57a9798caafe7.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/obstacle_009.png" +dest_files=["res://.godot/imported/obstacle_009.png-a837064651bc36e09af57a9798caafe7.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/obstacle_010.png b/thumbs/obstacle_010.png new file mode 100644 index 0000000000000000000000000000000000000000..114b7079de5e7a2e85dd1ac7c21ba9a06381dcb9 GIT binary patch literal 1137 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-HD>VA1w;aSW-L z^Y+epKjA=`qaTBlgYNh`WItjH>oDAO!DCSyi)YE=Xn7_%hkFOvKgb^Gl{QaO;{LxT zMRAfx_y$GBmMK$x#9uAi;?us+Sa#Xo&%2-3ge|@DP3^n&cfaLFPpy6V`@g~#y`6Fm zJC-t>&}1m$YM8^Mu$;!sJE_;1cdS_6FF$YR`@_rE^SLDjAAR*-r0V;*l;>p!2$%}^laXx;GKd>sRW+Pe6+HfayfK7Yu6M&NU_!=$x$@6WyMT^!8N(0NOu zfr}v_F*0yVr6f>dZ}YjgOLuDeTsbBX`%7&4exCXORR>{*7!!^KqDL!o*SxlC)7ZnY zAZo1=&*5`|u_u4p+}@}Wx4+`b*Uyh`-*dE?S=})8YQAOsU0!`Zrp9ZX4>nJpe88lV znX%zx_G0ygTjxE!`|tjh`rv08dmJu?%BV&6KDBi-k*yXFJ3DS z)w*%>=E)yDd6l9J7rGcM_VRuB^d#0{R)$Drc*o(xVKScARZpGT&G0C0?Y~!d&IvOY zY}8%+W)HuDmOqb!;cDl|Kvn_KUd9vqt&SX>{(n>aq-DGc>+WBD_}KB+&Hb#)m?NUs zm+uwT@w&J6kkVyF9%mrU#d=|RnLuRNJg=pHmiOGNQ-1O7$&S~GGalqJtc$ex#n{iZ zB5d`#_6v!rpMY$Q#q(!JuWO&+#VDe|;~ea6zkuO|W&=~C^)E(Nhx0WI*{@5lI~$y> zVaR-zo*u)$@X8*(1-3swZ#HgiGw9%75VP=yPC|Kk`HS_L52Y9$R5IwP-IKb^=raAQ z+v1C#H>Uni>(f?a_PBMvS;52RQM>8KvuVW|>w`^-8Sl*Ack}D#%F}!Le&n2CWngf3 zcek*!^ZPSbZJ+(Kdu(<8H*zvaNJ_rkRlj)O+LPxG#xNYnWNA?Qx5y`t(V?6rHTkI& zLqZAbghv{X6#F9h61(HaZii`hjUf!oL0{A-G%sRc%gE0^|5YGJvw?A=!OsRJjhMAz z#>QYq$tT?y0i$Zw3$1ng>Jt(_F|K8pdG!2?W(AAy8^hG(FK|s*bv=5g0>`;G->0d` z2Qb(!-P^x?+kN$mVi%kjU$iJ+{~f4@b%Li2Q#??$*n~*yrWd94uP5_ou)bJ%{l4rk zkbNFox5e2DH|bC2*JwC%?b_=Mv)OUJb_*DOJ-YpbnX6$QmGjwm`Q7Hyzf4%3v;)f! N22WQ%mvv4FO#q6f@x}lE literal 0 HcmV?d00001 diff --git a/thumbs/obstacle_010.png.import b/thumbs/obstacle_010.png.import new file mode 100644 index 0000000..4d12db9 --- /dev/null +++ b/thumbs/obstacle_010.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://gv4u5ep8yxu4" +path="res://.godot/imported/obstacle_010.png-c436677281ec794b506a4719e679614a.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/obstacle_010.png" +dest_files=["res://.godot/imported/obstacle_010.png-c436677281ec794b506a4719e679614a.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/pallet_001.png b/thumbs/pallet_001.png new file mode 100644 index 0000000000000000000000000000000000000000..28ccb5e7b6abe7b84bdea5bf688dec3aaa45f37b GIT binary patch literal 1481 zcmc(f|2q?S0LMSuY_kb#x+uw)=1aO7!j3g_+FCQ&((a^lw`n0KksevTC2C6v#f7I3 zeZTYga%u_H;)zN&or>MeHgUdgh_x|S=l+SiAKvfR^Spn2Kkw(A#|ovHqt~MW0Os`F zl&}?M|0`3(igyG=b*}(&Jd73u>LeQ`0D$MxDc`dB*EAKRR9mXe*_mXwhJ(c}xXlM; z7GE_UqtT|=xTJCHbQK1TMPI8F1V+tUtzwT9osl>%!t-tx>=z9V?6q>eGES+si#zdY z=axktS)1wpvUPjY*kJ5Xc?8jQ$hEsl=WzHWehP_^IYC}r0wcRYG7k7*vp1ju3rrkn z(4tNMSKL;mgB^OQRG!*ySbolY8g0PI)SiFe*(jl+P_H6*n!tqFLUQ55m`2NO6)4k`>7__3xd`|sg ztWn>h$8(rjirDE$WT0A(}GIv>(*T6;x@t7SGYZwTk^eqI4)wsq_2QA7rk+ z;6jOV&qjHoi4$92`8S6U|N_Xtyl*-{njt`;vR)}6s-&lQCNz28@ADG1V zA<^hWqJqtPx9mIRM~)Z?&OR37rz+JOH?_+fV>Cg@(dXi0ee*#W@~L+XT9LJoJ{jxB z@UnK;97r?~yT9X|3D{TOzWmEb@9>`mn?iaL37Uej=iY#&j8hBAU+ARHh@wT8q?v|` zlcS8>8G1E&F1OH2w6^akFU9%e=VlS(`|)F%>5x70lz5nI2cJ~paJx9I$!GYUMEDvG zmauJp+Eq{Fjv?3<#kRa=73~d-r9{=wDUT)yEBm*C2Qgdjxm_bZ!iXF0v#3)I6?|!& zz+$2F+#}B`=kBVCJAIwX){#j%NI~ltNZ?2zMYgdZy_~fL(C+rylvqoqR*A|etPxp7#^z?? z9;O&=L>Fy|kpp{XFU&U$koe{xS5{^1MTP@$eLMleZLsvfE~Jsz^^xZjtZ6N(KAk6B zz7%SfjpU1mmwl$r3k7)U##iJbE6DIbWGl*mowmDAd&NbP=}9N-KY2mG@y*m)qsF>o z&bB8LETV>r;vs;0Ji(cLOT**!_=j$lFxUEfeBG~AnjEREGwC#2lQzXrT&{Oh!{95e zOjI?R(<-#8`3MtBa4Iv^bzys{AiYw*W3a3hVHud2YQOR0x;Dq~t74osAwh^M^X40! zU*CKNTdn@Vx%$afWkljW8%T{u7gaxC(-ns#Yi6v5%6}diQw}J)(j>WrH3tA_oUu4E zDG5;j#`$a-S#_wBNxVwocgQ#;v!|gN$f{3XNpB~HcM?pw4mq~VbPu(%VM#VWn%+MF ztqi}bGCylfh3G{hn6l7c(JMV5)QA~n#b=aar8}3LgqCX>ptz`Tp?7)?ZaR4e zk;su6?KARg*if5L_n^W2)Ou@D#`T*}pw=S3^l}ps z$^%cs5QcW7DI5r}HV~U!0t?MG%uPw}bs%5BG5+x0|MZR|U*sG8g8#tG3Rk`v(5a!6 Ix*%@OKL!PYbRQ<(>?Y@F@2p?SDY`W zQfR*9%ROZ?ne9YK3L$252-hh|88dG8Pu%_RzVGwA&-4E9zCXN|f`fdG^tb5)0AO^0 z>U~hFoPVJQ)3S^b+pQJI*@M2GKy5E}4ghqU4|scoW)#ntyf`=-X2y+46WO}88}7C& zdAl-d`}yBerH|G3i&CQ+vQywu5Bxh%(8x|jN)GvEyp5M7Y2;N-YPD5F zLw44YMKxu&;TD(Iucnwwb2m3(66bR94uq2{$A{qr?iC$^FUYrobY2IhsKA-+z+N;5 zi*V=tU-sweIuxy7fZ-%6&BrGjeWG%6WlN<#gACmM^~~0<+kljfk@1;*#R0@caGT`anS&)$ECRLg#otg<-n<70m(`HF$8^lyPbPsBR0i9 z^9F&pEW8nHVt6j!GT($SAA!{I%6r?3V{eS$((#JGVmE6LwNtex3x;rRRC>WL zcSZB=Ox>ET`C#lUc+4iXHM9cd8hE0v{=%bUK4uOosrTy24==WS&UU?M?lq_NByC+%ERUxEfgp0JBZk7yY6gIe6}1Bq1SCB}lkzl{ zHI-d3=u_8r8A*{-Uen)qL?+?V-5%NZzP>Sj&n3+Wh)SDKQ2A3cJ*sN z%Ip|zL!m`2D77O5n0}o+uz(9-v^H!iZcSf+0bJIosZBo!)apz?f8XE4>zmh9=Z+(W znVEYItG@mi6)lCIA#h?}R>8QKDz~OfO30n3UkK;a2~{(NKj~DGT9kVlO~sa0fi%aY z?_-vzDT9tEL)<c4!N#Ns$_y#cFb26Ph4@k z931ObJz|x0$`!iRuFTCxD0|;8t^KVkUCxr!qFG<=On-deTda1Ls_je@&stFUGW|YO zvrB;;(RL78_4C-AN#(nmmq`oU>u5>J;mrZ6kTz%;hC;jt0uwVZQ#t*?@ii}t+l}K1 z@w&vOZ&V=Af*x)&mx7@!iK;SVio14|kC&Dc_|u+3XY;KTr2*|tqGr0+$+a#n*!{(`{6Ju(#k@dRSn)}n_RHW6|Xwyei zm=tI3LsiEa;0eaSf;AB&!svI5B@09Jq=5p3e@*-8 Oz=8ci-nE{z^Zx)~)}L_z literal 0 HcmV?d00001 diff --git a/thumbs/pallet_002.png.import b/thumbs/pallet_002.png.import new file mode 100644 index 0000000..3013a5c --- /dev/null +++ b/thumbs/pallet_002.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bdpjb7f7l0bj2" +path="res://.godot/imported/pallet_002.png-5441dc095cfac24679d9c7c4d6781000.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/pallet_002.png" +dest_files=["res://.godot/imported/pallet_002.png-5441dc095cfac24679d9c7c4d6781000.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/pillar_001.png b/thumbs/pillar_001.png new file mode 100644 index 0000000000000000000000000000000000000000..db1fe9fd1a1aaa00e696297814ccdbfe86b89c2c GIT binary patch literal 869 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-HD>V3zlEaSW-L z^Y-p}@5_ZU$3I^GBJF6gVS(Y~h*oynE#7Z}w&zu@c6M@E&ho#*%6t01#!VSn+t&nd zpDMfSX%mk~w^D>lq+(>=?v!@Z=lv@=wx0iC7vF#R*}i7;Hz%L}{#lo3Y&hZU+EW{> zocI$GEg3A>8J;sdkYSj^+)&I=z{hZo@c=1;J2bv9D8`=os@bJf`|n$9Ypedkb1q>8XUhd_%HipRsHbPy5qj~b1w8hO;z2!D`Z`WNk!%k*2}G;zZu-z+e*r7 zf)*<~N5^TOJCjpkH%&hOYDBKG;B)y72|1h1&%di&vyEFBW*S)W@jY9X^TvD3cdGu> z_#am zn_aJ5_ao?xKcn?ZcLh)O)!vNioZQk4S06A{e9JKU!jY?bt-4|LbHDtGc`x5yd|Ulf z_jv5?!r<1=)1ytpqB~0&wsP-2=6bHZfBu&EUIU}Owv(1vACPt^opJiW+0_TjjNGfP z$;Hc8f7pL4Q+fu&wbOia0<@-H+Q@93-xzjE^zMAUZ5gW!lIplJ-d(+8ovJGP>Q%s% zn=5zjH*fNjwUsH`z%YT)V=Kq6;@U||f>tg$x^z?AzB=KGRo4#3vYAcxRdwzc=s}C5 zc7BF(=@Q`@h7y7ir(#$ywdfeO$mNq`_|6s}Ytvx$Zaeb@MwLAb8<-8)8=f<4Srz(D z>;U5hO9szQ&NPc1> cA}!W41Y4A@+`}G`2h2ANp00i_>zopr0Cgf*V*mgE literal 0 HcmV?d00001 diff --git a/thumbs/pillar_001.png.import b/thumbs/pillar_001.png.import new file mode 100644 index 0000000..fa64ccc --- /dev/null +++ b/thumbs/pillar_001.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://gs5fj3y8oofo" +path="res://.godot/imported/pillar_001.png-eee810fc92313f7758f5db4dd5ba470c.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/pillar_001.png" +dest_files=["res://.godot/imported/pillar_001.png-eee810fc92313f7758f5db4dd5ba470c.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/pillar_002.png b/thumbs/pillar_002.png new file mode 100644 index 0000000000000000000000000000000000000000..600c8695dc787e6eb33294f9472a42c693fc7314 GIT binary patch literal 1009 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-HD>U|#L%;uumf z=j|PTkI98H$3LFGG?ispN{8x{U=CfOvKIl4$Is|pG<_j3h4s==@8wpdpOs2pCa`2W z1w;r0I;PBB?6i2%1%VdFQh~KE{{+iETXR#R`^)zY-=CMxdMvnagZcgEH|5gTtgQTQ zE_rR%1?GqdK8ACQ2P_#Z*cqNPJdk0S!`x8JP(X^{I+HI93%9&mbM;sk@2@$2ufKI) zyzrRiF)u^-7e<~tuVTM#?Eh7*;@O`c8@;knY55E09mU`8ZR)cwTjF{>|J&;u6UAcp z-P(L8*wuZ_jQw(TpDygH|Fw6t)xoYSkvE_3F=6JT}=ezP>Jm}M1wd&4-;Pms^ z{~s=HRO8_nbx@qSsmL?P|Nq~qa_W=1tQzL)s<+L_-8x&<6R2a|6^n_DoC?c#u8g~S z_3EnV|Ibg)|8ix^FSdDW4~0B@V8<>|W4kELQ+3v*Wv96IM*UF8$jR|(|E?n5@9po) zKC7Vgp_zl9_vL3t8RqS;5wDt)5RlKzy|Vj!tDK@n4TIsWxBFE$Fe;p{W=&w;pp(ZC z$2jQ(;|!G&AVbKCVe$jU3ibx(58d-yc@J!oVURIrn9r=z$Sm>4Lb9sG;{cn$;`^*o z4;UV7U`+Yx#30>Z?jUByaQYDIg{zg0v2(>g&9g54Rk0xR(BVI!A1;a4*45R0{CLzm zJgj=oi32$eAzDjAv{XH%nKRcfbm!#S%y{dT^{0Ek!_WGyNW42oDEseG0g-x!Dg5FMPr(U{ z@3-EA;LM$BMoVYSO}#JZlH0KDTi?;+v!AJ5-H_*3`tfFiaBKT*hMgRICf8WzsYnG# zAEV4C9T;uumf z=k48%*}{o3?H}{k@ii$-;ga-X?{;-9xqQ^#L1ylpJAXEJb%nL-y;6CVU~RD~!pwX;d$+gV%h-Kowfcv$y!aPv;$b+)@PKUM zUC2vDuU*y2n!d)96K|*G?$)*S6I{noz$Wl*>qa()@LGn~`tzsBExf#nKjG)a$0xtt zzS>^7`PYLBzt``LuzWeuYH9dqewRD@Yd;^jEhheKvWj%PUHXkaHFw7E@9ua_vZ?&{ z>k0cCh8za>jXMnHpI!UbruzHG8EUWQtvb)Fv%kvz=D+z8``-WY(ck-6W@YgzzJyyP zJmLCt{rBHLf9IWs@8y&meMN~clMcQ-b&$m%_wnm~m6LaFemwlYw#rPttnTUMXJIEd zcCGlQ@j&6XpvuVv0|&dGoE8n4;pgUR+BzAsF{CqiKK=c(-I&3GxdBdiIN9+TporX9 z{Y|>iJqhS0>y!n zEwxrR7=%g~-!Po0uCL$7EMVL4SGD1{90Pws&+jkN4D%ROUZ@@b#+!_n@K<^FSNCHW$&Xb03F009qDP^2qGB#ez{JYn>FVdQ&MBb@0BckwegFUf literal 0 HcmV?d00001 diff --git a/thumbs/pillar_003.png.import b/thumbs/pillar_003.png.import new file mode 100644 index 0000000..b527dc3 --- /dev/null +++ b/thumbs/pillar_003.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://xukr7eaglupr" +path="res://.godot/imported/pillar_003.png-b8155b45233456e99263ca255574d978.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/pillar_003.png" +dest_files=["res://.godot/imported/pillar_003.png-b8155b45233456e99263ca255574d978.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/pillar_004.png b/thumbs/pillar_004.png new file mode 100644 index 0000000000000000000000000000000000000000..df4d14335a5e185098cf26bfb83df13da188ab32 GIT binary patch literal 1073 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-HD>V1DiC;uumf z=k1;Rj4P!K$3LF`e#fu<`j%<70U~ByU65y*6sD98Kc)m)2 zMX;6Mi|5KqlM61vE{XLez7wbH(rxK&Ip%V4Th*r7OaIkOD4+Xwib47Q;`ir&U(DZL z{h{@J_Wk?ctIKy^xUt7-(&1?x)eL&~co^m}9x!I8U}HGX@IaEmhPfe~;R7jxa&iZ@ zZRNeSYnR=-#3N#I47Oks1Q^cA{M+^7v9G?mx6Pza+>8nD53c)D`hFv`)u!j4)$R5_ zzx~(PcF88qGtcxpGHze^b>se3-B=}0sWX3;?0s3cE(NG^8Urkneqve zCaW1e{M|mpuZrH~;(S>7)th~PdfYwB+VZx&xiZCScm0gUi&NZ13;7pJd24rd z{{FnI6;t#2S7uhm{uBF9AKv}kP^96w=_KB)$el6A+4Nptdw+9Bd+;TJ*A`P zJlAeMyyN8b0}NcN*B{DhUe?O6;d?j#l$Wn(eXB@1H)p^8j?d>A7HC|WYhAB(`TElN z`Z5<6wT4!0O>K4J=(lnnU*q5VZ^O*2m!@nA3KY?7S#YY0Yw7m=%a7ek z^(x=;`p3!5KcDB{`>`wT_LsaKWxd#r-~;;C>q3(yr|gQ z-={e3U(AZ=1N*gYSSP9NHCWH^;RZtrLk@%Ei|LK3HVo?-G8j(XWje5$L8?KV!G?j` zfT1FX;ivXHwFce?54jG^t+QZYXMZ5eAk)Blfbqv(1`CGs_A(96<@pZ02MM$~STJ}7 zIp_mTv;*@082`Ux%D{V|{(k|(J=Q~v6~7)b$jCI<3$n0J;Qq3I!DSS?X1KconvDKk&1Ear;p0 k#|PRClw2-RXiIHM**cd707;>nUv6W-qn5dCs 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 literal 0 HcmV?d00001 diff --git a/thumbs/pipe_001.png.import b/thumbs/pipe_001.png.import new file mode 100644 index 0000000..930730d --- /dev/null +++ b/thumbs/pipe_001.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://wi4fn21t17gk" +path="res://.godot/imported/pipe_001.png-d22afa99d51c73b7992db1259c8ca40e.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/pipe_001.png" +dest_files=["res://.godot/imported/pipe_001.png-d22afa99d51c73b7992db1259c8ca40e.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/protection_001.png b/thumbs/protection_001.png new file mode 100644 index 0000000000000000000000000000000000000000..c68d089daa43ad125f73f29f85d91e1972adb3cd GIT binary patch literal 1648 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 HP6U}o}kaSW-L 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 literal 0 HcmV?d00001 diff --git a/thumbs/protective_wall_004.png.import b/thumbs/protective_wall_004.png.import new file mode 100644 index 0000000..85367ee --- /dev/null +++ b/thumbs/protective_wall_004.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bvy0eb8ooaxss" +path="res://.godot/imported/protective_wall_004.png-99f9cb9362c0cfe09526dd9dbcf6ad1f.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/protective_wall_004.png" +dest_files=["res://.godot/imported/protective_wall_004.png-99f9cb9362c0cfe09526dd9dbcf6ad1f.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/radiolocator_001.png b/thumbs/radiolocator_001.png new file mode 100644 index 0000000000000000000000000000000000000000..160be8234520ae8f4c92105fd3fe652bf52c5225 GIT binary patch literal 2387 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 Vv%z*v{OlzG=Ehb=l{ZmO{|zhARjmL3 literal 0 HcmV?d00001 diff --git a/thumbs/radiolocator_001.png.import b/thumbs/radiolocator_001.png.import new file mode 100644 index 0000000..a96f27e --- /dev/null +++ b/thumbs/radiolocator_001.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://brq1gcri651dv" +path="res://.godot/imported/radiolocator_001.png-9cb36d96b007c08e79df526650fc7d15.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/radiolocator_001.png" +dest_files=["res://.godot/imported/radiolocator_001.png-9cb36d96b007c08e79df526650fc7d15.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/radiolocator_002.png b/thumbs/radiolocator_002.png new file mode 100644 index 0000000000000000000000000000000000000000..3485cc1dd27ca7972cf1e74b78a75c52f1d33862 GIT binary patch literal 2404 zcmd5;*IUyI7W^e95KtD8l1LLmQ-~Dlpd^qe5dpy~N)?bMAVos2k#Ld7g5nw!hy=wb zktV$t6F?yJtANs*h@nX+m%iM;V)x;knRz(pX}fg4Vfa0@f=1yf`+N`wWBZx5|NH zfhf+fqvS{mXu>4vlTPAak2DPpIZh{R>hEaIAHMbQ4E0RcjB4c44ymV$yPV5g-h?Ng z3k5x&egh6q<)747CeG&p*}4A%QHA%JFMjNl5T64cMb2m1Cm&Ju55v%EDg1tnM8{XO zN~i{Z{1u|Z>)iZdg|i6dW{bRU2ZU$7Rbq7rC^q`(FVwP$cB`t>t6K({ds;DlE+esI7;kXmiezGH2A6G_I~_}I6blx ze09?|>*FAg8jvhRQV7cU^o~J*|s@9NIbVjo7CsI z15PF)a`Dg)f;Mi2bJw%tTAtCJq5kO8ca?}5iYLDIJT#||BnhZqXs)-TeYR(hX8ebl z*T3q@s~xg|YKpVYJ~U=hnf4e+NxB?wJ|mzWSQa}R(8TJ(@g7`4Z~XY$M_|(c7FPW*il>6@~ze7hr-76Eb}>2 z93H`H3>!brB^}+?5^=~eD6VYB<>sUg)1!8}bSE5C(jSYybT&a>Q|ZF)@^1B)7=3PK z_iUP_BHVSep)L+lv{@$1hCTfXMGW0Y(U8ZLA`^hSYhlMo4NQOe-roz$^tbLJ4Ba^A z#p0QFEoxv0t9czg$P5{n3GcvxgkCg5HF4Xe`w~lmf^Ua%DXJ!e4^A`Wua#D&_J9WXVq$J5?^8~gEkf`(WyMzu zb%V6Jy`6@+h~2%cIZzwy6h-D4+vmrEy3XzUx~fTOuq|$u1sb`uO-b6?YxSjDnDa|GmLX z%b}NX+`8aOkH|DpPGZU}+se0+zUPNXv+DI^t$4B%1i%|@3hU~@S=cQFZh7$3JwIUq zuMvX70dXcs&RFX)ME|luaeF4Q6PKCR)vh|`C9^%882Az{FroU5a8vQUX6?G=uinbC z`Gy%+sGM%P%eMwDVQ0S_rY|SxhA^xx&zoR%Clvy~Q5x_(bgSr=WNfRe{I${;t#Gj@ z=pb0y*{=2FfT8!j`+_vFP9p@n>jv^pdv?n&; zUG0U`in(!0y2_us0_fFnD8__fxX`F2%2OXb zc$ZctK5TLmy|I^%jU;0&3XlMX;HCnLo|#haq4~}P6CVF|GvzMos$?8l?QOt8(MTyt z_fBAq$yQA{gefKbes23FyZ^gqr`L7G$S6I6phOkNLfFLaF~T`s#BMXn%hn+A#iFCiKalg6>{@o!9~oR(>7mrMfGaPNzSA{`{jG z+ra08FOY}t0p;jw7)9gi-&gg%k~WgI{5z1`U8_xvkdJ8|w>h0_(6QPZ-8uN#KF8NNG1*nz5Q9b5oguCRS)|2jIag3L` z+G}|ck<9JQd$&vA02Q*04-@R($e1meG4XQ8{mk5X(KHh)F*!*abLKN$kt+`gmAxR! zS9+WyEikp(aVRotpO`ru1|kWiK)m0X*CzW86%#6&XxZcW5r=2Bl$p(@-GvpXs2^~s z>UQ5$1#slq9o4UlKc4qy8ZSsGL=VLLsd>Jze!VJAFmn7%_CzyN%|f86up-)T>75BY z3~vnrkMC3@^C&13-F7?}^=(Dkyx- VKhU{~KdMc@)ytN+A`_SR{{lc0c(DKg literal 0 HcmV?d00001 diff --git a/thumbs/radiolocator_002.png.import b/thumbs/radiolocator_002.png.import new file mode 100644 index 0000000..8306030 --- /dev/null +++ b/thumbs/radiolocator_002.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bngtff4ba66yo" +path="res://.godot/imported/radiolocator_002.png-9a24a2b8d6eddfbf2750e72036725fb9.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/radiolocator_002.png" +dest_files=["res://.godot/imported/radiolocator_002.png-9a24a2b8d6eddfbf2750e72036725fb9.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/radiolocator_platform_001.png b/thumbs/radiolocator_platform_001.png new file mode 100644 index 0000000000000000000000000000000000000000..78954cc9074917af8ad2035bdca75186b8fe186d GIT binary patch literal 2812 zcmc(h`8(8$7so$lY%@bdwnQ0Ox*5b+vW&GPJ0T&8ELpFmvBgwOr5K5lB3rfwW4#%T zvAZTPmIZ6$mg}&Sg@XRnT(Lv zgnGGC(vg>KTt%IgEJvEsR3FWuMl&yCEYI+6l1j{q#d4=mIoU6AOkK?2m0t2$z#2_5 zed@AnRR_Wz)1w!)wqnr2uy4@&R)C^V@6d;a=r%zT2!qtz4pxO&`H>TSK)q_36= zh@0EyM3@W0L_WIrRhclK0WpXS-kA}eg2s_ z#=^K8Fp6|HjWp3z;ov4?SjK( z-AfA_X}Ri)4e(q5m?e?0Dal)WpC8xT`Z@m7ynQiV0LdPNt}qV~fmO70FH1;Ru#T-{eI}N!J4!@0#TwjW4k} z8-B48dSUqTAdQYI+ zevVy){wf>U;^XQ)&^OJ{N?3&18pRnA$6z$1En_FaME`q}ROs@(GVcQa0}%r)(_olW z6llV1^`sDe6&lAN@u+ZG_fq!fWy-1jz$GPdi~yZiSQrr)plTrD7v>^2y;{v&oX(eq zSQUh6!+9rDiWmb&+6*2b15)FNJ^rd^cS|g9S zGFZ)}2a6+VQ9?ANrV#jR9)D5&4V}F$>KFFPa8nw=B-&TieEV+3iTG%Lg_o`P952}- z)(kM_iUL5j$S)?+VsN}@Au8s3Ef5*Xl8SO_YQ`{Ktv3`d_ zxT8;ZjSoq8HA!*4GP?hPMBHmrg!KRs8Nz z`;4bN%C5O6s?SryX=H}2MAltOOhW#U=hRw)5#R9Sgd;dlNa%vJbUKY#+r9vbaB&7L zuLy~87=+ceBbo|xb@MmXtW}K;%Of(%N9sPpGn`*M2_>TVtg>SW+d?y2=R@3l*GJRhSEjrTNo*=4D~!n z49g&8TzG1(PC?RUkrV;)Cnjy-#)K*4feQ7W)?hzHWw*J#hgMb98zaZ@!&7xi?!1@l zgdL+~I$rpq1G6HPWsx7WFt6)J-7D9V7xu%;qo>;V5_kagY-1;+y5Jj|@=pLE6&&Gm z2oc39RXdRC$k19(jAo5_OxHzhGYjY_k1@h@#e3 zDB*tW9|>S_aq*a@r()^00nM_f3^{2lTNtwPSt9_pVFLL&2BR}_Ug2x!+Duge`%y_*ywVW z8w!nd2Y0u2<6p)qop~kXE0FSIeP^~eMSoWXkpDM9RNY>Gm3c%Nf#m2ui+1_Nz(?Kp zfgU3P1EWetSTln#F^AJtm7E6l%C(s|^v#tA(UA_!E?a&=>qrN9d15NHpJuJBF~6CR zXJ296^V~hD{d-BJ>^)pcO8IpLk`^mxAw>_eNL-b z>chJJz-C4c!jzTG>9i;N3Zo_J-o+|$vEHX*gdM0vlGkxr<~hXsq186fVwWbbyv5Z{ zGz2yt6LZdGbZ4NjCfd&(OjMs}4;HTD?s(1oY1n2cBO`Mo5UqlGi?f7x%0_U%N4;$* z(n7_gXk&{@S;Y0qSCCAwxf=GSjg=EDYjgPp%g#IK2N8RNl8lx^jes>n41J5GiG@`! znkZ1kp?AeTt?y zU8h+1>K%-?E`Ysz4Y)XLSAW+s>&JnGlTQD(EOF+K2Yp}k+eGMyg$?eQ^U zxSiI(#YxDV{oX^|#zHI)+e}tKIJI0M73%>&!bFl^Bl`|cdagF!TvWol5EtP{pEm?0{%CCXNe^)Y3Ol6@@Y zQI<+fXr>7v`*_RJU|!E3@t*gGdq4M_d(OT0eD1mTeA3-q9QgT8@c{t94?kz?evHI_ zjhFk_4_NxXI|fjsyMr~*Fedv00KlAZ+rKWvmadoLBQ8wJ5qnuP=0+TOC*hxM)9%u2 zpW+5*vMZyXwT?vHkQ3+9hzfF)UTKAz2HEi&y7zy&e{sk`+S^P*=<7>4GhOGh${kgl z%Cx<_#P)xFqjlrQj6?(4cb~MV?I$k9j9DygXq0uXk)=d@ z&$rM3IPN|NZ?>3KL=}(%Js~8kPGp<|aXIiQ8oL91|Cf{%qrl-gE%h1c?)LQ$fil;w-8tz1$N_Pq@dVHPh- z`}&m7QJ}EP`%yK;`O&FT9GVc6|5&2TH0{IdR!;+Cx=hXL1TEzaFMknnr`3nUk&%3iN=G=KZrrs6{?OL6LW*6mLy#NiAGq+D+s`5V0&v7s z$n2Eij6Sh5E#fhN(~05kiZk$5xQynp{P9~0A-ilzNwyh!^?o(&2=qR>qFE}VqMV#T z8vv#72t*5UR^oiyz>yy?XG!i+4D41@VHC0 zR^&28>1}O+=$EfqZB=*S9%`Hsdko)W!bVCxOMKAiyKYLGHTS3K+j9gO<2!-&GS6gEuy@a);ZhgxU8Gw#c?N>?tQ zj1tMRf5q&W7LydOs-NIXIxgWgyYt@d>QV>A`;`V~NI1rMO9EEiSFJ4Oxb zN7_&jOiyDK+a^4ET@~h*%?1+(an-8o(SPoF z*hP43@<;{%PASKmOAlcCz+GvpTutXhl!DUTe!Nn)$K%Zmv?H9cQT$7Y-WYdjI{Z3($cqyX3fdZPT?Ngx z73otT0=?45)@|ucj5XYo9eBOP@OE$I-kIs^?T#}j`0lYL?f|goUUad> zT(Q;D5SXg?c1a} zXOjW!R54H0{6R*Yv-}%r-Yv8O8S@X!&^@2diX#m0Q;i!vs-f+Oao9V0 zH-7r(K}#2NI~??C>8M7S?jI7G;6LgYc|fgqJ*6tIcMnvoal$xogua=X>$j@`wN#SL zN^^RM{ZHt<)6dhzq)g>eHWQ!Du4j=jCWmTcSkM|F@52Rg)Wja{ofGt7v;c_Ywz4?Z z6k`(Db2PuC8zqNCdgx1-bPopPO>p?UjIvPoCvsfvSe1ke-l>Ah3e5f>T+7E6ar<=p zah9<+e&;h)xD&9iZ)0Qcq(he^Qx0M*<6XX&J|#i}h~K2~nR}9D-rg;6mq1{6@If1g z@h0$5`14OiTmN)wO5P)mf?2)z)^hBcrv zd=t$IIg!ZsXCpED)H4&CItypw)G6nJif@x@H+0Dveqs8r%M69myCf-Zxd}l>+51-M zH8mT6*8s7`Z`q{R*tB7x8;~fjA+2hVk3Sr!X%W;>vt5D@AGHRz+|uPZ9`07qhVJRj zSx&g8B2{5d%9Tq*u{p3zpKH*fDWz;R2b-nV&%0Gn;96PdwPGWat%6SSOo#T@VRXmv^j<0l1xuZG$yB<-g(vNxT36 literal 0 HcmV?d00001 diff --git a/thumbs/radiolocator_platform_002.png.import b/thumbs/radiolocator_platform_002.png.import new file mode 100644 index 0000000..3092a70 --- /dev/null +++ b/thumbs/radiolocator_platform_002.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://vb0b5j4gwxcl" +path="res://.godot/imported/radiolocator_platform_002.png-39e9ad948f9bc27a719848edaf5424db.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/radiolocator_platform_002.png" +dest_files=["res://.godot/imported/radiolocator_platform_002.png-39e9ad948f9bc27a719848edaf5424db.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/radiostation_001.png b/thumbs/radiostation_001.png new file mode 100644 index 0000000000000000000000000000000000000000..aedb73978336e40b9549489d993d5eabb708c49b GIT binary patch literal 2109 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 j@yb^;S>Xm literal 0 HcmV?d00001 diff --git a/thumbs/radiostation_002.png.import b/thumbs/radiostation_002.png.import new file mode 100644 index 0000000..ca0ddfb --- /dev/null +++ b/thumbs/radiostation_002.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://daq6ej2fbbiwm" +path="res://.godot/imported/radiostation_002.png-029413762256a869b25b432bfeeeefb9.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/radiostation_002.png" +dest_files=["res://.godot/imported/radiostation_002.png-029413762256a869b25b432bfeeeefb9.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/road_006.png b/thumbs/road_006.png new file mode 100644 index 0000000000000000000000000000000000000000..eadd278cc435b383ba4a7cf898d8db1e1ff764e6 GIT binary patch literal 1997 zcmd5-`8V5%9{nbEO)W9RcFg&;~WrS_4U>PS1) zu~coXj!>bo$0XW}+CrkS6hRP`MDfgD@!k)gdw;m+o^wB+^Ev1K?29~qR9;ga0Dz+& z?yi1^jQ?k3r4Nzn5J5X65XSGkGw_hb#jMWm$=@nT!4^DDLOO!8PE_pM~ z1`HTqVI;Yw=<>hw;WE#% zTVcWEd~W4lL_2H?QmsZ3^F!rG5(%%QB}@%%Y_r4J)I@{P zh|W3TNlM#aUP;&fmh(*!bmlFV6Z0CL%!XggfzZ3>L%>U8uGJ{zs$3Ufps6{NTvq#0 z#>mn(&LP?k#h)}kxYrI7L3k-DLFXKb!pG`MdF1qD8H@L&H|hTxT(BpGTi53lEn0-R zx5c6~G!^Tj84=@wya+5^9m@Afi_Yl ziooH1?h_4KgNf?~ocaJsEsb%#FvB6RkI38=PZoDg&6*Jh95 zPNg{-oWD^#g=~$%@KsLjc@$%ZH=7GRo#4aLX6hhKtC<<9ND?ovA*;~`he4!w^L(@hbYfbd*_WaD8hCB{3}Tol4;h& zS&&T>R@2X!BYec3p4?7TS$hMFve_l3-V?CTP-ez@ymK8Z1`>jum^r31G<#jr4bdEvkvQLOjuG(Pkr${m z+_464!F}}XqA}deX`2y7vk5&}UZ!^a%Vm2ml=z@X?S^5b9263KP6HA0_mYQI z+2hgob7<|@J`?tCJ`de~jMfk*=#Sms7ljDTnoABhLq=5~%e4=9?P`vi-9`$aCX}Lg zt{3y2+qpQd-gL_JKAKz&?u8bv(Af`^!i z-z*a6vP)JZ*xN4VfQu;m5pN7C>`5?oD!XM$DvYipRH&Xe{~*v_@SjNCaNiFxoo8i8 zoSKID+uAS&by>RfbvwDFTKN`}&=j%tLy{T)=X#s;E`FSMnFmRs5BlBei17Q;h_>Oi zmIycV_+7nsXeKtgJ5X7+L;Sh&Hs5(o2bH4tLi}|v;&-E{i_+F6>0Tyyv~Ej5!S$-- z)w*QC;Gzl9D$H3n^X*>4e#rg9i=-W|7WX$~JyHs=`48UcL3@&C$n=vgOKZ$TJi+uz zz?AZG(%UgGW$?2U-UxB|(<*u8guANVj0EuIy?Ef4x@v~G5fhWj>(^&7GM*{{B(X3f zLjNepBlCG-%$lCVz}@-vmL8Mqbo04+HDSYFbXfomeYFE%4H?q}0DE)!C3AFkVX3z- z`2`2Xq3FO*03rGajo6P!!vWtBYA-=*KWp3;1Rd?y&5`uL`{_{ReSRBheey0kO_=M* z-j`viBm@9C%$_r#4<(F%{>j#sE;ax+>#{o#uS{7Jk`-7QpuEM5z1{zPA#FL9wRXD0 T3D;K-`x)?XL%P0p4u9}px!1AZ literal 0 HcmV?d00001 diff --git a/thumbs/road_006.png.import b/thumbs/road_006.png.import new file mode 100644 index 0000000..69406c7 --- /dev/null +++ b/thumbs/road_006.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c8wgfvuwjebct" +path="res://.godot/imported/road_006.png-05b8dba7388e0e111c2c9c0357c72049.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/road_006.png" +dest_files=["res://.godot/imported/road_006.png-05b8dba7388e0e111c2c9c0357c72049.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/road_007.png b/thumbs/road_007.png new file mode 100644 index 0000000000000000000000000000000000000000..9da7cdfdbe8c27b1a9bdcb3db3e349371c4f49d0 GIT binary patch literal 1907 zcmd6o`8V4M7skJdpmv?SeJMdGN=w@0O-pJjN|4kbmNqRBp`0=!RMp;+imjy97E_|t z+TPl_Olv2$GS#NYn2cImdu_2zkVwY-6*E8F`}yHH_c`aD=ZEJW(aBy(UPB%L03`w* z=XyZ;-*ZUjV0T&i^dA5e=4x*Z)N){p03d5hz+G^UDq3NE%s56mLT~qMM>sc+vt&@; zwEz^HZ^xs^)I@wKL_bwENVO23YjpIUD((=ZTRsA}n~gHr0N}daIi`If*;dY@v}Q3P zJ**CCr#s`9Z zwZa(EZ~g$x769-6H9}G88gzlNdprbCzO69$r$)h@rHXx)yR*5Ygf=G1ROyJ7i}A97 z^~;7r!lf=L5x|#vmS-dP&W}iySkn*A@B@X0u|KHSWS7_AM5^}z1bDt#C?qs0?Ky#TB zrDT&5n(n=lZIm?n{tqBcIdsNKEW7+UfaewrH!X)kB0s^?*}L|21P$+yKBsp(+cG5P zjC_dAHvuIvRj=_Yi(!=fsx;8!tbY%WvKu~W(-lR+n`0>0 z;Y~|_x+5UTVg+sLOkgw9JO3*p4VPf_w85v?J&04+{;5IC*B+`_SjMY(hd-tk%V?q$C#Vaun20aZ333SdQ zJmH>x{qV@ht?y7a4Jt2;4Hh_qcQE~K>a!@*Ze$U&FbDb*TCf9+{KyvYHwrUja>Xu?&#Q@BpmlR>tQMt-Sjm_AQq|sYQKRi55vq z14lm$tw@#PgFLU8P+!8uotWcl*N1Lsz8!_bZmce!38Uem`N{5fj@oxc&8Q#0Cy zRnp>haBXdUulqxM*7c1B4=bb|;^v%A>pSoGO-2`U$qLpAm{~+OClmAK4jw5evuLJk z9M*Fv3G6$?37vOi_m^h{pIBTyLKkJcYHG~gDLYlHaxvkV8USCN6OSfQ>U&l6w+Xb$`)HJ+>vi1Xgt6&}kv3d81RfuhJw#G>HW&H3qr`9Lck+JSUA$`-QLktRSe+1lw9C8cqR(mzxE_9^Q0p)`X9_EX zNk-MvVDi*E>FUcn zO?hl=Sv2~=R2LgU*OJTQ2{mz`F{f-^jZDO1u%<^9R&Pwy!Hn*aa+ literal 0 HcmV?d00001 diff --git a/thumbs/road_007.png.import b/thumbs/road_007.png.import new file mode 100644 index 0000000..dbd602e --- /dev/null +++ b/thumbs/road_007.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b8qu5ifwxba67" +path="res://.godot/imported/road_007.png-b3902b8757b1775b8ac04bd2dba5ab10.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/road_007.png" +dest_files=["res://.godot/imported/road_007.png-b3902b8757b1775b8ac04bd2dba5ab10.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/road_008.png b/thumbs/road_008.png new file mode 100644 index 0000000000000000000000000000000000000000..23e483a187c2ca6da35818ab365140a0567c5624 GIT binary patch literal 1719 zcmd6o`#aMM0LH(}G>k38Fqe81Ma6NA+FYi!=SU=lY9{0oO2TqC*W5!JOY^;{Sq3 z?|LuF`_(Qa!p~#vfW~1Y7XYNga2VSQ#D}~`XS0wFh{Oufk5bM@Umw#Z+R-EjoHNiR4=o zwH>F8sE$Du(c&uN7aM4J^XU0^dYYN;vt1h0wJcd3z05i2fkBdY~l_UfU zhUfk=!5?uJ)N|Fv)5)e!*K?}9m$zUaK2fzYbVZXL+%E#5t#T5>MhXWVj%d=58*35t zU^^M%ni-0O=&k3lHU^3vIGY^$2o{}^5DM+fM>{E&yy3)f=eo)h^fR7F?Dm2m!nzpn z^hWGnUzz#9JROp0x0~7P#aoos-i4cM6QbU0|C+Ja>e?T_`1v5T{t_zJemjbggC^S_ zczDTq9&=ZL&G2fXcQVfwDey0uy~cy9RYz=Yzr31ga#wzZ#!SH$dJ?3d0 zkmGJ z^di$Bedx2)Cb!4qZ&z3*8>4T!8ZV0{PlF<=~67ARejTa`PK#At_wPITF()-!h@LOQy#Z0vDa2TmV#$DZ~*Pn_iNr%E`fQ4Y9 zR{R&%(7-uRjTdW9?vzH+UC{dT1KP#TAB@!OOHC-*vDeSI-qsEQg5A}JTMJnmO@h&a zcmzgT=kf~iosF_j_KFGVq<}A^ZIF!|-BrgVTMFORDjP4bG&PR0*A}A)S9(ORo4Be^ z6Z(uMrdK7rG*!O$-#!E@gOmChC~TgZpvw+!MgOc7y#O@2~yp%oxN`-UH&fS0}HpzoF2Ms?#KIiCI& z(SB86pl7v_FEP?e?^gQFjsnVEYMhHd(eZIDa2XVQu=d7y8GB4>0a?}ZnF+%$HT=Hl z+X@c2IivnSL~~L)Zd*QGKF}m7iJVMZsh!jd2)vQbo~JN7Ru{~)o{2|i+Qkrhv!rmd zUoGLSN_bseJ1>_S(Y0zJZfUS^^u_6sLH~Z?_%Fxyk`d)h`24rX4N(Ypdg7Q| zTYKtJRuuDiB>1xr3{6Z|kGaDchXVWKbC2bDjGg*R?`mX#0MJ>2rfJxQid~z>@|PVm zz`?R1^#GZ*{j%ZsSeC{}6geVwnkIF$j#H(t12ae`jZf{T`dvw*p|knxmF4n)@}IEa zs}Y|LpEh)jV+ORfY%5hf)7TKa1Uv4r@Jx)4bHuNx-2QM8)o`W{mvFEN&jUKjRRkof#s*zxO{f2~)#!$nnK>SSC>DCx zqr((wTOp`_aCE_1DTBeQHGxPJibn>9B@3;Se}R1!1EA9at}sZmdH0C`oP!gl(T+g+ E57~kap8x;= literal 0 HcmV?d00001 diff --git a/thumbs/road_008.png.import b/thumbs/road_008.png.import new file mode 100644 index 0000000..af2dbac --- /dev/null +++ b/thumbs/road_008.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bxv7y24wu5fsx" +path="res://.godot/imported/road_008.png-41ee917d390a7849b6fb35d28c398725.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/road_008.png" +dest_files=["res://.godot/imported/road_008.png-41ee917d390a7849b6fb35d28c398725.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/road_009.png b/thumbs/road_009.png new file mode 100644 index 0000000000000000000000000000000000000000..4260e75a5fb0576c15398ce90f4c78b0636b7863 GIT binary patch literal 1831 zcmd5-`&$xrAN>LfLZ#+RQ=GSTn^RHQPy-R2=DcmXyqiszp}n?rqG5R%yRd?p+ndM&}?^tOqwl~ASMII9U1T_fIH?Bb0TJ0fuIM6a8z*GYe zhC}|#{(mA?Zhn!7ZZJ}xVpACpzsnuI5{o^eo9vW5qjDkLf4mQ0R^{kP(W7VL&U1r8 zCN{N^OvPvz#AF_EACe>QF>QiBjz%Su=?4#zA}^bU49U_e8}Ar90GhU|vFRjj`opRe zSIxxH?)9ZK3C}nW*5Y(g_}p%Q-pXE#hkZQWy~8e!rtPn3d4gv-f;5P7b|fy5h>)1f zu50!y56RD&9nT#_3>FlmzW~!H#(l;^b>AI9Qwk~Ky%^oQNNF>r>nTS?)At|1K4T7{dp*PASOwZ67P=QG(BeKvnU)E`aL&f2y!?vo;~_s2}Y zQwfN#zjt?vgylHsV&PdnmThjOWTdd!yOzChxVpyq^yw>n${tob#VOgXp@q@}B>%C6 z_vfPW7Qs;XSq>dBn@>DG|pV~dAhqQ#V?n`K=yh3P|?0!&@w zZWeKj13b;^1(nd4y6W8bu(Hv;Ifl=AuAheh(vhyS;8=0{sY~Dfo>Act5Et${QcpZ@ zrS>$6DeNhpY+UDkbr_8yfdr9E6q}K=f}LjBCs)|1_iHc ziDc^I3CDp3UvMvW26dThcp!v0+TMvpJCXAFHfSe9xYS4|tBVg%n-63;jqB{tj zM;3{f8gacRYT=4`E2A9;3`C{G&|on-@@?Y19FHdW>;;c8?-5f87@jGIf}g<7t1WVSc(aSVXbAZ{5$o1<~E^fyz-;W5lI$`^~(^UZ0(p3V%t0DT`TmgBs9C!I0F#E_;qdCLON06H^n#e zKfOeI^gaQY=Dk4}I~b*G7{Zwr+b77VcWV#ko%=+yQ>~X@HKou`uEE%^>A85_RN8ao zun2t*k?cUbQdQV;89XT&HzZ&gKsBD$JB>py(?zdXaw)nqj^A38zmU0+=g{Z)R_~GI z&!sA;BceX~-P8JjgAl+tHvU&U|8+7S74~C{-$~UOOVLQ~meuC6Vm^h8)t(9eW4Vpm zo0%amFW;lsc_2F7OC?Ak54O=&n{_SUMlGdKJN86 zZ_9SmEXcK6eKP3Xcly$&Hw3pR%4Ms9bKO-})%!FFGKD0?TcGJ#1cka-&CHEL8UBk; z$aF&d13MV1{q@|`=1SJ3qFN>^ZS>Kng*Fxsp)M)`x)*;p5WPa;u|t3DI{IQ3!ty54 zjrJUYeRr*VH;B1pn^3*X!IiY)v6{{0l^ESCjyG4SN3AM10U8XF5VpV6r>DI3ISXc~ z(TTc|V4uk?=!|Do&09`r@F7pf3N&j}luVNevsg+he@ literal 0 HcmV?d00001 diff --git a/thumbs/road_009.png.import b/thumbs/road_009.png.import new file mode 100644 index 0000000..7c60d64 --- /dev/null +++ b/thumbs/road_009.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bp8p1eak31c5k" +path="res://.godot/imported/road_009.png-5bce11978d4178dc6501e0797824e37f.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/road_009.png" +dest_files=["res://.godot/imported/road_009.png-5bce11978d4178dc6501e0797824e37f.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/rock_003.png b/thumbs/rock_003.png new file mode 100644 index 0000000000000000000000000000000000000000..b736545f0ffa7651f58a4ee8e6f24698dbb71dad GIT binary patch literal 2155 zcmchZ`#;l<7suaIn>EQ4-Kec^CUc2GO=z=R<`SAqYI4o}T0WXCOl$7BeB5%s=kh6+ zs9ckw$*svXw-$1XF(EU?$M>K3{BT~c$9bH``RTkKkLQUnHP#b`orD1ZAgoW&ChmFg z{|gG))0V6DoqGoIBkJLSvM-YJ002elYipSYWUw>UV{A3zPfJuw=K!_GSHBnObT;z(3nbjL@~%BOF!j}}X;;Qd z>dJGru;F6r@?$B(tSI(MBXjeMnsQbBWUHT|jMCk|JFf!HwG}|CJt(|I03HTL9umSy z9u3CG1NW?e$^Uv_>@_UNq4@bvsXSs^R=zf0LFk!y-GDJE+ta&bJ30I`7!IEsJycgJ zodcZ7TQ@stR0^+oxT0a+pamp};mtR9!Pes#VS9OUx-gLNIs}fh7MS?3#;`aG;xD@1R8NyC7ltTq_iO?i`)z@Gm z3=fsj9zZVVroQXGyE>^h#+`c?w${C)K2QdvIt_^+X-#h)NW5QYj#u7}we^H(mK(Uz z;QCHh>yfxTfjJcfr9jZIL*~hu{DJmsFA+F%h358aC7X`mBcLBMpZvI+EmeBkfiW>1 zFwRtcxioV$8ghDXWz_#h!eLePnf(`Ii{*OmXj}D<^u-ui%B|K?BUvrN3}{mGdbG0M zE-E(IfDB^mo`S)MFm7Y)$n*Gea}_7;prNd|p^ezKiJzL2-9ZgsxU?2Y-nINnfwvO= z1hi?wU>E=B{7{IS&X*;v< z9!-0LyG^qYMii$2LoD?KBeo|qmI16-+a4+4&AgQ<)%~lm!ueLj{;I;rM*@HAAk)s% zaNep`DA}`3@1pxkDj4=q_0cOram1X_c|fNbK{mruC-lH-u*Uin3X=s z7G{UUOxv3s0F`-V7z^~F9?$4!9Y^N}7sOR~39^6wV=p;|Az18F<`#IEHnHnBKz8n9 zHy|D4R<(Wwxf2nJ)I(PhjwA)%N`KlZ%rpMjhw31faaMg0fV8FYzq(rn_hv(RJDE2N zo0%SbB9w4Kv)Pos@&uD5f`z`pN`e5-(bNXqV>{JCCa=|#|30(+`}#BOP>Z5|@gM0z z3$FdWwzfZ=irH?~@(7 z^q2ML=Land*GOvTBL0Ns69Bi+qtU-enW~ul9sET4;^JPW#irtAN&%LQRhu^@ylt?q z{fc2nfB2Y`#E$%X@`HQZ?dS5q`8=QTMrF-qMO=2&am;y1#U?@9-Ac|Z*2q8|(sPWn zggE#HTUpdhel{HFYqKCIP4{AbaG{k~_-`5iuGL9777vMuda67dzX~%Qfhno+PwK>b zZL+xqhvK~XXD_?cJ=kub!t%Z2kg6#PS7W+7AYgG<3-n8XWo@NbEY_Ogw7)6f#3>meQ`33FcNb=^_%N(; z5X`Mr@14&cUt_Q(|Kpv{)mWP?f3zUjA&dJWG7v$^b4hf@&T0fD>ohO>kHA+j4tDh+ z^o3`gS#D2uUkzk{02Eum2<9_>8yH=US9+Xzbieil(p#a?*iOPRLW551>lXLn<08NT zJ>R?>dtAPs^HsVJ+wwYdbW5XZ;RIufWmb~ z99z}g*o*5z)e#xJwh#j}pi~=0uEy>UzFW`;jrz{Y<~691x;g6?4gkxgzPlocH9`Ta zs~$jbwaKZrPUh8p0M`YBuO3cGt zZ09vg!dgf6EY2MKTmSNQOIUs<c${2BpWF^VV*$}g6ud&ruBRO*~$U(V1F>`aoVa}vKMsi-*? zP2%Ffa)45aKq=3m+5!EtR~#Vx(_|~ymrubScl5zfFHQH7r-f|HYWEQ8W8D~;J2kOP zS9;i$=h|bbl02%sgpl{+;&kMKXZltZXF|DiZxNr9NnV^^m%|QjRrh})8ExEuMkWuAD*Flpkf`aX^ks!Z4x@BD08bW}@ zeGp#ci9-A{LAPcoiHyxIn5AS^s NfWD5gb{XD|`Y-9J<4gbm literal 0 HcmV?d00001 diff --git a/thumbs/rock_003.png.import b/thumbs/rock_003.png.import new file mode 100644 index 0000000..dec7ed2 --- /dev/null +++ b/thumbs/rock_003.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b254mqm4vo7am" +path="res://.godot/imported/rock_003.png-6406eddfb18e7e7888dc32d42edab90e.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/rock_003.png" +dest_files=["res://.godot/imported/rock_003.png-6406eddfb18e7e7888dc32d42edab90e.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/rock_004.png b/thumbs/rock_004.png new file mode 100644 index 0000000000000000000000000000000000000000..e8374102b239865f69f597267049d356686a8c3e GIT binary patch literal 2226 zcmchZ`#;l*AICpKY_yFC$31cjxmGT@mh z(mE)FRxOv|gzsD?li6IpzW>1Y$MeJM{ruteC=FhEXR~cn7SLz zU$x#xArkJZwpN%Yjue2s!{zrLK2jx2n0X}Ve+*Wt1&1tvAh23aKK_D>Hn>*x0oVcL zM{`z`w5GqEyu2EsgoPRJeY^f**|ZK7fuZEKeEt-fk`hiS+e_RfnO^@-<)MR@TRahf zvELIAb#h73QWvKK^kYO3&j7chPT|tf%}r!o4fL_mNn-wCo6Q!OojH^ zkkg-=BZ3P#NXB};b=IxI?nUM8nIQcoK;=mHlf-$|E2_UR*tXrV^*#v#TfiUvTNkjQ z`=BDY%PYU_w35f-pNpvoWLeob(^b^VD+*p!g}r}kDxmtsUhDX?vfDLRxpQ!Aav6~` zt(^pA7tKG*iE%9^kNZTG#ow=i3cHR7SACnr6Iea&>F4(r=zPjo2~Shd?r9XPgdHLp zr@Ialu}HQI=-`u}KyBgvjv2{2At#`gjQ1&RMZ9xeVa&nvh{?^?+zi_jp!#So&wW#2FPM49VVTj%b zbmi^9;nSwXd-!p(a*?%>s2WbgM8E z=F)ZodFkF-AmXQ~-a5FVSQ|88^A6u)?DM)S>Q9j*{?1tARKiW; zQkTG}=pK`U(WEqIjbq`+LL6}s+0`O7dyXKK%52q1)mH6xAJo?qS+zI)GL@Co3J?8g zu=srfdcw)gN}j0LZjKeR@!){~qer9LpN)umo%doX%H(`|+7_UqmV3wdZxP&U&x~1f zW(xJ%?1G&!m)b^7QeK%0(kcb?J5vtetV6x^fp!u*R(2b6*{^{b9}vBXuGQp8LL0IR zXiE6m_Q&;ZbB-Ck5CA~%w{$K+(aWcbF0Q?lKeftJsF%*m>N|4bxjZAqGV38aq)BbT z{oJ?)o3}~E(5G$;OVz^x0Lxps2m)j#J2Kjc6hR=BBj~ic)hYi`y3t)GSHbKc@EB7r zOfQIR`JT$j%mn}ix}El~IiybWltG}B3-033kgY&%Nmv@Qjz-;aYsmKND-%DqDEFh> zhmy3G9Wb=ToON28VxWR7VC3yJP38fXD4GP-Ru8Yy7+I`VhJkRb>zioTRkPdT)8p&S z;( z!if!)rq^7x%M{sW!O(B-bw`ij7F$C^Q{y&npcOdePw z`=b)`#6Z90I%hr%CS60+`DDx<)QC|5Xlv?C=8Dn6vuHc|aMO3@I?k@(1o+6bkas6( zw!DhPJ`HiZH)J^Pnc)uxw7tcQ@t%e|Z>}HCM(}PH3K2P8%m$4L88amtEyr(KgeunX z31|+h!Xz~LLB0xn+&WJXwEw4|%I!z#|7g~gghw;nZ`FAOqxfA0+XH*Wv=Ggl%6hVz zSN?z_FXHvnr9?rShS9$LGsXOR-%6m}7Yotvp1#V!HBy$H@n!D{FbgF_0%PSi93_46 z)SuP9Zi-HI&XVEZzvtp!e`6#P$ltsG+9zV4;&kzIhp0LvmWr9Km zdI!fsuVG(56~@u^5fh_kj6YmE4(}Xs!~0!nKRgE8c){t-pAX#PKO^ybZo#{6Rg5r}EDciIzh-uE;%6Tez?;DN!b0;=b_5$y`(hcm-HG15HFwPdQ zq>d7>H{-v90NvEpbxlmlp^Aw=z~#MVjTev{0+qSTYKxVzVjm5e5L$9H(p49lb|u{U z3;)uCiJeCkO^!w>pb`QEmmGb-<=pWtj8+RUxFVI{rqYc1SM&4#h4=hkXsjK2H8uSB QehC4b9o+4Swm}*H1++2(egFUf literal 0 HcmV?d00001 diff --git a/thumbs/rock_004.png.import b/thumbs/rock_004.png.import new file mode 100644 index 0000000..d8d3f0b --- /dev/null +++ b/thumbs/rock_004.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cdo6uwkifcs3y" +path="res://.godot/imported/rock_004.png-d2fd680906dd10ff4135d472ea916307.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/rock_004.png" +dest_files=["res://.godot/imported/rock_004.png-d2fd680906dd10ff4135d472ea916307.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/rock_005.png b/thumbs/rock_005.png new file mode 100644 index 0000000000000000000000000000000000000000..564d56a10c558acd0eed36b4cd8c24a33de47526 GIT binary patch literal 2677 zcmc(h={wtr8is#~(Ad>BTFxYh-B>!RM%C7&lIS2>GmKKfK$Pv$=$aHCU^Vpd_ymI`tHu81;0qjgi#Sm8v?LoCsV)2_jdv^XQ7luvFCsU43iG>QFU z31A=UJf*gd50IJ}K~BmHFNH)^w^5qtb0|wJ?^+pJK3?F17o_IR@a;wlk7>4Yp7-*D z>=(cRF3~GLuMA%loIfNhbU0n#f>yurnMs7+nVH4^s%^rs!LF7)%!zyF9np~LH6I8q7&WTx=Pw}6kj>^_;p4sY0$UsWH zTmJ|L?|Zr`av?+HiN%{?mg*(Z?> z=wF86_C-9Y3ojxv#Nu_*#1t&SotTL4@8_>BH8-W^BwCxC&_&nSKJCsZa%V(<=WN3? z%D%>^$XXbyc2+^-;D&|h?dyKKOCMM8Wj(Sc(Hx$J-3eU>aI0#ZL^AG8&4LlvLGrm> zR%`9%&Ji4%WxH$+eet0>OWZ8zSanJ|-XwaZ=jcI6jQ19VoCRUM;`?R}R#Tz`&D$eY z*@B>|phZIwO3-a+oIJ$axO_;K17tiY2?f79t{dEn+VJZCzSeHHdP?m$zrAh~{4 zLAz94HRtN2^(Z6;E2FZP9DC@mkny|VLH{8xe&t)W6*d#wv!-LchDLiC4pUSxwgm@j zuk_EDLpiagQv_Y1gqwGY<#%6YfA;(AAvP2?y}xgBhTMe${_?L_G4#r)8e1C}>)&bm zZM1A|EaCJ#e`%hoRq8?_JRP0=f|jhwosbnGUyoO>HahzKGAZvI%K#)K-+O*4j5=9+ z7lRri`EyD3UeqT(R}ck}h((yNmDVP03^nTH}~(!5x@pg&wnXe0>NWmh@ z*+CAE-(=mL6m8NXjRbsFAeOfWWtXY><$FTgIBOY>ZOJ&jF^2UQGG$BA@?R;q zbmUB!_$quD3WDH+oM%^Qv|5x5DxB-mt^>z-W*aCxT%;9lV5?6bBv&nLs!n&9B7_Dp z1NVjHZ!v3aUFklTi@sDzg&Z5F-fg1&10R8cEAnSAQr1v>q zc#eDYL*f|XePWy&MGVdr_pL(+cf1-MQ#ikoOKo4Jr{!FX-g}1f4hyI!b`Kh8oR(Cv}VKIb>+Ift(G#eTE4AsDT$(W=EsuGkpkeA8bZ$+pw&aKE=?xIGgf zSoXDR>dU9$LwcDm79Gh+?_P25vgBe57{ONj=@~;v?9Ws5h*4H52 zwU}L8XNb=u-_S;9w4>hHMcn+zsHS7|Zku9_H9^>sYC$EaOoWC?K>kVuoaI==_#3(hy>j(Io(|l*n(Pi{dv6 z$o_BZ-?FRGFeQv*f!x}sjj-c(S=h$a4|!b|L3Xau>lYj@F_hWb4I;8kmoXw!;#c#! zp?!Y=AhT4zW$yF*%PUrQwKAlE3;f4Xn|#4;F0VI(nO17;m&Y9fy1N{<4H+(OZny9j zHppb^aVE*7phzw7LWUe~`tE|$Q_z7SK5TiOYxT5yGAd$gdc6WYw>R8jdZgjmG+)Dx z5}Z*@@IB9W`H1s1%2NxX8oBDJ+)ht!OQCqJgVK)8rtZl=JT_(9s)AOozFpgop-G|a zvh}FGBFjnFh~VH(dhz{Ci9Sn-itq)j$(+s9;=#_dS`7ET* z>eg4n^3Qy^GVl^RcsyD^?j31CH^YPU&h1XrjegSqKUmR!<*e`oWYrJK;lQ``PdyUA MpsbKp=I-(T1{9d{k^lez literal 0 HcmV?d00001 diff --git a/thumbs/rock_005.png.import b/thumbs/rock_005.png.import new file mode 100644 index 0000000..c7b26eb --- /dev/null +++ b/thumbs/rock_005.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bbh3fcaqd7w8r" +path="res://.godot/imported/rock_005.png-662557edfed6291b142f06b7e5b91387.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/rock_005.png" +dest_files=["res://.godot/imported/rock_005.png-662557edfed6291b142f06b7e5b91387.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/rock_006.png b/thumbs/rock_006.png new file mode 100644 index 0000000000000000000000000000000000000000..8d69ced7367d0b2ae15b8c2022b22ddbdc40a447 GIT binary patch literal 2006 zcmd6o_dnYS1INEcQRAxWG!@FBW};@r7PO&MtxC>Jt2G+CF|ILUS5tHx;k44)o)%R* zTodCioZ2L{FVu?BII1GS<9R**#QpI3ynlHA0q-nlCxnEktSA5g683hst|!F*Zz4h` z-)(Wb{{(ywToKkl?V#Km00=*|w}rdMz1)1&mn(;q$5R-y6a68@J!6Hs1#yH>J7?)+ z<>WNM(%`& zqTG*GFim`fJHV_0x?K3uO8G?)rzCU!9YU|&2S0mfmlsS$2lIv?V;}C-qnT?8hf$S; z7JrcavEfF|PGwP2Q0z*@K=^Gk*CmbXi67Ysw5xQ>vNB?|uW*V+!DHG7eT&TMkoOYo zJft7D;Cj3143fVidh05ym^Q`I#ARkIpuO5TG6|Lzf*^2Vnts--^UIC=tWtt9W%ucG8E0P%ezw39ndAd9oFDT_k_r($&Xi7YRBAc z8IIIM zhqY=6e52I{Kv>P6jHG|o+grO|m16|=ciP5K82j>1@bSAHtZaAYHp)D|HmHoktbdYn!m*4%;QX-P*-qVUD>KcsdxSU9Oh zSbD8?diH+b`-5{O`V?L7m-X%&jJFJdvn78kfV8iCXf$xU>9_I8Fs&9P+I)LL>^?~$ z>CyUKc5uRKO#qQ$M75fyDz+6{d`S0QxJ8L@9FdC`qwAR(*58{9Am-Q8qtIobmzq3~ zzukq@)0U;@2SdL8G^1?di+2blIcyjTcl=}%XRcI+|ISgN1-srjp3lNL@ zCw^CcUUx%P-dwB|yZ6g`nHCQL@pSKef10H{<*5d-IiDIS=Lqw!Y6C|;CLJFQ#BsrX zW@p2R9$;vH@-rnZ3}*XXi5iKvV=My-{QPv`msXKhsYD(VH@XHntg!CmX> z;AkCBxewdVBNgG{Z>XOZlx$KvP2ke|_n|>PqifP{G3zR7W#{Mj8OOM3)9Z*>J|bq za3LX_hr=1Q_G3GMvw@_8kg-Gyxmg<>#&K6E4Hmbm1L%7}XHXz6x?}TAnP6BGeLSdj zLKff>aGd3#L>w`8xDcBS*ehLlE@j(T+lPohT4kCR8$GAiOmqr9I3!*^3j3>L| zRW6ebDscC!q%H MuR7V*TBB3`3pORA`~Uy| literal 0 HcmV?d00001 diff --git a/thumbs/rock_006.png.import b/thumbs/rock_006.png.import new file mode 100644 index 0000000..6cf17c0 --- /dev/null +++ b/thumbs/rock_006.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cfs37vno1jid" +path="res://.godot/imported/rock_006.png-07688541cf5d99552b98a8550642d3b9.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/rock_006.png" +dest_files=["res://.godot/imported/rock_006.png-07688541cf5d99552b98a8550642d3b9.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/rock_007.png b/thumbs/rock_007.png new file mode 100644 index 0000000000000000000000000000000000000000..c70d073119a702c1dc421cbc213631c7f7a44327 GIT binary patch literal 2294 zcmd6p`#;kQ1INFc+{eiMPC9GWiBd90Y%Up^%aK%Ga$PtsAtudcG<4!{C>?SeM>^_`@zKj zMnddIcU$`P{{Sf34Py<|3~8Y(wwfx-sf9*Nyt6P-!e8keM8{FyKAsGegYgS4y&&~Kff z#WpZ5HBbBhQuMgPcYKUJcVDlB+uesqe`9QW4pd9pQLH7h4RSo-)yl;>cP%p?2@#Mz z;m2ST^&^iYJv&{fdjpQ|X^tU9Aa4uO(G-8pWG{MCe+*yQ(ZG_x1rgSG1EH8=m*#0} z11?1p9^B&0Yhxq5I8YCgv<|Xq5U4G-?BlaYuf=T)y;(zU#BMy2fqz`OtdKlE5T9BM zMdKj9=IDHeFI4Xsif|WlGi!NvmcAjmAi?eZSIXKeG9Nxz`e-~e<_1$mWeg<{}S zqU46dO@d|^6X6Zlzv(~S!YmH6uatYJ&Hb}XEkSLxn5Zv?h*PXiBvI|;Kf@zfCmifl z_pD-{;^^ds88Z2+JofoSlg#0C$XY8#fdL7ao_Sv=&^R3Y z?AtjF)rFDS$ij(;D#Zxz7AzTQU5bqKF>-=6m7G^Y8(i#;QU>qVQ=quz>OjgN-4Mte ziXdrzB_#>sAaAdu4SF<|4YS_yJ4iQ{=L^kvQ4ITupB_5nD4Jx9c5I#o`wHz;#-d)mzEQe>R>@?d z5|UlCEU>f*z}I+?wRhu#$lOLo0iZcPr7Lqdk~ewHH66m;*mN1V;QW&WOd-Ffe;oR) zF(0n@s{?HJ>%0xnc6Z)wWk6F;b=v zXdeF@1vKM#U1J4ud;m${cCJnaV06UhIKqV7vq8<@Z&!@jRObUJ{%)!@N@{VI`Y2sv z`AiRKj68YBD1+4OESpQ&Tkmd3g++0+Xl)N++rk-C-JsVz&*1>dn8hW$FB5r;qB zGn&sR79g_E5PA0*`;2~)k!t~@PVOK%mHjc?BzR4p_&cRoJH9mMy{yQ=Jj8Nd1F`9IVV%b;Fi*7xOL~i>YQt{q>bT^?pTfGHr-i?%_TY{C zKCGB)d!Fkg)fx6N8v80!P6)Y^@UmsW-JG0#XFOI+pRlIvY0#$YGyZ_0CGK_dhWbIH zlTV&O*8o<*W@^lyuW_aJ(3Jwoy3Orq4_l=keIijESZg+^m-jYWgdUq-_wjC_;flSX zZ*OYBmD%HNcR|DZQ(?#nO2wJDiNHU5N)Wzf3LJ?Lq%$n(^1~U^Uu0?eP|>jPS+BT+ ztgvGhh{r0xTrbA5aA(Qs?uWMVHyY@lF1>^0581ooj5Bt}dWi38r>`C0E7FXl+`SV^ zmyKlF?}be^x0LFKgU`oXxO=k8FDr)FCHr$hZLLL}H?7?>-p_X0@E6VEvF!zSzVgq8 zlcQcNBh_K2RhgBf0uA~up)7@y(J(eBPSzG(g<#I9k7_HqdnWpzc6zGLYhYg;n6qF; z8p}36cP`oeS@9rfJAX}97`J>-jJgb>InYqD_bh@`D$&m_QNQeJ9D*qIR8eyKGS%&i zX-mvDVS@yTVDM*#*SynOx^u;5KSi;1rr%)~=-6jx6Z;ATZo`u(!vX21baF3WoZ~~& z=4cm}ee1ea+RO>=>DW9ubC_Py2p9}@aZeRu&-8tas0EaEjzH*%KPJQ>R?N(E@xGo6 z^NA!;{xOj>-z;qF9H2?;u z&_(bsgeLO3TInCeEv_B2^5lP>E1#NW*G+^6Rifs3FEMRlpVla+%;g7y2N?iaw359er^H8;7Xfoi%v(l%4V`V7P8FgeF5&%s&*eZY2fb6Bm3dYb= z3*uIP^ckank!&>Q?IvW1P~Ad7X&3Gs_{Ivx^)cgPgDNRCGm}nW9U&r?+5Y>SjT0ZZ znM2CklxCtp9j4^H{g>&{A6#jc9cz(GtI9z`x1#=YqPB_#55-^=d<`%-vAVCPx# literal 0 HcmV?d00001 diff --git a/thumbs/rock_007.png.import b/thumbs/rock_007.png.import new file mode 100644 index 0000000..d1a48c0 --- /dev/null +++ b/thumbs/rock_007.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://g58x7q0unqhm" +path="res://.godot/imported/rock_007.png-3cc03e62a568b43af0a8d5cae3ca5ed0.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/rock_007.png" +dest_files=["res://.godot/imported/rock_007.png-3cc03e62a568b43af0a8d5cae3ca5ed0.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/rock_008.png b/thumbs/rock_008.png new file mode 100644 index 0000000000000000000000000000000000000000..b2a2febe0b664609d3283dc459cf4bc28de33890 GIT binary patch literal 1728 zcmcJQ{Ug(P0LMSy8D>sK9*(%_nupe5aYcp6Ee|EeIqI~uTj=uq%!YkYhl`~s$;0HK zR%;pMJjU`&%tMYGg`9_I9&UL!EZ6-J{qTOjet7-=e+NXaInMgFVUhGvWV( zlKI@tR@9fD0fo8R*?=cPt@i-P&>cv}-JNF?HT_W_G^VPRsbiPVIeM!SWU<)@kHYWV;ib@2x(ryOQ##jAm zrt5SK>Rthn`*JeXl?-7@RL+mec~fHlI9}XSwU>ylW=xqh1wSHi&<{_Tp>8HmnFnjh z@>+HM8)A-yH-1WCjK>|UtY=IA?FW~-AIKpTy+8bhW2SCPB!_kk1G#}m@e2T!MDAG~ zvdQ8U8F_);^>@vyan%J(_aki05oA<1k`)k^1F);ztP)eg<0GEQOPAD?{6vevfQ&BK!p|!y$<@U zxT$O?y{PK^8q7_W*jXbg5OZX&?Ya6JnmE?jgy-DP0yoYG=iX9nrgwN-hN|^bW-umS z_gYxps{`9-k8Y&XwR`9R6=^+kxMKfw&}#1xDW)Hih6zjV0iPl^`x`BReT`fGgW1w=e&;T5Qkgx@^vH7xD;H zu`B_%(1go->>^se8oye4qCWPiUr83j6IG+96Y$hobj5P@w?l)kUU&eZ;WP5ugj5T% zS}f9~wfGwUb2%}OE%T8QG&gdwb9lXz)Hl}WKj{3NJpc0qpHWeh6qB31RPuVw#^|Qsg-oxT|bzSErQdf}GVG`HNbl%-V zeGZC|4K~wDA4f8jbb`8{te8e3uKFcS{WLqPuHLl!TcZpmL0Wra`K}D6?*)m*fZ1PL zi~TP155j9L$$Yql)Mq@r`gXfh>KA5Ha-?sI_VjI-q(J80?-lu0?dVPQ$OGF|XOuF+ z@!I2gwlWSGY|Glx*RTBOTkqqpXOFsIvY6XAMHu_EC(B}4GZf*dsS(x|q}64$$KD2Z z3aaJ_=Yda;^y@n!CVlq0t*W&RJmMOtbO}{xBJABLGurn((%ie&&Mrij!2IB~ww$S? zqmii8z}9N*dtWl9u*uQf@h% zx{S^EwdX!ty^skaFOp)h*yP-wS{##<0VW3ncr$sFx^w@mVRdkVN_IT9K+&N3%#Y!# zy%Clc<8;bgPE1l7ur~iXy2f<7lvR9@Z=CKaA&%42y|6nTglw_&eh5B@u2&Up z-@p$*-!Yb5k18*JZtC)O zMj;e&&XbX`afIv8;fH5Y%&a#1%WLYAc~uMmuO|n@K6iioM~+8_9Qf)KVb`Q5(TY`E z71#Y6)i3ILQ;Maq}yXpy|3@C+4~ znC^pZj+;^S;h9Mu_XksE uHuDVICD2FK6S{)ASq!MLUwoio4``wRpC literal 0 HcmV?d00001 diff --git a/thumbs/rock_008.png.import b/thumbs/rock_008.png.import new file mode 100644 index 0000000..434d079 --- /dev/null +++ b/thumbs/rock_008.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://gwjekiuijf60" +path="res://.godot/imported/rock_008.png-bb03792c1e1cf798ba35cfd9f6c6ae94.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/rock_008.png" +dest_files=["res://.godot/imported/rock_008.png-bb03792c1e1cf798ba35cfd9f6c6ae94.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/rock_009.png b/thumbs/rock_009.png new file mode 100644 index 0000000000000000000000000000000000000000..25321e514a150ada4abf64eaee55281147f9f2e1 GIT binary patch literal 2611 zcmcgu`8(8$7yir`hM}x67!4uR#C%isW+;+zFV`UZb}OQrWyq2-hRB{<*~*%^LJOe@ zVHPSe7!9r{ds#+v$u=0v_5COA59hqkbIy6r`#k44&pB_}Z+6y)U`j9m01nw)vcw-C z`Tr&=a^O2Keyjrkh2yQy12uh!1ppA^*;raQMHlgkSlI|`6*8UsPt1>w@%7O{DZOuG zDH((mqCHJNUo=hJ`q+IefJnS1p$(N&vx*Fb7>9zz((>hWRFmGRS&(zI)f_}&=?NO} z-?i%6YGddv85g2%xv z%uVwhzFlSXODuO+q}*q4R!--z+!9DyQ`cvWl?1mmWYi!-gf4f*%pVY1V?$|NYWa`0 zegka5*E2+WspzAZ<~N|Np;Hoi-bUeCy74t=JfK>`OMpE)x>e_8LIP-#emTc8oRYrf z98`4JW@Fbt-kU_f7l7?amLtwT6%A+jiZZxdm<*>^0qi5HA!T)1dTJ5bKg5>&0Q>Vo zhzS0JC0xS4%xj1GsQx>eYf?ejk zPm!+=L*JT&o=KAqzwUe zID8DChb_d7b+-C?iW~%|uD|m&N<^PH`p=o$&q)C!sa-Q2XstWo&%gP z(J_G?j6xpy;12*3tAUXwYo=bDvgePOfw?4Hq^p;EyR1G*rF=5!^j;sX+Hx}1iKRJH zpYRC`B>7o345Sq%MpU`T?JD+?^PJ75DwN5UQMwg9-q$d!&61R*_cCVtpIs!ww5;#c zfgv_abk7sgcctUvT&u81qtvQR3mFZj!taFD)@Wt*%wre*P!Dxv;F^pj+V13FeUr}o z)#|sN#!ZR^@mDy3(rYAV*#EqN$|Gt@YKzPOQeK30#0^CsX~`) z%!Au6p{aMYQ-w}+WjM-h)}1~=bQaW(f3|BaIJaE@&Fltd)X8Zp8o=)EZnTjo+MvY# z(+zqF$GHbKx`jBg+2x+(0ROr2-LUEQ71LAWC49{aIgnMm*xJ+Y?<2_`RWM z(EXk_Zr2H!7yY@h2}|Jwo-3i?YVFAM{mMP!$ClP`xTbl_7YYKhBN$uM&whT^ z!#n}-Qzp#~P?H>2|fH;M|s=>>%${`h24PZmq1)K$=6GME=;E%jCoE`{FaG_$& zs*E4WW=aEqv>s>KEZhCLmo~W@Oe>`Z+vdVzsTa4msEvCae|u?#&pH2bGe~e2*R|51 z%KxlraIco5=u-%otqhh1FXY`*qCm8v7CUgGsmt{Yqu5@5%w~EW%mY^M(|fMcfFpd& zkRJs6_*?nXM`5}l{21A=wk^tII3fqGNwzZn6FlBwOKK={KIn8Z@Rgn)U*=MWolVA6p?4t~KGda9zI@mkUXK?Hq(A|+%eZ5874XxW+{ zMeC63+= z(3UiB(tTSlSLUL0z1*G=`WPcLH+V5f&S!Jn9;iC|W$^LM{@bhEw8>DXohYG79+bJ> zwwrtygGvSdv;jidU0Gj0dmdU1aZY@07}-Q?v~L^^xK{o46*EOR5FFtY4utY%4;LxJF52{8kE&`k4O~u0K7>J)0qLFeofypC{ZrhR215izwWm;Q`muKH^7}n# zgHe?vDRGtP_w6vC4kD#DpmcaOkaTJREmD#%zK7k5%|e>3a*Nyg)vrDg?vGhv3I_Q5 xw*|#(ZND;g+m%3w_oyCiMwromFL;XfK~I=F?@jGuD-Tp4U}I%xS##bu@m~*#)35*l literal 0 HcmV?d00001 diff --git a/thumbs/rock_009.png.import b/thumbs/rock_009.png.import new file mode 100644 index 0000000..32bdd5b --- /dev/null +++ b/thumbs/rock_009.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dowcg0e426hud" +path="res://.godot/imported/rock_009.png-863a80ca7d9359375762aba7e143265a.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/rock_009.png" +dest_files=["res://.godot/imported/rock_009.png-863a80ca7d9359375762aba7e143265a.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/rock_010.png b/thumbs/rock_010.png new file mode 100644 index 0000000000000000000000000000000000000000..0a7a981149c5da6e68940d88a62c5393da3d6a15 GIT binary patch literal 2264 zcmcJR=|3Cz7RG;xEw(mP(G;=Wq7+wRA==nNms=4PuQY!FB(Ld2!D3;(VUx)${p$Plm0vnIIp64*(!&VUD&xRs8=4 z#(lbb4ZMa=1rlLzW(4X+B~}1{rqo1!_mu0grj~WU&{USj6{Cn$8zp7&*(;nUCSW8rH5^fLp z7@0~fE@p?VQr^wxCE+NjbH0~yDU9tn`CIqwPI~{N=%}h=0LE3Y? z>B@}+?Z@#x`W60o#uA4|DjX1t1cvxG4(NGh+K6teYg3)27_CfOs5vM^TvNP4UaH5W zb~fK(&)abt?mHcnv*U%av|r;Xw$10T3zs(?0GC$cF|Jt1;gQ<;=0L< z{@{+79|A>X{O*5^Gw!XdnRAwlA7Z_nWpwW#pV51y1UwOavS)Uu6k`zBLq}yzH8*X| z*{0REnt5>h@|lJ(#)=?JsjPH{6Ep&H^LK&NH>`}368(g$|f0Nb%E3~M1Q}0 zZqpJRJLw)6;)P$0Gwl&pB9>UDaML6!q4J3aNZepvOe$=6oz8fX`KT z;j43uppDG1;_mSg66&>g&<;@}WY46W<6w5?2))s?C0HYE83on6ZQR13Y)cNO!i8UZ zkzsGT$1{`a=?A?S*FZuLNvBeBxG(JbkV>tM1JRMoysvVGo~4(NpR@V##lVQqiu0hu zkRdr8*}2QIENuxQ2+dXGl_Uso{7CMWig~PGqj&Lu%qlQIi?D-cp_LBD%Kzp3lvqb! z`93dP4tXU%_$jNr7J?@<@fi?pxw5%%l1i*aT2Cq8V4lJmYL@pL^#r8Me|{@9*0&A zk9FN6_(6duK|CclHGCdYb*;vYCqRw7t9-yjir-DBfte(sAnzlaRaj0$=54&ztIguJ z8|FoORXK~fl_cP_5r?dhD>*OXbK-b4U_wS-#*iY$$gBAF_DWqE0J& z-K>A6Am!Al8jMNWI42e}YLcu^4-9lxYwv&iW5NZ1<(=x57N6TG{;yqoyqRVRvpP-B zNJ&geu*+=)Pw81ZR^CEVvkXa9wc z-;xIE7U3xBCxG(7!u(kX-T3y6KWi=v%QK{&m^bY?9Et>Hn*J;w*Np-YE>4j6z*A~< zHuy~EU13zQINd#HAVAnsTj4|wN7d=Di%qjlW@xuGit_wz$_x-b-g z#yNs|?7>5dN^wtGv(}rs1%4qLOkA65%-8DFYfuShqTWMITK)HWQ`?PdZq)uKBEzo# zPh{CsAU0bvEdYF+h|5DKTU(_hNMqeAl+gtUpo{>xca_(26>t8uh<;;JMt7KV)f#H` zUTb4~umOvNCJ4{5mGAPG@`?Q>A~W1qCCc5qwR9Ngq%Kecwd4iTPF$8As;w`?HvNe= z^N-WToZcgCZSmXnZnYgDk#Ym3)tWvdU~-#qT6iKb%wC-7EWS9c6oAO-uFp9-IhY;2 zx);)9Yk%snu7^?|5Cc}~x0NtLmZwCGZYNE!U#`|~1tCuZE*}XE@og+b*S(SAE0B$A zW*mE6WTgd9je6=!*y^j`ZBBL>=cd0dmel~TF>|-RM=~ay8CWQ4l@WFQB}4hC#lXh5 zQq-Ng9W%u%0O%iW>4nebE^EfUp0yx$fZWP*axBhHn+1`D>L1L%Fnfd<3n!d0Fht{J z-&0H1cy=UsaED)K#afJSB|ZfWjtL&vjJ%)Jvx>(y6+`=j4p|Esp*Npo?(R-(nPPE< zW8oXcm>{+LlcLWy$v?C)ZcJ;HLYvO1kD(`rHbueEvj$-(x3S(r|DN&P)*alVh)`;K z8{GU3UZsmg-23Yp3PtKdcf3zu6<}dvjjl8D GO#B~uTp{HE literal 0 HcmV?d00001 diff --git a/thumbs/rock_010.png.import b/thumbs/rock_010.png.import new file mode 100644 index 0000000..9804a38 --- /dev/null +++ b/thumbs/rock_010.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cq4q2yec74cmx" +path="res://.godot/imported/rock_010.png-a632f46c1a884903031cfec0915f9d66.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/rock_010.png" +dest_files=["res://.godot/imported/rock_010.png-a632f46c1a884903031cfec0915f9d66.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/rock_011.png b/thumbs/rock_011.png new file mode 100644 index 0000000000000000000000000000000000000000..a867cc83579423e3393758dbde86df5f27520dae GIT binary patch literal 2304 zcmd5;`#aN(8~$w0r%+BUhe(Oap%B`f8iqt`nL{zBjGWK4VosHm^7S=`oJtn2mcxs} zoL`5+Ceo}~By39#y=Y|Y-S_)fygxk8eLX)s_jO;_b6xjyXSrQ;kdcH)0stW6h=3yn zi2q-Siwb(5rQfgsK(R;%Ti`WCl>-3cZH{moR8q-uDI-!9t%mPvU3uM+FlUxf{A4K9 z(ZHtatYq$f;Tk79sp_@;5?H(QyFdy6bu*C%OJq4Mq>2gK+KE?ZWXK^zoI(!EAjYCX z5H=ar7vD`L_~Y)-H@_^#Bo!8Iz7kLxx6mxRTs^mcj1(2c{^FK0Mi557rq`1*D^4wX zDO-DZ!+}wGkg6H=L?(@a@i8wX>#vbXu zaZk*M@V(cEHzhg-??+Tnd(6Usi|C2rPDmIQ z)S1XO0*(>0H{uqGNbVr^NMQ6yJFHiQg5H|r*>I|?m*_!ElcAj}TIY&^61-C%f}(iUwnn?Rv#@^ z8{YqRn|L>8y#QT*?8M+*#o6Y*bQMwQYwA@H)KY5&p73A` zgp(S62NfD0T1NXDa&Yh&s-`{|qwF(VY1>cbC#4N?t%fRRct0O}ym6Fn2Pi8hv=zVNC^~Qb5#rrY`Q~0xj0jbBC^4~VwpRQ^UQY`teqE)NB#=wBWFpRvjcN7mw=zKb_|4gso+uwFakLO=c#TH@{KfB|t zpgY_4Y?+5i(~%8<&Q&gb-Qn_E#$vJ~o6?f~vc8t~mIdKq&Wl1eD#)5i^Nogkpz6s` zj5#nuI1yLu_{NHM$d0S=yeWVYc$L-my^YXB0uBb>wDPI7>_J4LIphz@GqPJ7eLE6q za%cA4cF|(EBq71o~Lyo5oW)&p9S^aDiJS+cJ|G>nVjfn5pU%3IZPMU4I=W?Mwq7)y!j>HAnf~${ipaMJ%Y+XgOkUH>CS!7y;&c$V2b_ zrrKMm@iO3P{b^kath$GwwMR310rbJwN5fB9_s)J{S}QaeXBM%8sM}M7{?wh-MfQxV zNz0?E0rotUaZ4#-GAF260rSGJAMJZG?jtn)G_)Tf+5m`sXa^6Dvf z9G%N6fSLN&dpE2I7g7bxGVbTccxZx9i(fG02aOo~XwT~$ yWjZg)FM4oc_%#Za&jn>D+Wiav@&Dt&wpHNXTE9};V@*M%0UYfv!e85B(*6Ou>pX4% literal 0 HcmV?d00001 diff --git a/thumbs/rock_011.png.import b/thumbs/rock_011.png.import new file mode 100644 index 0000000..b075b41 --- /dev/null +++ b/thumbs/rock_011.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://k0yrrki2qabv" +path="res://.godot/imported/rock_011.png-c90924d27851a7a5c7733e6897e391b5.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/rock_011.png" +dest_files=["res://.godot/imported/rock_011.png-c90924d27851a7a5c7733e6897e391b5.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/rock_012.png b/thumbs/rock_012.png new file mode 100644 index 0000000000000000000000000000000000000000..e636c34a20d2ee386a2914a50a709aa02dc2149a GIT binary patch literal 2529 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 BXjK3J literal 0 HcmV?d00001 diff --git a/thumbs/rock_014.png.import b/thumbs/rock_014.png.import new file mode 100644 index 0000000..e467a4d --- /dev/null +++ b/thumbs/rock_014.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://spstllxv8ka8" +path="res://.godot/imported/rock_014.png-9d827ab2547b61b55597c0f1eb83b9cd.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/rock_014.png" +dest_files=["res://.godot/imported/rock_014.png-9d827ab2547b61b55597c0f1eb83b9cd.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/rock_015.png b/thumbs/rock_015.png new file mode 100644 index 0000000000000000000000000000000000000000..4eea36cf6a7818291db76362aa59a9a968cff40a GIT binary patch literal 1776 zcmcgt{XY}<1OIHzFu53!VaRh6LuJN!isT{8os)8G5z50Y!+B`8EvrMF%VR1^(ZdbN z$x}BBInKifJB(?0PK_jDnSFi#iTmOGe*f@(|M-5r-*wz*HI}ydESx zW@f>iowE;JIi%dAvfue611?X{GcYL6faU5UlrnUmnm9caTAb80osGAZal1JiH@YDv zjD-zUiX@jlblR;=8OL+c11XU!)NOn8z_ZkirUiNES$wRGQ}Xj@Ex*6h9Zi&7iHc%^zZ$pyX+RuTE?j+A?c6uybeibwrJi>&f94HOpk2 z>mB5^loEBv&27%aD0~V*gr7a0-^?@d>GQA1hTcR5Bt5x+FcDt;B0;u!L0V`Fs#)F2 zA7^K}AOP_Q)Wd?@95MvR^ny9vtP_)e(4b@F%uxQt!WXBf4V<5pkwue#xNm2F17Cq{ zibbQ>ty?o0IXi!mxisNPLu zz>^K7q(v*}64##|W^CC7$j4X_RI{tA&V4>Mbd-%0_SRPKX9S}>q^Rcm8PDTqqX=kt zlBcm?A7IeqAH=`A29e`DvR;mWRKpgp_K%)lD}Ov)X;@jQ-S&x(qO)Kr1wD)*Hbu@G zO$bh4BTMCFbdSuH=G+H`func!IX#b)H4fG*Zuf!|ev^1T@jd^ZlwI4bs7-~=RWRpx zJWsX3hO6T%k;%Ye_Yu8GJkel*UPx$J()#%o{hP zb&9FcN?jRwylX%{mDnh#`NpFYqW*H9C;wr=06HoPqU^445T_;*1L&-zp}W>`D`dd?6sZg7bQ;DFwk zgg7n8S*mRdQQhz5*fWnxNawJqJ98>uqo`kT_aUDLD{aHe3`<{6wDn|q9#Bm6SwuOk^^Ar z?}g$tx3m^yutteNZlu#Kb@LjnJYi=+%N4HC(SuJ>5bcgF2Pf-|y>w6a(s!?_4qK#Y zi1S?j!IoS$lO;Ru@m}u=JfSxB(~F)r6}~2MXM`=l8r%P?Be;=yek%QY6%0Q87Bsx1 z7WqC$YK9z{wDjws=Tsa@9+53FgjrvUeql!vQPM)_HX1~EtDgvdR=w2E35 z(6EV;3j<3*+?};Il4FSiw{`^xe}2-YwO+ua&g1|DZ7viRAh5Q};LCZTF2u6{g0 zuMOSCeJ3$8%`IFu;qUep5ND=+e+wca=aaKnzNM-Beh-e;5?cd6mi*m+PICLny{Ix< zN@s6%mSlFsD;Y0MJzeS`xT^!PURW0lbg3?3)2p{O7aYHgcFXLp(2>AnqgAnC{_1!Z zTP)i6+8Nl*TZf$3vywV^imm2EIZtWMl}Uh)i6TQyCqxmx%6a9goV{#cXB(0p{ht7R zOah*z1VAc@j#C$kf4e&c7cfh}or=5fI~TUSr#3%KsGS)`$H*vIu~D*05&zL>b7>Qb WK`zTe4rBMifQOrp>oXVPmHz=gu_HAA literal 0 HcmV?d00001 diff --git a/thumbs/rock_015.png.import b/thumbs/rock_015.png.import new file mode 100644 index 0000000..aca1c5b --- /dev/null +++ b/thumbs/rock_015.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dywjcswag5dce" +path="res://.godot/imported/rock_015.png-b011539f6ff43fbb09745dd21d221fcd.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/rock_015.png" +dest_files=["res://.godot/imported/rock_015.png-b011539f6ff43fbb09745dd21d221fcd.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/rock_016.png b/thumbs/rock_016.png new file mode 100644 index 0000000000000000000000000000000000000000..bde1a020ff927d08465f271f3d411b01530334f3 GIT binary patch literal 2621 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 literal 0 HcmV?d00001 diff --git a/thumbs/rock_016.png.import b/thumbs/rock_016.png.import new file mode 100644 index 0000000..9662a5d --- /dev/null +++ b/thumbs/rock_016.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c5s5qpxvic06j" +path="res://.godot/imported/rock_016.png-3d97e45b49f7417cc8cc7ef4c47cb1e6.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/rock_016.png" +dest_files=["res://.godot/imported/rock_016.png-3d97e45b49f7417cc8cc7ef4c47cb1e6.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/rock_017.png b/thumbs/rock_017.png new file mode 100644 index 0000000000000000000000000000000000000000..f8ec40925a3023680cc668fe183b171e5e8c916b GIT binary patch literal 2156 zcmc&$`#Tf*AOCFDYz-SiCuB0CW9Z==N;M;0$SucFxtGwwa3-c)Hn);*5x#Pth%U!Q zAssdwIvh*k|(l8*zh_h{_w zUgkTRDtROF)4je@`czs1t3CoLBF+vxMQ8jNs&>Yoe)^$SXR0!3Xfmf|JTwgU+YEaj zTKB9Eyc+f*W;(5z@*%cgRvDUgdR~ho2;ehPyYD2^;?njM_Tz5miMi4^zaS= zI_sg@yrkB-id?0yBA5*w-w0C+4|@Rt(8^z)M792)WqTb3qNGhdT6TvZ9an5&!jae* z?SZan409pqm1uv%Ly}@maMh^A(#**^1t@Luwwt0!OxlAG9jpc0H8eWR3C}KU3)sy!TqOb<}44>CSe8cC?>MOC`Y7)2Y z7cr+X_jD<>>`#vkZd~ts?m4*hN^1h0kW^)_3b9G6UN%PlWa?Y$B~bdf;16&4>aE`1 zzl0hz?evJ&b<;hh6B})@WUNnGzT|e}f~B2=Y7@~Uc4+?4kgfyHs&Of_GCl==XytT1 z221`kH!;Ou)doqdT|JzbqT9t@kB{W~vUU`!fx_1_`3PdgO^`d;gtfB_4 zoX_!VyC(Z_pP6(k(5QM^eKM9DB%C^#sRsS)eIu1(RnHy0<+}b+9GzRt3v1V!hZ&>{ zM`}&Q6-VV`NFId9i^CnhlbgX4c4^Cfv3>ok;d43%N8&Tt$M(2bxB9j=-C9eQ2Gw_* z=zW>3kgztLHU22TDzBYqU7%>z*%&@@XUfzbQCOhSM(q#^-kZPkkU#+)3XQSsMMtE= zK0MVe3>jY4Pu1&c^7(z-eHmAk2L1@wtlXr!DHrXil;B1(Mtyh~YWk6J;@aFtt!vq5 z>;VGH6xeUQjLV}~>MJIiAlq?sz9{}Q6irH*y`@Nx%{7?eQyW$#b|Xu;3tWO_qNI8@R@>LYKl;x2WesHb7P zC448S7>_avs4Pyo@P=nA-O8WP-@ReYYdatbb%r`20d_#?2*D6TI-lLPa(KT5D%>lK z(Nk4U9hiG8zpx6hMZgN3geuC2{FT{()MLL^F`f+aGyIidiCkag{Jk2X!cKYExS1vG zr6r1l$I4+oukmaGi?+Dl4ZW1pS%78bE#-S=h5U8#|4%0Uz*fnn-{;Wpa<7Vu(@$6XJ_Hd#SHH%#^`E+(evdv^^C-Rwm|nK!9*cs~isI3(Fv2x7eqtm1&w&W-oZg5i0P%XbYtC z9RXDb-#yLshTsC)zSnAP7;hZ=v%7CAq0Wt5d5R01lRcs}_)6&iLqx9Yy=e}Ii!lv7 Q^7jEa9(Q$M+Xtrn10MI!s{jB1 literal 0 HcmV?d00001 diff --git a/thumbs/rock_017.png.import b/thumbs/rock_017.png.import new file mode 100644 index 0000000..c249d9e --- /dev/null +++ b/thumbs/rock_017.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://drkke18qhu5kh" +path="res://.godot/imported/rock_017.png-53f778954752696b5993481730949cf0.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/rock_017.png" +dest_files=["res://.godot/imported/rock_017.png-53f778954752696b5993481730949cf0.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/rock_018.png b/thumbs/rock_018.png new file mode 100644 index 0000000000000000000000000000000000000000..0902abfbc606f3530dd5b622c402db4436579617 GIT binary patch literal 2347 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 CFnMAC literal 0 HcmV?d00001 diff --git a/thumbs/rock_019.png.import b/thumbs/rock_019.png.import new file mode 100644 index 0000000..afde03e --- /dev/null +++ b/thumbs/rock_019.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://ltakv1s6ut50" +path="res://.godot/imported/rock_019.png-ea6a69d709ac061f707a3eadb2e8c4c7.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/rock_019.png" +dest_files=["res://.godot/imported/rock_019.png-ea6a69d709ac061f707a3eadb2e8c4c7.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/rock_020.png b/thumbs/rock_020.png new file mode 100644 index 0000000000000000000000000000000000000000..6954498e6c37a970fa71e01a2752273734eb5095 GIT binary patch literal 2164 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 E0YNEL(EtDd literal 0 HcmV?d00001 diff --git a/thumbs/rock_021.png.import b/thumbs/rock_021.png.import new file mode 100644 index 0000000..2579162 --- /dev/null +++ b/thumbs/rock_021.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c3xt18gvmbjc8" +path="res://.godot/imported/rock_021.png-9306fa934e78495ed7e343ed6ba57eb6.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/rock_021.png" +dest_files=["res://.godot/imported/rock_021.png-9306fa934e78495ed7e343ed6ba57eb6.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/rock_022.png b/thumbs/rock_022.png new file mode 100644 index 0000000000000000000000000000000000000000..f4f18fdc2f64c1cc64af73ff2cc6659a926c83b7 GIT binary patch literal 2193 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 literal 0 HcmV?d00001 diff --git a/thumbs/rock_023.png.import b/thumbs/rock_023.png.import new file mode 100644 index 0000000..1dfcf2e --- /dev/null +++ b/thumbs/rock_023.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bme2keecsggkn" +path="res://.godot/imported/rock_023.png-6a57648ee7fed36bbe1d45b7c9472e7d.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/rock_023.png" +dest_files=["res://.godot/imported/rock_023.png-6a57648ee7fed36bbe1d45b7c9472e7d.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/rock_024.png b/thumbs/rock_024.png new file mode 100644 index 0000000000000000000000000000000000000000..cd458c127486d40522e985ebfc942f11cb9903f5 GIT binary patch literal 2916 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 literal 0 HcmV?d00001 diff --git a/thumbs/rock_038.png.import b/thumbs/rock_038.png.import new file mode 100644 index 0000000..3873e2f --- /dev/null +++ b/thumbs/rock_038.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bhnrbk60qw13u" +path="res://.godot/imported/rock_038.png-e65832d80b645f82440aa683dcf8a0fb.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/rock_038.png" +dest_files=["res://.godot/imported/rock_038.png-e65832d80b645f82440aa683dcf8a0fb.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/sand_001.png b/thumbs/sand_001.png new file mode 100644 index 0000000000000000000000000000000000000000..1ddf6c2eae78ae4d1d2e5486a38a19f482291854 GIT binary patch literal 1593 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 literal 0 HcmV?d00001 diff --git a/thumbs/shell_001.png.import b/thumbs/shell_001.png.import new file mode 100644 index 0000000..3939457 --- /dev/null +++ b/thumbs/shell_001.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://d4cchdjjnj3ao" +path="res://.godot/imported/shell_001.png-8ad2749145bab9aa6a8198539339edbb.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/shell_001.png" +dest_files=["res://.godot/imported/shell_001.png-8ad2749145bab9aa6a8198539339edbb.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/shell_002.png b/thumbs/shell_002.png new file mode 100644 index 0000000000000000000000000000000000000000..435fd48c141954750e55977fbc3af9a51fc38f0a GIT binary patch literal 1248 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-HD>V43CV;uumf z=j~kkd}UXOWAksuT7P@j8dG%1QGC0JpwJ^>1zAy{U432o4(`si>WYqz?wvn)6kaS? z`anf0$Tjm_hu>M6Ay+W6$VS81{qF=J{ARcrU}Y45YA$h%X_|KyP$Q~jsWfrTepf@ zx4gK(74XG&&;A|m&uWCsXLMZPO6X}U=DSy&lk?#lV-({ioouZJL$xB4j|)T;-djGY zlhf5d19p(2r2Y@G5B;_ z_kcvR&gmDo9K@^}^fIUaOf&z`RXU^2rE?k6meckP-hcPo@)xW>w(-y#87anFTcQsb zU(GyMG*AGu{J!gM8V z!-w+dCIzPmxff4w&pjr=&BbVB?;I$iaat%fa@|^n`574&U*xzJ_2%8XLzeBEHyh8|*^v12+E(AT ziOTQTy2L(QGdNgaQS&%(?sLm7yQ4cEWH3JdC}C}Ft2ToJ% z`kh}clleV>gJF)hfY<+f_vAj=98WNC2o0U#qc-Dgn#So(nT)UdMDLhpuw)dMl&~ax zykan|Mc>(wJ%T;^((MZz1#?r3JAvM=p1l6=oi@#vxf(1P>gARf*L3m+a1@B1p4#Zi z#l^VJ_;k9Lox>){74!DX&EhJU{QCd=g#rq)F}3Owo-Vn6yYBh2Lpwu(&d@o>yiV%j zDu(i&zxj4qaqDmK#HhOcHZGS0n!$X#kdcdV-rM~L;_utVMSP3*wEOWc_|J#Wn`iUA z4s%d!U@!Rb=f|f{rb2%<{{Pdayvz2&9HDQQpTAGOaDKv4&Pzug9BlU8^ZjT)LxcVP ze-ickZCpdGLq1DA&TKuu?|#2bq4@<41IyaZ`}6CXbWA-avmBcf&i3AR&F2+sokOGd z%!;ZsvrCYaXmxbwR&OiS4GY$m9bJTfbe}^z<)7XlSWySjY+%5B6y7_3SMFL>rfW zXV>Us+g6y#mvEGIab#o5yW0vP3L6RzW=QGx-3ZvqP$)^uoQlot^^6@xA13NwU*Q5Q PvKTyF{an^LB{Ts5nBfb9 literal 0 HcmV?d00001 diff --git a/thumbs/shell_002.png.import b/thumbs/shell_002.png.import new file mode 100644 index 0000000..984b115 --- /dev/null +++ b/thumbs/shell_002.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://csm3cf7cs65" +path="res://.godot/imported/shell_002.png-5b0ae0e83ddffc4b4e2b5a3b671ac11d.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/shell_002.png" +dest_files=["res://.godot/imported/shell_002.png-5b0ae0e83ddffc4b4e2b5a3b671ac11d.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/shell_003.png b/thumbs/shell_003.png new file mode 100644 index 0000000000000000000000000000000000000000..08c35d77a647ca216cb71df7ef1b4916807d3deb GIT binary patch literal 1057 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-HD>V7~3?;uumf z=k1;S`7*9DZ6C|io?o+?qwWeF<`tJei`%lq zt_;4J$aRQKz$xHdYObDPTuWJCzjlT4ycO%R zua>TTTD0ytHRfLO#2>K@xHS>aPi{AC7WmO(`&hW`SRy- zX5||n8DbbpWBK#`?V4YFZdcXct%okJmDg(s@DIscxN6n8@P^adSeTyJHvByg4)GX< z@A>{>kK!atraem%=aZP)*kx|zE)ZL5`Rs~742+qLL; zKfibX_OcxeR`Ks+gDXnbY+GAeWHfb)!#?2yxs0pho@~p#ZgKK7qqu{Y=kDFRo3lUv zjH#}!uKG|Am$9m-AljiP@b>N7QoU|miYs!X-@bXXB2&s&P5AGp+s&7h*NNt_u2|LW ze!!Wd%W&1Y*G$4wTe%nfe)HdT{-4rxR!?A9*t5PVakOA)SSC4-OB`a|(8b*FN?u^;LDmPl2^``FQh&K0^^|eo zH)Oao`9SFJz5Fc)1j8BFFFY1yIFQcNUcl&aX6Zkp9SnaS@jqnRpvcb9&i!DMZo@89 z3kHiAhSmFo%B<$DE1Wc)S+8Nv=CsW>TVF>Kt^5HEK3=ZC-Frxah?e!n)pYD&@tMu`G$kkQo32AH|%H-99r@;`@TueJm8 OJcFmJpUXO@geCwWam~;G literal 0 HcmV?d00001 diff --git a/thumbs/shell_003.png.import b/thumbs/shell_003.png.import new file mode 100644 index 0000000..5fc5384 --- /dev/null +++ b/thumbs/shell_003.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://by2uh7amsyob2" +path="res://.godot/imported/shell_003.png-3758afc2c054032dfabec7fb26316bce.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/shell_003.png" +dest_files=["res://.godot/imported/shell_003.png-3758afc2c054032dfabec7fb26316bce.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/shell_004.png b/thumbs/shell_004.png new file mode 100644 index 0000000000000000000000000000000000000000..e51f303271cba3b6ae83ebf478ed6043e682fb15 GIT binary patch literal 1136 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-HD>VA1k)aSW-L z^Y+gE{OC}LV;`UI{r*dh_b(&MR57+AO)n-XE#Wdecuf9cFK1_CBV(G{5e8*$orw*i zD?1h%3;DRN6$n_V5Gcmdv207}n^r|a>(w2d{ObKXzu!3S8*^jF zl+=jOmyBz4*cqNPJdk0S!`x8JP{7Ah^)w;?*{k`*~*cgaH!sU;H{vK>>t z85VO-Si)7s>hN!^vXkJ#IiC+&G5qpj5O(bG6uo_uo~0#cE?Y9)FBje9`0Z!+^b84>9XW>NRZ3<=6eU>$qk5+?qEr z4_{8>7kAjQJS2O?u65tnGq~Rs;+T-lVEq6T;4*p*+4*}Gyw2ZmRsQE#^!gXCo<5&$ zACS1i^}+M#=U+3d)@Hxoqh?zdx2xP8h-TNXdwnf`yLbQgk{t}Yj{cjvwzz9|kXQPa z&AZhy7qHZ*HSA{f_^iIudQwo-JB|O$I~ZmyyVyHFU(TxR@A28cUS3=O>(gy{F5ghT zcVYqIQ{#5+Shy`WG<4yVNpW=_7yY`;JlC?;Yj*g4ZQDmd57#l2#(FEBefQf%G%EMD zk+WzE_k!Cjv##xxU-0%T$P9yqpXT*G_oU=reJv<=iDUTt*7ZHdtUv$0|7&Ivo_f^V z&in7bZL^jI9!U}0VJ($eZQ=5cNs^be7L^dzq`CF#qUn8TA&FRRXZ=wwf z`W0L1k1$?%a=6~2;cv)f94K`DVyh6RhPZ{ zP<-C*@!N!^@AkjF>i>NGe&s(eM`-Aa>9_a4zPx_Frd2d&Vd7&U{ol6odnzL}Rrmh> tD8AHPlTEgPF`uz)2Gw#D)(rWVeV2fNpRm=${lFrG!PC{xWt~$(699}$>%0H} literal 0 HcmV?d00001 diff --git a/thumbs/shell_004.png.import b/thumbs/shell_004.png.import new file mode 100644 index 0000000..13aaa06 --- /dev/null +++ b/thumbs/shell_004.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dbtfllusr5amv" +path="res://.godot/imported/shell_004.png-8992c656b7d6dc59367555ad046c8ed7.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/shell_004.png" +dest_files=["res://.godot/imported/shell_004.png-8992c656b7d6dc59367555ad046c8ed7.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/shell_005.png b/thumbs/shell_005.png new file mode 100644 index 0000000000000000000000000000000000000000..d73701c6c7a89c20539ef4ea2c347c02f5d1d8c0 GIT binary patch literal 1188 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-HD>V2Sf|aSW-L z^LDOp-eWfbxA@7EG%j7UU`{t=Oyis2TXs`opF7|5V4exmPnbR)TW-*!@=sZ{%$U2? z$n~_bwcv&CwhkLuiUOVXuG8A4Vfp9J>GiU1({f%hoY@k=P^i;jA?6^%tZKZIYX}|t_^}csMPH;}R?8u>F6|vsa@Liu~UsKV0%iHVfgS=YKhBf^A{;Bw& znS#2*{6|xSa?FlQDLXF0?x@KacKSg6+exn57R(Bd(b3OvI&7~m`E}W{w`o&0^Xli? zm9B7iPGhr(&f%`*Xw*5aaeC6})81jLMK|BD=ZNa9Z%XtT&>c8oJ5J$*p)jYu)QI&-zjyj+ z23|M){{6d&uk-C~){Je>wG@;Od=N~2^7Luz*DBwhLiGayOxy)dOQw9AWdH7a?rouD zm8Dy(&6lcNlvibum{ymt{t0vbr1x9}Nj%}D=M4_lemc(IdY6Hd@z;~@OZUrvId;4~ zbU|+PvtZU57ZsLFk|IU1z z3pf38^k^ttbbmEd?f-B`uZDl`7g{D%%+o%=IZ0H0-^?3vY)k*~JB2fT*d>3#_)iT( zT=@Pos~lD^9e6m&-fmsUKS!U2H9tO_b=>gUYT9b~e%WhFJUAKl>=rk;rxoVt*YHvG z-iH6t42*oC4gX4GuM4}G@fI;XIo*Bt^F|i0>GifnK!YCoZ~W7|g2C{Z`Re;j9ELJ1 zQ-9lca2c$(+jo;O(;H?v2Wip9q&_{SoZy|Jh)O(l_6(xeR({J6 B`3?X8 literal 0 HcmV?d00001 diff --git a/thumbs/shell_005.png.import b/thumbs/shell_005.png.import new file mode 100644 index 0000000..95bf1d2 --- /dev/null +++ b/thumbs/shell_005.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dl62knhaie5ml" +path="res://.godot/imported/shell_005.png-00c5f35369a06655f9761bcf14793142.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/shell_005.png" +dest_files=["res://.godot/imported/shell_005.png-00c5f35369a06655f9761bcf14793142.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/shell_006.png b/thumbs/shell_006.png new file mode 100644 index 0000000000000000000000000000000000000000..87bcf9b31c9be5ca59938f2d1371e2cbd09cdc79 GIT binary patch literal 1423 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 literal 0 HcmV?d00001 diff --git a/thumbs/shell_008.png.import b/thumbs/shell_008.png.import new file mode 100644 index 0000000..674e7ce --- /dev/null +++ b/thumbs/shell_008.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://ysfusuctrrrx" +path="res://.godot/imported/shell_008.png-ae8d7e107b1bd74e275a361562c88218.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/shell_008.png" +dest_files=["res://.godot/imported/shell_008.png-ae8d7e107b1bd74e275a361562c88218.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/solar_battery_001.png b/thumbs/solar_battery_001.png new file mode 100644 index 0000000000000000000000000000000000000000..be98faf10290c7bb5efb30e1f5284e4c0db62893 GIT binary patch literal 2019 zcmc(g`8(Tt7RNu|AYu<0Y8OjUwZzimswRk{i$T*~1{D;wt6FbLqNd6yx7JcAuG^~8 zYFav$+M|Nn9=nKOC`DtbeZTt5|1k5zIq&CrpYuHDoFC5fO0u)H65^NU2LK4!SmPZ| zl=3qW@RLlx=>FwIpnDEh=AgVsb^!q1=QemVLKKxly%x;EOEQkHi`x>+ac&Mwn3YFz zM!nhPIGv_QwCojo=g>ksMPX|m$YUDy#G1pCbk+@gQ(Tkhl(=LxAdJxGGOuS%V|4PR zem5Mm^CK0^tG)Fgak4(G=lSIOv^lRW`qyw7M~1!-|S*%BE>PtM-v z0V-Fb(jF%2ow5L+{q}1%Usah9tNSTuNnS)M+sumcJnKdwlP07MKCYlE0b92sO%obY z#p}U$hK!Hr$>bDpyjGd7I%K?UN%>;|quq{zMgCAX~ttnBWS3 zw&s?Mh7gf;B5g-)x`s}JDQ=C1e)1Lb5`coW3U-v@rp)uIw}vR={{5z56Fp0^FFdU` znDmD{Y$GRlGE$m-D=!rtMkm=TcHAJ)<^^z9)>ur#M>|hVo#0YX#Lb&=p%&r04u%c5 z3I@rvF81$AdM?%VrpTgmV&B>#-xs)w@Az-1qBo8_QhiA3t!U+@h?7BsVXq}{!O0j6 z+;&v_De;!DJ}TC4j<+aibT3LC&x5iLBOq7VC>uBdg}?=J8EwT>ISA^(99eCK_^@pE z1s}|5w^6#MX#TI2 z&NYY9JJBhEb6+B4SayMxj}9;ghUHp|@N)js_;ib9H8=>k_TBrN@2M0KL0#C%6^LW@ z+Mtf8R?6WSPjZxPKyx#Pa|yN{c~*>1$t5a8#!xtHZpOzB7LYe9Qu<0@VAbmdOJB@- zr$5STDs%Onm)%P*N2T)_jeC1ZQIp>+n{_bIHOtRQP6|Y z^a)Z*{^J0##1D5W-7AYQIS5)#*(qv9S<=L^#sQZF3N5&q5Z{g@!1bgS-mue%1s&+z zRHlqc$01wc!`Dj*SL;FDi2DvNT(!x#-l#(E3l}vocaiT8y^_Pg$f53Ung@7`7;7is zdrOU+kUfoqA(M?~Z$i*?m*^d-^fv=+5y3F|CR+Ume$iwErBg)E3!|*Al#ELn_%tDI zzH$Ld8=h%=et54q{@ToME51&_r6Pzj*GF^X1eeCGQVo8! z2X}-IZa}`OBo>OP5%*$zwiil9g<@431}=`M#Bu&4hj8$X zN_<4zNWFq&6!+@rIKBI6ej8({iiYAx3ZuO0+a~|Pm*ZZ@BzRV(wc;WDLN((T6_SI6 z{aNv6`Fbe-_%NYHbZT)k zSoFB|BO=3DtERcQ_6>8Rv&H*X-*?XCk`^aa`{4W02Ty7~ein@J2uc8-H~uw@kN-3l z9gdbe19iQO$nGf+zRB3i9f|ZKZC1t9R_jbFNbX!{a^GFdxN$+uYOSY7Ik8`1$?{3} z*gOQt95=Q2WtO??{!%zuA4|krhq^F1-eXlM#>t??mxgio26?uvsD9XYd3@4wM<@~Oi%1#-qpW#-E>?jU4=_5N07tacbr zqQMVeIniaG`Mh0RqB9S`8NaW`)|%(cHU*JCkhxr;Vp^ec%VE~gF9(c}d8q&XVm}Rk z+=9hec}-oF#c*656-f8EN?X5h{`tgefdJXexp7T}ijc540!8GV!U3+6bBQ|#r zQ^HL#xGt9Ir-iFkQi;|%X^BEqZ;g%UKM#&o-`h8nKgtZ5;|X_j`8C_)oji7NwDDqI93OKaQ#`qtlI> z1n)<4_~kDi%;V-8Xy=y$=T=%oiSY8+Be~Wzu8T58NNa6g{d2PaH#+?njq5reEz+(p T$C?G4P#f4-+TzR2i4Xn)*k^nD literal 0 HcmV?d00001 diff --git a/thumbs/solar_battery_001.png.import b/thumbs/solar_battery_001.png.import new file mode 100644 index 0000000..f3834c5 --- /dev/null +++ b/thumbs/solar_battery_001.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c4c77x5wdjodx" +path="res://.godot/imported/solar_battery_001.png-cac0d107b06e7d519b28fd5c0f73f2f2.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/solar_battery_001.png" +dest_files=["res://.godot/imported/solar_battery_001.png-cac0d107b06e7d519b28fd5c0f73f2f2.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/stone_015.png b/thumbs/stone_015.png new file mode 100644 index 0000000000000000000000000000000000000000..675889b6d33f9950c4f1d39eb557f6315da8eaba GIT binary patch literal 1729 zcmc(g=~vQu6vn?lM8zE_wakhEY5^QFWHcrSfhz_LD?;fYEOUu3{ z3rmo2BJCY&<5u5%9UX9zTsT}+%2Z_5a$-{AqJ}*B@mJi5cHLsqvT9z(5ricl8IZ40 zZoH1_OoY$w0i#9Wtvz%j@&_0-eyJ?KxD{dH2NvpO*wPVhc$A9Msnzht!WdVUiXH_x zRnD_OM9W7^DE0wb#AWD-8`BlTgG*AMOocA|i`zaVPL2IszWC5>^>%4_GSs=5k~cYd zv07$=s-73f4GGXL4HP@?38~?q#>zo*iM~jgEfKP8GZo`KJ!t~+`)O|P2+}{dyrpUCLf|MSIzQyr8)iXABbwFjdWq5QJAx+@<^^2W3 zThC;3GEIu>zXbf`;MLXCL2G4*^OmA9M}DYoR|mFZwy0C!nKDLS^N4Q+w+)<0Y%Yw$(G>^0_dXE{}00<(U+O&x>qPm(?PUM7qG6OJ*F|KYioHibe|}=--yxc= zhtJ2JSnoS?Oe0nu!^qhJ5KT@qk1FdULPngm0){NWbUysMyO{!Og%G=1L6gQuj^eDW zdl$F?q;tB-xr~n~g-aO~wHdUB3{kY5R*~u(ZL=`^!0L5k0_2}MZ+(f*zKX{Cr(1S( zZ!h|TC-gJP5uR!1Z)^6?v^es{HMl$*31C*$SK(Vz>e=l`h|?XKa=%V;v}P+oh;3|l zo-@oH$^m`^0E}10$g{MunHcG%)`cBcIBJ1jwRsxPT<)zeG0Zi|wny*4Qynzcew~Uo zVACi2jv8Ab=F&uNoVfjlBEqs82{wy<;{RvQ_i((2mg98*Wa4bo_uji3YBmQN%|;r< z-b7{u>F;uaZ5gzGQe+hqoR=*q%CTY$83Q>dZwyb$(*{FP-qVi8~9(pf6*0 zmPgK@OcFcD?Z==Qn~1^qqWF{xVhilZC*RymNn3lJx&+X|7_p)zl zC|}B0X&F69ij^<^l(1M8s5IDD2);eoKiqKq)SL>jQM2;eoo2BL5kB872Q6klI%fZu b@tqA*mbs25u}1N0odkTm_R^kuM5O%-i$?y$ literal 0 HcmV?d00001 diff --git a/thumbs/stone_015.png.import b/thumbs/stone_015.png.import new file mode 100644 index 0000000..7714ce0 --- /dev/null +++ b/thumbs/stone_015.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dtb1og3iwfwe" +path="res://.godot/imported/stone_015.png-894c1e79d658c36c3fdba8f7f9d3490e.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/stone_015.png" +dest_files=["res://.godot/imported/stone_015.png-894c1e79d658c36c3fdba8f7f9d3490e.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/stone_016.png b/thumbs/stone_016.png new file mode 100644 index 0000000000000000000000000000000000000000..c26145b0af459b341fb8c5eeb8ee0e959c00b256 GIT binary patch literal 1703 zcmc(g`9IWo9LGO1=D;Y#I>#E4j+G;kX__(aBO$e$+YD`ODvB_S@|~HKjIybA$T7o~ zO6APG80(m%@K_y^VKVNcVHqY%?d(6WzxKoX_4?ucemvhlz25I@zTR$|l=YMW0GmAA zo&Dqv{a1=8xwet0-ExD)`nfrR(jM$I04S=5v%^tZ-hBR{$5M zys(1Zj)3nFAbf9pgGSDoHMnhSuVI1Uh|iozR|A z+k_3HCbiFQGF7!89bD)8)t0bcWLZumvhMTeTzoY_JA&{j(}HcBLC9kD9tK9PhB}iZ z8P$N(Vq2minm8FfMj@bSoLWK6%!gFq=T1f-TzLa)WLkaJ8m}aP|H>!KN1U+6Q)#fs z&3w8@?r)#CNcw~oB`-G7qQoJCaWd)JWBsOgU)d!mVC@;5bP#1VUl!^A0wp%XNiRv3 z5~t&S$Txkg{CunHk8n#&o(4^~k{@&b*zzZ%x+r(%&Z$2u>hF7viW9xF5OM7-=CCy6 zu!r7&Np)fER%EjKXANEsXuc-M2FgIXQ?~g%WIVWeVL0Ni*Hp5cXFWjJ>x4?H-(O=j zPUjzjx@^m<4UlRmNA81^`v=6)UEwUHg@IOMih7#jkmZfW`?$*X@4XT3oLSgMwBVUa zQXtOwgxVV;vP~7F|IQq;!}yj?FgU|Ife@QLudw9A%ZG(vF8@05rDL^QR0SQuyp&Dk z$L2QAUoF0?LN@!w?_3(P=e*t;F~-xUDGx7A0#ob&m>(a%ucuY}gxaJONRFBB!0OJZ zLpoyy*~B#69=unuIt}**p2Z^Ky193V_D>OeSpH-a4-nX&PYf(k$5}?~L2!q%Vd2*$ z5z#A;DlJ$cJsaI|jKV(sB+__+VOk$Lw24Q%{LmG6iYqbZWnbkP3&(E#;L?1YWt=#9ch#tMKxUUo@PE15{mDZEv+ zx)3T7P+NszbH8JiOwL=oQ=%qAdP+eJ5vQP1 zR%vHVQGeM8wIyB^wrM5AtHOBcB85AfUdZ$`x2jpbidRe(ikfpDq) zY5H7m;7~(?;%MEy;DZYcPip{z>uFo$<2uJ?gYhf&A_gU3Q1PXeP||zOUz2WwG<@g} zKwZ+bW_)pw-QsdZ>hRZS42`HBuNpW+$hJrh4U%K7LJV@oMgV&w;K^Gb(m!JttDv6; zNuqeY$%Bz9B;Q1of5#p6_Wld!E50A#CQLbn3Lo1{ZQF(1Q7;E$p#pywKIgCn6kj3> jf)+=<=>h$}UJWYFj|1~a1`OI{4xApV0kIvk=>fq2l`(Wifex7pu-Q_bMe&1Vs{)||*{+=IR zjTefF-#47`W}Fbr@I-{clGVX)@GuW3+tvJ4t*QC&>CWztM-Y7uiochyn_10X_Vm|o_7}UwYOh~SoPF@jgEJ52Q$KDGwJk? zzp2qrq#m5^U-$6LJ*n8+*A`myzqgfof6?S?_IukspFi9?Sk3<2W=?UbF?%uJIiC6Z z{~x>4zB#y?`$0GVJ*oD0e(Y~!WxtsuJb(S{zgY8n#u=M;-F*4&ruF)>wGq~vcQ7RR zoUlCHP_@gv**M()_u~(H%QI%N<=$TOw#p>8T&m$_nXiGK0E2POr)N_o`?Jc$#1EL; z|7n_HRCG>b=@rSoY=-ADbIL#XcIRz9_Ulb>#C*%{b@2y(vKcs^V>Mj*D@tU+f;dT= zZ<`+e&z;zPV204GHxrB6PV*gYSjqC-X4W>>>)$hOi5a>rnIe#Mz<{U2Q0Yj=9HSt= z6OTXa|NC?MPX26lF)0TZAKo*mJLWWG9?fr?Vyxr#?4mbFMIC;4z}bTiUj7 z?O*q>sPQxBJ#Z;tNfdGKuQ z?TWJhHs8+AmCpavV_u!J=bU>iw-5Kemvig4SRT8}&j0UY^|ZW;_1rtEehTT$sh6s~ zzA*RpN4J1jfoV)fBn*#qJbo-Jb8r9tTG_)7)Vui-ioSkQWjL_v{l<6IC9&MkW!e-U zoZDM{dw#OipOlI6jQvS6Z}xB9Vcq!Yz6L`PSHm18h2;z`D`x|X O8U{~SKbLh*2~7a3Tl$Uw literal 0 HcmV?d00001 diff --git a/thumbs/stone_017.png.import b/thumbs/stone_017.png.import new file mode 100644 index 0000000..23638eb --- /dev/null +++ b/thumbs/stone_017.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://csker0nqhe4bk" +path="res://.godot/imported/stone_017.png-5c30ba648fbb65a8fc2be2733cf94caf.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/stone_017.png" +dest_files=["res://.godot/imported/stone_017.png-5c30ba648fbb65a8fc2be2733cf94caf.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/stone_018.png b/thumbs/stone_018.png new file mode 100644 index 0000000000000000000000000000000000000000..6864ce33f499fac07a266d90c84c257a044dae69 GIT binary patch literal 1338 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 literal 0 HcmV?d00001 diff --git a/thumbs/stone_019.png.import b/thumbs/stone_019.png.import new file mode 100644 index 0000000..5ae0217 --- /dev/null +++ b/thumbs/stone_019.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cnbgtgfmkftoi" +path="res://.godot/imported/stone_019.png-ed78dca9c9ae8571f83bf8341e358dd8.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/stone_019.png" +dest_files=["res://.godot/imported/stone_019.png-ed78dca9c9ae8571f83bf8341e358dd8.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/stone_020.png b/thumbs/stone_020.png new file mode 100644 index 0000000000000000000000000000000000000000..b99fa492e3709886d13753f9c5c9f55270b7ef47 GIT binary patch literal 1735 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 Z8^R6Paj+P^YSHlNK}b+&pfn&l_kaC7gJu8# literal 0 HcmV?d00001 diff --git a/thumbs/stone_024.png.import b/thumbs/stone_024.png.import new file mode 100644 index 0000000..b1bce82 --- /dev/null +++ b/thumbs/stone_024.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://3h56equ5a4fp" +path="res://.godot/imported/stone_024.png-56e46fc89968a975421c0649c991de80.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/stone_024.png" +dest_files=["res://.godot/imported/stone_024.png-56e46fc89968a975421c0649c991de80.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/stone_025.png b/thumbs/stone_025.png new file mode 100644 index 0000000000000000000000000000000000000000..a7a6ec2753e2b9288b409b0d5087c05e7454c390 GIT binary patch literal 1470 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-HD>V6E_UaSW-L z^LFm;Jeg3LWBZM(XW#s));DE3180kphGqrhERhlp50NDS7bl22IC*qLv@mgTRjrsX zA?RTnn@SwRMFk}n1#$JVYxm}UwikJR=G>cG%MMn5th?_oHGk&j&9CSFtb1;z_hw%8 z$EggC-rHX3D};5kD7Z6CP-Z+ak>QC4Ly-!DrBH(mr$gVs3U3Mj%R22W|MvBXH}o&) zS2;{$oY}3)puix;kZ zl9#av%qso*?{j|Lt|R&TE6n^F?#_KJ@$K`?1IFgnld@&PAGV2@NFC3(vV4~SlMc(C z58uuOtxLZ+r<$>>d|mSD`HSP9IBaKDxDvZ-_P-f-*O$#cc%HR3YOZ;+x${e2{rf*^ zGOzE{IQLZM!E^olhZme^+#}tbxiu|%YxbKR$y0kjuPR_<5w}0>m&L#FoX)no_q_Lh zZ{9U$YEfQQgZ%qF-QLr;zkaue>+a5o=YAYNOlCd)yYZS`c)pqLUh^qSj~}V_QImVT z=}7kb`qFRWyIrouHO$|)qjT-s#5dPgA6R|i`D?8?)^bIryR+ryYdO5)T(Opi96Zdk**Ww*n6hEKW+BpCME zU3kf~w#;UERldjk%1ddPpV?-#Fa5Yr=W%gk*6b;&$0l2d)cig8`t)AS^b@zfGqk%4 z|MWi#ew%<&X{{ofFVUJetp#bv+UW$$u?4Z8yGV;rHdtGUW?!Q%QN!a z8+jSIhjab+MW5Vj$qn@Q#fyS&?a4V?qYGpE-OS$yT{w5X?El$$Nm5zG*)4ZpyjvUf z+@IB8M(dSF{oEg3oMg;lyiu-;kGGboEp~MAT#JE0gzWy~&zuzhA;4 zagq3$pyPtf>&=f`kX~CK)*$ikaHn*H-V?arO9u`_A_L(f3|2xc+v*)l&~1TrycuH&0%={_d{XLMEKO z<}J%CG9@(jK0Nq%`H!#P?GqIj=-Ar*`!;=P>~AGYb0(9WrC+(afGJ0Oo57ps5+ase zHsAOdq`dzKAM#%-ozbUsTwW=3Z*$~<{Q5tw`{m#H#^0Xup|M!YVRCf%dIp9~I)|UW zRcvc!YF^atx7$|qz@a|^2@El_^sRPm>Cfcs={t7gc75A#{%>h@_tjeYa~c?YwIsE+ z>GKp6USMa4=n%G=uU5t|A(ii(Ws2Ukw6=OV`=b>>a=+jBa_>u8%rYZAuA^*s>!shn zW-=~fnJO?_>Qnv3i%fIeRN0ard=B7J$h!6~pD}6U;3;2FUGhBM`Mrp6yH#W?us~+; MboFyt=akR{00YW~dH?_b literal 0 HcmV?d00001 diff --git a/thumbs/stone_025.png.import b/thumbs/stone_025.png.import new file mode 100644 index 0000000..4b5068b --- /dev/null +++ b/thumbs/stone_025.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bj3dcn4b4nmm5" +path="res://.godot/imported/stone_025.png-b43ae463d9c2cc9252414ab2aa42293a.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/stone_025.png" +dest_files=["res://.godot/imported/stone_025.png-b43ae463d9c2cc9252414ab2aa42293a.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/stone_026.png b/thumbs/stone_026.png new file mode 100644 index 0000000000000000000000000000000000000000..e5e8aea6a8c6bc21bf67490d33c546a739831f79 GIT binary patch literal 1451 zcmd6nc~g=J0LEWl(KyC3Q}YV2wARE*ti&S4(9Aq&%_Fi^U{Q1s&q_tt$Wlv7X=bg= zLdxmb@+?Ulg>~(4H$&{yR8X{8uq5zUBoSTrpZyBEGtV{82l!n$91(1Za6|wAU>R~S zFmk22{}^Vml283;y(c-Sr%5Qxn^~x zlgJ}ti5vHq1){i~tfS3i=GN{9X{9qT>?W6K8`rhg)Rdhao7h7 z%oh=^Hh=bH_id@_kiSLE&wcwG6P-`X`AfXU4C?vu!FFQ39h_JJ#RP-AO_1L&1D_58 zS+0PuHP`vSy&dWoz$? zG1V}7Vy0&J2SK>H?+(g;J)yrhQ!;gL`>c3_YOXNUn56R)=uuTZQ9|0W{DQ3ctIvN@ zyEW^VSoL8BWh;Lv`q4{Hv zwS@_9QAWOD4^6DXGnd!ey7meh;INQV%HV8ZDoX(ftom zj1TA88ETFwRE)X=_2sQ6eh=1dpl10#$y#q8!7YF?&gQ0Ncnx|>lWHn^Ue({6d#}ie z##ln4*`oPx@88P>0}PEv*B`AVO@tW&Sv*8PPqDz0ZU}bm8#cR77f9PBa3T7{`KFHr zw(9GY^fydMRV6J}>WpDmM%*=wE6@+cAx*yxAu|e&DGjaNr}z*TZAsB)1~W5mfV)>y zQk1mK3R^7SISSw513e0ZWh>)g_iMUXq-dYGr%OsN$>P%MLt5FFM@wKBi{Q`SD8v0+ z#{& zjo?gOQPijJW(W<7^!~@aCXq-Rlkd`?9zWMuee}fu>H4x8oI^I&-!!d?685y}b06iv zw3cK(3aj0W`3G#23*<2V(!^_as9mQ|~ogR@1+`QkgK>RFD=pAlU@AM z0Hma@x(!HY>tae;-x2sRxu;H){i?5(ElR=>=s^IouoJhlv*idq2M6|FnpBL7R;%84 zyOqB3#jB`Exf~t%_GN9JHXJFT)j_W@4=$x`54Q2MxaCB|JZX)ZrYx?9FOR pBZ1c~`qN0O@}U12Q~ssfGU!QOYOUDoV7o$JAS5UvuyH@N=x?6}dr$xX literal 0 HcmV?d00001 diff --git a/thumbs/stone_026.png.import b/thumbs/stone_026.png.import new file mode 100644 index 0000000..b050e8b --- /dev/null +++ b/thumbs/stone_026.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://tn4oy7opc5x2" +path="res://.godot/imported/stone_026.png-38e3ed718926a8f0da542ad755766c25.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/stone_026.png" +dest_files=["res://.godot/imported/stone_026.png-38e3ed718926a8f0da542ad755766c25.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/table_001.png b/thumbs/table_001.png new file mode 100644 index 0000000000000000000000000000000000000000..5b1a2913436a0731f3862099e09d67761fe2cdc4 GIT binary patch literal 1335 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 literal 0 HcmV?d00001 diff --git a/thumbs/table_002.png.import b/thumbs/table_002.png.import new file mode 100644 index 0000000..ff3fc08 --- /dev/null +++ b/thumbs/table_002.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cn6bj5h58agkc" +path="res://.godot/imported/table_002.png-921835c096565377ac851f8559043288.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/table_002.png" +dest_files=["res://.godot/imported/table_002.png-921835c096565377ac851f8559043288.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/tank_001.png b/thumbs/tank_001.png new file mode 100644 index 0000000000000000000000000000000000000000..5f2bec52803c72ffde134646f18dc9510449cf6b GIT binary patch literal 2653 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 literal 0 HcmV?d00001 diff --git a/thumbs/tank_002.png.import b/thumbs/tank_002.png.import new file mode 100644 index 0000000..bb3caab --- /dev/null +++ b/thumbs/tank_002.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bq5qxregnaxa3" +path="res://.godot/imported/tank_002.png-11d6cb0882eeb82c362961414d5102f0.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/tank_002.png" +dest_files=["res://.godot/imported/tank_002.png-11d6cb0882eeb82c362961414d5102f0.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/tank_003.png b/thumbs/tank_003.png new file mode 100644 index 0000000000000000000000000000000000000000..4f909011b6dd18147466926e9491fa6acb1b3cd8 GIT binary patch literal 2674 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 UtRDDq`3C{$>lnj6YCDGgA0#1Sk^lez literal 0 HcmV?d00001 diff --git a/thumbs/tank_004.png.import b/thumbs/tank_004.png.import new file mode 100644 index 0000000..9ee0b6c --- /dev/null +++ b/thumbs/tank_004.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bc7figva0ic8y" +path="res://.godot/imported/tank_004.png-58ee25ced666f4d510e39059f9079d09.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/tank_004.png" +dest_files=["res://.godot/imported/tank_004.png-58ee25ced666f4d510e39059f9079d09.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/tank_005.png b/thumbs/tank_005.png new file mode 100644 index 0000000000000000000000000000000000000000..18604a1dcba526d284663eb8ed578fa9c9fbd72a GIT binary patch literal 2366 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 literal 0 HcmV?d00001 diff --git a/thumbs/tank_005.png.import b/thumbs/tank_005.png.import new file mode 100644 index 0000000..253a3af --- /dev/null +++ b/thumbs/tank_005.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://m5ah6ofker4o" +path="res://.godot/imported/tank_005.png-02a3369a99b88568fa7312676f272360.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/tank_005.png" +dest_files=["res://.godot/imported/tank_005.png-02a3369a99b88568fa7312676f272360.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/tank_006.png b/thumbs/tank_006.png new file mode 100644 index 0000000000000000000000000000000000000000..aa645afb1b1fd45933b3424eafbbfd089c1a5e85 GIT binary patch literal 3493 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 Gneborf`Bam literal 0 HcmV?d00001 diff --git a/thumbs/tank_006.png.import b/thumbs/tank_006.png.import new file mode 100644 index 0000000..137d508 --- /dev/null +++ b/thumbs/tank_006.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c1ho0muqdt5gc" +path="res://.godot/imported/tank_006.png-636d9710c0942fdb0662ef2f5913ae08.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/tank_006.png" +dest_files=["res://.godot/imported/tank_006.png-636d9710c0942fdb0662ef2f5913ae08.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/tank_car_001.png b/thumbs/tank_car_001.png new file mode 100644 index 0000000000000000000000000000000000000000..deb37b6e207e039ee04d5790c8dfeaa7adb409ec GIT binary patch literal 2867 zcmd5;XHyf177Y*}G(kWS7o-K3juhz-Is_NuB3%e&m9n8~gb+H?L3&jQAO=JQR31u` znn)*flo$*UHX;&&8fr)$`zzkNGxwekXXehGbI*s9ecj1Ui2ou#000nz+FLuHV)DNY z;yIl|X8z-+z;V~v&JxfvCAA3v@NYw{EnHBKx2tdFfn6n&`@VG&Xh_YtDw5=rNdD&nhwd<_*3cF(sl^$bf7bl&{}uI^<&=~RUwxhF6oBO|FC+2_J{o3rgXTsFc-)VKNx7t%NKq>NIAJrh5V!nD<^3L^ORa5i(3GaK`JOGhS z5!=76;^_g!5xKrZ4{fnka;_Nq*jm7DrC}t*|N^Oe4Z$ z-;a!aA_8rjY-grFHRO9Rkzdev@WUqD&;;7tH5S-jZn}Rc0sp5{!u<_3f&D0EZfWW7 z#N|1Y{@FZ7R(|~S+%LE}R$j?PC500!KHTu(;8Vnxu8fEt{aLsJm`!&7$Dy%1r zGB|oeG&6z(OY&{1{HNJFvh6sxDNz}^x!r1F=rgrqsW{_~<8bF+>A6A}7-M}$F%J?G zS;uTRp8CZY9Ux5};B_hyZ1M@e_2?CkM|F$`nh+Sf7#RCD|2Cc*bGvAQu?tb-A4-si z9(Pu7VLf`ht?CM)$yjH58B4pbzP~|bZs&8r zleX@hzoDAlaeH9)<>YLhbf#(C;NDKPL*W>lGUYmFm1&dzq1RgD>ig(m>G4C#3^V^QbW-1UK!lo1D3pN_v%4jqcZT4 z#>OKKSzx+zyY|F##se2<1N5zW%0Aaaxcv|#>V2|f_v;GCoaOFXtg!qX%oqTr(mrlZszE)4E;4jTRa3flItHUDnAvnC{#ZmYM7s=1qz7hVkPb#2=vuUG~loDY3ccQZp|H&c8i9 z6fRjQTydcx;wlVAf@qL|boNBlujv#^;TpFC=WrQR)dU0JFTRmu3MK7EO4Xq2M~f29 zu~>m(Us+_U%G1^4OHeaZU%p7Hy**PFtc1sJjz{EdF>UrR`FwO-{oE(k*RLXFKS1Zt`_CVp zRVU9Pe&)%jSP|nfw1z4_yHXXP8DhOOAZk$q2v<(G)H+oOK`x=m=YU@b++)f<*~~1> zaE0-hVO6^TOAODWS_ctZK_MZqjkotGDUKcGwzxfrER>;M(`n!K)fG|$FC@Hp0^48G z+kRPD;vnxT^*w#uHC1*@?@Iywq%csYAI^9sUBGbU?WXM^>2;^(q9SU7)teiXJZ`qG zcbN?hS&e>^_8WK~1bg+yZT#L2zIl2)NTDj!h00aavcji)NFj+q$*$!q>yEe-m{)g$ zgx`|sqTZSf_Bo0CAiWo(^rOYv4tRi<`4Yk)g%yN_8o9hUqfoE#A2j-3%MvGdo8i6X zSbF@qFBexkSw2cnvkDNS#bFQEhLq&9yar+}n*FxGql&n?SC$bQ6MfhKig)1cPQEo` zoAP(}%3zEB=FU#N_oX3(URz(~V~rpQpQo*bG%Phm2{iq1Y5iPJyltWV**;6KwVI95 z&NWF*N{5*%k()fy%TM(s)w(}FCe3PbtkD}Ebd+@!LSMb!yrQjbox}$GDIS=lGjrL( zjnae)+50%ZXqI@5d>64doL{m2+|2zKw|`pOGFVhze>mbhp74f>)Zh}gP24iy$T>;J z-wW^C2G-p$;XPIDHuE~xmAv6JO`#qM3-lC1VfQ35f(z*kgVE;N)SOPZA@2+&hO zON^!kA3cOnSgNqJI5~ze^}+Zi_8jz1*f-g`GtJX*`v>pM23ptwKN z-z9k4L=zW+3SIR6=2XIXZZ#(m{+u&HAF0blkqFL_PEq;%t}9T-$V^+?v~2FOc-Ezw<;lNVPaQ5 zt3^VVKqUz75(E+(As-xVmYg_<{;5gpo5~!5`j`G^5$_OUWHKgcDhO>pO~C-DjgxhY IrC;iQ0al-HcmMzZ literal 0 HcmV?d00001 diff --git a/thumbs/tank_car_001.png.import b/thumbs/tank_car_001.png.import new file mode 100644 index 0000000..571fb9d --- /dev/null +++ b/thumbs/tank_car_001.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://d1uspdcqy671j" +path="res://.godot/imported/tank_car_001.png-5fd8a4828dea78395c66ed5fe8909e79.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/tank_car_001.png" +dest_files=["res://.godot/imported/tank_car_001.png-5fd8a4828dea78395c66ed5fe8909e79.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/tank_car_002.png b/thumbs/tank_car_002.png new file mode 100644 index 0000000000000000000000000000000000000000..55b553dbd7105ea34c08657cca07cdc21dab79df GIT binary patch literal 2828 zcmd6p=|39?6UXC@pw2qll2CP((zsiRu&R+1m8xS=v8~p%?n+isR4S#YHmRkka~(x2 z8#kd=X}iTzM};%@@wuyc=pav5rFh!1S%vJ?u$i%@N-ygt zFGpkTAPc7oQ_5u~RZBYDYMH7@h$WCJpNyW29>gtPa9*{m2x3BzAfs$dbRlHW1^Y?$ z@=x7StJxdRVTL&NL2ma9{Cj`5|4WVR?A$H8#@+s59GjQNJ7nda9cfuB%(y5%0UcVC zHQ*?mkN>X7XVeQUFt-JKxyGHIC$>=s`TKGX-xxNT^h&84dBuXhu@3I zFV%d^pbWPL>uy=5wLm}9c*4)wOG=02M#p-56XLTVwy1MRw)=ddbb*NbpbyJM65Au` z(tnuM)4f&A(gYPKraU*`@ayvSm0ovnHq$dGOIPniw`>;}4$2BefnpSPgy$&Vx#!T1 zM{_y-^Dc&w{JOMFm_r`-V#c}0ZAXMpd!rj1r~czD^|GmszEsMcr9BuWmSqM=?PWih zXV5n`CL@}0k%H}6Ky94^Nu!jF-}yhV%pS32-o~=Y?~Y>|a|)%I;Ax)tFgj!9@ad5I zueph~X#u~aRvf_jI=^pf!}nHQ>l^iW?B!-o@WYi?rpD;i=}C?EF*W3O3 zkVg;P_umiH%$H4Jo?6Gxd&49Qdu!IZ->|T|ax483_$tr0`Kwpd0ei{%QUYn!0tXKn{f}`dvxocvGLUb{GQfzAR}FLE>6_AM8xLxecsjl3rHl0$(5p zqjGu0^3OG^VUw6mJx`q%&?%cXy*REG23UlYO5*Po3!bF5*q*e28}JU01pKkP*RCSK zi$1F6cA|>j2)DSWm_D1uw-gW$a8lQx)Ni>kDA_wBFh_fQ&>AQS!M_+uk zS^)8~mPerC;?{9v=zFA0lbJlILe3hQMAVN{ye8;lGrWzT>vLm!Lu-j)Ef^2C+z&@=^tCYR^l$951Nf=xQ45fV`GMkhmb!v_|FZLEk+yVs5C4Ohqfh1 zz{N8G58@7tNth%bB8mUP1$h}ULa92+u7re`sP=HP<8|P9Kez@jRtWkJF8)nJfBZCY z|24bxg^l%$h;%-fiRZH)>y4UWhM49!FQ3Xndzc0$R292->JK(tj^43rzx{kg$W5V1$qmE#tyu`NMI7_=wrI$cZK`9x-+9ZZm}fpD2cXlCYa0Yjt7SB zn|k|34g?P&YL3>F*)4&;Z9h#9+h1{OH#QU@UA%<#;k$myk!5M~pr^KpBX#j}*{nN_ zQ(9H}s^q|hNgyFhiE38rf`A(Ey)MZjA`0tNVO$<$isvN!qVnkYt3-#jX+}pn|7-6! z`KSxNNX1O*+#mC%sgbViye*D0#W(V>>To45k&K)ADa@y#wayjPjMJ!DBCDZ3Z23O~ zCrMYjYXF7f6n(D3S*Q(zwH`~_w$-KU-V1L4nvXeqRX&amD|dqepr>M_8mQcn`Uh@q zxpbd42Mc35VJU1}$uIne)|g6HV!NRo^MaF{^xV_eaZ-i3AbWjm>pykD?+V3ZP~O-1 z{1rUwl~b}zJ0-De%0JgfitWPsmQeo5A+=XhS{NiRN}*@Y)T>$YuE}gz+Y4ezrQ~_5 zruKAJa#M%nuvn-kn7&c*?b1QDMo+*K+?a_w@4&P4MazaxhgN>J%YnCw@@C3$9Ju-G@kk9shSwRGd8VDTAT+#%=_$e*W1ZQY= z^DQ~oY2T&J4zu-4$c?&q!#c1fu~s>wy5-A#40F<n93K`K}nUWCM zZA8CFn|;LDfGIo)AJ80$IfGXf$|P#0w?P8*Ici-lUrRR?wA$wEdMI{UTb+axt%io41OO#z_`%MYYflI=~p>5?IP6>f$#5chi4K9&72?F zQ`_%lmS0@AdkD658lBkSPed~JRV8|hF%kG^C2U;G)qrBgsCb>hb0{pdFbu5<1>6Nw3U!Y`JeDZgKp@ z^4{gtdaGq>PzSiyOLBA!JMf<+-UZGxtnD!jJ0%f|6ftv4@!7pS$e&vRo|c{4G3WH} z6jMfXszQS6ohl-H+Kar_eE=y4xj$i6kFuo3_`^)b@sz&~hc1WaRZ;aB5&Gk$x+AQy zxofdcumgob9dMd0cv_QrtI-SP@eocm>iuZyLKTZaO@{!@H>|_aQS|4Ok%sXH?($pp z$=D!q3;lfRtrTi1t2rXN?lhO7lSezi%5!4E#{62G15EP4j0W-%b#Pa_;AKGPC#cnC zRRBfI&8H8E*MUChYqaON-M7td_gbdcX+?BETNEpDSi#hTw zMyoUj4d#o2hDDUV!BEWoZ+}fjEy~Q^#i`fh!+uu)B^ZVS1|(lx3()ko|Js7QJBoP{GiGzqjPVJ6a9l&pkL z0PVdSQftnyMb%Wt8Nnx0HMcnx{@AD;Lf7DqeMEo&SJ9A?BDV^ssmk-EbHkETA5Rbh z+C_5^t`qAU{-*34Xu>mp^fzb2l$f9Z8Nj{eY7HDMP9MS3=qZIVouRWz<7YZU0}cLH c%$Ca&nA9~>sYVm*PVg3Bcg?}3#u}UWFTev!1poj5 literal 0 HcmV?d00001 diff --git a/thumbs/tank_car_002.png.import b/thumbs/tank_car_002.png.import new file mode 100644 index 0000000..530836b --- /dev/null +++ b/thumbs/tank_car_002.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://crjupmrbyekbf" +path="res://.godot/imported/tank_car_002.png-49c3d1c03a40077701fc18374f4e62d1.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/tank_car_002.png" +dest_files=["res://.godot/imported/tank_car_002.png-49c3d1c03a40077701fc18374f4e62d1.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/tank_gun_001.png b/thumbs/tank_gun_001.png new file mode 100644 index 0000000000000000000000000000000000000000..bbd0da594ce0ad1b1cbe99b628a14bf342333d00 GIT binary patch literal 1472 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 Dip|7u literal 0 HcmV?d00001 diff --git a/thumbs/tank_gun_005.png.import b/thumbs/tank_gun_005.png.import new file mode 100644 index 0000000..2c868ed --- /dev/null +++ b/thumbs/tank_gun_005.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bljeq26jlq7bs" +path="res://.godot/imported/tank_gun_005.png-cf18e26634eecb8c7287dfb84e745cd5.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/tank_gun_005.png" +dest_files=["res://.godot/imported/tank_gun_005.png-cf18e26634eecb8c7287dfb84e745cd5.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/tank_gun_006.png b/thumbs/tank_gun_006.png new file mode 100644 index 0000000000000000000000000000000000000000..0ef4a51ecc4f763b9a1534213491b01b34dd6691 GIT binary patch literal 1569 zcmd6n`#aMM0LH&=ZHSc49Ga|*?xI{fW-MVyVanZ<9g)jin=BhksLbQg5D{gS?RC)R&MM?!f zLFP=dZ5Oh3*6P52@}HhMNOusIDCuIHU)jMPII6jl;JK(zvmNyCx&HX|IL1KM1Rv2B zBhH$L5IJ9uh-vJbSV~DQJRGpbESX=rRcy4=7$N;2?^uZ~*LZx?Nlwk>cftTOrGR1 zR|}i%39;di6|ebxf_?%1E~Ah0su9)E;(R$Rj&ZZqVzrbo2m@YJDq6!aO}w;km%{ws zl*>3@hRdfaeys{Ax<6E#DLzDEXf=}B0jc}U$Rjnyv!Vkgxj|U?xlUcNCxf1icol5n z3gLYAHCEt)NuA+UBqKpOb;zqB?1;}UqLZ3Lqn16pVgrVH!)fz&Tpdbs-{l^ z8^>K*=$EC6PyOU4Ttd`kR|aMa$Nxl^|J&1jR&0iJ4+v;$y zG5hW~$WLp*pv{?l0mGnS{0m#%^pR4iZImt32a4<_S`ici-psnTb$y$QS+eZM?)9EJU!)@gKDxy(CV8MZQ( zD1F&)4JavG^Hh8xukcN;Kp5DY;HF6tab10@ty`yrjwjcu_UyLiXTO&hhnCVMUE)7D zQ38!!@%1!;r@lQApDW_RIb}LTL76ISrTH&uArsq<{LI*IZa~B3m>fT4K?yq3H2vIu z{ed|}P?yimJN^zxTAMVXnTe2bg*Tx3ciZN@n&3I7H67^^vA53oV`5F?CT7%(Z+V{o z?tA)V>XSr8JEuM(XK>sPWHyiWgnTbTN?1Q!Z-Va7<7#pqPs^o0B50sWUx%}Rxy<#% zsk`%YPKK7IRTMVbV+a1no5ttYJ%F#iamrJQ#_OD{)=-3uyd8GYNO&5uH8Z$K*u0CIo7LY(VXb0+SpmuW$f4IIi_ zwv@7p+bIKnb+9B;{Mvh0;mqLqGr@+%f+!O!YdG}a-ijaIY*sy^@F+_zH+EHTk{PYi zDHL-izNCP$LH)zT;5=29EabxpYY(c_myFl?4cG!M`xBIe8yXSYpAVqVx!6{ruqpom Dip|7u literal 0 HcmV?d00001 diff --git a/thumbs/tank_gun_006.png.import b/thumbs/tank_gun_006.png.import new file mode 100644 index 0000000..c46b238 --- /dev/null +++ b/thumbs/tank_gun_006.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bao5dy3lx3w4l" +path="res://.godot/imported/tank_gun_006.png-c7b73dd1c8b8d2629eec79dd0f593867.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/tank_gun_006.png" +dest_files=["res://.godot/imported/tank_gun_006.png-c7b73dd1c8b8d2629eec79dd0f593867.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/tank_tower_001.png b/thumbs/tank_tower_001.png new file mode 100644 index 0000000000000000000000000000000000000000..1a00e70fdeb51961eddb16daade46c0ec1f0ee88 GIT binary patch literal 2157 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 KGcPwq$Nn9n%%6(@ literal 0 HcmV?d00001 diff --git a/thumbs/tank_tower_002.png.import b/thumbs/tank_tower_002.png.import new file mode 100644 index 0000000..83808d9 --- /dev/null +++ b/thumbs/tank_tower_002.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dc5i07vpia11j" +path="res://.godot/imported/tank_tower_002.png-79f5bbe100430f6115f52fa2c5b11acb.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/tank_tower_002.png" +dest_files=["res://.godot/imported/tank_tower_002.png-79f5bbe100430f6115f52fa2c5b11acb.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/tank_tower_003.png b/thumbs/tank_tower_003.png new file mode 100644 index 0000000000000000000000000000000000000000..cb18c82bed7ec62a452613ec8319eebd4fed8179 GIT binary patch literal 2105 zcmc(h={wtr7RP@{+L1wvs!B0v?Ts-?DGjPbiM=YyV=0~9L{VEb#FkhpjgDQ5qI6M9 zi>jiQ64V+?E!WZ@i7g0~)J`$(`~&yhy)Vx9`{JDQJfG+L<{XNxwdo0d34Q*(fo?d|9p$#(}) zEZ3e*g*m4FbhjV%ss7>mD6Fe_x4Vbk29M|MSx)$hyOy?|KD}Ep$o-LGfe)o5FolYjMtbpG8l?zpCWpZEShD>Z0Wmr4Q z-&8S><{t=|H-1lDT|1TaR|SE7!9^{GvA+mr99&l*Mtl}g*C43LpFJ}ym0!H0VLIjY zvVd-7QIjp+c<16Jy_U49YYu36Gx^jIJ;mk^3a9zZQ3ZoRK|z&8?_xD`RSZ52TfJ}T z=XNTKirx@}v>2n7g8gQxHPzVfqBd_Foh0T{ewaynhXp&T>l;pfzb_~#$PBE7Eqj5P zQRlHu zI@8I&P0Pe9&uW zowsynLyq>LEYnRawnK@qKTE}ySs3^S2?1Y+Q!p!WbELMWgVBCZo#@4Yeu8T&1s{qq zUdP7)MUy}M@s`cecP|`;$KA8Ue=n(1Aup;a*e*9&RMl?jM9M9+#r%7_0k75gu{w6p z5X9mkI8SXFWH7zvF>_;KeBL8h)6*i~Rpcc&JIv=u3fS~L8`VTykQx`z!9zoM%$Y1I zB&282A z#EmzT5uyOo$l@vm8UH{s1H#_cUGnlb?p5(O)}s;l62N` zD2Ao+sKfUVvpSV7)U}ltm#I$?X z(4OdGIy$A?@-hrj!g-8-%3AfFQeSo!DNoODaO~?zLmL|*9#SLC!c#R>_lG#pvcz(1=eKEB$=n@&9x)I`rQq;f#{EoRR-wcWBUcRI4GBo^u}>CMy^A_Uvp+qVZQH|K3tG5u3X zhkFt60{cFU9hhliLr3F&Hl{XhpRF6b+x=HM=UfDtoYk$sz7k*yL>4Ngg=<@-)g?*G zJ~!vS?K;y<0|V=uNwzh?a_;WHz?ghiCwn*&|LZrzGM^!fH9-`|>0kQ3z>G1z1sZQy z57eZO)DgToBmisIm6o7-Sx>%5eu!M~+u$o6BUN|9OmEK%luPH;@JcUcW$@1Vp3aHBKKJrdlP*Bx1p%W4NsXMBtG6;V{sh((e3RSF literal 0 HcmV?d00001 diff --git a/thumbs/tank_tower_003.png.import b/thumbs/tank_tower_003.png.import new file mode 100644 index 0000000..8e7d781 --- /dev/null +++ b/thumbs/tank_tower_003.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b6lw82uah2oto" +path="res://.godot/imported/tank_tower_003.png-b9a7bbd7d320493884f67a7a97c5c24f.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/tank_tower_003.png" +dest_files=["res://.godot/imported/tank_tower_003.png-b9a7bbd7d320493884f67a7a97c5c24f.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/tank_tower_004.png b/thumbs/tank_tower_004.png new file mode 100644 index 0000000000000000000000000000000000000000..4d088e7c153ed72a7d1c3e30a68904a9d888bd22 GIT binary patch literal 2601 zcmd5;`#;kQ1OCpPduc&cwV`=&Ps|^aJgdBx%{B`Bu7I7Z%HdTR;2U-pIN#@4Pl9Cbh`HFh zsN=8se;E%;XlPw&7uK7#6qTMFk4oztemBI4dXdywGA$q()hH>sncTkq*eL}#9oGkl z9T5c+Wo=^&f$sl@a7+VLq&exJj5NfZlET}MKzr)$fc)*%-|ypU$m;CxI<&sdcTAC@ zos>{F-A!8j*AWWAzW;ssOiD|nQzPDhb6sJkwD(Br!f+ -AJrzL)ZF&LpRcQQFF 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 E01K;Oc>n+a literal 0 HcmV?d00001 diff --git a/thumbs/tank_tower_005.png.import b/thumbs/tank_tower_005.png.import new file mode 100644 index 0000000..4bf47d9 --- /dev/null +++ b/thumbs/tank_tower_005.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://vh6e3dio2mv4" +path="res://.godot/imported/tank_tower_005.png-cd1a0f0deb4aa3511d715da8e99f7dbf.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/tank_tower_005.png" +dest_files=["res://.godot/imported/tank_tower_005.png-cd1a0f0deb4aa3511d715da8e99f7dbf.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/tank_tower_006.png b/thumbs/tank_tower_006.png new file mode 100644 index 0000000000000000000000000000000000000000..7db461ddedd64a3f6b17b9cf7977820a31e49aca GIT binary patch literal 3494 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 z zL;L0jWF1n3&F-=RRX8_nmbBB~1I9B)#rAKFE5)j-ErlP-V%k_6s%wP`8W)n@WSXD; zG!Rtk0s`s6tJX3&Y#9sL{IUPQ4M#j6py<~ZE#r7C>(?ww5%*gLWTx0TWZCprV>VV9 zr^(_%=O3(|v)Sh=1p~1!Tb-e@`s$LqLKi(xgoBWz?3zCQE`BJsg(bXpVaV*fLTx}0 za+zzXlD=QEi%a3dSzKdD((&XU&@6OBXS94*i3!3jEKV}<*E1qwy{46jux5sc48+JT zGFKa&6cX$48H^XabRA>3C_k0EIrF4|eUdd<>LrzALmR4#w5dPHcFQi-tM-Y# pY!7q|@$5K~=Z<>+UqRw2m4RCAwC6tQ@Lv)GOpVM9-x=T|{|8&;XJ`Nb literal 0 HcmV?d00001 diff --git a/thumbs/tank_tower_006.png.import b/thumbs/tank_tower_006.png.import new file mode 100644 index 0000000..b9cdf99 --- /dev/null +++ b/thumbs/tank_tower_006.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://do7q0034128nw" +path="res://.godot/imported/tank_tower_006.png-2aa7cde95e9c8f1eeaf84b7fcb158169.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/tank_tower_006.png" +dest_files=["res://.godot/imported/tank_tower_006.png-2aa7cde95e9c8f1eeaf84b7fcb158169.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/target_001.png b/thumbs/target_001.png new file mode 100644 index 0000000000000000000000000000000000000000..6c7648b2ee2bdb9445abf1c059b5b2b26930110f GIT binary patch literal 1612 zcmchY`#;lr0LDMxFT2<(a~Uc%cXFHJR4f@ysAxHz=7`Lwmr5pwRLBgyhF+6PM~d8z z<5s*}hvc%TBv#3F%3M~naU0;w}gqe^Sm>=#Pcs)P#@V>7EH+ zl5l7!b0}k`G40b@WNLSFci@A`l~;=gNQ*+(rv7Fh`fGREXK-tn0pIrfFV#!^3@+FU zJ`>Lpc$b(RnLg%y7Walz>B~tPO#aisH^VSw5jhj`O)gPMiZC)*Ia9~00k};$vL`lB z$EH3@a!DtOwYIp315O`i9!8RPQyu}a-l(|k2dvea61%FOyA4J~xJ^Fk4rxAsMyk1&7lK6FtRAn>w^OP*eitp+%aj9II~v?m2FGt+hulz_-+Yxp zn~oJzhylxEyt3_Fv!LQ^DF1ft>B<8?B9wHbTor&pa1O5Oe=>l!$#*LNEx2j4n#Z{O z43VlGZ2Ly#kYRPQFgcq|?)T(h_tW@doic#ggD3mosWfQBDtl&15Fxl9xwO*$y0f)r z)uhecxUgz-v5J=ZY>LcLa%!sr#*jvtn_0KTCzzTWska^tWyk8x(PG5W>+$;=OIab% zo+w+XWJ$SyOA`luo#gYL?lm9dkM=5>>Jo%JC~98q=Q*A;4Rvymk(VX&eu2a9Jl<=` zoYHA5zId1zM>0A*T~e~yNL@=kx(fSb=gk6%aHCY&I(e}x%F6e=+U1vAqaY)7vcpc) zw{?DwXxszK*?qBL>ahi`;rEiWqe&AU2#%Rwn&q{MS^}vyPw>^}SDexp;ZOd}gO=vS zDu7iH^!WImMKX1Y7`8W9)5#V8dKUoBLEGm}#ki~77zy_^(q(b2$>N0E%FeB!v-9N` z<>ic+bmN$enh82%)op0)xxy1Xc(HvlIDoWZDbDe4s;Rwcc|h_=K=6$EX6F-See z#-_M^mdIFd)kHNsmq!X6k`St9tsU8@eiQq8`Ju_RX7Veu z1Erpkwd5!SVAa)4TMGtIPwCv`Et6^qwQEEERSRu>8i^P!ZtLZ@#bsrJ=8qZlIdZhY zy!I=DwEF6L&svR(2uDP4(Ra}`twW;{vc%tlRAjjV62Q1~U2?K(4>muR;# zF^&mddFF-BPefV4>4)IPei_1Eo2A=>G-gRH#hNfjH{jCwT}&Uxqph(b99h2eG;eM` zFKSuTz3<2enx!hdU+3!eF11ZLkK+mpRk`1<02gF73NI%3*cK`_xYJQ z#PQ6(4K!_=S~yW*G{9X1I@gYZ8;w_Y5bbz)LUUitYNO4j9L4n{k7+ZO1M8UbVhiHf zsCWC<_m@MP77iS=u2C$Tvg+YZt{dilOd|sqtcSO^`u8hk`yenIHrw&$gSjb@sQbtZBw~WkO0T%cX1`4g{xWj+ z9-P|(Q_%nv3=|z5UKcc6LsR;gfSs$9Yf2eNCbKOd9UP|{yyE-@LfX#(&nwdbY!1Co zUi4RGC8Wc?&m;8Pq?a<_xYtyligg=6hvOEU7NB?_jouMR@x!w;RsIiU$pB7|V0YJh RDRko=fQzFWrQCte{s*0A$Fcwb literal 0 HcmV?d00001 diff --git a/thumbs/target_001.png.import b/thumbs/target_001.png.import new file mode 100644 index 0000000..3bccdd6 --- /dev/null +++ b/thumbs/target_001.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://g3x5f182upqf" +path="res://.godot/imported/target_001.png-c6426b6c4c8c479fbb0375762333d747.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/target_001.png" +dest_files=["res://.godot/imported/target_001.png-c6426b6c4c8c479fbb0375762333d747.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/target_002.png b/thumbs/target_002.png new file mode 100644 index 0000000000000000000000000000000000000000..e2077672bfaf46023d377d0d6649417f3629c87d GIT binary patch literal 1258 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 wbCuLk5w)(nNED0QV{oi+ozEuPu#iS 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 literal 0 HcmV?d00001 diff --git a/thumbs/tent_004.png.import b/thumbs/tent_004.png.import new file mode 100644 index 0000000..1c6fee5 --- /dev/null +++ b/thumbs/tent_004.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dvfrvy68xi38m" +path="res://.godot/imported/tent_004.png-aae165d254da12b202afa5df354a9597.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/tent_004.png" +dest_files=["res://.godot/imported/tent_004.png-aae165d254da12b202afa5df354a9597.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/tent_005.png b/thumbs/tent_005.png new file mode 100644 index 0000000000000000000000000000000000000000..af1f00ee3f13a600eff3214a40cb4404cdc5bcab GIT binary patch literal 3202 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 YviN9Yo+c$E9X}O-rMaD19ojSgKh(ja%K!iX literal 0 HcmV?d00001 diff --git a/thumbs/tent_005.png.import b/thumbs/tent_005.png.import new file mode 100644 index 0000000..5976f05 --- /dev/null +++ b/thumbs/tent_005.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://ccomssilu5yod" +path="res://.godot/imported/tent_005.png-9baa1944ff86ea41fd0ac529047a1f6b.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/tent_005.png" +dest_files=["res://.godot/imported/tent_005.png-9baa1944ff86ea41fd0ac529047a1f6b.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/tent_006.png b/thumbs/tent_006.png new file mode 100644 index 0000000000000000000000000000000000000000..9d3a6d1a942fbe7205e1ca99e974d429e8fb35d6 GIT binary patch literal 3005 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 PTn7LnJySFVg$w%+(L=J} literal 0 HcmV?d00001 diff --git a/thumbs/tent_007.png.import b/thumbs/tent_007.png.import new file mode 100644 index 0000000..5422b3a --- /dev/null +++ b/thumbs/tent_007.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://datgl70wb1ail" +path="res://.godot/imported/tent_007.png-b28e355a44128512cda80e7cf5298170.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/tent_007.png" +dest_files=["res://.godot/imported/tent_007.png-b28e355a44128512cda80e7cf5298170.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/tent_008.png b/thumbs/tent_008.png new file mode 100644 index 0000000000000000000000000000000000000000..536c5bf55c376781179d6b1ff05a589da6f7cd73 GIT binary patch literal 3001 zcmd6p`8U*$8pl5d*_vytF}Cc9>|@C;WTwncFvi$YS-zGmF&SiELiVz! zrSsG&b#2|-*o2WmfvZvX&K2;9QVG3*&F-!0kIQsTWy2)%RuH;0pUzlj-GAwzhK zL(aIc=oi=Ev{3PyO>tSf|i!?@UVW!htBrQ&>?cWR)H6TtYx6JzRe`8Gmb`vXPs)8pXKwc z>*a3X*hR$)yRBI~s}&;8$KArGEos zQ(enO@!w8ixGPnDmN)Um>DfitQbVPgY{|u zf|e`T6sJ5MT*pxfagmWUm;h)EN_?O>Us8Z!wTW+q?6l78@avQgWaycVYkA2!uMmoU z=*)ghHT1LB49$2NdA7Q^(awx)>y%;>9-Y1(HO>r#jZF`v?2I%TY=-8O@K(mTX#n|s z{XnoDb)uhAqte{Ga0#0-k(U(kd8(AMdtH=QefK@SX!bnRiB;+s@X>e7SJ>)C_6){k zeAg;0fp(d5GBtAnW*C%7>F5^8RAJDqAZ>04gTNc#X}@tHpS!fxMs zij{ijlM*N=zdbBvy2~@Be}vmN)ZsGAU~<5n&Nfg*BfY^;Hj4=xn*Mf#D`%>(rP%~O zpY;fi+}k6Mix%>O!kCo>s}ARNm*eYe-PVg+R6vWYoY$efl=!p3MVM9B$)qg`sHJ}O z4b}|;LYhE*xtwj-#;(cZQo7+)j*N{wD8#B`C<)%|(9qG7r4hX-RhW zC`*WX*d?Ova{=z~&tAGl`#bkt)|j;?QU(uo6_4-Rj8d=IbFtKPd!^(mW3Qf68J8^@ zpX!OZiCpX8QPa%Ikh}j|F>kFjd5udm&Y)d!Dr}Y6-KXo9vBG1({xxS8M1x(6XAYv- z`wyHkC5T~heJ@x!ggkm*f4QfpXTq>a{yF~+TOON{G@PG&GH(Lm;*^G%2d?ZBUTOUH z`~8+n7IcP0$#GmrNQRN8X5y9~z+TliXxg2gGhqz!qa0XL5Q(7%cY}YOot!!VbWeWS zEvQkA+4dvk`(3Q$*?=^;H}iIUa^`7rTz7~J{>6jub)8^gM&;6h;b|~lw#(LPXFz)? z$!tAIFSpI*_e9g!nK_+e=0 zwnOo5(sEEs$Gkk-f!y;IcAHl*Q)xC{?ISmJe`oX+pN!0JPAC={4YgDM+Ltg0`#QD) zH%Vv2C9=uII3>Q8fQ9dt ziiUYcrS-quXF7gZE?FK&EZ%R>jLDTbJlEcw2NdJoRzLrk2B3dS#l@ICHK8{n{o3$e z^Y0RiJ#o%29(5!kEZ~z(cQkS+$JBpZ>ty~Eb>Pyx|M*SZ1zfRjDbHl}cxT<(WM9kG zE@4}iUwk-S(qDO+`k`rHlGJ7m@{sK*iKP7TcI(DVvgp2XR)lnknA!qS`NxQkSPN}% zkUSS`QUq!#Vj=bAo0Sd)P0`oaNebmciHdxKrKkdgPQIBqXMg}wS5PzkSkp;7eyE|8fptU ze1+N#lr`#%*+QNOjg!Cic$0~MGc8)$j0MIHu5n%K_e0d7Y8$^bhsKTpX!)nK4QfQ z1Su)zu=fad88Z(>#$3rIt505hX`NBnD9XZYSCs6`re3hJ<1AEG1wAr^7v$x8h7}f| ztNjG41QK^iAvt z6(yO8jtYK`m3r-opLw>^;qQ5wlI0UgMX|Wx8LC@VonWzDSBp~EL*DI6AH-L&jBOPi z;rvDm*IycoQ9k!Wqr!P>sQKrOl!0jQJlX3vrJcK5K2a0`(fS~^F2yo``=0xH`WrGJhfX<^TaLjI! zqiu-?>Tbv5vO^KL8z@VKn7hZvV+>JAs&}7VsCq*AP|D|jm^Fr)VdB~QgqdzVVz%8#?)SA1;{u^Bnf0Y0L literal 0 HcmV?d00001 diff --git a/thumbs/tent_008.png.import b/thumbs/tent_008.png.import new file mode 100644 index 0000000..527adce --- /dev/null +++ b/thumbs/tent_008.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://xff8xuxq62p3" +path="res://.godot/imported/tent_008.png-365a89c0e689eda53d96304f5395865b.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/tent_008.png" +dest_files=["res://.godot/imported/tent_008.png-365a89c0e689eda53d96304f5395865b.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/tent_009.png b/thumbs/tent_009.png new file mode 100644 index 0000000000000000000000000000000000000000..c9e38b8c564af9c38ff16f8599bdaa245150be02 GIT binary patch literal 2709 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 literal 0 HcmV?d00001 diff --git a/thumbs/tent_010.png.import b/thumbs/tent_010.png.import new file mode 100644 index 0000000..e329d63 --- /dev/null +++ b/thumbs/tent_010.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://uijfkbw2kitk" +path="res://.godot/imported/tent_010.png-fcc004d0730143c0cd392c57405a5aab.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/tent_010.png" +dest_files=["res://.godot/imported/tent_010.png-fcc004d0730143c0cd392c57405a5aab.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/tent_011.png b/thumbs/tent_011.png new file mode 100644 index 0000000000000000000000000000000000000000..2e288e7c73c922eb3279666cf36b611c45942233 GIT binary patch literal 2701 zcmd6p`#%$k8^<@+%y1~m$emnLDAy9kaWHq%k;upqV)#azJ1Y`LosLLzo3bfoqs+aT zj?6LHm@=1U$UV&clFPo%kLM5gzFyxSp6Bz!=lSJ%KF<&DEO%FX38*|2002lJ9Be%g zHSM2*fDe1SWnlNA0AoDuZ2)AZ!W;kqwMW=md&LzmmY}K>uE?d~4QsbH)y~R5WwQHh zrQ75osg5$jeNXGlCPMZCWtp4J=P)wcCA%GI{hrcgG;_ON~1z#9-%@B$!s!~*unC>q1R;C8-bXwjL^Y-Ppswu+k&9hrL90v>>z z*o%@B*OiOhnJDS@Do+w!oi$-uTmaQ2R3YqGW&e9Dlw1|)m9*5ks`}HOSAihT1-q+)HOhWwA<~NNaC!q$Y zFsjAaaGDqC_M~;SY4;Yu;FExT{d&{OE-3=wOHTv*RGofqJ-i45d8co!snse;ItCL4 zPp9sPaGQJ7)gJi3@9Y+?W=NIQxqN@o-h~h{^wh-;=&5fP)vOxT{)&*QPnx`)mS5J1 z8;~n&Mo9!{4y-4o-()2Ikrjq?bZbIrd$a3a+07|e0O!MizPHi=EC>v#L=fU!1pRNb?LLr&-CC6s4L2?dF}7~b|< zy7T(k38BN2MJjgW6RJ3lLr+F^SXWL5{N~$iN(!TfEhN&TRzWX3Rl|)O(re04UPS*EZTdXvG&SIbg_wg`L(h_4Ul=NcPHLo z>nZ|OKTG*b3#1|H$hbj}wR(wT6PEPeav(sQm!8-<`u8tulJ{QwdV6r^ZzU={`$(LY zyJym7N$2H!7Y2!o4+fE_J&C9qV`Nh)JdA(UI`=VR$|Nffs&l+Zuq@N#%>JbD&{>UW ztJ8Cxwxi{!o5$|3_l+Kp*P3=J0$E%Tdll(3WgK-Fd%s!^do(v9vnes9%E+it+WcT* z2GApJ5l9$GF7KnL7Y#U(X2WF%eIlP!nqS2($10bR3SIv1<-o7)gBa9H*0VM9M}+ zP6cr+_aj>HZ9@}(ZDToWd;U>Y=`65xf2v`yB?<;w7^%g7_yB!bl6+tB?U<Xa5l=c~`W#H*Bn{r&;=LGCn@70pn(EH|BWVo~eFwuw(%Rw~W z*lBJbjneOdCcF@V$yEm#kbgTV-;II!ZB zgG6{XVGo(6n0w7&SqGF?@cl!O~- z9ScCE*Sg{6{Ojv&KabJ5ahBoOb$gIjAL&n zlAe!hhwS{tQqXe}FJ;6nx@cMJnq-CAb$$;fxh+_BYkYgC>0Lc!l#l$GGn*h;6N)3@ z#JnS>G8D~ynpZvC3uC6o2KrIOTU3fPv)GrpShw=1&a{)Y3-p~KvbBR}zQuDnp3gfo zFVv)d{u1919GSwGzc|H7z);WM90n;Tlz{*p5b8KKWH4^Tc%hPbX17Cms2Q!(A~{I! z1$?V+WguQM-&un-Kkw8(8V%@WPzV?++2Tt^wwm3}s;kDy-uLqcAVHS}`HJlQiS852 z+x;xed!qmRx}-hF5HP4O=z195%@HCu$LXD{xAM7k#SnH&Jt%rU!gQ4zYC6g&WtVYd zl2ne0dR9I?`y~65BI{Y$Jrd#8-0WI~+vyHe(ZRsE?KX3;a>AQ_D+LQxfDoEi->n3- z)xr}NpFj789H3OJ0Q9S()u6udZKHK%cGx!U!0naA6x5- z%o*>bCBHo-e8z7RfNxwmkUp@8y;mv)2s_Dj4jmR%;VjhKs>2H*#+{U zf}fN@;}0UJeQhw|{5&Izp_4nWjkztHEq@wJCtoXj<>R@~Aopu4+#VKsh1_D#5(U&u zR){qH_$HQ?l+T$?KmHw0G)a0qE}+s!b~ELwIgD83g45AFiu&F_CVs^(C4AtY)$zV9 zI}dIhrlog*yv3DB2$CPfI?;C4Ca$VLMFFmD!7?9ytkBg~hd!$Y=Htdh@%{j8f05!{WBygE7rk@`r-|j2Iv(xEO91)D)jm!q? z7g&csJXc1U?tf#7p8F}GfNUl9Ox*2jj3U?!GwQQ2y03{SjQ*ih3nMGumi)oswbe?3 z7n@U`>O3WztuCdk1Q$4W$MUjTj{&McX`~gKX!?TBf--rfz0-eknw8YJeaaad(A6X9 z+Gt4_QxZ+qf-|MJ{4%BP_J^=0dW4Nn#tDPlujra8tkHP-;X9p<$aO$TOTy4oV0eAlkO(hEa literal 0 HcmV?d00001 diff --git a/thumbs/tent_011.png.import b/thumbs/tent_011.png.import new file mode 100644 index 0000000..eb56935 --- /dev/null +++ b/thumbs/tent_011.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c1qlj52ut2qme" +path="res://.godot/imported/tent_011.png-a0a225a754aa52883d67f92e4fa4b349.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/tent_011.png" +dest_files=["res://.godot/imported/tent_011.png-a0a225a754aa52883d67f92e4fa4b349.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/tent_012.png b/thumbs/tent_012.png new file mode 100644 index 0000000000000000000000000000000000000000..77ed00468e52f78105524703fec1cee0a374d405 GIT binary patch literal 2310 zcmc&$`9IT-AAhr9lx(CeR!lUD93R?;98Jx&nIlq>tN6Id(Z_ORu5>U*D$>w5qfay2 z!&S(dD5jcn#2k@3M>$)%hiPgN9^c!1aX_i{fT4O3msJ5$(*x1AsLc`XQ`A zSUW}=p3V>W5y2>)w;3kJrhB3-#}@GYAxF2q=cHj;KkT|Z)4w0r`~@2; z-2zFK-Eh|gC^nBXO1H1E@d$zh|HU6^-*Q#s>7w_8Pr+&T{D*?KghxO>DL zclN`TeGn&D=WtP3T%s1GD#uxTP=2K48D}!!svAKc=fYijej!xe38PK#fvcT8UQ0TO z_5k@*e{Q2QZi{DbqSai350>=E3EwCLZg37}qK2BX-D{T?>E-UuIFuu!5Mt&{wWYrpkgQwnw7M|~DVaqHL1fOrn#-$C#VHxD`!n?>9`T~; zhE?9`go@{SO^rRnkwrtLq4&BRF-Ba~Zv|CKL~FSyWD!<i!9 zOBVQ-^`I`uxHx>oL#&wmYgP-Kk{L)k8pC@6iDJ^|_`p|4MTl3eTobA4?ST&fxthy=YRmccrrTso`ruDr6iCOAFBh z(UsKGpti6rbwa4=mA?2?f(TZ$W{|Z@%fPm-yI961)OU@a^l(!|g2Je3G`vR#ZM+hG zFFy$nwg%G+AVM}2cH}OCqc$a3st|uIxF+R%sm1pCVa2I|4eogH=a%`FuaPVzJ6n3@giq_3<@5B9d5~@k zvkZ5}86>%If9DSqd{DzsFcXdb<%#NYz|2aNAeidAld2;7qQ1S7GB;GYRIcKe7^$4_ zGwWja=OhCQ{Wxq%KB<|xG75M6l9scbQRLbigni&OR_nsJ6dWvne>URMOrM{*XwmIE z?_v+Ow1!tPg|$K(1uO)PHP?mD`d4aC_jB+2Jha)n!PD+C{RhzN9<`}gd88Nn^Nl;r35IN`rl7)s0ZLTgjY;|g`HN+(%0A@)a*uMMQbp;rn?z)P!Rt|?X!l4 zh)nmo?g%e9F9UV5pg*g3)W&LwISKwfy zlInjN4Tx&_O*Gd|((nWQ&dT5A=gF&1ZK{dBWnf%1s?#fiMB#%l*6UbK*?YC0Tu;K) zqh)YbORNU7D5Ar_)2h_WFs8+-Z$8^tSbgDwWF#g4&4x#EVqjCTJw1FCQ-y@{?x?Gp z%V&-(4Ps`Erm|KVrPL7Y-OlX`V<*nApC#Ag{Hq~Du-B~5jqF1Ks$gkviuaaSMk?9l x0S^D9f4&M7x!*$~ooVQt1o&Zh5jm(;(ix92fyAISPcDJ7f{`8JP&}9h6jc06I&?1?~!Tbig~%$GV;qi zl3fNZ4@V%;7;P2`${91Bg2HU6YKjg$oZz5fZk+(bTf3uhGoa8k3q6K6RUvyN{X*^w zwKKf&{0Bc>CALu5a{J`jud83(Xl?&#V%j2qm-~q|&w6=dy(1rEP`kNW4eWy$U`hbm zgJJ1nI64h^NJEumtOpS-LDb*0FfU{yXFK?+GHKkwoL8-Qxj2(obousd@`ixxJ-*N5 z*-l{ogb&D4e7;xeJAY=cx8pR|_JZq|kxYo2bv6|q@bijPyc~O?bzN+l{t1prc5)P* zQ1a8&h##P^wWqlkyf>TR)?8MZ&5-ia=YrD!P@TC~h$6(-zG9{5()87$5QF3-mo5E& zSh$Y}Icp;(Zh;X;87EX5cNZPQB}2FYO_~Ri|LWI2%mW&A4cX7vFy6fWEq4oC3gwRb z^~;G=b2s6El7WmqdFQ5d!oJkG`oiU1%id zxpbF`fT0iEJXlIj-P`ye0UfH8T#J48CVGDOzR-x@XsL;Uy&-gXMNsh^DYoI8T*^VybaIwd!cHCt&VvV{SW)ABp6?-_ zTJ)OJQU|2^uwSJ5{h)v2&h+|0XDxe%gDQahx)m8K)MBhF<9&4=cYTK>5g6rV9$4r( zQkxyGw=~syPc6Eb|D^>kCkb=aGhc=NTlBTl_y(-iR}Evkl9pQ2^#Jw+qX35O($mYY zc=8O%IKQ}_8FapBuyrrcF{Chebd+Pv`Op_l%l?CtT`A{1z^t7jrbe7&*-Nf{ zQ*#UfAX!{`8(P#2Pxw6Z;U13KPFpY;ER!Yr#d%H^jrUJF^ROEqBd8m0vh*1^P^!=c zUH7=p2x5XAd5W=?bOGBNlGwe)R<^)QQHpKN=0uS{ZE#Eqe%MyzBr~iaI;oy+dye~S z0frfGyJ_dWs693o_O?tdUaJSe-HkXFB}*KH<6VlG8Mkte=DL&>N$t!-{0?Az%znBESEvGbJro z5G}#!*%Q=>M>YicSG9(f$jx<@dc^&2!m4(zNz%$f9cSO4F)*!JYVRRb=>d??BOdu8 zw|od*8X^c=2z;E;2JVMf)q9;~2u%)&SDh4I%(9M1|IJF-VnQW-9xWjVR5EzFK1Y5W zHhdI72vy&wAsTXgzZY6znDz5P+Gy%0IDs#?7-=O^D3U!KnNlmhIo!^K;9lJWCpDQb zEzN2IA-vWTN<5NAv47LC=7h zB=nI@%JnPiAd&>Y((WHj$oY*S`X;V9>QYt01Q7?7HHiF3GxUL`|9k{JXwuKJKI05d#a_ZK!xUE_vWs^|WfYO&Rt=7wsvj;?m-KazS_DjBto#+V#GIU$Xf3>>Pi}(e}L2JtndT1@$;FSH(CjDk72bS6l z9ITNR)3-p-9{2U8t0^YR4FDAU-R%JcZg`m-^_!=S|E4!kk?-7J?x2WDxHLFzNrD3yJ*GNZl?^M>7Z#v|wI zc^?tr5j;{q>l7Vm@HD((!_YpL8vp-HLDHO*y>J$y4c-Jo+P$%Pw|!yHCdpRwcQw&} d{*LgF@yZ{V>D+6z%h-=e;NeQ8RJ&YE`Y(?zKb!yn literal 0 HcmV?d00001 diff --git a/thumbs/tent_013.png.import b/thumbs/tent_013.png.import new file mode 100644 index 0000000..920160e --- /dev/null +++ b/thumbs/tent_013.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c73gf472npmoo" +path="res://.godot/imported/tent_013.png-9db85535198770c5aa434b92f63e77b2.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/tent_013.png" +dest_files=["res://.godot/imported/tent_013.png-9db85535198770c5aa434b92f63e77b2.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/tent_014.png b/thumbs/tent_014.png new file mode 100644 index 0000000000000000000000000000000000000000..e396378f8144ac6260876e230ad2bba3bb85aa2a GIT binary patch literal 1922 zcmcJQ`#aQm8^=H2F*9TwMkZOwA;*d0N`}^8SY@~n!&A-;i9{mneCX?(JPewY@DM{u z2I~;E855ITO=QP8$FjnrA?I~k&mXZr-1qB;_x;2By6)?GztipQEX76TL;(QeR%8px zA>sdz2>Nh$n0WCH0fka5%>lDVejWf}qLqc2Q)J;%5s!wuDF0jA-cyea5ia+)Tu_>0 z5!BulQM%%NDxDU&%pK3@>YVGgXrG*tt5H8%hSkrl#opne+^I)&qO={7c)!rRe4|?x z6k4A@_j}^u8(tOOy0vFwRc~zktG@o;&hE>qmjP%&N}P_ruFp!E2jtsa3%Fj;{SE{+ z4W%T3A<4_YhT0&+8GQMd1Uth;QL&7X=`<*EUZ^PE;nPHfsiJ2}YVu}tyzSUxU5867 zi^ze|4+K{>BNs-Vu>^5muM^eY`a{07li!H;VmBj#!}dSIk;XKWvx#(1c%--u{idfP zx;w4}J3BDpDkw4et1_%CfhFA5V87gnF9I4_@(4g&-R)T;ndZM4G@8>Yktt<{#W;#) zi^iDlzu#R5%;skyzMh@rjLn>Y`6Cs4+p3<2Rr(a6D|MuZ+i`n*xM0wqMMoqfbCLH8 zNXF<};xAlcsY(v$+rIKGzzcAa8mai(=5kL{kbMKL9DHr9v)jCJxL2yhV>b`KZo&zrC35t zH)zPe_K{PzwHXb-m--<@x`MD9znmc3B#_AZ{C2crXW|ah#_i5`O zS;vCaj#&(HBZNK3>8esU)e#ZL^K@6nyWU<-zG1Dwag%=d#IRX0-AOj{6yWr)+3d%f zo&%B?2cOs>!%sy94Mus^(7C1FN^M>vKf6_{Z&ls1Nzb#PVB3Ox{vq;U{90!_|NSMq zv@mN8QpT<7th#EIt#w+cq3PrYn&S3~4f`O5;3H3OY5S_np6<%hzJoIAzAIinn$H{* zYkmKVhfK;>_{b;G1 zVcA=+7ybFK$*q~)qJ)LUe0mcKfRC%#6lK^Fv%JCeVNceGbyvXrd3#&q({q%W1lmI+ zCPS-vNM)|t<{^Qqe>Dsf>%qmg6aRCJX#; zR(V-m$E}z1+Vb)=KXY`re%inOhLA`S7;qhkY$0eaC1%Sgz-P)-F7f&+f~0HAu}Ej; zKs7rRZ><9l%9Y9dm`GS5N;XDcA0C*?;A67M`IE=ar=kP1`ivzn?PwG5EMQJ{62p`{ zTTSV#h`KRExQ@voB=Ir!8P}7&sMWE39qXE6?ho#5qYOjl6_IQgD6r=b3ontG-{ry7 zVVF+s%)7%E7JoQ==+pGtD{TKlEJrW)?O*`$lcs}giNfQ1CrKCsB+zZT(eIuhqXT(i zsqbD3W~1VL2K2MA<|D3zP5or@eb zKVFgGE?4iuIRfPcGzNye_~F4OBL2sSKIfL2Zxg<+UUj!0fhw3|`Z1RFLWBxLnQro3 zA7wH|0}1#&k1AV$oAS$K<>X*L2@p&M^`THW?tVLVeYi+MX(|`Mb))S~uJf8=_F;b# zf-!zbduy*i?qWN(4`~Lcl+Sowy{=R!Rf1=<$Z+^-hlZbj1t1McW^nIUhCz8}p`chC zL)s5%xIcTQEEKYNpoah??2}4n>ULn<(#X=_@q$mBO8R$OTeOQTx{ytfbT2UQWZo{k z1+k0S-VFK8@BIpPM>tQ?7=RfY9IB^;2YsmwkY{@Q3r-akJi|Ld5PFKxy`YLBuNK!p zzyaDi+Ix5)zfU-iq6*z5i*jz0PUIqjw?=z$u=wxFr{S+=RJ0Xj=fT2oiUcclR+R@G kBAq6xZlFT^-)NV8;jGAS#_RC9!eOZbtBZCPOmk}DKkc+zv;Y7A literal 0 HcmV?d00001 diff --git a/thumbs/tent_014.png.import b/thumbs/tent_014.png.import new file mode 100644 index 0000000..84c5b1f --- /dev/null +++ b/thumbs/tent_014.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dpskwwxwixkjv" +path="res://.godot/imported/tent_014.png-93a2bb1c29cd9d7c36d77b55f7f562f1.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/tent_014.png" +dest_files=["res://.godot/imported/tent_014.png-93a2bb1c29cd9d7c36d77b55f7f562f1.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/tire_001.png b/thumbs/tire_001.png new file mode 100644 index 0000000000000000000000000000000000000000..bcfba99a51e8a094b76b7659fe4b1d177d7e6bd5 GIT binary patch literal 1578 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 K{Q2~xia!Bfw)YhP literal 0 HcmV?d00001 diff --git a/thumbs/toilet_001.png.import b/thumbs/toilet_001.png.import new file mode 100644 index 0000000..0233c3d --- /dev/null +++ b/thumbs/toilet_001.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c7lb2lxa6y3d8" +path="res://.godot/imported/toilet_001.png-0178f20b01ea8322b2abb14960ca6f04.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/toilet_001.png" +dest_files=["res://.godot/imported/toilet_001.png-0178f20b01ea8322b2abb14960ca6f04.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/toilet_002.png b/thumbs/toilet_002.png new file mode 100644 index 0000000000000000000000000000000000000000..64201959012f9e2f2a922ece94425da28c115da0 GIT binary patch literal 1785 zcmb_d`y<=;0{whLh)A2DBzGZAQHoH*j7#}0L+UZYh<2tD^XkK^AzsB-D19hyZ>#DN z5nJo(rDm*HD;`xQRJ>;7-UhvCnddcA^_=~-KVUzcbACAIr}M)(*O}goL)Z_n0Dwd8 zr(OIG6!`-fl>_c};z$kz;`%Y@p#G)qJOC=+xx0MgpIp9FF<7V-uG=dfdb-4`)8rSS z*CRyBP>;(I)+u&=XEx(?%xrWwgfB_f-dD~h;+65((9oxSoi{s6;6Q3=A3B8p;Xi~q z>NYyxFF9Hl=B3OxRm{tHGN+-HckV_NFM}R#?>dU#&U+;VIzC%TLFdwbYVtwuThKuK z88F)bo^zmU-6%pHntE6r*407m{#v8_d}T*dYsS(qNRTP*)URE|0*MX5X#bXQCob(- z@OWCHs^?I<-J;2$?icDz-8eBdPrdD^=Qh4zg{|f03Dt-EfD#WQ1QZ>h^aVsDT8U71 zD*#h-2Fq@l?&(m6=1ll3)XwGis+)fLMVeK94Y#GQ8M4M{yTg}cx#2P-yvn?R>1L6y z^^K^snqI@?$g=`p?4W{fva&nU#!aut8Pwxc5!?06aJ+7^Ky@O1rp4P+r5BqzqCq#?2ZOkv{o9$DA09z|y<#cvmwA$K$fBeYmw zsyR+vU1%#gd3QRMLKWSh>Jl+ZIh>OH(D+9&XvF*peT-~mCWvX_@es=&lL_q zBLO2*){0Z)wmVi8q9tv*wmuG9+n+BQr&>xXx{a-e*5qA1&Cw0!tT#GP7JuFK`!sB5;8L0eUAA3-12|!%!aB{YqnW0PaoI)(?hg8Z)IDr%IxW0 zN}^^gr#8wAw%yFx5{r8l`b$EtG%|DUc~5|2A|4G{d8M1y}%Y7n5sH!hSahCG|p218hi~q`;N#p#ts=M zZ_Z8+w#&kf&&f6ie|&Os>M+W|K4~=~H7_o4_uKzOYpRuI?w4AS89ogydo!d0D?J+> z;cu}HZO^G;HQFtjP!CbaKTv?VH9z2|klZO7*+dKN6n-|l=4bt;jNyE3X zVKivuJg#5q>EC)qky)L^X$Z^i_EY}tzk%BwkGViHgfnW)?rnH&I<9w7A%qjeTSrUl z?6ra|y^s&-U*EH2BJM`UP3<@w$pl#Aaj+XYn^>|ANBdObD6x5ZXszq{Lz&hO0cC&*;*HwygNal)tv}MB1|wW8obZ z!a;#go2PuceKHMNE{8rh7&!b!O-e*1rem6j?6)7=2P)aW&Kf?4&|jElwYuFm1J;BH zb<5)1i!lqTUPSijHLtyh8|)lV%R5@jbIw%swJKJkN>$u2MV1+A1HC68grXVtx0xF= zh{J`vcocBI$GjNw^WEU#MEFLBnxn-d%9&}U$I=`f8Gn+qfX)O;Pd%Lwlol&Q; zoJf0ykw>acVSReB$is3h9myveUB#1(fYjuZJLR?GZLV{o%msP$nN8$aFl@XOOnW?h!Cb+Hz}?l`rJl~_ F{|+OM4Tt~$ literal 0 HcmV?d00001 diff --git a/thumbs/toilet_002.png.import b/thumbs/toilet_002.png.import new file mode 100644 index 0000000..6d1df4e --- /dev/null +++ b/thumbs/toilet_002.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c2evauos4cjmc" +path="res://.godot/imported/toilet_002.png-3456db6e77d680f24d4c515a817a3abd.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/toilet_002.png" +dest_files=["res://.godot/imported/toilet_002.png-3456db6e77d680f24d4c515a817a3abd.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/tower_001.png b/thumbs/tower_001.png new file mode 100644 index 0000000000000000000000000000000000000000..c47a20dfffccde295e339ba1c74a874c50f15f6a GIT binary patch literal 1709 zcmc&#`9ISQ0RHZ9jJ(z{#`~I^wYkqXM-i1$sr1UU zF-5L&AE9zfi)4lzxsTWTPrUCB&+~jf&-48JJc)KTmQoV(5&!^5;jFOuU1j_WanW6F zFm`X-70@4eOH-hvQ*jCaM5#Ee$%T;onS2-D0~ZzJYn<)&RFF|mCJ2yy1+}a=Y`3g- zmYj+fmW0g0TtTof6PNyC#s+GL#6a<&WW8pHZ3qq%E1Mu+7>GM{ymS!n{ZXczV}5eT zz*yKxugH4jR?#Nh**Th5c{f*QW8+(U`#`d8pb*VEEMr@xQSeq4fkCS?XcvGlPk?%R zP)s3M+)@OdCV^D^Pl5s|d`7tTM8}feEzhnFH%txb4zaMmTXz(ZaCEX}P~P(?f-6+W zUGt!Njr|NW2>zyjRUi++%kl6-wK-o{29BfwHX;o|c(CdCV@<0tcI*53{OqRr4DS8= zW`pCJ?U}RwFyaZ!b5pVY&~Z&b%|?-0ACm|~gbR;l_NeJZxArFlSyulvX&3DEA%?=x z(GRt?$>hmvK|#8JibV<(ym8P_C{jhz%3<$ygj-_ulg6w;*IbJypN>DwnJq*X|DA`K zY}ZfQk5bnnyyY0P>$$d|;0S#%iZh9zY(L{Mo06g&)_8nt5Gg-9-P1YevFe~FV=BRM zC~x`V4$IT|q1HP3kpH`##u5GNmm{Euq@4(DZItU1usuc@c@?F83PU-y@5|YKteVQ) zTa(v>{gFY3ORB`YQJNl>0QK(uY`MG5L9@e2!&yZdatgjiw8r>2Rc+-`P02R7=VR!b zusyCR#V!DYG=dDWI#<+w?n=XIge$>gl@L-4&)4gmxbC*!zamEIP(=T#FjZ`AerXPP zD5YfOc@ZI1@s<8viP`1?c=MztTQzV~eVN7F)J;77Mka#p9olp6v%|ghFl=sLT(EQs z`it1y0o&~WeR4I5d)BVoKZ5q`+_6n}*17}zsk%&j?-Y*&h;zV>J_^T2-=NS%L4`5~ zk!4jdaj4K|^Va%@MEmkl{HKAaPxXi;LELm#6m7}@gTB%rnxS{q!)aAIUL@a;*m~d9 zJY_zr>1o3wX-$W!NC?F;-K+gaT{@?$3DzfRM`tGu=upd4qtApVt&A?_5YBq=Asb?( zJBBQiu4QW13teK#nh~e!!JNiQ)|$uXBFzq0Tw}@h!XbQZNv31O*M58}Y3j zTiFQU=biEKqFovP89l#1TwlUHu*L6dX^A}5NSm1+S&c9j_zxG*C?>Ry+OH$|&Ik9p zR7P#di#9v+7(#Oma;VcC=Cm?I>84gQf9=BsK+pH&k)sm^r@hXnJE^TS{3fx`S8o3* zmifC&vupVgGHI&LjJOci;*u>{JEcP%a1DI&RbAO~p9R3kHdy@5pVxN7SijxmPD@zX zMBNq$J6?46x)6w3a^vPp31>kzFo;Y$UmVc&fetD4%?N+}l!XSPRx_bdK_r|;|BRHGyc zp)Vw(6pU6pal5OFYYWto#!6=?`-QMQQmJ)vEI;2AKe>@<)!v2WrXv0wtm!b+;vF+! zYj!j^Akxg?Ls??l^ag0~U4!VsiPeu^0-@fvrSsRexPawax56+7vMXzfv#CzbOcvoD7NlP^6vitICC3piK!d&A137hG5`Po literal 0 HcmV?d00001 diff --git a/thumbs/tower_001.png.import b/thumbs/tower_001.png.import new file mode 100644 index 0000000..3236f70 --- /dev/null +++ b/thumbs/tower_001.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://btie0u7u5us1j" +path="res://.godot/imported/tower_001.png-91c2f86403c14f45fb839c0ae2b49f9e.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/tower_001.png" +dest_files=["res://.godot/imported/tower_001.png-91c2f86403c14f45fb839c0ae2b49f9e.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/tower_002.png b/thumbs/tower_002.png new file mode 100644 index 0000000000000000000000000000000000000000..bd73c6b399aa8791a19716cc34a6862a4d0a4f0a GIT binary patch literal 2551 zcmcguXIGP36Fmt*x)dX!h+qNaN>jSh1(6bI7F0k$G+d=~c$P@Mxf&+3|q1~*4c80trRSAW3#M<4+ z?o^(zbH#-xaw5kZa0IHpUZL`&$F!Pr%G16gPu!zHkx=VH7iKL>8{D$7?=x={`&{g< z$$zQm>0dA71oX>{lw{EG699aqWUFi$hjayF73 zMUXwC(Rcym7i%FUBRlZk8Gb5W${d>llJXFVdz7KEL$HH3|3OIRzS%d{BRp!aNY+L; zyx8z?XQmNO1(3`kE|;hu#E=~KG&z<6#BZHT;+&rmd8wIFNsxh1V? zLCw@`n;%dp+Yzthg5e}^XLi7Qc7VF;y3JQzaz>wQ`HL6#?b9{qdlR;gOcQM)-^%lS zJHsw`_6&w$(wKnH{RJu#`N>kV;ikTyUV8XoYdE7@4?;TosTssws+I=y8bLL@<5n)4@&1QSo zq^2hMYp$+}lfx4F*(yhlJYF^J6Q^&a_m=y#3hSrQq*u7ltp^U8qrcBemJJOKetLDb zsB5{Y$pV;eu~;cA9aYu#a_*o2$LJpZ`Y)n;3mPt(z-?)QK<&CxwC|Y#Mo>3a%TV(P(Jz zcOxUCw~W9=6DD!t0B+q;ksvyi$Nkk9raM9VL7Ur3><{0rtLbywkZZNRpUge}oWw4L zUw?(a6wmE>WbHsP&1sEA@!g#0l67%$0U0`&_;uQS5fogT?WqWageuw?y^jJZRO938 zMZmod|8d}2dl9TZ0VXFWr_RjG%yfTylZ0;E)KgGUIH)QvHW3;cdMYRR)XWpB0tQnj zR{Zm?+g~?l#0;mzrnYt4u&#CKm-vW*Vr#Iey1S9IY=aE58$0;;_?A{yOdmAjXUcBF zMa?#1V}+-urgC$0p`!Dp*wtANEDonp7QW3Tobxr6EHA#fi%!4C2~S&om1Xu|QPoP} zlB)TfUU*=jCb5ySv=j_ZKQWYi6!=rPUs%Gp?;|c{|qgkLu|b3<;y|Rw6X8(;NaklQbpd=>T3PYO&}U05ifdjBueK-nkmt6 zKIk4p2qC`{9(8#Uh1#8zlG2i-Y(K}@(lszh&dBK4;;a__Q=%|mXLf0k4|jL4{;q2e zWp*|Y)YjJet3kyo5fQ3kNl8g=m41@E=0DV54uh7KmYfB`!%H}b&(_-4;E}Ru(Y()1 z-xLgWN4V|#k5ItbKQvn$4%g9N*KM|{&d<-kwzW}p7l+f~QN_b(%-UidS~q$sZ=lg1 zhZkdcvYc9c;r@p;3TkRlyis&kEPXXlAyV4gIXtYCT{D}D?JkL4DTECX7v#gPPB`dB zogB7+xFlF0gZeRO<(t(vy!x)>Ncw`X>Zf0X-_lj}?_wn0g$?;85M@F$zM30v?hVoA zMn1!k#^)%^ z%kTM1UbbGQUd{R0pVma8DMU5V)BApO{J5+x`h-Z?R#T*aWR*O#B^WM>`7@hSSzVpg zJ$V&_Nlr`KF(pp43R{XYR~q$%GSC1*GkeSa-a59y;rtyCP*r~|dU!tMW*vjYXwZ31 zcqGFoXg+0-IGUNUJNM;FOiT6a*XjT_vpn`bd4d{l|C9Nc?WEIaVx=Tu2l+YQ8J1u$ z7-`g%v@~h5M2PWTEEe0*-K{Di_+~y81>0{&N<08ykrp`E{K+n1P>V37h*P?4lqBfC z=M!^s&^#!b=_1h8&a_N%%*hn^KBm^&JAVep`YT~aG{BS;k4|#)h?1EZWt%&xW3FZF z_0TJyUfnZl%eFajLLM)t-3FQ}NWA1CUQS!wDBdPGN1T);OQa#d)-Ge-$fxku=Iy_< z+n^H`xe2gQg?>RWytsao>h70y%@+E2=}ra{)CwcnL2kZTSLALB>>R<@O|#iADk{D@fZreJ87M(j{_6De*`000 zUa~t#)l^yEg}Fn^>tSQ#1nn zJVoL`c5|W2NbKC6!si=2w$`VuN-Vu1{s)rft#<$b literal 0 HcmV?d00001 diff --git a/thumbs/tower_002.png.import b/thumbs/tower_002.png.import new file mode 100644 index 0000000..d1895dc --- /dev/null +++ b/thumbs/tower_002.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bg8egveebkqtn" +path="res://.godot/imported/tower_002.png-55f31a0aceba2b7e4b1611daaf434151.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/tower_002.png" +dest_files=["res://.godot/imported/tower_002.png-55f31a0aceba2b7e4b1611daaf434151.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/tower_003.png b/thumbs/tower_003.png new file mode 100644 index 0000000000000000000000000000000000000000..99ee0ef9fe53e5aec14f01efdfc082971affa7c3 GIT binary patch literal 2707 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 C$o#|r literal 0 HcmV?d00001 diff --git a/thumbs/tower_003.png.import b/thumbs/tower_003.png.import new file mode 100644 index 0000000..1ea42cf --- /dev/null +++ b/thumbs/tower_003.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cqefoivn65l07" +path="res://.godot/imported/tower_003.png-2aa924c8ab1012498085cdd4114c8e0c.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/tower_003.png" +dest_files=["res://.godot/imported/tower_003.png-2aa924c8ab1012498085cdd4114c8e0c.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/tower_004.png b/thumbs/tower_004.png new file mode 100644 index 0000000000000000000000000000000000000000..35b0a1035ddc746fa6690c23382e2d0637668f90 GIT binary patch literal 2665 zcmcJR`9IX#AICp4lbyz{WDLpLB_V5L?E4Od48C*!hwt}?bKXC^&pGec<2=uKKVGSJHl{qBqMQH#@R*w!IWQyo z-@(qxoI7=W2AKgA;b3Y2d?1Le0syC!xskqOOc4beYUQ~EYft#|b6Rfflh5u}oCt}D zR~?N(W!CB%QG+Nq5B~{8`D@>+)8IkJb}qu!+?ReE7FOH&5}nrA3Kb>aI10GqT$}T} zZ=#wDJZ@@YRNM8MDxZ!!axNLnDsOZ)EzeDhcohxo>JIN%DlIQ*EpNU!r9D6_d&J$Q zSC^Q){$sX3l2t9=n5$IN4d@;P%Vi4d-Kz(ly=Ji!Q$)|-0STJ^4^prEv?2K&4;Q2Z zmi7dJC8DTmUg6N(4a#mfUks)ZP^wBTeGJI!)3Yz3MTGobxS_QmG?f%UNhM7J3vhAb zF)Zv7oB9W|rEGmsP+KI~vn?G^;!l=92Pf&cU98F7*N4xF$B>DDDV1VWt5kbMhWms46JyI6&e<=$VfxA=1Hx04C!{ zMtxWEoQk%%6q4MlJ4;v@i`#Y<1n+R&n;q5wyrc67+lv?McrRX28h7zf%kK*UWm__E z>D*WGYH(dVyObfB^BxUx4t)TZCGVMvod0y>eW0)nj_(l;Uk$++kbKB}yn88>ywKA~ zi~S#SEG28vXFfG7EE_9;(!H;m)J{&FJAWwpK~wdtGF8#WEK71bGk&5+_D%HB6uLOwYc!ktk zhIsNGs7xSNkGE2qAB|?#m=jfGn16}<5BOyIHWPh4mP@ug3P!Tj92=b6KVwpRZYQY) z+vZm;$};qX?~fiTT<|OMRV0K%LTpw4Wj3wMiif=2cX$+dCr|)}K%eeG$416_-t@x1 zc@tEU`N1xddzqqr}6__H#ly+8REMJJ|i z=4Z-}hj!)9GkVFHI?7ifZwUV(Bewc=1J>uADFT%~15|doSF?3Dw#9w7$r9##*^OB@ ziXi`HTQq$LVm_Dj`5$FnDF(O8gn7Fxza&H7?@ADh4~2Xe1ky_8j7=Vb(&r7l-G&aY zA~Nh9^X_}RMZs?5Okgwit-I~+kjj2t6EH(?b1y1&ibocM%+BHwajv*R5j=-eF1QQx zJ#R~ftdu~V_ft1Cy9MEnXT1A0ubr5l>gIvv+(7gP}sMo4iF~<+l1&(P7jF#d=f~h2TXoVGBr%W|n2^m`%n9ku#;zJ`=32V&QL*QLr|4|s$NRac%sb>l4>@BY$ zVMzU(<$~?lwz^FCW}ECqU1#K%fo&mGl%S9hKTK?%rdW*{lM8}&MlwX_!P}A*0Pvi# zqCfp~wk66PcMI0UTzn7%35urQ4@D)F9B=C5GpXG!l05pnk~ErS?>4KGb3b#K&8flKaa?VCYw0q;tn7X6i4o3gK*Kpg zQC*8RC^Pjm5*#yC`zcX%xg$L@Jv%3-GnG!LtzPTTT~HX9K*46A?MJ6)eQ$~O)F0;I z?PP)Tuw??D|)mpI54>+oUwI0pLab$2>}^>+%I`P%MP7Cj&D7VGZ@&N ze0)cE%qNQMG^}zF%vHo)Y*umn4kilZ_LjHV4<4dIw~yTmBkYz+3Bn4 zU{30Zc;d9jRpXY5&#A#&4Ag3ffdYsiJ|#U)Bo3#Mn>Am9CTl-sZGXFlN;vo>TD4a6 zSvLrpRzFZ+Vnazt>@$Uw$-k(Ul6wg#jrSWqwn*mqTJrqE>sXGL)qF(67RKyyuxLfR zf|&)#1lgRez7It>S-rPveW_}`#|Qh1pDq(N z;L1@8{sWt|;|L$>cIAvtUvxPic_Yg+ul2YnhGx~_j_hwdM*H=k2#Ton{doK1SZ0fP zP4RHSb4UgZp*YN1~sK8KB6Y+*9rDk!I~s|L`Th?P<9oMO4D(AFq88cDY&y6~ z(M0qKDIdX&H@ZLSt~J=@3h6DB)&o_TcsmauqhkjUW%GpmfBX{DfbAgpZnniph433Q Py(3_5Y-9Anz&q)`)mj2a literal 0 HcmV?d00001 diff --git a/thumbs/tower_004.png.import b/thumbs/tower_004.png.import new file mode 100644 index 0000000..b89aa6e --- /dev/null +++ b/thumbs/tower_004.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dcbh5utqixwk0" +path="res://.godot/imported/tower_004.png-6ae6dc699a0e3a8bb84571927a82542c.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/tower_004.png" +dest_files=["res://.godot/imported/tower_004.png-6ae6dc699a0e3a8bb84571927a82542c.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/tower_005.png b/thumbs/tower_005.png new file mode 100644 index 0000000000000000000000000000000000000000..43645990a2dd51825b57dd6eb5b37b84643bd536 GIT binary patch literal 2434 zcmcgu`8U*U8^33U3@J;+*hMO(s3Br9GK3adY+1*WZL(z-=4*-Ul_|9ayLE`UY0ljtd5Ti95&3x0quyZL$b~YmV#k*w`+8hzmB_`GW-&MJ5GfUK`yeYXHz^YtIZ-S$5-^)HzZ>phmqEmpADhqImWb^Xwv$J$H7}0 zqw7uvhB?c%O|S=RO8kl$dm){xVA2$JSNVSm%srcA0vv{$S$hEG*9@(~&7V6zAF4Ie z`Qsi@xm0*(gG@7@@as+kT}1!RNafbwvrTlj`!^I1QDWnIZn-CMym??h<|Q4j))wri%!kBZf7BJy zL0_ZF40xFS17GTPu04b0)Q7hd`uDs>lzMPH85awkDBD3R(eo?C*qG0TM@JC3!j+uA z@cizm^kR*lBEH4k>s8-2TYDhq&2h;FZQ{Nr3!$VhOV1P2fO$;J6fK93S3q%>5jLvf zf*W{*0ga&l)KuRdD{vNTd+Qfl__hgDp zC$7U7alb!*C>SASwyf8&b)+xgPs$o<<^Z6^-IS~wOcC$3USVhksA<9rWf%04RZ7WU zzDvmYW3pi$FFL9kv#aGevEyyaA#Tsa7-nk285NAy9iX9iz4~YDi-;&K?UZHN8QP_& zTMg-cXp%TExNxSm`md>`S3h05e`?RZeLZSB4hOt*LJxzV%3_qd0T2;lk^gnEd8Wn> zabxw%eH*<4qgMJ+lw9s`RnG%IejgRx=mQ0#*j@o}7}Hhs%bRPeKXth9K1>&XY{bt! zXoK0Tppd6vOste7Gzw7St>GWM2ODEVm}ZQJVHmLO|`$@;^7ULk0hI?_uXp2!dK zWc4(n>5W{xe>ZJTWX-i6U&uO~I?Y*{7b;@D6lTf}BPjN`cp#r$5Rgmxm}q@mA&NGG z=G)^Mp%Ooxy?IuIxRptl9y^Co0aG37$^ZoU`)_~L6=!Me*M$Y^YgINYnLGOP(;k9T zAT0qm^mVLGE~~!-4cFL;!3ww6L}Ih3=koO;ODB@WHT1MHu+dxY#O?7S}4> zgUBQRp8JQ{sQbLxTXP;W)#@ANu#x}_LL#)QNp~!)nCqOCr-Up3{SzrcCNsyIV!nlj z0!w!tBf-gB@x8`W*QjlSRh_A1af;8Gr)$UFi4QTlCc+Ags%+HkUVke0gn>kt$t54L zFq>3$tKF>;^rY|-cXni5)?sndN05%E=9WK1tYNz3WaO4YTj*w5-JXG=;i!+6=Nm{g zQGEm}^-QJ$wj-Ac8#I0vY2+r@95J_dsU(G-DN|m5GzD&ar7~yW-o@g=!;^lecdCQS zj^GHYB>Q_bIj)hAb;*K1YgV(UDuLaeN`beboZrOBrK_;GckZ`u-*7rX5`~hScd1#= zwT%evr*(^{kC3V#;GZ09-P)|uY6!{^p>ruyVTkyGi;~B%8P}d3S(woi$$So)M{h`}JxJ1px=s7d13R-!WDbqOWw`xSu39 zDG;+&=hqoK- zH#0lL={1=&B&bAf&pg{YzGz_kM+p_1`aDX#2BJ{Q_d)4VP6IU`oj*uk{)M(FC)l3D z7eCKU3vv*%1|+SD##IHuq=1v622{-|=9|Ev*-6vx%_WCrPjtLC99B+{QSaNTQz{2f z?N6uOIoBXZ32(1y6TN^p8JxKGFuI6Qz8awY-LdCVBF>t1L(ofk)X@r#5yxFt)wbmmQ#E?`eS0@chM)sZz!gg)%%71hHUO&?N9pawig14E}Crl zvRO@usSDPUo$<}O!u`l%GRbMD1yb>}4oQqz>es(|Ygqtu s0Q!c%x1oSLPrZ|Wp%23jW&Yzgd8P`O8JiouGQ`LI2e`n1;{X5v literal 0 HcmV?d00001 diff --git a/thumbs/tower_005.png.import b/thumbs/tower_005.png.import new file mode 100644 index 0000000..3bc81b5 --- /dev/null +++ b/thumbs/tower_005.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cgiiaafka6icd" +path="res://.godot/imported/tower_005.png-711ec9dce2f394c1335fba09a772767d.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/tower_005.png" +dest_files=["res://.godot/imported/tower_005.png-711ec9dce2f394c1335fba09a772767d.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/training_item_001.png b/thumbs/training_item_001.png new file mode 100644 index 0000000000000000000000000000000000000000..d709eb9a074a1b2840b00f70b829da76d7089cf3 GIT binary patch literal 2400 zcmc&$`8U)JAN|f4!;GmBYS3iKnieCnFB3u-c`Zj6HJ0q5Cq1?qGnT9&OO~;xC|e{H zh8a=zBy04bV$@i(FJm6>Kk>dl+({R;qKqSpeR;maZ*gRrxW}@FD;+8 z2;EBPupSze-jI<^!<~<|xngKK*ZS0mR0-L5*r*CuFjP{#XDwPeXbJN)!NZ21`A>m6 zZk-lzQ|$g4RvYBuv4?4{Q*QRTf6m>5nRnxIpOeQ1nW>kRQ`Zw~WNLe5?65&9 zxO4@B;09!k*EcwT_*nQJV~$*8srDfxgZ*4luUg+mB{{8iUUGlGRtdGo6K-vKw^HC{{bNe5b6oHeaK;6kkaMe|SQ*78CH#94fd95<$ttl;>lJX`Ti zt6R4Kd>8!E#`_+8;jH#KddXNQbFU*G2B*f%`-cs2-#=3zI1}rW#YGqn+@ZfH-`X6N zN|k?yPu7=gdodTtS0G5Y(1D3bU(?l#E%hR1ji4F>E-}KuHfqbZC)9qcB4u?8Q*2C= z2X2def;}E^Lknb|Y3C^mr!)j)6T_4BZ;64l)dYj(aw6PfRBsp9p11qHzTZEg_a1P@ z@wo^?pL&zrL#dIasZ<{<<8(9=BA-5DK)j-Ktti{so+$F!)9orOk|FWZrrd8y&EsVM zkLslGb(MZYR0Anr4-IcC)Gwy@^&tq*ZwJ2&c_a8s zwQ|RTUWc%I%801MSPx}NeyiFx2&xryh`xw~fvGd8&3a1`!Po-_eMzFO z_|XUTi?Iq<`hWfua%}XI$=Mo36tk4+%2m2wU6o{IWzmyJG0mnC5aMvAL`d;tbTa<=|2I>qK zFQlrf3fNdui)wkyi~VK{X(PG5sz2CV5a!)k8@-#iyWz>0+zr1fBt1}k*~oae@mY{ zsw?T*Aj_AXeN9Xl4Vl@zJ)AnzPuiU3bDkY=(J*_IloC}{0+R<7sD>_wMKTEaI_{~7 z5xjtS3&#(qDv#ux3f^P!GvGv*so#i(2HVIK(Atg_i&Q5?);;Xn{$Yf_2w?XP)jGaT zo|#OD2 z`r_h+lId`cdgGiZUXfnnf^sGh01Voz*&+JJ$K+y`W>aYTj|YX?WiH6HNPJL`RsaUwW4wKPO{ zLmiQ)&gkk)1PiU<4MJ6~s3M#s_O#_+GD^N52YO7RxO42A8IF52Y2YB+)h|#1=DRgPzoK zLX1~If!_#zmu@?Z?*2(stRh9p@t|sdEV*SW)AM~TSSH?yVRPz z4s2!rNMWSQffx~7Jo2V0V2Ugnx;#PaO;{O9K7OCE1@<_biY2TzmTT-66-WueQ+wz7 z*2ogrOIa1~TFnixp8BAkjB7W)es+dgF0<`!%w>9=2!V&x!B%&P3r*|$dJ~aI+z@2A zgzWitNIFAz$)T<(@k&MWyiOUKNb$8@%2L`H><}sHEBH2l(Bh13DdDOhVP?9t22$In z`Z973*#jD6`zRzX57e`P%voR8r@LK_9}yH9+-A{|T^*mAt+6FO1pZ=)>j`u3xh-tkx$){tI+nT>=0A literal 0 HcmV?d00001 diff --git a/thumbs/training_item_001.png.import b/thumbs/training_item_001.png.import new file mode 100644 index 0000000..43f8cf6 --- /dev/null +++ b/thumbs/training_item_001.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://d260clhi0wwyy" +path="res://.godot/imported/training_item_001.png-746cd8c21d3c85a000e222a1bb380d09.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/training_item_001.png" +dest_files=["res://.godot/imported/training_item_001.png-746cd8c21d3c85a000e222a1bb380d09.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/training_item_002.png b/thumbs/training_item_002.png new file mode 100644 index 0000000000000000000000000000000000000000..08dc2369116d617303894a34134eab39523a34d6 GIT binary patch literal 2322 zcmcgu`8(7L7yn``m&rQWHABeAE=yd-zP+*xaV^nUn(Ry2vJJ9yv)(8pOc_yO24(Db zlC4ojku5UTT*erY8d-Yh{t@r{Jm;Lx59c}0^Z9(v59i!*ak4$dFU=1Cz$tq>Di;W!kcb2m6hU7M**^EZd>X?9!(r1j+E7#yC zb)aa73tu}e(?EF{J%#3L11w1d?jVy5A6F!%-MRXackk%Q7wy23O^lPdUI3}D+Yi! z8w%E)Zp|8KgSq5EoxXzdAXf;gf~VdN4rSR5ys7if;FQ_DpH^qccKHi#`f|Q%pbcef-Sl}YY^xk81W^@*hiJl z>R+l9_Bh`iDBq~=t3eWiTNXeDcj|0*Z!(S?ftD-)EWUOxs&qU!Ug{Ts$-t5D;Kh z55L<2H+kGmF)gBZcBkta+bMHL2NjJ*K41s+i!v!@B3vWSaz6W2+iZu6t80dz-kpmGwrOp zlfsN0ltFCq+s&h6Yq63!=EP~di^_ZEKDMeVxX#^Sf!v&qAgt(+wVbKculwYaOH}HT zkwyy$FJTA2V|BY!6b?F0!}VP)9!cE>xoMg$@DCS48=FcrSK(z2;Wzcm&p+_;@d=EN z6dWr^j`Ae>4aUe4j#tYky}34KTn&uAkr!7h1%rKdmUZV=;t52 z(H5oSR`GcDI(u`uMY4T+J*y^#^Z+mM0voaZ3!Su3c_piW9w}kuRcRiDECwRT3`jf@ z{B=IP`*q)-bqWoghRPtP94Muk;%@SLdU$B5i_MWrkOAe&77mVqN1+yPI;8Rxc+4?x zPA4oC#uqvA?I;p_J2UBB^IdTQ#%MRVSWUhTb^&^EZcVDZBaZ<1DFZ;Yy#%!=#tR6Xw2cusgNZ>G$^_EOs}61TxoEGqnb35 ze1e85cIRpOvh=cGt1YBUQf>(T83$-oW0rw}B$)4YF$@eJ8&z8S>{kTUAiphI@JZW@ z8^a~1mmjg>Ha|YpG}wVqN&x_YNQkt^j3f>xGfyxMonW(u&vlcLdlR@L*0X7&^zCEA zgZ=@}hRdOo(m5OjZD$JFPN?$(8h>G(7V%bt{?8}pD4j*^$5JzEFVJQ~XS1?X4~JBD z{f~A%eF(O(qoHkoq9jwk%^|j|SkJU4Ib~BBWvhn?3rXwPJ2dL6&rT);av0opuG@iO*m1AEF) z(!N~cw~r0QDdhniky912e)C133eER2v;~T#MVrTE<*#S!JOB*QZ>K%&oDH}w@z|_w zwZBwgrzc!)f-BJ3)$rhvnV7K9 zX>}VPTOWqF5AT_LBqHTRT}1EUsq$7muVs5C8xG literal 0 HcmV?d00001 diff --git a/thumbs/training_item_002.png.import b/thumbs/training_item_002.png.import new file mode 100644 index 0000000..11c61da --- /dev/null +++ b/thumbs/training_item_002.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://legpdh1bx38h" +path="res://.godot/imported/training_item_002.png-232692ad33ae84b8d2393caf35639360.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/training_item_002.png" +dest_files=["res://.godot/imported/training_item_002.png-232692ad33ae84b8d2393caf35639360.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/training_item_003.png b/thumbs/training_item_003.png new file mode 100644 index 0000000000000000000000000000000000000000..f9e899c6cb7c720a1e5f6d55556655f570623cd2 GIT binary patch literal 3223 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 literal 0 HcmV?d00001 diff --git a/thumbs/training_item_005.png.import b/thumbs/training_item_005.png.import new file mode 100644 index 0000000..8bca724 --- /dev/null +++ b/thumbs/training_item_005.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bf6184tgvvaxh" +path="res://.godot/imported/training_item_005.png-122c28c8f1572cf44b125c1455a52164.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/training_item_005.png" +dest_files=["res://.godot/imported/training_item_005.png-122c28c8f1572cf44b125c1455a52164.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/training_item_006.png b/thumbs/training_item_006.png new file mode 100644 index 0000000000000000000000000000000000000000..525605ea733b3644c9bba6540fe1a239b44d02db GIT binary patch literal 1617 zcmc(g`8(7J9LK+dW{5#q*N`Kg85`^9FphDRvvCt6IWke6W)Na9jfuh#wkC4K6vb{L z3gaHuy~&XyW{k)=xfO$Pto-e17@-^rkr4TS1S*jspMywXrsLJ~H{= z5d$E^~!Sq04!`{ZstmOzC7-Lqx#D?udlK)p_!$ua-6oMyqr)C z?pA?0)-MTy73nfF!V@qKEKOB~2Lw6uM=;y9IE0?y^Yic!?T&aI*mM*cC3NNzb#rxs z{%8}=i%_T=xf{`+S{?j#pG4yitbZHR_2V9m%jRw6t@jLI)zvD9L1L!0Xnt|~|AlZs zC2^On5VzO{?jIbxtO|Qw{2?R1*NvVy4SNjwnaBh!um@eXcDwpX$b{)PWEOu&eBV6e zy@t68F>2p{?d4TjSsAj?CPYsh2}u}YNHvkhVi%Vq_4Krx`}>t%Iwqy1iSCh1`Wgx2 zuTSVEfB|#c+yh6$Y+PniAiuV(0%USjxNnffLPtg-@p!yULIp?7GGUj}QK0d*De~M2 zx#s9a{y%PQ>m(mILb%vJKXXwr+kqQ9sK?d<+8FJ@ zyZf=YOmO*|9AHGf?4*^I)fhcki_KfGSt%TQoJAnmOXWwD#k#R;|WQAEs}?o_V>YKA3QKzbM%%L(RL!;xS==g3UcK&0tg7V=V^*G@< zGoel4pCP`tZvAc;xxzP#xZiN`r{<)Sgb(rQCx0Egk|o>(lj1EGFHK<|Lj{!}fx)vj zs?>B;hUX*Y*%qp)QpmB<1wjU`o6Ae;oPIT^OG&hE?U(~QfsU>rU2~yXLez)tbB$yd z^yvuD(GyqfngTsksWt%ty+|A`h_$6|dO>29%M-TRiO5NjHu2l&;X&nStZF>a3gPK) zw>JzXq}t-K6$OBR=eXvs*Wt zx<*R2?I`=`RU5mvgMdK5S$TPzGi}mQ8@9e@GXA=`jfq_^+V<^ClX{W@|HzrGV?Qx6 z)|uVuhKQ~5?Or;yG(L8<&ZxfY&PG-dC9lFp1HUS)Up3k71vKwtlAG93@}0^uBH#4v zIckjT)wV$0d?+wUYdhKKC7MP>(E6|}-GQg$AEG^{y0PRc&i|WrRC9_e;aRenY^wZlD8RRD<*(VLKd3)Z>`)eFreXkRRVAMdj5FV;Jum zwu;b&>u`rMzydq<>)iZ&HjSp$Sft)EM=$`$6>I0QQygc3u&^-A^e#`7qUivJkW*W$ yU-XsNy!?`oT$~OXqOx?=$xIm3RPVo{CKg184It`edFZ2#0BkJm&C4$O#{B~p2h7(1 literal 0 HcmV?d00001 diff --git a/thumbs/training_item_006.png.import b/thumbs/training_item_006.png.import new file mode 100644 index 0000000..4bf21c9 --- /dev/null +++ b/thumbs/training_item_006.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b2paoa51kaa24" +path="res://.godot/imported/training_item_006.png-bd0a155421b07558b35a9059386cadf9.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/training_item_006.png" +dest_files=["res://.godot/imported/training_item_006.png-bd0a155421b07558b35a9059386cadf9.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/training_item_007.png b/thumbs/training_item_007.png new file mode 100644 index 0000000000000000000000000000000000000000..7ff78ed6ca12819e443635057624f23f5941a2d3 GIT binary patch literal 2165 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 literal 0 HcmV?d00001 diff --git a/thumbs/truck_001.png.import b/thumbs/truck_001.png.import new file mode 100644 index 0000000..326b90d --- /dev/null +++ b/thumbs/truck_001.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bhy60eturmo2b" +path="res://.godot/imported/truck_001.png-ee421c40fa315b11e46d401a37dfd2f9.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/truck_001.png" +dest_files=["res://.godot/imported/truck_001.png-ee421c40fa315b11e46d401a37dfd2f9.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/truck_002.png b/thumbs/truck_002.png new file mode 100644 index 0000000000000000000000000000000000000000..37d8f5d3294bdfb21872e0453a06bc10ecac2147 GIT binary patch literal 2467 zcmd6p`B%~j7skH=K3YwXf;FL8vxM$*& z6>h0WxTd)!F1ciGP4SpWd`oI7iK zahIh3j9XM;|M!sg(}*S}Smsl9l5`1DJ3(CX~~m+K0DF2~&s zFg>kvsp0`BAwlbpKLQiZXy|IC1Kk#pmXlLVW_LhZ=V}H|{62i0v1Ae3FBGqzS}J7z z6>{&-Nq$f1k@jkKdF}>>qY4-OO>$UoZz@*mbhe& zS}i?3z0`WFxrNbE*mdFsj9WPDN~gE)2*6jfN3gY^*`~QV+bg0yK*Mv?jb~pSjdJWs zWe$hC*uAB-wdu%UDkFA5wj??;L|3+DU;rvkVo4g|iDTGN-{Bu~+T0}YdbKvPMvR+C zo=eTXgEJMxtCojw5$7+m4_!M+gi#TAl}}8&+tID zr5+c?K4U@>x6P$UVGE5H*c(#}1;f`IF9zi%n|@yPJI7ionz$r&=h4GYXWQq(=8^1Y zCr6Iw1V+fsP6@+%1Yev81EhOk@XrWddll{&f=icESUFwgZMM3#i!$#w~$=nY<9y?D~~Mp@f0NLu?NYh2jn#*9P3FqLGL z+V6aC39{A@Sl*@&MngR7`F$hF_SKW*06=}~sRp$88r z-c*+2epxOp?QR#}aGLbq(RfwF>fx&s%jr8m#}89G0^^{GZ>FWP_GwZsZ?v=e!k>ey zB3qTBlwyaO6)>K43FC1s3`5kF0XHEUtYIPP6P<+<#4N!5KtO0g0}u zp(gCrN?~D@L;n=7SnxW?mIJM|X=Zq+^knkVMS(yHz`KMTr0)Ng_}D5+&Zz|YPL+BI zL}cB+Z`i_IQPCV6gYRX3y8pr0?7C)Gj#L`Dr+_B?{+!cRl_c`Jxzi|I<9ndVnlS&P zT}@YSUg*Ma({BLwvRhigl0p7SGTXfTsFHzK3)RV#zA}3z1AabJwuT)Q8aa6^rJ#v2BQa;>(FtN2ZX0c>Hb&+=Ozw_hW-8Z^4jDsKv@sKnV(l@KfM zN^l-)Uq+uP%Hj+5-R>tq<<2#A0Vme@)hZ^ZJw^<(?VItC(t$4K`^XP+;(=06S z%vjUvDV_DK;S>B2pE?gA~j#SeLN}Nss9`17PWhwS1&seFDtrq>?kqm>-$-Kq<) zd#LRB;+`;Coz|F|JfH7lOW%%p#WW2P zPjeE8qHqJlxmb6_npON}lQ8d&0skpHtdWE!pk7=V?OV<-h*#w$We*IGVJ~n{%WJFY zsmD_g`=SKf<~0xO_M@y*G?G}@Ws4M}YT7TEd+*r({rvjP>nu!Pq^7gT02$X2^76`V&OXS?nGeNY()PjGZ{bbhP0?dAp2w{6r&iYMhc2{h z!uc#inV;_Pu%>+iJ6);Mo|2pjB*F{etmv#rrnbG+1{qMKi_zMo&zZnoo&Sa45xc2K VK3YwXf;FL8vxM$*& z6>h0WxTd)!F1ciGP4SpWd`oI7iK zahIh3j9XM;|M!sg(}*S}Smsl9l5`1DJ3(CX~~m+K0DF2~&s zFg>kvsp0`BAwlbpKLQiZXy|IC1Kk#pmXlLVW_LhZ=V}H|{62i0v1Ae3FBGqzS}J7z z6>{&-Nq$f1k@jkKdF}>>qY4-OO>$UoZz@*mbhe& zS}i?3z0`WFxrNbE*mdFsj9WPDN~gE)2*6jfN3gY^*`~QV+bg0yK*Mv?jb~pSjdJWs zWe$hC*uAB-wdu%UDkFA5wj??;L|3+DU;rvkVo4g|iDTGN-{Bu~+T0}YdbKvPMvR+C zo=eTXgEJMxtCojw5$7+m4_!M+gi#TAl}}8&+tID zr5+c?K4U@>x6P$UVGE5H*c(#}1;f`IF9zi%n|@yPJI7ionz$r&=h4GYXWQq(=8^1Y zCr6Iw1V+fsP6@+%1Yev81EhOk@XrWddll{&f=icESUFwgZMM3#i!$#w~$=nY<9y?D~~Mp@f0NLu?NYh2jn#*9P3FqLGL z+V6aC39{A@Sl*@&MngR7`F$hF_SKW*06=}~sRp$88r z-c*+2epxOp?QR#}aGLbq(RfwF>fx&s%jr8m#}89G0^^{GZ>FWP_GwZsZ?v=e!k>ey zB3qTBlwyaO6)>K43FC1s3`5kF0XHEUtYIPP6P<+<#4N!5KtO0g0}u zp(gCrN?~D@L;n=7SnxW?mIJM|X=Zq+^knkVMS(yHz`KMTr0)Ng_}D5+&Zz|YPL+BI zL}cB+Z`i_IQPCV6gYRX3y8pr0?7C)Gj#L`Dr+_B?{+!cRl_c`Jxzi|I<9ndVnlS&P zT}@YSUg*Ma({BLwvRhigl0p7SGTXfTsFHzK3)RV#zA}3z1AabJwuT)Q8aa6^rJ#v2BQa;>(FtN2ZX0c>Hb&+=Ozw_hW-8Z^4jDsKv@sKnV(l@KfM zN^l-)Uq+uP%Hj+5-R>tq<<2#A0Vme@)hZ^ZJw^<(?VItC(t$4K`^XP+;(=06S z%vjUvDV_DK;S>B2pE?gA~j#SeLN}Nss9`17PWhwS1&seFDtrq>?kqm>-$-Kq<) zd#LRB;+`;Coz|F|JfH7lOW%%p#WW2P zPjeE8qHqJlxmb6_npON}lQ8d&0skpHtdWE!pk7=V?OV<-h*#w$We*IGVJ~n{%WJFY zsmD_g`=SKf<~0xO_M@y*G?G}@Ws4M}YT7TEd+*r({rvjP>nu!Pq^7gT02$X2^76`V&OXS?nGeNY()PjGZ{bbhP0?dAp2w{6r&iYMhc2{h z!uc#inV;_Pu%>+iJ6);Mo|2pjB*F{etmv#rrnbG+1{qMKi_zMo&zZnoo&Sa45xc2K VK3YwXf;FL8vxM$*& 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 b?S(!4G!Qh_>hkEkP67t^jdjYk93uV;7gz)I literal 0 HcmV?d00001 diff --git a/thumbs/truck_003.png.import b/thumbs/truck_003.png.import new file mode 100644 index 0000000..d1b2c53 --- /dev/null +++ b/thumbs/truck_003.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dsgsqlhoy81t" +path="res://.godot/imported/truck_003.png-4f0bfd9b2fb6cb3fc39166fe53705849.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/truck_003.png" +dest_files=["res://.godot/imported/truck_003.png-4f0bfd9b2fb6cb3fc39166fe53705849.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/truck_004.png b/thumbs/truck_004.png new file mode 100644 index 0000000000000000000000000000000000000000..569c6fb668d79e1ab63c93d5f19ee793a5e377d7 GIT binary patch literal 2671 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 E2h62b5C8xG literal 0 HcmV?d00001 diff --git a/thumbs/truck_body_001.png.import b/thumbs/truck_body_001.png.import new file mode 100644 index 0000000..2f5029f --- /dev/null +++ b/thumbs/truck_body_001.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://ckr7nlw5sxgii" +path="res://.godot/imported/truck_body_001.png-84f77501a1f79377dbb92f122f127a47.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/truck_body_001.png" +dest_files=["res://.godot/imported/truck_body_001.png-84f77501a1f79377dbb92f122f127a47.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/truck_body_002.png b/thumbs/truck_body_002.png new file mode 100644 index 0000000000000000000000000000000000000000..94d0dc24f5c86a9ad3354cf061ea98b277b11c69 GIT binary patch literal 1883 zcmc&#`#;kQ1O85I88*#jn9JT=db3>O9LL<69hc0t@d~+B=S69)vJl2x5>Ysu*n46* zF-fA^OLN&~$y;vIk;5@8m$qd_H4Rf8{S)W?;d!1Po}Zr2=XpL)aY&G_7Ssp|0DzX? zVK3s2(!OCgc!zl&#|L)=ltT2y1NTRaB>(`?^YiiyOTW2N8+az{Uj~JYT%V#=$8tiB zOw)?yRnYew7auo|xOU@73{4%St-sf+9qNPB?{au`S>v`v9=O`d@@#SO7=>xx$SDj; zKBi7d>Z)+D9TBi4B-h%J(c0{}M`8iiu_xt~0y~FQ$epfrv&cCx?*q%HXF!ery#w?e z0TtX<+3l;QeI1H6*26hl)6RtfZ~ouLsXG@TeF0koC4gI&{mY3J^;Guj&;`?97)4)3 z(T5}`q@NZ{`R56{?`+fOCP+JO%vXF75>4fmepnRR?+I2S=RUtPCJWlRSdTxb&TDS# z)&++_*%E4XtKE}|p)!hVI$0dst)fd@#TV^CQ$MQ!FBW5(Z2IQwGb0H!{JX%S?`?2f zTWWDarylPD8RGatp@<;kJ(cm!%;-bn|A|#uMu}N#q!%L056SPWZ=I{kW%xx~+*VWYVHoUD+Gy&}FS;~*l!PB4MIBET%epU*#h5yg zXBUm_tny8=tiPYnR!DWnKAB)-!Hv!Spqmw6MCF&F`wv6N;*vdX{!ZlUn{{z6>sCTA zT$^6|uq<5Ab~*&9(vY*k#|ANdUOK)y=3d`+L60H{KmyHNw&3|xvsy)Bq9|P9sfT{7 zGFiVb)ZD_|{3WxBZxbwDir9?xSO=HGvtz#a(#_siNJVci$*IyYGg4NsCL<~qZ;7+S zLvq%ZIO^GAQ{X{Tm4uGnmxVTSD|jNG9*?GFXqX6uAf1c@(BOeutFPiK?hx3)s$L`k zd6xyZUt3Z)b${_NP2oi2aQ@*|&vW34iX&ZXOuOK^3C6ih8-PNUQ>T>Su)9&911*Mw zr@`BAs*O5RW(le}7dC|?CIfsxW^@dVm=%)lT5~4Fb3jC~)2CEvgEGIxlF@>w&qsCZ zu-qGV<=I)_dj;^Brj~sI?sOOxlYUEK0EBmI(PSz8{vpkLkS)Wlk2h3hIQ(%`fP8xc z?vb#99%EgW&p?2SIv(SAT3Hz`RAVu~vOSVeK!Cu@jT};(mr~KV4wP^KZl! zQ%xz97|lPN$Op%LfO8f=J0fAOM;Xoj*h?scfw;RK1ReHq|Cnmzr^YK{6p!S(v83)9hLt42Vb?D zA4i%SuRIMOu??^N&+0CFS4kxh5VBMiKP4=A2J`r(_o(7qNNDHlG!>@fm)1#R{`mak zejQociKFIyg#5Dpw3_{#N6ovElb<1p>rnpe#Lx!ic`cMvC7}ELJ~56@p!8M5FTF+| zJ*O47SQOVFO_Lt#OyFIK3Zr2LPIW{XnwdsNs7ZNNX`rMMVKusQ&{7Q^wDD<4z&Gpo z$o)0tUcZoZ`hx#tD`o(c)DdNX3S!wUy1_vR;O1)AQ(=}jgz;JPx5UqFnLgP=8Fa7Z z63v+yC3kvUUdK7sGjOUb(_$?gq)ZOQl$*<@9G&OVDhF3Da<|z*zq&`6K=TzR{Dtas zhVPe+gzUt}qAV>LR)>=_F;_3{jj)lZVSb$eZ3%)(oApxLRaK^A+o*wzQ^g11p6`C9P-N=Hp6g#r@!`VEs^Q|S1 zBECAHVHt4^Fxq}qKm<^U=MB)@1*x&u^l&8r>gMJbvJL9>foOGyw4Zg&X<)Vk-VUhg zD!SJ>r8OilR4oNe+Duf@>q-)Ckh;I%t#$l%vm%k^lez literal 0 HcmV?d00001 diff --git a/thumbs/truck_body_002.png.import b/thumbs/truck_body_002.png.import new file mode 100644 index 0000000..eff11fc --- /dev/null +++ b/thumbs/truck_body_002.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dmuoiyehf5fxd" +path="res://.godot/imported/truck_body_002.png-39ce38f8309739df0a5de4645e231e92.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/truck_body_002.png" +dest_files=["res://.godot/imported/truck_body_002.png-39ce38f8309739df0a5de4645e231e92.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/truck_body_003.png b/thumbs/truck_body_003.png new file mode 100644 index 0000000000000000000000000000000000000000..639120f9b199abd09722dc564d63e864fc8bf2f2 GIT binary patch literal 2104 zcmc&$|3B0F7k_QO%@9V{mtj&YQx_r0m&ruFB)Klt+)*mJ#4aOZER>JRRNO@j(XD*B zzVu0C%%-~#R`*iZm)J-s#yitC`F7oZ;`908JfA0uNwfM!MD{=AwT{JMW62hAq;^(l-q{(GcXU~g5cZyS<2_x2a z6<#o10Y`W$XwZ?y2HRZ^;ArGPF!3049*1RB{vQ*G!lmKkB)Va=c(lkk6l7nEG(lSW&Yri;d>ACb)Tobn z?S&^jr<^Y7crU|(Vq#v4!+O|j!AW)Y@Vv^9B_pn8ZS5^)N#Gb|rxa@WJrk4dRHBRC zVO<>kxhW~R0>|0vB=Q+*3ZnVUbirE0EAUUtCP2DSFXnnaZ~bYM^d&(dsl$InV4gLO zo6yND!!k*5#0gd@iRd|iK&}BHz>yqsxqCk5my=1 zx9@|wuH_doiZ;1Q@V3p-G8n`!i?N%MIuPo!g0J1^a5_A>0C(jH2Rqr;y zQ<-^;xi8qk+-pCAcu&#V9A0vC7DV{rl{gWXbdL1x8h(E{x=gI7&WqV>3N|bB;SZz< z%>#(qtq`av)=>^Cs0p70AL=~nlIaRVMT=rodkN>>!x zLa?8>XU6x1@#7n3bv1h$O7pkcVlnwHjVYt#T^Jee#$7mXt ze5+RnnT|_Pq(sI$TDJF|N5{mV}&wDzl>G; zNs(>f*xh}bU|?u;7FP&Cz~UD7_>y_YH}$p zy))Yk0g=OR(B&?gqQKRkHBMU@JjIKf)8CH`EINHaq`lPKviy}onfdKbmb~rJ&^5_T z>iqflcrN;$2`7(quxF40-yM|c1YsiVbgvItTt(X*3Cpm*|6(CS>45g<$!_7q6T@_~ z{BSNs>Y_US2Krt2mkZ}k*w7DZo%dtz%KI}BUlHRJ$))pm8&(q6Z zWSc4b#~{i3Gd)yy!Wu5x?Iup^sEAk3eC3wiOe+R?-h5s~xakixL8iTJs@~A>_{)*j z6nvPIq|JHh_rI}V{z9jQgTYkar-&6ufRTgNJ9G6K^jTn3DV7mGKK=Tp?D>>|NNL1- zdeiq|%MIxR`Pj%Lg{1Z0T$Yj%63UadCyLsuAl3$PSheI=eW!_uaLx1=Hc6IE{U zErmpd22=7RGO<_~vAB^}$4{JV3m?Sjb)!0*qdG#pp=%FSz&7P_V{SE-PtyED>!S-Y z(0-D2aFlmInpGW7_IqJ@%x4*pYD>#skL>nN<5dlbCD+SQ<1Vh5 z^>jupP^>{sDN9Zi+x1#RJ(EYH7y8SYubd-gA0scoRP(jo5lpzHejX~t9#g$iSds5{ zuAbCiWp04%bIamA!RklXUaCmu0d{+XcROhwVA1*V8>ogC40k;ae+2w&Wn&YpbS(63 z@0@ilZAR8FlT+(ZOvM6iQ>#d*=>yB$waSuR3%u9;|7XW;W|Md2c|>`p@ATFy0K5+S Kx!1XcW&8t~mB`Tm literal 0 HcmV?d00001 diff --git a/thumbs/truck_body_003.png.import b/thumbs/truck_body_003.png.import new file mode 100644 index 0000000..d80209f --- /dev/null +++ b/thumbs/truck_body_003.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://ei5kwymgtmcx" +path="res://.godot/imported/truck_body_003.png-ac50887a1d0ce8c991859cc5427bbae0.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/truck_body_003.png" +dest_files=["res://.godot/imported/truck_body_003.png-ac50887a1d0ce8c991859cc5427bbae0.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/truck_body_004.png b/thumbs/truck_body_004.png new file mode 100644 index 0000000000000000000000000000000000000000..2fab29be66c3b7e4afeedb8a5e8c5e9d856607eb GIT binary patch literal 2085 zcmc&#`#%%@7L=o3<~ttP~D~q0MPLD z@jSA@q;I3Fw1G{o$N$+NNZJu^55Vj~PXmA)_4RZQ&7{s&1e`|4Z*9woE@da-S)aXe z@&6WIcQ*OFU$=pNj^afB0qsclAbXZjb4@nwI+#j7`hYDx(|D2WN!^Y%57o`nG!1;@ zDI#g*u}=_&PvGw`3As1RGAnkI{R*1SXT~iw&3q*i?D_NcCo@_{{AG$4e0hW9p}4s) zgjO5eEc3aaf}OTBC#8mhu|L79U`XCwsIoUg^O~v=S`X{^e>8AgWZ}mq!&$DQ(?gCn zp(N)CYuc%~QX0Oz_&479XYZb;8SVNK-kSF&*0o89VqNMw*q4U+LL6&J1cBLWg5-Ku zu15n{zGMqJ)~2F5S%s>ar^d(@&C7E-9{0ZK=U~N;Z-L$jw#~4fhf6JVB4=3}nDX|G zc4JuHwouPVwoSm;2p-q8u!f|rjifBB-L4k(1dcYk2eTtj+*{=NyEzHdrPZ%)89#Ff zo3=G|CRzs@{H03arRUcPq6{;h=ryXj*2^}94LVr~2Pe{4t9MQP%a^-Yd%zqGC+3>u+y>vaDGYQae*~{!r8U=gF{N1S|r% zKpc&TZ#Eq@t&b8Bvny%`4y`1hh87Lc{cHAz#P>-!(X5d^anGH7mQ+6F!ry>oXBUvs z>9jybmifoOuKPIt7I^q05(rb>5mI;Ve6J3$%cbqh^3mMHl@zw&pF&Ax%H4&Hm4)50 zt1hRRFv^AcFloW+eBD#%E}U%V-HG)D)0HbK<TqB?n2e?}tTCenM!255~Jhuv|Ra@Nmn|2$1{`gmXW*1ZVC3>LbY8B#mLc z=fxN$8W7;Ag-R$&%uwRWk;9SdUko$M-Rpd4d$kTg2A`?wizTPhW(*k7w^qg5X^=tN zm0Kz!YCB#rxKc>~&UDFaJ_wUZ!cS^xe=z<%Wb0XlW$H{<3}#C?_4ao+6oPDp)1Ldu zdZJIOmY|jGp7@K(PCI4v6?nD&EY^$trm47~iX^gY_X5l<3U8v!S0OwZmoF@O=g^!u zx0n!(@BxJOMNyo}_<%a&gGo(dq@B$*b;PmR&go(DqTkxs`1;ohkpl_dcl`;HGGz@X z7YN&lmbu?nBN{TV9f%%MAB^sHgR*-?t=joL=k1h{JckVODEI`Il(>8{j51VU21a9B z)ZCs=ioY<57n-x*BNJ!#N!$PC&v&%luBu)ANP)L(_XA}bMK!GMSmh3hBEfR0`!W)f zBF$#Kc`$x=eL2s8Pw*G~QtCHn~?H2Nt13w{X zFfl7wLU4=Gme3QTL+kUH^&`&F}x7x7&*#lS$M8Ul4Pd~< zT+S6;oY2vm=arU!_Fik!Zt(Vo10P0y-BF?-Qt!%EF1&y4t&I`nzu8rlwhm3bVLp_1 z_Ggm`Os|j2SA(Qd=_S+-BDx{-GrHg2Y+RYK`nAGL6cA6KtoICR3oXwQeELQmXBguP77}PQscMe0t~37Sfm$k0`0ZjxE4Ng=(6~csrYFt6yqlP8xz?*F?y+ zK+3iidfGvoPYflAmKwyUCg8Msi21M*b<&1oj2TIXqEx$IUoL1jz!H}-oXwzel+N8sQFT0RcUE$bQ=f=n5(dTMwZX+wl3%H7qt2lfm)PQd74X!ARKYc3 z>t0!a^j1MNc+QV>fw@V|j2IC*3){bxf4LfH{sHI_=LNjY!|H?8!rc7Ws}X9VGv~7V z28`_s%s3&?{-bhWVGE<*<+^h`z-6DHh5#S1XEETNotufc?#3}BJ+vX_OlNxsR`zH9 zC_E+v;=)|VZ63O?En+W%{!&uP)Y-UzXl@~E-ARM%#EDZ?mI?o1A#X#HmgJQd7Nob% joX1d1^`ZY+tx*-Qjy9KV{6XsRjot^oUV)xW4;=YFfY!^* literal 0 HcmV?d00001 diff --git a/thumbs/truck_body_004.png.import b/thumbs/truck_body_004.png.import new file mode 100644 index 0000000..037b452 --- /dev/null +++ b/thumbs/truck_body_004.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://buu5pqdjf8ko3" +path="res://.godot/imported/truck_body_004.png-2573db4d9d2dc6273750e34b95f09a27.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/truck_body_004.png" +dest_files=["res://.godot/imported/truck_body_004.png-2573db4d9d2dc6273750e34b95f09a27.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/truck_body_005.png b/thumbs/truck_body_005.png new file mode 100644 index 0000000000000000000000000000000000000000..0848772f3e6b23c1a1ccfd00867e0b47023d0f06 GIT binary patch literal 1760 zcmc(g`#+Nl0LI_VUN#YtWlS!gjHJk=bUAMEaVeJ^xlS{u4s&}I!q)8FII4r_awwtF zDKRs`#N-lEIgLZbieHq*}`gnT; zeJA{{(5m0P*O@%{9f;H*FL$6`fS(5d)iNIsx8Th3j}?>9=41Nj7z6r8nxdTZt&n3YLE-+WQA)I6n^0XK$Pt*bZ?2!z)Mxbf$AheL^Rd{@+&8q@IzY*{j& zxUeg?h2lP9WFx4Yye<@025!CPH$T5v>8z;{Ub(c2)Mt

    +U@$W=z*W#Om1c^rf=0=N*Ox=z#H}>Hb{!cR z5g)y!-H3dN1zI+~>gJ4FV-bLhvUA~U+oS35E}L$fY-N01$HCMu*a;qz+~@}yt3Evj zH{B}{wLn^bXYfkLV(Uex(?wN&Qa28A8_M?F@uEvg(eeXb+yZM%*8{^lxy3fzO4by5 z`E<_Q#1bxD0~RxT^XN_O^nO(V?gY;dbfQheWP0YUu?A;ae-wpVF0i0m`jX zEHqYDs=}_4dL~-3@-u=NKlsdKKIlm&^TW+KB8HNrsjAHBEiEjC^yy>K6eag$Ri z(zv2K??a4dd}T7un^M8dsoA+MyEXo%f}+k~Atin6Y3$jL$TA%7ac$pF)D5m~C)}n! zLGr)zX*Q&nmqs8R7mXbimUisCi9sWXYum#(#_}3uxj|wQRZ%uq$H<5PgTF!$WS`5G z%p^ScY@s}kKB0i2DA;xJ_TYT++}d4=AZKjloBuZN*yXSzLahY?fvcAMS9SG#RCi6! z9_!y<%b&1~PGTZRZpqEgqE4x49dxkg zlGJoNOHG`h9l8I-`mAsMo=|2Q0m5a+WdHfl4QRaaOJJ^+!lc_hp3{M+2oVTx%vQZ( z`pooUU1XW|@Iix^8`Z4&BZ6?Yn)cybi%ic^aQy9Uo5tUUFM4Pp;8aX*F}K>AMq6KW zWvn-PJYO_%b*BO}g6 z6dIDNzk^VI16SG|aSb}As||progzX^yI{StOel&{^sfKF8p-D0aZG@TPid1K)l#bRvwh z_L7)-WSf-`g$R^xx@Ue2oZhRXOpX8LXg`OAysVFomxxuIF>uu^idtqLVT3mCcJyRd`L<;J@cA&Ss+3#wtqNKDqk^9XG9z{Q_T&2!%2C_Ri1hP<0Tj+ve&Rxr+-MGgF& zi-fiwjJ}WDkr1x&=u-)P>h26A-?h^-(Iw|Jdra3G0o*~U`WlA3elXlzwM$VkJ2l{y z5y?~bt(g%BP>Os%at8p6KDx~-Ola&jz7c)EQ0l>@`Ezu zU%rZK>CfJ7-zWl^Yt>|beZ$25Cr_>{?^lyu3`|3WNF^wIC(S()p%0;xz~~OZU25*fRCrYN4mS@B6tn;U literal 0 HcmV?d00001 diff --git a/thumbs/truck_body_005.png.import b/thumbs/truck_body_005.png.import new file mode 100644 index 0000000..11a13c9 --- /dev/null +++ b/thumbs/truck_body_005.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://073gsyir4ypg" +path="res://.godot/imported/truck_body_005.png-0b227355f61e0f20f68e91321c2b807d.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/truck_body_005.png" +dest_files=["res://.godot/imported/truck_body_005.png-0b227355f61e0f20f68e91321c2b807d.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/truck_body_006.png b/thumbs/truck_body_006.png new file mode 100644 index 0000000000000000000000000000000000000000..748f066c408c8790b4051a6cb751335dd18b0563 GIT binary patch literal 1826 zcmc(g|2Gr*AIIMt!-ieCZMvG)wc|O}>un%eY2 z5dZ)~FN#~B###T3o{mPlNTK~2gTw`Tx`5i37zqG6<6dsZjwhB#ODAIg3EGvF9wRxV z^O@3b?ER*C|AG}&*EsBU!)`0owl)zS9T}!}wXw(L9tuiomO_1tt$crR-94QvQf5rl z`4t8&T(!5_`+&}Z z`+YJbVf$~WQ5Fn~)OW_9Sq`?~{0T7q5Ojw^vb+AjK_ZT+;7-yjzcE(dI@n{4R*l3l zgq8blWWjn}7iZ_f&C*xLUnAD;wLApGy0U(K47WTwSr?pJ-D+HUNq1MSPe9tUCpL6g zOWSV>SNtQ*JVZ`m=1{#S2r)*|@6RZ2Za*xdRvV}yn?tW-D}Q2fKwTNB{_sxIQr`7N z<(pqRk@=bKopW#PvW*YT>@;dsG&a>)BaD<6q}@qA!EW+D(&R5=mh&t1wvG=IP}tK& z!Jgjxcy{8 zU*a%}&M;{^hJ_Kd4hQY~gJyl{i+O2^W$W14E0K5FnH>|A%wSj%Y@ny`@sWBHT7L3; z(p7jKsM~!rAf}(6dsawCQTU?2bWDtG`M43$m#8H?9w(n$l{sugXy1~_dZgD{4iTyBT@tGds zHz^e9ZqbwQ0QaZZ{V`oEc{Nab&ph0oGrCF3|6CItzdE&et9krW zv!0j7OqCrmVNDVDtOcDp&@nv!X?<<_;YLf%T@;1)D?YEPBgy&4xYw%b2=?i{c0qET zXYUaQhz>tq(bT1_FI$lu(`&=ZK3XS&t`ApD+SvGZ1J$`L^ku81lP7Va3Pr_>-@i;n zZJg4;kFo_rxs&pPku!2gS-PqHq4T3_wAn>{msm!__nH1=4#poU4WJ3^lGdG_w=r#X zb68^YXsDlFek1GEtE&ZEz`1p4VLpX08 z?FtjtLZsYbtdLKGyf*mxXQ9W|SRQ(dCexA(=r8w)HhXnrjZQ$o741^3cXZcGD!FLT zKtr^^r125izTV_H=ltef*MifqQ57Zy$u5SLj8$ks>aW=R%|uQfWurl_cX>m6@X1Cm z`k8Bc8~n>Yu8okH;{i(1CLtxYxNFE2TMNy#_+5=I=0{E4wjixD`d12_`H&Kyt0gZG zMnr>fg`Nv$!IusXAvj*x?+E}V1unb~0KqX0@?thlVW-P5Wizx} q*j@P279Q{kkIY7N6#Z|n{I)JR)w0p7yxmgs^njPUpIfaVEW+c;uumf z=j|QuAmKz2hlkRqCeAXFF3=NB+rd4pf&0ToS@8wlCj`U}%@K9Dk}{!z`Rrno{&(x% zmHewdC#lNwAnfU5v#;eR9{hRq$&%-GiE*!!ZoVcV>j+S|XrUeCY3 zR*rw)KKpAHN2jnISXX!F{@VF(95&rt&1;a(VDOUh%G>9EV|k|eYc*8vWK>&ZW5RUf zQt=U~gN=2$IWvBKQFNQ@b0zkl;1126_iR!5*HWRO!%VOz?-bC8156pKKW*of zaQLYoC%u$8;Qh1>9G4hZ$V)deC^hvsFnnOy(6y5_h)JSvz4Si&3GE814XLq85ogqR z_kDjkRm#ETa_)hfEH4>#UNaqh@ho_AqMrs&1IPdTglG*0!BTzBpZcs845wW_sOvOz zSlxb5&k`B2fKeyAOTn4xNA%X*3H*%=|2o?o7^1EA@Ul&0ZDRPgh5KM|Q#rG~^qlyZ zY5zK(yJr@Ct^N8V)2!3nT)ukFvb}d0L{C?BX*5Wg?mt_ztCF+fIU6)Y5n)RgTe~DWM4fZ|OcV literal 0 HcmV?d00001 diff --git a/thumbs/wall_001.png.import b/thumbs/wall_001.png.import new file mode 100644 index 0000000..44b231b --- /dev/null +++ b/thumbs/wall_001.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cdahfjyse2yvc" +path="res://.godot/imported/wall_001.png-786d351f1a1aabd7f95d574140511397.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/wall_001.png" +dest_files=["res://.godot/imported/wall_001.png-786d351f1a1aabd7f95d574140511397.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/wall_002.png b/thumbs/wall_002.png new file mode 100644 index 0000000000000000000000000000000000000000..bb658886052e8b7521858911bb20ca0fed17c79d GIT binary patch literal 773 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-HD>VA}8L;uumf z=j~nFJmEkQhlkc3rU#e=Ts53T#U7W0{3%((>K)S3=6gVGj+&kTcY~gb;-uh~Ll#nh z+>gyWb9wjknyGV@_FbB@C*A&ZVR1o4iSVJSfGUQmsSE{d4Cz!MzHj)#P+R%$+vi*J z?dv{$`Sxvkxqh3}a;Z$F8&8gZ&)>e?-1XA86{2Ut9SmMFzj*ar?x4#R@m|I^D`n5T z`LySO%I=Sz3Ue60EIGFS9|!XRV+IT61`zS$;+M;_FDaL#K^>XNWFad*U2dUQCewvH zo(1e%<(SAFl%7&NsxA7$YY)T zlqccsRkOy@AU1WFcjhrZO=PEE= OGkCiCxvXV4CLX;uumf z=k47D8Q-n9Kkk)@zP)#=_l%8*)g`-(V;Yxd%{cP#-}#@7 z1{|}vzZdM?d2!?J9eaKWC+@ZS#!wQ&#*ofXKpjH;xZHuDegE&hi|4=p;lbgbKmUC_ z9=}iYP;x4h#H%9tgZ*dI{{PHZ-ZxFm=On|Vc0nIQ(;45J6DBN|M&B^==JyV%3 ze3m%C6lKfi$HQ=*;Q1IsOEAQO&994n!VW2$r8NwDO_ehKN?0(mPN?uG;m~SG zIVjH=`+7fT0k^or`Ku4a%o>jHCNc3ZaPK?7@Gc;nnYp4xtdUX1AkB0|A%6nH|F7#g zwwasj+f4c@aX^@FEnDoQ^Xu=+r8{sNH%wghj+ZB)sjHmp?$M{A(f{AabQiHU7&BNf dQ-j#CUuTQcE5pfatAWXt!PC{xWt~$(69D^L4|)Iq literal 0 HcmV?d00001 diff --git a/thumbs/wall_003.png.import b/thumbs/wall_003.png.import new file mode 100644 index 0000000..bd68bf9 --- /dev/null +++ b/thumbs/wall_003.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://blnks8o5o5vgb" +path="res://.godot/imported/wall_003.png-8fd8648ffd61f131cb75dc95693e7d7b.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/wall_003.png" +dest_files=["res://.godot/imported/wall_003.png-8fd8648ffd61f131cb75dc95693e7d7b.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/wall_004.png b/thumbs/wall_004.png new file mode 100644 index 0000000000000000000000000000000000000000..9dde84f36dcb0a5b8488298e6b21ddaa48cadc54 GIT binary patch literal 726 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-HD>V4C3R;uumf z=j~m?JmEkQw}r2YDFI zF|h55`2%D-g4hpMaUWRU@_VHo!`Ea`kcOu+q~<^GUww+<-hG`tk~Ispm@{OJnxw8B z@O;Xsa$c}P>P=WJ!&+yTfL~G;jI0xOsN7-`b$Fz@kXzj0G{?L|W)B-)p$Z1wA{Mp{ zm%f{%4{HDb literal 0 HcmV?d00001 diff --git a/thumbs/wall_004.png.import b/thumbs/wall_004.png.import new file mode 100644 index 0000000..4f708e8 --- /dev/null +++ b/thumbs/wall_004.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cas82g46h5lkl" +path="res://.godot/imported/wall_004.png-5bd305de29d2bd29a5126d6467991a74.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/wall_004.png" +dest_files=["res://.godot/imported/wall_004.png-5bd305de29d2bd29a5126d6467991a74.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/wall_005.png b/thumbs/wall_005.png new file mode 100644 index 0000000000000000000000000000000000000000..6fa7c41c23af1d655f611f3258095ef207846ca7 GIT binary patch literal 818 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-HD>V0z=};uumf z=k4A7d6xqu+CFaY;N}SWufxGVly}A3_uhUD*i#xyGUOv_LfAB*_ zp4`gstM|q+7hn4Od-LVbTjzT_GdGBDTQl##mGAtL;YATPEbpQ($>GygT z4K6z}xY-v(oiUF~-2R)3J>h+U;z_mxCj2d`X-p1D+jko?O*nDK)q~+`(!Gxc8Xv

    0>p2deT znjy%TSLnV$R?`6~hsnlF3^rl9dAk%<1dm)`Z0MbISs{brMMk#NksUX!nH~H!SxRI5 z_s>vfZIE5-+nml3w*CGmos1_88`1;!*S6Hl*)Cu^_~z~IGuo2+Y6lo~n|tax8NN{| e6@eqUE9U|;0fVQjpUXO@geCw`LN*cr literal 0 HcmV?d00001 diff --git a/thumbs/wall_005.png.import b/thumbs/wall_005.png.import new file mode 100644 index 0000000..be6f3e6 --- /dev/null +++ b/thumbs/wall_005.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cs1l5va2uy7h0" +path="res://.godot/imported/wall_005.png-ce2af2ea151c77db1f3bceb0c63f07dd.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/wall_005.png" +dest_files=["res://.godot/imported/wall_005.png-ce2af2ea151c77db1f3bceb0c63f07dd.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/wall_006.png b/thumbs/wall_006.png new file mode 100644 index 0000000000000000000000000000000000000000..32d4a44e72336f3dce6119c469f9ee5f4d04ca42 GIT binary patch literal 761 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-HD>VA|~I;uumf z=j~m?JYh$XhKK1#ER`5TXO&p8%d#$VzQf4bH$i&F6cw*i1@juFSSRe}Zryv3@%^dS zcfV%b`(Hox=`sIL`;A|3)H&~W{+zsXguWO5f=xUO=NKMPhlradm!R|BuI|>)KPO+C z`}gbbtFgOgan(cEVRrlc@BaO_m2Q@O$`U@)Bk1#s;aAm<(gXu(@%YzW#~9dd@ultj z5nC|naD^~OI)n1ckFWX-7;Kmuj2SF|M1$bp9s9Iwo$}cj(isZa7^bT=+&*3TQgGE2 zH3r#Z3~m9h4GUTrA4oFHVLSjLdX^kZe!#(e0HPaWL}Qj6Tb}{Lo)E?#Qw!=>G6mGL z88k)tGb-~WY>0fx$YumlcJS3bmP@Pw-)|SzykzPyXtE1pTkv-&?*oa|2eLL=99r$8 zoy#DY$NJkt_JHA?*m`~2LkcgM3q)T`vuof`elba}L3+Q?JJnc*+!)rf!z==Zjx3z3 zoLCq9f6BAq@hP8zi+x(D4CeQr%{6a!`w)JLK`OXTDMI(PJzJlLoWl{TrdY)tTx*u{ zFEDgvDGx7|XLfI3>X@O{bZa3~N5*}j6$OkY+msd7Gu>cNnzx?q3daRTlM{kJwiinK zvi$xNo}jjl;s1iahi)*G?btgf*~y@RFIR9)e`E0-!!w{5_vR05ep}sqwP@la5radb z3Hj&4n`Of5Tjn!WWhzzt{^$JA^VnlChUa3CPzDDzg+x8W-cuPmcg_YH0@E^sr>mdK II;Vst0JU`q3JaSW-L z^Y-pWKj}aLw}lCMB(}oqKg|@xCla zJ-0^%k>|bA%>GyXwLbLA;48zdX^aOX8Rk%hxO4If^A@B15xIZ({e)AJz9> z?lofE^Zeh#!dlz?H~v*c89Zf{$gVM%A6Hvj{C)FR5BF3C_FeTqHtvgCH*eA$fAceP zdpKK+8{FpA|NfoKP{4NKQqC*JW5x|(R(~FUb73J`J9q{on}02OfrV3=cqr)XPHNIT8%>ki00f;<;%-5<|sOrVkT8 z0Lcp#Y!@8XM;}1e2G;w4=K;fBdv*^VhVu-3S3W~+)fR8)Z#k|h-f+y2!2;}vNgzk; zmAn&pl7a1b&w@iz7MgMnk1{v-{si(n7JN4?VB%6J^xVR!)v)C5{1!iZnLqkF7}(~q zo!`Kya!*0+0|VO=4xR_BUrh`e%rgWf4zTT>%Vv6yUE+ZK9`S>#PDoi8Hmo(9&$hWH zx^7O&ylXrO?xF8_|2)5_%p+K1`P=lP%G(O2Hw#aFoR8{JilX)}W8vv^H;X>8y};zh N;OXk;vd$@?2>=a$3HAU0 literal 0 HcmV?d00001 diff --git a/thumbs/wall_007.png.import b/thumbs/wall_007.png.import new file mode 100644 index 0000000..f29d97d --- /dev/null +++ b/thumbs/wall_007.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://y54evbcyrynm" +path="res://.godot/imported/wall_007.png-6b680f6b365fe0200c9af7c03cefd201.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/wall_007.png" +dest_files=["res://.godot/imported/wall_007.png-6b680f6b365fe0200c9af7c03cefd201.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/wall_008.png b/thumbs/wall_008.png new file mode 100644 index 0000000000000000000000000000000000000000..1805bc82e2023ade07cec0cab23f75e632962ffc GIT binary patch literal 832 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-HD>VEX0h;uumf z=j~m?qRS2vZ4b}$Z08WUu+-C4%ggGW182E{x#JWS-r748P5juy6<7;ekF4}b)Gm}+ zt9vs$^V|P>+c(8pSa0qxoBFlF#>&QOUT03V*%yY48w?3@3}=`dDj5v;8J;m7uwj_N z&hVLR!9CBN`4z(D@9)p8`TO;B^Y7#H_t(77wm2%n=CJC1{lB~Reu|Ort_sZ%W;S@p zSn_t4_6%|M{(195QWr8F=!^Yd%TQcwEnA>+`>5}NN`@05o#Fdg7=FWDbK=I$r|TEC zU$A6&l4bIRVH-Ed#d{1G_VulAlXIHb%II*LwSniZ&uJUBX$%SSaDUCT+O6?kB7&)* z7VgWG6&L)QR2dVVd)WciZYWlb{~Kh$P@{5ZZvexJ>W2(G8&&3uRdH#svN+u3;#}}W zdb1rjrvsDY?L$lp%39eDXl>Yef#KK6oV16GQ*3R2>nk)Y58kKGviG z5jhM&pV|aiK0jifFlAPrzz&9lWs_T30_OUM<*^+No1mf6uuGl8D34XJuW{)Eh9y(4 zCY<%zy^iG};}u(l6XsW!$}@YrF)Vqi+xWZDN}J(QlDC9EOH*YT!>eZ;vx=P(xE&^~ z`Z#sfk?SYTlsFb0k#dOTYIJ6ZxUxlxW#@_OYzU@Gx+aSW-L z^Y+f!yju<;4iCNSL{~qfAK9BZQa!D&JQB3~u z>iO;8mMvd5d|}(7!`xuZU_ljP$MU7-22-E^xcuw)+p^nh?928)zvX9miKXCd-uCQk z=Vj&g-^`iyb$xAh$jl}D3)cUwyT9gjLfGo7SC6m1{#xIDx>zq`Pl<)htkTd>LI3sK z@0Qu$XDKVNd%m}K5@Sh;cGId=X}3;p;aSk$Gx-2R)hV$?#siWE7-lYOVC1lByiD zy9C2LpivBSAVg2dC&Pjk#s^Ee5>9#_TIwa*@XNS?b4nGLL?S~48$&un0TN;0^zu5R z5)Z?9pq)QO3=T1T;9<~h@vLQWmQrGf!U}9wOboFyt=akR{0D)xnW&i*H literal 0 HcmV?d00001 diff --git a/thumbs/wall_009.png.import b/thumbs/wall_009.png.import new file mode 100644 index 0000000..d03b258 --- /dev/null +++ b/thumbs/wall_009.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://ckpoj7l3o1mhf" +path="res://.godot/imported/wall_009.png-e1dac71d1d81478531ceb0afe40e5d0c.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/wall_009.png" +dest_files=["res://.godot/imported/wall_009.png-e1dac71d1d81478531ceb0afe40e5d0c.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/wall_010.png b/thumbs/wall_010.png new file mode 100644 index 0000000000000000000000000000000000000000..16d14145de5ff31afe745fe215645440879d20a7 GIT binary patch literal 710 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-HD>U~2GmaSW-L z^Y-q>yvqSHZXeID;Ge`bP4Dh6i8UQlc`vTzXRvlow<=v4`>-%-;`9#VX^b*cH5^Od zetC7TxNh=f#b5mD*RO4zQ=+~+onP?U>PyTkbeJ2A87!zm>{xt>`OMQthj-6?zuz)0 zr_a9j-!G%XAxma5eB1eZ>m8Z*-A^`NKi+-zqou-(XUr0>>v9abkJ_(4zyFG8FQZS% z{+PVJ@YVb7D4c)dsxXJ~%#vgI^+^mBYz*lP1#AY(*L`7lEO{Vi*OOPz(qC%2K^?s# zjcLc8eY&n{8{Hyu{klwpzp1g;(x>f5HAZ^Nrjyb}-pQu3pYEpIaia wU>5dtaSW-L z^Y-?}A|Xea;~(Yw`WLbCZtToI968Hywk|3_?rO8Zg83pNZXtB&RGXK6Uo>&35N$&j*o-^u9=3GzV4 zIUL&;TdQN+@&xAAM24EodsF3{rnWLVw6iww+|?Ib+FnqA{Z!0Zh!mGpsxcCyTeD0Ft=5=5?xbG12gc;xV=`g&RHq-g(u1Ab7 zW(aI+`u2!%f?v;qJRd_wo^|g|o(_y*Xbx+99Hl#5@_*FKM@$ne_<1zU8s-%#?%21- zs!YSRn?K>hovL*#9~nJ3pEKICJY+btEVsX9cd@$wpF_Is=T|)k*c(`yrtM+y==>}t z-zeWO@78i_v!)3QX_uG%H<+!g--dPH|?BLa5Wmn*h;I-=dJ@>w@O+)Eg zj&El^?fcJ@wVzi2YD%eKyPCCzQ zxQT7UI|UX;7lsGZ&b*D`a|9y=2@DqJh{*lU&Mg$) VyzN5FM_^uI@O1TaS?83{1ORP(UKIcU literal 0 HcmV?d00001 diff --git a/thumbs/wall_011.png.import b/thumbs/wall_011.png.import new file mode 100644 index 0000000..9e2ef16 --- /dev/null +++ b/thumbs/wall_011.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cy0vwmslkdn7l" +path="res://.godot/imported/wall_011.png-f5193560a196374e1e84c7c8c75cd6a2.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/wall_011.png" +dest_files=["res://.godot/imported/wall_011.png-f5193560a196374e1e84c7c8c75cd6a2.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/wall_012.png b/thumbs/wall_012.png new file mode 100644 index 0000000000000000000000000000000000000000..19c97afd656d90f26edf83276d956601bf5b5c02 GIT binary patch literal 932 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-HD>V2<;2aSW-L z^Y*T9-sJ#^)`!AJ7>@A0kO*g8xp^J)wF|5Ud8*36K;bvkx)6$lCfNBtP6E&369(9gNR-7}RVU zwt1B*|G3ETd2RA4ll|WUKh``>PQSjM@Al44XQm0i1poNki_d@kHvaT`&b-1~7t|Yn z$H{13a-DjCVMz%`QOy@`Hib@GPM(BVAr?(PEj2xXhQsy0*cE3iz1hB!o5jIOtx4v6 zjiyY4$=mJ+f0BRiI;bfw;4sTQsYQ5?A}fo6zchv@lRWB|x@H-^=Gc#vwvE?mG{xSKZ z(S{U;=&kFekIdy-$RN@gC-g4PLCQ|DNK>TY%GdQ@jy5DPSW9iXGyApHf)s}4t_{!b zPi5rM(Q2w-aI?|*zW>Uc^p6Z4i|5aFbrKLhz~bsCAbx=5`~@Y24sM684<@x=l9(lS z7EOH~>Nx8t`vc7j(KQU0R&W%>u};xoh)I`WuoKxL#^+%8zS7gevguD~E3-l7&-?!! z7#QDenF2J}?Lr5qgHcndBBRLX+y5pzhKmb1T=ipN_i6m3_dcF|Jr}QolmYL9_NEUE ztByGo{CoJeF22Gkk->wRkMlqP!;*QJ`HWzpD(fZ=-EB@^xjWX3}aOFZ#cMg z*RK;RTmL@4_&Y@L$EROsCw^CnwPQK(S&_OacmGSJu7;^6qAmlo9fPN-$ literal 0 HcmV?d00001 diff --git a/thumbs/wall_012.png.import b/thumbs/wall_012.png.import new file mode 100644 index 0000000..2960418 --- /dev/null +++ b/thumbs/wall_012.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cxp8vtp5x1nsg" +path="res://.godot/imported/wall_012.png-95ea4c8116e16dbb87fc796d8b2dfcba.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/wall_012.png" +dest_files=["res://.godot/imported/wall_012.png-95ea4c8116e16dbb87fc796d8b2dfcba.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/wall_013.png b/thumbs/wall_013.png new file mode 100644 index 0000000000000000000000000000000000000000..3f74fe7e44d7afc2ff3c77d1a7600993c8fb97fa GIT binary patch literal 800 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-HD>V7le$;uumf z=k4A7d6xr38a^f;IVIHDx>cB4+W$z;gIKHS%U^M1Pxpviz?0ITXwh=a@6YpH*KF^9 z_YD+TI_=Zzjm2+woxNTDzP>%NdgC{?8@o6e<}o~=4zV|;n%V2?v&YLm|2%tEZIPwT zzW-moN^W1#cZuOe_V?WKnmg@Jwwyh?|N5Q!bNp(y4I9rg3J1zdF`juNa^~O1>s`@C zy8KKJITr+&{`=<6!7v}{F2{Xr^X~C%jeN5_XaApwH+!dZ88FVf$9diQ@jNz$3sX66 zEnrY`DbV0;Xuo~;tN6{xOa`CRnhXpDZ&%dYHAPKtR2E=pJ2IDrsX@IV`HUt5qe02n z{&ohY1fR0|`~1{;Znjn|o;%x5xS2;SAR;92Se4wVMY zaF(ZYSynPscvaM_WZ*fkd4Y}9U~3-B)^$v73mA3EOACA(8GUrGuVdg#cqMY88A$nA z3UDM`+vxC@gN4DLLD2D^n?ghKW5GA_-??*+e^zVQ8ER+4@*!T?{;XP3b@+R&gcgPm zoDbHVO8<4@5~D`3*NkQbSqACp3{}ZKjEpfl_Dqa1y5>z&807NG79_mf73NSx=q*RU^?yT;uumf z=j~nFJmEkIw}<5d-G#F*OsKtZIh9c*He z{yh#koVm=1p|AA&>vu1|8mj!(J@@@U%oX-vIfwi2>h{a{T#}n*#js1oxaQ_ryBS~q zR{dh+S#!-Z!TdYJt<_=;lG%mt{k511L|=s3GMud8kUA1B>|pdarNsAKeImojCB~N? zJyE~Ps51H7nODDlm;BFJ@`~Bx)?Him4n_sRgA*+ngal<)@HCvCe){sg8?GGHQyDK< z3#uqGd$>jOn!WyNAw5gctRc2paf{_o&!xu?CU3FtpKw1=@W94fcUM+FRb-gQ;FeYT zH}{?59u1U0I&i@3`|O?V20&45)(21A4}A;KWVmL}*b}h2oKcwZ0eW~IXaK5zW^b** zP{AY-G=0swTYI@@a4^hgcrcauf%3z;smuncz3~hxf(-j6F=)M+85}C)U?ke~ZRJ#! zg5sTLdexiNLxm2kyS_*1#=7n6x4qTW=2fV4d9d{1$5YHVzDjXS3y*id|LjU4gUUS> zD-kY-M~V+CEf{vYe2@@xc$78a0OK1aWq||tSFCPinCI%O(7-%*i`16?5(=FR|85(y zgyu1;dzP2gG5!p@lX&;vpYPU(Zl5(f?f>>Zt4|E0-?~>j8yTuXK6)K=X0Qnd`k+Cb cD#Um8pP|uDwRr;n0Mj^wr>mdKI;Vst0JP6Fc>n+a literal 0 HcmV?d00001 diff --git a/thumbs/wall_014.png.import b/thumbs/wall_014.png.import new file mode 100644 index 0000000..9985a3b --- /dev/null +++ b/thumbs/wall_014.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dwyxruyfoubxc" +path="res://.godot/imported/wall_014.png-95ef8d1734f55bb36b4876a7aa8d8796.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/wall_014.png" +dest_files=["res://.godot/imported/wall_014.png-95ef8d1734f55bb36b4876a7aa8d8796.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/wall_015.png b/thumbs/wall_015.png new file mode 100644 index 0000000000000000000000000000000000000000..9e49f88023ba33d57ea0b939cbd4b7da6b234845 GIT binary patch literal 831 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-HD>VEXCl;uumf z=k49|e!__oZXcH?J@Q-6y!cJb=_tKcRkc@KdJN@NsX{yX7QV?Ua9l37a7*y=+-mxq5Vx}&eSr83xLOnGAV^XKF1ZR>a;QhG)VDv!=3c zID5`+`%bPIBJ2-DBH}U`Iyt6=$~D-^GBpGz6mkH$Vy%n`{q0N-L@Fe>9E^0DK7L(N z8Dhb3vVbG%{!dPk0~6+&?ctiyz!+jt)y~1KAm|t*aKQ6?Ip<};Da;%EQdodd){uEc zQ=wsJ2ZtAvh2_21wT3sYayv2_sxp@33LW%)tk3>li&r7CUP{L`;K2)j28LbN=Cb*h z{#yAq^#KcuLgB<08v__7{afDhilcyGmrH@Tn8T%fsSwu&whOLq3Jsa7{hG5lSU&ih zurO6D`5)<(r^{$_QHkYo;qUcq@1%e!==KBg)z@CWzO#LD|MAH}s~b9n6P`X>?l^U^ sy`aN-tvKllu7>9FVdQ&MBb@0Gz5rEC2ui literal 0 HcmV?d00001 diff --git a/thumbs/wall_015.png.import b/thumbs/wall_015.png.import new file mode 100644 index 0000000..3bf65fc --- /dev/null +++ b/thumbs/wall_015.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://ep5vm4lpim0b" +path="res://.godot/imported/wall_015.png-a907296619146b727d888319661b300d.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/wall_015.png" +dest_files=["res://.godot/imported/wall_015.png-a907296619146b727d888319661b300d.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/wall_016.png b/thumbs/wall_016.png new file mode 100644 index 0000000000000000000000000000000000000000..18196007866a807fee7d0895c7b843dd15825b27 GIT binary patch literal 886 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-HD>U^eh{aSW-L z^Y)Iv-)#qpwvX3C-#aZ7TC=0`@Vq6q&ebg?cfScOz3!-VJR@k=Qtn49mK>R9Sazo7 z{O>hBKNbt#KQDaTF=YAk>HI}E?)mIxFwbRUIM47vlEH?#A)Vm^55qjh1I7#$WDDNA zy;9sD#N6J__VrE-B+Pa-0TN-JH$O?@Nk;aTpBF5%W`}OJm<2?&@8!*J|Kg4WtOz%U5^o}!s z)od7EN-SRKHP@cG!Q@j7m+U?fK8N2bT=OnxurgnmD`=yu(C|($+%taa^+$)dH`YHY z8y>gn`&yJcRP3SL?w4e#1yqggl%7#^GGf6-ge!V>Vy(mLlO zgUZ?K9J3xVPUulsJcD79anlZlN$IEE1jHLsSU8WeJ+SKLPdF00;LCSL6()w0{;ax& z3?7RWHGb+XaABGtny#L}cw&||v!eyW*EMf-6D1Dm4bZab}Z$5wN+x)D}JFk~E z>~5G;-tgqrO`|7Y8yHhU&QI(A-=-$OV$XWuGaq#mWc)tMFd>Gsbq9bMiNVv=&t;uc GLK6U-3Sb%l literal 0 HcmV?d00001 diff --git a/thumbs/wall_016.png.import b/thumbs/wall_016.png.import new file mode 100644 index 0000000..4b98f62 --- /dev/null +++ b/thumbs/wall_016.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bw106wuwba7i5" +path="res://.godot/imported/wall_016.png-a63ff01cae0b09bb921b20f7f04ee105.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/wall_016.png" +dest_files=["res://.godot/imported/wall_016.png-a63ff01cae0b09bb921b20f7f04ee105.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/wall_017.png b/thumbs/wall_017.png new file mode 100644 index 0000000000000000000000000000000000000000..3fa67122ea9741819439bf6d33041a33ce0b6b72 GIT binary patch literal 781 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-HD>U^?#U;uumf z=k1+?zS52|ZXfd(tAuNLFcvh#WH6dfc*4f2va(B0LpigNjp@lWk0%Z}EN_^$UEe+H zfA#+6R26Tz%zNj~@ipcB|M0`?P?hm_1`~be24e;bst`N27xO3Rh(G`P|Jj4X7w^6L zd+_4dki(g7Ga1@q{_Tj`yWgVz=jSa6r`R{F+uCe-r~1R^gU7cmGHlR|{kMnz+4ZmU zRo*|BKErm0<&fk7k9X_-eUo6A!+1avNc60jUCkhE&@i#Yb6-vVYe54;1{;u*cNj71 zoQt~CbauTD!>u01o(HQgCOoqU72|mTzJ9hot{agR$#!ZYWH-A38`RnR@5&ncO&R>7t-etMJ$$BZXM~zm6 z=TC-7S0YxIFNtALU+$lN`=@-EUW4L2u3w2v9*=@9FpD~DuevCt)o|oz{hAb@lGyiY z1tRV0jIL_g=xANXOU54{&NUq&%3$5YH9B zsN$c``NiEihQZrkso@aY1e+M%75!~57^azZE$}d4`*1(YwBqRzv6=PE6*(K-SVScp z`j2L|{|qi>t~eIJV!l6HhFP8M!=j^+|Fb^4%>E4uh&@qPqnjAlBxaaqL~gIIsImU8 jU?Lw*rDOt3Y`@v<_Bq7;7yjc6Oy3Niu6{1-oD!M<+xarq literal 0 HcmV?d00001 diff --git a/thumbs/wall_017.png.import b/thumbs/wall_017.png.import new file mode 100644 index 0000000..6cfe7fc --- /dev/null +++ b/thumbs/wall_017.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dv5mp0kjndnlq" +path="res://.godot/imported/wall_017.png-4d2f2293c56d5ceed7cb998eb614fa4d.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/wall_017.png" +dest_files=["res://.godot/imported/wall_017.png-4d2f2293c56d5ceed7cb998eb614fa4d.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/wall_018.png b/thumbs/wall_018.png new file mode 100644 index 0000000000000000000000000000000000000000..62160aed12ff1b491fca9252d16f0988cd7db5c3 GIT binary patch literal 880 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-HD>VAk?3I4xM9h4sl1B4T3EHeen)t zG+_Ovr^dj^QY|Llz|v&f#p~eJrQn|bksDJ0Y|h0QT?-DYtCF^4Xr`_-NY8D(m@L@w>-|7piMrHOgM4(%6O zHVxk#1o#f5{+;%r_U-LAy$Ui7%l2&FX(`R{_UES!Ob1pzC^Tf;@! zA59SDc*o7TU={Ddg}T!#|65grW-wf0W8B_$wv|1gl!s-fJ=?S%1`mHr)h&u0hN^2A zJo^1P@7|V3UOamfa{z0T?>2@dZ!;fs9guREYRtrN=W5CB8zCZG3_sR;sy8LQc7Dg0 z;6C}~B4(!vcf}c^vYj?W9j)Ne@jQC+rt72nZL`v^+uL0|zWQoZ{{4E%Les-XS#E58 wm)&f`?9jh!J@2RP;D$;c3KATa^!k@s)F+JLjr8)(z%0bz>FVdQ&MBb@0L7?TV7ByhaSW-L z^Y+d`KdC^8wuk-8y3O`7>o>TGs~z3(obL%+&iiww(+{kR-5OiX_-3j}(xqv71#T;h z4;(mi@N@n9*)x1Xjv3ngn=_~Li{E*Dai!b$WPUTf*ui+fhG7Of!)JyBIfgUL4V4TA z{0z^?7tHUkWz02|`?umx&HpFPl{ICT{Yx!xim*AvZoeG=^rP{lxVPWG``?>>Jl$M= z_pUYJ!4(Wwbwk=8l>G{j>uD^S&oT!zM8SnSDz<Ywh7B8ka4>AxdV}K-gM_bLX~nl4K-P6IBbb)El&lXBYY+?+U z^6IJL{4)$9Te}r5TOXX1!|37DoO+C*YmXph2h3duwyE^of+PQ%CJ0SShCwt znAy>SA@j7nqX&cK{dvBz9t=TJEZ>XO7*gXh7&MnToZHtipjCmj6p>pB$c%xE{%P`Sxte&MJ+4^rjj9gY~4yWg}I_a4j0u}+ReB( z@anL#D_r$wUUp#92ZpX)4h3_6nr%p7aY&lHLQ9+B(l^#c(Pa!>VS*O^jL{62ewk$S zD0E0=Gq_eOa|kfZ(^}Rj&BX9$`fVmb2GL%%X0iWQ|CF*f@LpA%VSDTb+q5P3Uj9s- zbAQ?4V~5{A{rIME;p_E3-!pmnG|cV(HHo2t%{4~)gHVE;Fm+Spe+F;$Uip}BA3p+f O6oaR$pUXO@geCy~%Wb;= literal 0 HcmV?d00001 diff --git a/thumbs/wall_019.png.import b/thumbs/wall_019.png.import new file mode 100644 index 0000000..24bdff1 --- /dev/null +++ b/thumbs/wall_019.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://hko1isqno3q3" +path="res://.godot/imported/wall_019.png-4eb4b2eb3d1e3d7d24b4c645d5787de0.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/wall_019.png" +dest_files=["res://.godot/imported/wall_019.png-4eb4b2eb3d1e3d7d24b4c645d5787de0.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/wall_020.png b/thumbs/wall_020.png new file mode 100644 index 0000000000000000000000000000000000000000..dcd180eceb2610310b296e0b094090fbb0c4b62c GIT binary patch literal 771 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-HD>VA|{H;uumf z=j~m?JYh$XhKJiby4W;rWkozE>Vw_Sm1*KG5StLR#C=A?L=Qo(8xt&c zx5ch6H+lbm|Ea>SD*uhM&mSw=TwhTld#Ea)ieYLhLjfB@I#r188@@0E|NQW)@cC!| zd2jF9*i{tTUAMUEA?z@}yMKPZ+;`U^Y26uL773?r99()Q^sQ45(mcGP=%Y?|EP#=RhwWq%@b$By070m=^S z7nIx+80!DL{*VznErKV3_pS6XwhIqaHXdn7V37XeTCnp}A&-pU#W(VDvD4)iv2Cw+ z|4~#bdR}-AliLpFKik(#XQ{WTYA|d1zFtmrUW!#5(}O)Mz)%JUHO0goeLn5fQxO+< R76DT=gQu&X%Q~loCIDxp7jpmr literal 0 HcmV?d00001 diff --git a/thumbs/wall_020.png.import b/thumbs/wall_020.png.import new file mode 100644 index 0000000..f3defe6 --- /dev/null +++ b/thumbs/wall_020.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dldpyeay7prkp" +path="res://.godot/imported/wall_020.png-0d74240dc06fdfaa9e6f9d01e9424293.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/wall_020.png" +dest_files=["res://.godot/imported/wall_020.png-0d74240dc06fdfaa9e6f9d01e9424293.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/wall_021.png b/thumbs/wall_021.png new file mode 100644 index 0000000000000000000000000000000000000000..5bc42168c84e0d6d1a944c7828f6eaac4e51a6ec GIT binary patch literal 979 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-HD>VD9yFaSW-L z^Y*TFo^YVV(T~O*Oh@=U7?}jMeRr*C?hBZ>)PZ}qhq#>YCTR|ih!$hbhJ^*|<{rN> zuR49*@$Yj!Pgk<^GLn1w@6Xx8heE16g@u_u&b*=Ba*paB{P>{q3J0^4@;V4^CldP!u>~bN%W2`JdnayK?zn z^qrC=>Wz1&nSDJxafV$;r-;M%Hm86`tK}E4U8p^M7_aO@}N>2L-xD-RZ?djv0gANWx2y(wXb`z4et&{hQR!%OBH^E`#+wSa{3WF zLyB9#yGP6^3}ybm_Neahcsap=H6fK#KZKRVilHHgLoI#&WAi<#nT#Gil|nBVJ#5mG zT^F!3yl8FUZBk=caQ&*ZFjFi;gP?<~!+8k-35T2JpQ_Rs9DaEw)&|-rFmo)`NqN}K zFLB_kkXT7k)Vo-R0}SunKCJ3H$#6@^$$>p##rBp^feVZUg^~wWu`Fv~T+=Pn$XL=T z!Km7Bck<(her(Q5I5Zerij*?+^xN)!^9W>SF!EvEtSs^I`=l!U+fKJL se5~ORIL~mznBgOjgAFrvn7{ddnN8c!#l)}^m`fQvUHx3vIVCg!0CT8@(f|Me literal 0 HcmV?d00001 diff --git a/thumbs/wall_021.png.import b/thumbs/wall_021.png.import new file mode 100644 index 0000000..3ba7974 --- /dev/null +++ b/thumbs/wall_021.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://nscatca2vouo" +path="res://.godot/imported/wall_021.png-972b7d16653e43a4f691817ae1f0dda7.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/wall_021.png" +dest_files=["res://.godot/imported/wall_021.png-972b7d16653e43a4f691817ae1f0dda7.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/wall_022.png b/thumbs/wall_022.png new file mode 100644 index 0000000000000000000000000000000000000000..3c933ac2a63ab2a90997fa8c00e0beb7a0930021 GIT binary patch literal 825 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-HD>VEXLo;uumf z=j~nlJYh!(hmYqwyd4~~f|odIK9KSVcp|rj&sXDtlwNXPqE?WTEY}VO0jFfHYF+D( z^JCNBrtbS5XSz`*d&$qYZ?ck9_x}5MQibPs^E&l}yJ`#-ObzN(A-->T&AH|3%g>vq zu9vs1vyz`5zsKrA&M8gahSJ#D|3>oboj2XMxcFbmg>H-e6?>OQ{B0~+#oeg5YD}F9~t!d)N z@PUQFpW(wL28lYW*Hv7u)7To`PGg8#aV7Zy2jc@_1{=l$AYw~M=kWuAOb0;T%vczA zU3iB(Q^Rx~hm+Tn%vG5M3Nu))v&u8Or!YTYyRajKq3!WOo<^Zp)3^>4DXj?hV_=W_ z9k_6LgJ2}%nPTx9VQ~z5t(l_(;}`_j)%F%K&sg44`jq{_+Jxkvj5m%+Fx+9ic8oz_ zqd3du`^-~%yOV8$t-BqISeSN%#P7W!uY(jAx=7(8A5T-G@yGywoDazh6I literal 0 HcmV?d00001 diff --git a/thumbs/wall_022.png.import b/thumbs/wall_022.png.import new file mode 100644 index 0000000..0ecf9e0 --- /dev/null +++ b/thumbs/wall_022.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://pxqa5mil2jvr" +path="res://.godot/imported/wall_022.png-577ff2d1f588c8e6f1055bf6a933037a.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/wall_022.png" +dest_files=["res://.godot/imported/wall_022.png-577ff2d1f588c8e6f1055bf6a933037a.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/wall_023.png b/thumbs/wall_023.png new file mode 100644 index 0000000000000000000000000000000000000000..aee40379a00d8233d24a02095a460fb381bf511d GIT binary patch literal 887 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-HD>U^eu0aSW-L z^Y-rkyvqR+Z6D1!G=o;@Z7@t}=xpuHPHfR`jOJ7>Fx<;DVb;Q#2`fdeED4nCTD@ee z?0?I?(tY16)wXxdQl2}1{}R7he)slO*Q;-Od-DeOf*n?PX7Ozi*Af^PIF_$+`|$kN^}h#QZslCRbaQ3cRJD05W^Z1wYo`A4 z^k(q5@~q7En~)W2gIH?Sr0Z-z=U&*95zN3K+ttFrz!^RFuS7NHT4smii+mUvzGyHp zG0YHWJ5cnibjt6uwOlQX1@U)Jn;o8N+?2p@EOYkD)C5hHhQehI>sVP78W&VLG6q~` zVou;P(KKLqIfbKW506eOyTfrKh6B!yv1|+~0wL*44or@fZa}8ZSssU9Mf-SkBAFx- zxKeB)oERhg#Ch{)e(Y1#6KN<@b(*kKHJKr3)!pc`pZ0KR++?1x$-cE(jL%{F+b^yH zd=B4tDV>n^_h7iYUFH4RH$ff@e?K`1h&k-f{o)9u{@Vz&uwAIK z3_)5fh07f)7+z|*Zhi-p+*Gr+>eF;JT2}W7RX zQx#uWvli{=(UD}F(B?RyI*dU@PDn1DeL;qN<7bf#tO~Mz%;7B87`o;Ne#n3PFI-{9 z{hF+j-x?7!82YpRi61j$a_~I;@(>#nL)I#%g5A;Dr3*QMR}+dqSm$>A`c z;1P@8s&(8Mp^Xo&{yMya+fzb#fpg%o{VWW>DNK7P+W#^e1f>68cl@z4Fefp1y85}S Ib4q9e0Jt<-XaE2J literal 0 HcmV?d00001 diff --git a/thumbs/wall_023.png.import b/thumbs/wall_023.png.import new file mode 100644 index 0000000..50f3ea5 --- /dev/null +++ b/thumbs/wall_023.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bbxs2ywe7ddhy" +path="res://.godot/imported/wall_023.png-46ae83fa6ce554a669aec8a32e16ddda.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/wall_023.png" +dest_files=["res://.godot/imported/wall_023.png-46ae83fa6ce554a669aec8a32e16ddda.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/wall_024.png b/thumbs/wall_024.png new file mode 100644 index 0000000000000000000000000000000000000000..4a6ca1037042be465c0c1ca7b5148311288b5766 GIT binary patch literal 786 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-HD>U^?UJ;uumf z=k48%d6xr38XgKCF+L!&al;np?fV$L#NAG;{;DdmS>d8!+@iT3ScI24drvo7!l}7+ zwN+tF>G}Wlldrz?`1e*ie)*{<4_^GxYx%n93xn2ah6g+h=cq!wOMS`M_UY%}+t>E{ zFJFKCc>D7B<5J6|GMQdnGO@pQJa%HvEWh}>^1cEGm+&uGzwGBuyLaMeEc2P} zD!%NPKSL*zMP$qrxrJVtOc%;{5*Vgm-@erS#w>^mi1w7aZ+pLRL>n?#FgF;(h#P@t zZyyk3YnZOZ5YPF2x>iHdt3P@kE)oY6p2feq!`frea5uCD?ueLO3|jG%+^6d?e4T96 zVECSC>;1wYHUYzPojdoe{B7&t@`&MB!0)T_6Kxs{{Vp8uDrZ!l#4a%LvDV$?Ul?Cx zzGRxQb&t?Dy$iar46!{6VlOe++&w?lq@iOQ$C*bPk1%dAZfXx=Gl-sZJf~1DcKL0N zf1Z*DP8l`*{V_K|+Cr(4LGbi(Cwbo8OZgL0N~*juGChq?4(dPYSQ0Cz2V#pOymrnu6{1-oD!MVCwU9aSW-L z^Y*r{-|YYqhlkQfRwy5P!@xFkp&qLkLu_>Vn&!yct_FFGigijC9kVzDF3+&}{qk<{ zzQ8GtpH$@IqtAbOlTi0X${z^0%_4j;&V+5l(yIyoZ0?1|oP1s(%#qH}x~1Zq zy9C2LMiG#>h`cx*Ile)*+<00kX(zm&oE0g&` z+9lS4J)b-({%BtKH^)=_K=fPrMTJZG9ps%^9*DeX=TJDr@oNdsgCE}>T|Jv{oa3Ii zq(gcv%hDMAckaL6YA)qdc=Xq#fNRe*yM}WTf^%&DXngVhn!wZ{@qN+-tq=x5{pl?F ztlm2qtlT!V@G2xpGX5U>5OoaSW-L z^Y+%pyvqR+Z4b|PNGGlg2`tsNj&Zp$LnFAFF~p#Cr)-sIf$fHphf*G|*1Z*waS}QH zT;lk%Klgw8g@s1C|C;}&Z%xSY<>~!Ox99oRGR!h#n8D8QnIS=r;S6&_C4&J!!!yPM zHe?IF|9OR7VwL~)`0{^$UpzVb>(|}a;mNYgXB=Y4c>V78`LCtYlg{?Vc%be8#m!_*%yr!yqT16_4sLTIqOf<4el4GUK- znZ24nc)pS~)PZpl4DovR{c2m3xS1P%u{JQSnx49kZQ3D5jSs$Oj<7O2>||v*Aa+7i zfq|3dB`d2zohne)iCLnUd&=%YCgurVa%Un~*%cZS>e(1n1h$BCF(jYU7ist_+vdJE zM&`-BWKq5Y{|q-PZ{uc7sI&C`p)Zgl#^n(Fy~FW>h){!xUeoN=pAWt>ElXrva#W3j zS0Q)LJq{=433ra)j;&zG{Ask2;lSbrw%iOsd`$WrW(-T_T>Pc5foVdxc~jL+jd@+N z4SO1=+TDBihQZ^o;tG{m@jqe#Myv`OIcGg$w79XR?2bi4cLBpQ@y$;TJ~^*{;K+6^ zc7^SA9FH72xD}G!{vMNLc8p=T#9^!@@0i0NIo1ADT`P;h{uyic@pviQaGlaqX;|j0 zRIx+<_wxt73mHA4Zz~us_Z5(H2)^Zi?EjRe2frTwu516YhtcEZZ3QEyYzE(R91I_JPstS!WMtS@Bf8r&NybEufsfJxPs ZF_tyFab}-e4KTAXc)I$ztaD0e0s#L+Nyq>I literal 0 HcmV?d00001 diff --git a/thumbs/wall_051.png.import b/thumbs/wall_051.png.import new file mode 100644 index 0000000..22b4519 --- /dev/null +++ b/thumbs/wall_051.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cguhfqfqmmh3i" +path="res://.godot/imported/wall_051.png-305b7aa2e7c03efbaef32687c5863565.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/wall_051.png" +dest_files=["res://.godot/imported/wall_051.png-305b7aa2e7c03efbaef32687c5863565.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/wall_052.png b/thumbs/wall_052.png new file mode 100644 index 0000000000000000000000000000000000000000..0d896a3634a6dadd50f45d4996ca4215e6d580ff GIT binary patch literal 779 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-HD>U^?pQ;uumf z=j|OwzuN&KZV%_La>`P@^@eGxWBOfoodsL0Q*3)~GE87x5wMl{mB*4si$3Ac?<~{5 zh@=*%)>jtJTPjoY^VeH{p4+=uvTw)~X0TyAKpmpm{wqUrY2labr>~E1KHvTIdZ2 z8=FqQ{+U$!`NM=Kk4p~ooS1!JZPx$yQ&~2Y`g6>)`}$3jo*UwWc zV>+PDP{Gs?&UWDDpMqC{v)1r1NKa#Md-3dH;VVHl^@fR7GpZUIITKo<_WtN(_`u09 zkHPJgd-L%FP|gF8$OF!V(|OW%YqQvkIrHN*8Mak2Nh}QWXB1|9pv}JEsr%;O z5IzT`CSNVi1HZz>8g@JEKgHzXa$)%;hMd}`jBkp>GyYmSFfmN{5&9vDgW=>mfh{#$ zGa49fyb56WqxEBd5rf}#8zHfSpHDH~NEbCwWDMC+kle~Lp<@9zw}PN!kjR0Te+u57 zeV`#K5F+FdF3;k;{^6bjh6O<~4wv%HC0Z67SZ>eA@ZuJ0)92mW`WuA>8jd(G3SG#c zl6+6$+Jh$M3txqrq^57Jk6<`?dN(5{qm+ZVWFy1Bty$&@3IYd$OjwvAF5c^#bl-ug zVkzIjPkILRfA;=QESth`?aEuW(;VmC+xZxszrnd6eYHS{2ZMBpmHnAWLk=d13*VJ) l*DEp9Fg1X~nPTF*cxZXV$_S%pSAeOT!PC{xWt~$(69DepG3NjP literal 0 HcmV?d00001 diff --git a/thumbs/wall_052.png.import b/thumbs/wall_052.png.import new file mode 100644 index 0000000..f2fca71 --- /dev/null +++ b/thumbs/wall_052.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bikrkhbmh0nl8" +path="res://.godot/imported/wall_052.png-e22e70926688d02881d2218a97b6d58f.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/wall_052.png" +dest_files=["res://.godot/imported/wall_052.png-e22e70926688d02881d2218a97b6d58f.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/wall_053.png b/thumbs/wall_053.png new file mode 100644 index 0000000000000000000000000000000000000000..0b3949963bbbffc275b54898b4a33313033cc20f GIT binary patch literal 813 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-HD>V0!N9;uumf z=j~m`ASp))hlle+);(lQcz90xgpu0RCps#5rd6u?O6(t)q}sMdYG^bvw(%Ih{J(d5 z;TD~@tNy*1m$_Aj$N&7i!y9T}R5M)5XKGMqsGtrZ|69%>`tIGB{69ZVW^CCbSNrSE z)q*Zf-iBRr@7_wMsQ_bNzjjcg;8bj2Jl^2p9z%>GO15G-9K#=JG%%?jUru>kWw4KiF;PRZq z%Z{z@1jhlXsayvtKK)Wo+}^a;n>9gI@J(nOgKXF<%>N2yyO3cA z*P7`f4u5mH61GkODzP`e$D=27Fj|vQ=T=)ncD2F}+x2|EZ~c!1nzctE<4?wp>*`N5 zY#UtJ6>kK-1bS70L6AL%vmum$RUxU?dqF;{1w*&X2O%+sBd@X?TpQRnbo4kdtiNij zx6U+T&&h?34E3gY4GPXoH!f5Z?UZj};Y{!@wxK> N!PC{xWt~$(697&PKOO)8 literal 0 HcmV?d00001 diff --git a/thumbs/wall_053.png.import b/thumbs/wall_053.png.import new file mode 100644 index 0000000..39243f3 --- /dev/null +++ b/thumbs/wall_053.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://m03vdoy81uu4" +path="res://.godot/imported/wall_053.png-c12a32700dfc9e48c051bd6414ac67df.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/wall_053.png" +dest_files=["res://.godot/imported/wall_053.png-c12a32700dfc9e48c051bd6414ac67df.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/wall_054.png b/thumbs/wall_054.png new file mode 100644 index 0000000000000000000000000000000000000000..f5e839132b10a12a5ec12715dec3826d4c4e0be6 GIT binary patch literal 775 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-HD>U^?jO;uumf z=j~nFJmEwUw};m|bORKlmUsm2G7;gBD)T(4c1fbqC8A;V5|>`fMHI=kBlE{_Su2`S?5g z=haozuPU6ilBdDGd?WbH59-2G3^Qu?NL9C}X)_<-^JcKU^2)FPsD3Mh z&w}~2E?XITLKlnMujE+pu-nk>D}%~ng&lkI-b+}lnuW&Mr9TnyU}9P?tF;k*5hicZtksZ1X-lz!-oH8k$Z{32qY z$W*}nN0=X|f9ec|H+Fgq+Z}|A8eCWwGJAaBV3{D(xggh($zsvdB)e}M?&=New(UQ` zuHJB!&!M3B@5=v{elr;4*lx2hMTm1aS~5h}3*A%aXewf;;%#tX=ns`?WO%@tFr6#E zaS}t?<<*mid*X>cyc_Fxh1Yn=RuVG`pu$Bn)Lat_x8IHK&?{2YKHd7P|Hj2>)N z4mlPw4SIrq__!4crBw ze0q5@|3#R1Ls0(%|4u8{C$P!urfddJS3j3^P6U}p1laSW-L z^Y-pVKPg9vwuk-8%$;*>KlAxy=d&G_3p;wx!FSKLtZI2ZncK}}6PUVn&b+hw|J{!L z*aU{jXHK6<<1mn#KhKtX+dW=e2A*z)GlC74Oa|@@&o~aqFwRhBC}v6MBU`ZA{tH9V z&fWW?cRzi9U9QIB=axNBAN?urSJrZ#!C=;_V*C2~UG=#Gl7o zN!`9JXu+WAdg0jn+eLHN4s+RmI`TCCtF*%piH?Yw*V9oGcR@S5DR!Y_Np{hr;B@#^VQs z7*m4Yr79qW%z=r|SnI?RL>Xsri!$VMZWq^L*y7G0d1hUHyWF9Jpiq=qeJ41^_ z;mlF)1s_y*=09Xg_;;IAyg@}PLotP6@zeQvXP>9;=T~6mbx0Dt5q^U~>Uh zJ7`ug)aJ6Pa?3Ux`LkawhT-zbY1>;?E(qMguq{zLBTcZug~d0A>4j6vyfsV-qBlg0 z8eT5BRcE;3j^LE|;1dj!<_gMW3O8aPeY24N z1KSN2g;HV1mur|Nm~ChI{PR1v!q0qDgLMbY7+$8D7Tn`n!|cJ=rQl(}^5J|*(8^gM ziE3r>EE|?(S=e-SF>G6*r#-uWmhb^SUqKzQ&-2_b&As^J%bMNyLwQraUOy?`y)$p$ z)Os$BjZANJUrlph&~@2kmcVUroQr~Fg_$bv$bU$TU%lVPa~CjsFnGH9xvXVA|yA;uumf z=k49SdBTn&4iBYUG*$>KZ1AvQ;FT4XJ;bbs>>7UG+D&?#Wl1 ze4n%amdiBbOLF&PeW#qgxcYkjzm^ShQ{oy<88KKeHyBfesE(*&46gkCsqpo8|9Q5t zvitx4c^YtfrQ0lqU332a*lG2yE9LIVk5LB8e>Qu{JH)4p#~zf~y6@l7kCUzA>n;B7 z>Q8;!%h>bf?W60jeq?Rb*fA+_59gi8bMBgw4*GWmul#t~Z@^%~{6hEo(gO@^Cxsgs z4@e$J`0wB7e?OmVO|lHL#L|D>V8M)1|3(wWGtc&O|NBy<>>=FHX4t?Pqx)+2?|cb{ zIY4b-;($xm9kxD@kqG}wtbCUHfP?vfx2VI-c+TsZp$xCiGpGf;)=Ow%d;ry!@s_`D zMJvd1kJ9>oybR|V+;+s>3A1MsVkmm}+l3qHEZ5Dq zPu>@=xstgfV>VmVbi0OQMopQ^9p2tPAh>`*>6@_Q+WKiKV2GNqtdTM2f~ey(kl${s%9cvG!P;ZcFgJCt%8&Dl zt22};e*X!4IMwGkr-8$?kMfBO6>JRY3`lo>o-{an^LB{Ts5 Dhd3R_ literal 0 HcmV?d00001 diff --git a/thumbs/wall_056.png.import b/thumbs/wall_056.png.import new file mode 100644 index 0000000..fce3261 --- /dev/null +++ b/thumbs/wall_056.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://326x51ump384" +path="res://.godot/imported/wall_056.png-0848d7276eda03eac9ecdfffb0cc2881.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/wall_056.png" +dest_files=["res://.godot/imported/wall_056.png-0848d7276eda03eac9ecdfffb0cc2881.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/wall_057.png b/thumbs/wall_057.png new file mode 100644 index 0000000000000000000000000000000000000000..62ccaa596e0d9f482bf03020e9b67c91335c752e GIT binary patch literal 842 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-HD>U}o`jaSW-L z^Y-rEJYh$Xwuk36#G5;(=-EzZunm9k#lo%R=fW1YcRB}ZZ>;lucthgJ*K>Ni<<9-Q zw|&zh4XKwl^ERe;`z#B;E6eT%w*Nf1g#E(S9 z66f?B=IBg@J2gAj?`@f|l+ocY(*XwE@YT1xU&w+zw3Fe;o}SfFdJI=~)-Y(jWfEN9 zxU`2srLT$aDT~9=r>qC`0z%>#ggCfP@is)A=1+JMtMJKm!xIJvDOtxSlhs5UW*_Zz zKcwud`RT*b6o#m7yS0K|>=S$#JZj`JPO&wZ@HPE(z7y?m zlEoeCYp*~4^VWE}RKpfmgBRh4QbP0 Hl+XkKYRgUM literal 0 HcmV?d00001 diff --git a/thumbs/wall_057.png.import b/thumbs/wall_057.png.import new file mode 100644 index 0000000..5dd009b --- /dev/null +++ b/thumbs/wall_057.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bwjm5rrc8vriu" +path="res://.godot/imported/wall_057.png-4f90ccd424adcbddeaab2407797e0c1d.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/wall_057.png" +dest_files=["res://.godot/imported/wall_057.png-4f90ccd424adcbddeaab2407797e0c1d.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/wall_058.png b/thumbs/wall_058.png new file mode 100644 index 0000000000000000000000000000000000000000..ee733fb0e0475f476b0205f2ed771225fb5fa32b GIT binary patch literal 668 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-HD>U<&heaSW-L z^Y*S{FjJt2!^7@m^8*nYVclo{|7SPJxa4+lf%gRt$7Ve%zK-2GcK2hIEDk>JZ15vP+!0S+eQl*ON~^e_cI$_kOA6QkhIQmSxWR z`gNPfKB@lWuV25u{k!?hm-$Qh7py*-v~k}%DIb^GixLOs?PJ>qxu>>TPJ-~4_2?LJP)L!SlBi&zBDmtkk9E>I4xyyh@tFOnN-RRpv?!?r|wn#@%*Cf7C|3>e=dI` m8UF^kO)~$nxtiQ4&A;c=_@icfzX&k7F?hQAxvXU@G=>aSW-L z^Y-pWKczsChKI&!@y8tAthtu7{gV1cr`4g8@8*WdA2@gHdy{zM%dG{9M;a1mG`_a| z|3B1RtmRFVohs*$D#wYF^XJg?z$<>AcByZo}~uIY@9UyBSI=7lxSJe$U< zezVuSv4G8Bg4F)Mf@}@x3Zz0f|b zR0c`A8P1-P4cn$0HJpAOe~%|mGnIk+ch7>{+k5wZS6s@c@W_^_y!q@U_6-~QIr8fN zOaHOu=M{EnX?JVEXOp;uumf z=j~l@KWRr1hl}o0IL}>S+UB67s4B$mInDXl&o>>h69hM~iWn-h+e=RN=X zr|R>E;`q~=%S;$n?Xt11+_TQ%)0T_E2FeUGzA()C_MLOaYN-UX^0N80wpM>G{hGDQ zhhcq*xS+Im-LqG3O6qEDcXk9W*Uqw+XVKIAEv>=1z^zmu#$V4W-d&t?L0Y7GBZJfw zK_D@Ww~--CLzszi%Z+a*&o7*Q!Gdv3#57HX2Gdgw4h-30R!t@h$M)~z`?lTNZ30`v z+Gz|?FP2?Me!#)_K$yXX@c@X}64H76fFRQWa6nAwKCr3&;a2gdOa>vWhflLFcs{$( zSogbxg_1Huc8C_knsf!R6)m6_+I#))?_IEI)9_fz@Q|R z!#QCs1AD?Wj(3NdI#yWnPEvMYp5f}I(9kYrAM3NoiQ#`}r^4~SbrTuHLM(ZOlmrfF zhbr!v8~1JhjJ{hp?%vk_`SxA)>pzztKj*mbrU^?&V;uumf z=j~nFJmEkQhlklmxH2Le1(%#=TF|ysB{qhEcgfZ0#LR8=T&JbJq^KJFh`|*3K zHt&?%U;jJev52xS!|#~?GWqMiyB3M-&iKM;a@AtS!`E}KKjwdLHUH%do(GNV*4O2% z`+uhHyM?FqKF${7hQ293zPL*;%ws$t$uI{iq7Cw#=F_zpOw$=;XVmF_7BM))@BwH^A_MFE)87;l83f%5b}V6h z5zxt8AZp?Ah(W36!T(9@1u;wO`2-p{4umf7+sB~w{`*HIjh`Y0O34g@c3*g(@GO`V z8saH_;K`$$%8w_a9ammr-SGIu_uYRM6tM@a{4@L7(m#wlM6aBZcW4p3;vorA_d6|M zYY^LpZNiSnS06~S%m2II-}4oN(z~^6vH7f=WfQ+JuDP1esr&AULej6N$*(KtarrO^ zuI3Q3*&6G_DzNdEkXz_##?3r24B2iQT6h(bBoFRa+@R#ZzQL{U07KZS@a8`}59Z~v z^n@N@(8>Yw1SK4LYXx=kie#AGU3l8mmv67-4{X}KUwO}tnaeF$dkR=BBCh4j8#b`1 rE&g1hxP$e;P9|uKfTM*X;!eD^eA>}v&c@e)>72pS)z4*}Q$iB}YBMdf literal 0 HcmV?d00001 diff --git a/thumbs/wall_061.png.import b/thumbs/wall_061.png.import new file mode 100644 index 0000000..312412d --- /dev/null +++ b/thumbs/wall_061.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bl3kxy3i0hklf" +path="res://.godot/imported/wall_061.png-7662bd0796216e92122954c106d7ce89.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/wall_061.png" +dest_files=["res://.godot/imported/wall_061.png-7662bd0796216e92122954c106d7ce89.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/wall_062.png b/thumbs/wall_062.png new file mode 100644 index 0000000000000000000000000000000000000000..4544de4bb26a5fc2dff9d9d5d7dd2ddeecd8e94f GIT binary patch literal 752 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-HD>U|Qwr;uumf z=j|QaJmEwUw};m?JVH{~znGM~Y3w_?QE+<8(+iH`vm%mIH0E$lo4GOlkNK~6mdm@8 zw127C?=#-1T>16i;p6s(IqRp{HR#S}c)-apk1E8yyO-E^gyh@t|Nr;z?%&hr?f2Q- zdtvf6gzZ2?|NZ}aUnYB$EpF80Psl4ixaTh8WEFd9XXOUt-&>iNRsWj%D$2JUOM*{|adxG?;9#So!e+hDeu`GDUlo`$nlr~Mk;)B_|L z^i6-c>4e%ca9_#26~n9^%4or=7B1Z2yH1Z``GF;`m^@qz7T#i*G+Xh7+^uM4bryy) z12zVI*2RVlDoPTa%nE`B9dsDJ#oI85&tuYE-zcoqaK!td-%^I0YsPUpO)5tj&iJtu zFr0K1*s_b&hh+n=4JXS5c2|XlyA2#H8{~N!8QPc>1r9_AurOJOFf=msl`=TKKF=t` z=#xEl(`5&SVkw6UpTrCV5B%x!W!kU)VG5U`hB;%JtVrwbxxP*p^=Z{n&hsNyCxMf;FEQeywXg0szu(PNLwn|9_4 z>P@*33@2w^Uhr2oK**xO?vshYf#NIG%#3ebofR4yJ%IMJOF3W2&05na%qWwaBUKWA z`#zHz(~Ov_-cG#7%vZS=e9ydD9Al(@fHPF`e<#BSswIf{I|cFobfo`Z1}0$!Pgg&e IbxsLQ06`BLj{pDw literal 0 HcmV?d00001 diff --git a/thumbs/wall_062.png.import b/thumbs/wall_062.png.import new file mode 100644 index 0000000..85366dd --- /dev/null +++ b/thumbs/wall_062.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://33vtilvkfhl" +path="res://.godot/imported/wall_062.png-a2333ed2476f9984836ed6570d18bb01.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/wall_062.png" +dest_files=["res://.godot/imported/wall_062.png-a2333ed2476f9984836ed6570d18bb01.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/wall_063.png b/thumbs/wall_063.png new file mode 100644 index 0000000000000000000000000000000000000000..7551f3764480ba44c98bf01dd01c7f811d11ee0b GIT binary patch literal 740 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-HD>V4COY;uumf z=j~m?JmEkQhl}Y)^v*C%Qj1mbayibnNo>{<5BF;mgswf{+ub6Y!uXLd$#A8UV4A@R zHM#RQ=Kp_ZdsU-%zRC6T*S5>}`<*{G-zj3f7yp7yJPhX;9#Dsfn=Y52Bfsu`?w{XZ zp7@s6R)73yaX3W9m*KX~`**uv=T2NRd!Enk*SEX%*=M}?Kgq6P-?Z}6?{?)I2!3@< zW?){+e%a=ahQ-Oc8exuf2IZ9>Z^|b!RIo9mGZcUb#WepNjsPDDJ11e_tb1Ry7Py_fnlw)%ZII>k{@scFbK*C0O z%hrYWTD|*^!mCRxSbGYX-@NJ1o$$1|;luI8)tSl_|3Bv5baZ>-%`iuw5gfAAAifK? Y>t^%ax!U&tm~0t5UHx3vIVCg!0Ebr+1ONa4 literal 0 HcmV?d00001 diff --git a/thumbs/wall_063.png.import b/thumbs/wall_063.png.import new file mode 100644 index 0000000..c1e362f --- /dev/null +++ b/thumbs/wall_063.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dy1uco0gdpw0y" +path="res://.godot/imported/wall_063.png-0840cd8ba105f347650428a4b00950c3.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/wall_063.png" +dest_files=["res://.godot/imported/wall_063.png-0840cd8ba105f347650428a4b00950c3.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/wall_064.png b/thumbs/wall_064.png new file mode 100644 index 0000000000000000000000000000000000000000..ae41973052547d25ff00acf8c5b6f2a113e1dea8 GIT binary patch literal 777 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 bww`fiNDTjufYJxROvB*m>gTe~DWM4f5>rpp literal 0 HcmV?d00001 diff --git a/thumbs/wall_067.png.import b/thumbs/wall_067.png.import new file mode 100644 index 0000000..432c98b --- /dev/null +++ b/thumbs/wall_067.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://nly86scuolck" +path="res://.godot/imported/wall_067.png-89dde7c230123a94a0cdf39a159c7afb.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/wall_067.png" +dest_files=["res://.godot/imported/wall_067.png-89dde7c230123a94a0cdf39a159c7afb.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/wall_068.png b/thumbs/wall_068.png new file mode 100644 index 0000000000000000000000000000000000000000..66d76dc504f60d0093f398d2ea9a1d939f9de7f8 GIT binary patch literal 945 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-HD>V9xe*aSW-L z^Y%_)-em`gBOf^*F&<$pVhUKjBB-fKxQg*X$y>&%?w0lglApY^t}J6Z)V%Sjir=HH z*UQS&{s~Q5>Xfu)f6cb-L2lyV*P|_N#_`rN<=xuYkpyl?Xna=4et@l|lkeP0Q^Q@sl=oZ{ZG`_0wauA2Hk>ex11fB5LwO~aa% z7h{<6#4hv2&;5RE0-MA4LM4NS1*-)A-1+nJr_G~OhJ%H^Ow1V~{7gm+w=d1NyQls4 z1jCfq%+9|!IvA(C7IONwOEZs|*@)rOuU$4vCQCHfD4!5!WjHd2O*3Dlm@#9E(5=f2 z+zyYU{F+*vzTsMCtk4REJ7>~wI=-H`=JO5@)`aC6*Hi0Q z_Ao3el{+~7edaqRrZ)_W?#}(}$CSqq_}JwDzrrhHtNUja?HLv{_e#mJNHJJ-GB@%y z_-)I+?7o1R!K3Q@zSUb8T=M?D;hYdRkIDKaBf}ykk4kZY0M-XxC5%6U7#ai|K59R- zl4O);5TC}_;m^p-utYF`DPzmLMI0K8HM7ni%43s0me3~T5NFWTAewrEjqL;@gJhGQ z9IvF^-v)+;J$eE)el^k(0!$1hJ5)GSSQ$8WsBAd%!}uiQ3F9W6NCtU{3IKaSW-L z^Y)Ho-em`gqaVeOFddOp+Qnqr?Zxty>ny8=mbsQXr+36Np#y?lMT}0ZcUT3)R^DAQ zuki7ac_sI%>sL;?YPM4Q|EHUC)g)!+&(V9BQeE^ywxIni!x3YKk30@G%mU}B#GEHr z#l9=6?4$0FpARo~XH}Q{)VlgEMVPlC;`8eJSHHRnipHsf9K!3ZHK3yH`{0QYlgT~AcKQ&liAt&J0Z92yX~v*$Gq@3G zZt2Swk~rY^Q9*%uL(FfFkDEXB^BkzsG4Ll8-LYBAJ2r&nw zv7|0yVDN7aJ;ZQoi=YGp!_!Qld$zi7(D?UtgZ#@!OczcTZ`z{9DB5tc~f0jvovq_YQLu#j>(QFqZuLlXK7W04IY%lkQ{I3*I&2?ROZes#o&yGg&cg zP0nNKy~yYh{f|R~amj3^%6$qYwq6VlQY_tvgdKL>k^jqJ*&q`9z~*tNLxT*%gl|;} z$6qk+c=m!}4(mVFH<|+dd=6{k1Oyx=F$(lNV0brMghBp&6)*wD^WW(gI&iZ@W{-r9 zano)M#wn(XE3OJ1TtEBI^hU-a28S9cmj3MzR2HxYY%^^Vn_GXbT2exQi6N)bOJFur z5JST+O~=0>3hWEcaD<&?VlZ3YsKu1YklM>}!non~qHcFVQJn~$2XP0(B{s{vbzl?7 zFp|BlI6=vvp)HAHo#(Vh#)N{JqEnx5f4TAI@b#?UyCNRR9@J8Jz`3FH?%v-g9-m@} r64_&R!e&0xkV3zQ7aSW-L z^Y*4;&}|2awuk;RW19O!Dwt$NSAJv_T9*)Xe9qA&J{GLc6=E;_WMUNFzQjW(DSDFX zo^6}{f47^OAaP^n|EudJbT6KKS^eO()%(O7>I54snGD<+o^c$IVVt4NP|T9h$8d&x z!S%o69JIDypFZ`zy+vJc9RE4Hx7n6AIfNbNzP$VW(=NS9^|CVZ)2=sf{^)n@i#?~j zL-^(0@=r@wC)|_MtF^6|9&W<2Vd=~5&lBqG{=6zw)j#aKz>>*B<@oM+C5CE{+k&)y z#W|F-Oz@ic^be=PRHsWvuln9U{h|lzXmPcMhfhoId!GoJ!SKO|Wx|2KI_Iw+5MsOm z_nL!}7o6TOYzW-J zaP3`bS)}uTrv(zkGMNdd>8&zt%TvM zyW^~rwGz*Niv@7WHEenOyz$KYx|0eGX^d(+mKHG1=~v6XfBSgggw+L%R}`DF%owj2 z^&ik;I4@|vnakmkMuezQ!{>`jJ|z}3a?ESxNm!`a`!ShLv^ZD`Yp` z^b@daX!R4^@~87oJhQhOqlauCOaJWnNs$bfeocH(Cvt;z!-iTG!$TW*9ir~>#*{O? zW)PdBtkAIEY_CmJuYwmB%Z8*Iuk2ej9;-Ka9lp54s>PyMU(lg>7e`wEX9GhKclG7| zwfaiz+vnR)yT18m%=_cU~2MoaSW-L z^Y*U2pR}Wd!^iW2TRg?}7+8fCIXrS%$=tq>t&ef}f+npP1woMo4NvSRX(s48luh}1 z?p?;Sz42Si5^E>jKesMTw{pwwdJF!<+LN{opNtqRm>Z0#Lfk%K>!8Ix+kX1K{af4mLn7=kpuyy-V!umSq3!6olm`cC(VZiq2pvkpi)xIexb z{7%rykYUFvrVkSfszX^9eB)7Q3@T?-=3zJwwS;HE;--2Y5kaAkz1V+d@{-4@4ClOIfe7_I1>C(1+YC$R&yGL93rv~}p00i_>zopr E0Iu!{C;$Ke literal 0 HcmV?d00001 diff --git a/thumbs/wall_071.png.import b/thumbs/wall_071.png.import new file mode 100644 index 0000000..864bf5d --- /dev/null +++ b/thumbs/wall_071.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bgcjm0epv3qkp" +path="res://.godot/imported/wall_071.png-b70359800c74e5edc5be0c7196471436.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/wall_071.png" +dest_files=["res://.godot/imported/wall_071.png-b70359800c74e5edc5be0c7196471436.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/wall_072.png b/thumbs/wall_072.png new file mode 100644 index 0000000000000000000000000000000000000000..b40480b3aaaff44d1c53d81bb763613e52506ff7 GIT binary patch literal 835 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-HD>VEXIn;uumf z=j|=qJYh$fwvXk4<%)iZt2_!AEtq8vOzC3@VM)wtnj)6R>dJBbK%p#GwYblt{*QiT zGyea!aW(N2dF%1{^P8$UX(o0%1#f;^@P%bX4ub(d!!yPMHViY^89p;4$T6H@Zm1+% z@ZRA|!Y8gCZPzdV_vgopLi4(Bk4^?$Ub)PG!K}3M>ssl2r%&a_-5+0Fv5`So&LL}h z`2F1AJ6M%i+6uO?OqlchmNyrVLZz>7K5HV#;N=q-mTm4_wvxX&H;u!IDP#6I zHQQ-LzvK1#8(+5zNi}S7DYy}Rc&p=$L(Cbc`xjii`SZ1$@h|&Lj0#^JC;ZsmwTVeV zS5U=~<6l4q`+~LlO&TgWj2@l49WTs1AmuRIn2BMHSG8G3GXul_Ey9j-woYehu)e)h zn#GBsK{wZF1ILH^2XfD5)D#6*37M7{{=U^K-o5i)?W+GG0ZHsPc0UO|;>G0PbaHuz m=n>rmHf2;uPDrWoFWdHpNGqZ33#@^;g2B_(&t;ucLK6TK^h*2y literal 0 HcmV?d00001 diff --git a/thumbs/wall_072.png.import b/thumbs/wall_072.png.import new file mode 100644 index 0000000..abcc0e7 --- /dev/null +++ b/thumbs/wall_072.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cewasyojsk17n" +path="res://.godot/imported/wall_072.png-2ad893f4e196bb08701bbd37a5a055df.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/wall_072.png" +dest_files=["res://.godot/imported/wall_072.png-2ad893f4e196bb08701bbd37a5a055df.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/wall_073.png b/thumbs/wall_073.png new file mode 100644 index 0000000000000000000000000000000000000000..8cee78c4e35937ce3e75da970b82664538aa337e GIT binary patch literal 797 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-HD>V7l(<;uumf z=k1;Sd6xqu96suIaGr8$=MX7XW0qcjVV}dp*v|q_WfyrYb)NX+vXO`YkD{jM+bw-_ zcYL>gZhqH9Zrzi|ub)J{d~o)5dA(DF|F3xszfu_r*cj5OLVVxyp0gyis3h>`_lpk? z7TMTYudr#;@ntAYn;w4pfw3l&<$?reOmj8-AYb%}NI>6t^Kkak8rlf=NSHUyu|9z5hNZuL7 z#C*eR9tTfCwxyCmLs*#dihqlK?2vSDXA}JR@bc?@%P-Dg+!FR}?Ewa>z&sWNV?$|N#WtYrEy zv7mS*Q$R7>g~p(AMr9s`^9&Do7|t;~xWpRp==|niQ}h^2CmS`?u47ud-a?bP*|9qd;Y{8;9#!Uux2|8 zbH;-*(-WU$4=`*is`|I;y=KWVsOP~UKpF8)|I*#)nq0r*TY%}E!PC{xWt~$(69A>4 BNU;C_ literal 0 HcmV?d00001 diff --git a/thumbs/wall_073.png.import b/thumbs/wall_073.png.import new file mode 100644 index 0000000..ef9456b --- /dev/null +++ b/thumbs/wall_073.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cqe2wcli55th0" +path="res://.godot/imported/wall_073.png-83ec490132b1fd9ff3ed7ed6e1229aaa.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/wall_073.png" +dest_files=["res://.godot/imported/wall_073.png-83ec490132b1fd9ff3ed7ed6e1229aaa.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/wall_074.png b/thumbs/wall_074.png new file mode 100644 index 0000000000000000000000000000000000000000..323c2b93b5016fad89b62f7d175c280cbe45843a GIT binary patch literal 876 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-HD>U{>>VaSW-L z^Y*TxpR}Vy+r#|DG0kR^G+*psx~&#;LN;hw$twq|V0H6{N}W@taknH~p2XCX`zH2% z&-J)x|L<*&ii|V7WMiG&s~X(v=O^#7ZLee%gGmm90YAet#sfACGuRnEGbG3{oMCRL zBwO&_?Se@$1{1 zV0RBFc*vk~ex+qo0fX4g^EtGFcvv%fBUGllR$e(fP1BNAMmYW<}e0Spq1~JKX?`65zALQ6XR_kVKpQxzr zY-PR>@-1fDy@-7R(hS{3YHR;g=AGek_!c&y(wj4qae~8#O%oW-9h=-M&-VPSN&i8C z78Zl`ya$tKZjSW)pZ2}-`@T(1%oApXH_zSH>h7XIZ7#&*}HY}{N zscaIEXJm-Vaw-siA`vlZ)y0!94_|23Sor#V_kZOY^WE2v=Rcj#U|R0!;uumf z=k0A@KaoHYhlkO}j+*clwERB6*yqq|&s=Y|R9W^#S(WtNtqd|Ar5rC8t?pu9f8X|b zj~34f-yb{ruVn96t8N%VGxh1P_+~hnYHN?Bg|3c3_rJQWiMi8@$cYjfH84 zFmEHnw~`F$lGy2NO$_fcc^upPnfXiAm#1If+Mcm+|Ni=S^M3E^U(Fw{h($ literal 0 HcmV?d00001 diff --git a/thumbs/wall_100.png.import b/thumbs/wall_100.png.import new file mode 100644 index 0000000..4f5ee7e --- /dev/null +++ b/thumbs/wall_100.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dioish4lg282" +path="res://.godot/imported/wall_100.png-8bab351ae8e296ce26ecad69dfe5f0cd.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/wall_100.png" +dest_files=["res://.godot/imported/wall_100.png-8bab351ae8e296ce26ecad69dfe5f0cd.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/water_tower_001.png b/thumbs/water_tower_001.png new file mode 100644 index 0000000000000000000000000000000000000000..5226d4ca998ef4656d5540c3e38705615fbfe929 GIT binary patch literal 2015 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 literal 0 HcmV?d00001 diff --git a/thumbs/water_tower_002.png.import b/thumbs/water_tower_002.png.import new file mode 100644 index 0000000..6ad256e --- /dev/null +++ b/thumbs/water_tower_002.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cqerb5dftnhky" +path="res://.godot/imported/water_tower_002.png-b651c93dcb12ea354ad7f3e281a6ca10.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/water_tower_002.png" +dest_files=["res://.godot/imported/water_tower_002.png-b651c93dcb12ea354ad7f3e281a6ca10.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/water_tower_003.png b/thumbs/water_tower_003.png new file mode 100644 index 0000000000000000000000000000000000000000..ea4263feba6f72e6c2dc1b0ea602b1e77bc1207c GIT binary patch literal 2053 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 T3-|JrDgg@u%`xkD;fZx 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 literal 0 HcmV?d00001 diff --git a/thumbs/wheel_004.png.import b/thumbs/wheel_004.png.import new file mode 100644 index 0000000..fc5d444 --- /dev/null +++ b/thumbs/wheel_004.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b1t3f3sgiu15d" +path="res://.godot/imported/wheel_004.png-a0711a78e020f0781b8804d92f5087bf.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/wheel_004.png" +dest_files=["res://.godot/imported/wheel_004.png-a0711a78e020f0781b8804d92f5087bf.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/wheel_005.png b/thumbs/wheel_005.png new file mode 100644 index 0000000000000000000000000000000000000000..8787074ad89c3b2ca70186d4a85a9892de016997 GIT binary patch literal 2428 zcmcgu`#;l-7yoQF#==Zt=rMW{$)y~F0(H(v3Wede*b{y^*ZOgU$1k{FYov3yw2-Qv9mcNE+#Jq0D!oqg{i|X zlK)MZ@NQ+E_UPUPP>91BW1!}v;yeI|>RX!P9U}^s3fw}Zhf$q7*ZK(0)a_1k;q}%; z-6a5Yzij_8J(B@qcRQ5WD}I5i`J2Ln721puKi%#BNG`T4gD@^xnRY!mGBP?yWu-Ml zHNL#pYvoTFpW8f|7VbRYn==PP4xd+>g2C0i$9(pO$&PiPRs;R3X1J;ohC=S}>?_x}x1Rd!Lt>$H_Iv9G ztZZ?EFAEKx7dOTd3wWy1ohqZIjb;OKr+3Chgd!fkzMH>iWvhid9Lq`b-3Ji;BS-c3 zggXAt24}?&jXEAA2gs(Z#N1GkMX~R<934xIlOF2!>WYWc?Qq3*rp0z-k{dRCk5!Bd zrQ;YG7A{yDyS&ANFb~Lrw~C552QcEyCx?MYT3(8on@8^YfXJ_=`DI$$TQ9fd>d(;-Vu&0xQuzZoFuae0 zM9Ja~#jYi9_p)AxZ|o#_`aqJ5LFpuA#hVdII^z-u1a>F?y@7xlo}@?;Vro4!1P^`K z$19}G6|RQp)`ptR6D)QK7(&v8_CY)Z8Rp4*z*p;F^1SJ7NE?5C&V5@iL3J8Mv)Y@J zqo6=^lXWGm`Ag;uT?~?HFyzhVFVpT4Uobz^)5{v-oct2b!fAh1Fh2Re&PGD%2K9r! zn9shLQy0!NZ8c(&ga2wW(<>so9O%FIRQS=#&LneVVi})oQ3eI>AuZ-{FOYo;ngFhH z(0Df*MmlIOd_)gi)-&IaJe=BV1lc_$ZSn3;ZCkPata!EZtB)c>P-| zg+dX9;K`pp*#qt0yL0R-2j56?V#iCb_5GIQo0l*8O+p-mZ&AL_tS!1H$4CcuuVo^q znrabXqpV8G#wmD$S|SdSn>;x?t2#S3$6e=(@QA*ieH`9kv56f4@8dNGr!{GE!zA!R z1i!3>lUsrU5z8`Na&uh1VW;Kk^sE7h_Sx@nIDA*5nuRw(ieF!ZE@TgDJ0Gq`Z@^=7 z1to>IGkrj`=}ChCGORNQU22Me*i9}{vj%RjcFKnyGTJ&7+tMMkWL89X&01y_ck+s= zG6O(>f@U=c)eSfhF1!q@b`AE31lzA$nQiS^iF>o*yHA@tTBEdh z71~gEJnRZivdt)kHTUtF?U>v(BdqU+WYV2hksVhskVQDiYm)?s%$muWnLppXdq>N9 zHiB1AvS&0cgew{b|CtGO^nXPj(TgV<*@WL z=PXo1!$eOY1HdwuV7b`5*Mv6J4ye{ zj~~|sNEwiGDy!gA=lyaEb?nlo*;8-Sw<7CZI@TA4kLv0sR8**+wa(kz@@-1(?X~s~ z3>4BqDPR1-vTPsP;T|Ci9IjA$-~ihGN{MAbif4UF)W&l0`1P?6KR-XUY{FG>TGsQZ z4XxC-D!*q1D;5Np_{JEC5(pS%rDo?jBbXT$VWZaX-+W zt>H}E`nBX1|3F^KqI}z}8GSTvW%)iF^hdP;vQq_ir3>J@Ty#qs5_6A<9HLeZ`Zmv$vtlb; zaGt<(x;jEIWl^>4ERU!4&qG%D63z4mj1*+%EcwjB9n&5ss?jYcF?Z_8fIf`8xL&^X z;^JcaYAcm{lbT1)g%K*3%l4kYlWh>~98%r*H#|mdKby6GPYaT!)Yt9hT^+<-eBV~9 zU6A{_vw;=nRBKfWJFNdz;R(8G_2d_yC|JBdMxYWrD4fFMeVL?&u%tQpH3j<_&Oadb z{G|geHE6z1<^^e5qvqzx07)vRq|97mEl(mP}1xl$Vm)sPLYYu z>+&mn&`#nsI)$BT=RmxpPPg7}`puegAirI&ZaW9`KM5G>t>H63iKw6BCg48K7q(vj zfiV~5ee1r(IZZw;eGEujsLj1+U9FZblhcteu+MKNp{&OP<2jeh3;ArJKnp6r6Q;1*6|n|gqKHF=Y1rl5pqs5Ch7vxY0Xwm1NS-;GrSzYAhX3;=1v^5K XlSfBU}E=laSW-L z^Y+?CFJ?yx*N27*W=*XMUb6(I3QWy-{Cj^>ms^w6B^K8W0y!=Lt9jof6&&^bcXrSV^=Ce0UJa5AR?}xVBoW^z9<~#rp&x!w#~9BJPUi=*e0BG zx=_>0=djDsY7ylK!DGb*adwOXujoU73y@YK7V~X43%r7kkFBs~KUX(9Z*O|&F z5_7i?%$RcF-p#Ig8w}V24t@DqT6XX5J)W2#Tjn2&mrvh*vvToQ!5vGa*go*TpZ|L2 zZ>>57-UUua`JdeU=y+k$C!T~xy}WnD-!CuzyFm4`U{dgOaSW-L z^Y*T5K;?8RiT)5p#+0%@ys9>MHs#8TxKbhcHZb#jsw; zx|Zbc;dii}ee=^-+#jySB`bexQF&t4@b~fN8^V(&+-5M531N78spbvm%x10yw|Da^ zwgg1Y=-s1Y9l*Hf^ zu0FTFxHwz)(WH-t4T`e!;%chTc?+<8aR2MLM(3Psl#vwk5B2NY`I+CRb)BENe@hZW z@|Q10e;+TMTD4WiO#8HOoJoe(H-=SZ%cZNGI1cJF%p2g~+{?HwRFh|k?v?4lgu~$J L>gTe~DWM4f%BkXW literal 0 HcmV?d00001 diff --git a/thumbs/wire_002.png.import b/thumbs/wire_002.png.import new file mode 100644 index 0000000..0b958ba --- /dev/null +++ b/thumbs/wire_002.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cn2co73gakqqt" +path="res://.godot/imported/wire_002.png-ea6f3513581dbf00195cc2ca794b7405.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://core/thumbs/wire_002.png" +dest_files=["res://.godot/imported/wire_002.png-ea6f3513581dbf00195cc2ca794b7405.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/thumbs/wire_003.png b/thumbs/wire_003.png new file mode 100644 index 0000000000000000000000000000000000000000..f8823c53f602911b3403ac0e38af645a5893ef23 GIT binary patch literal 620 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-HD>U{dpRaSW-L z^Y;3EZRbLn_K*5or&ur5P`j1nE&cQ3|NqP!-fqz;B1`YA+$tr0i!;#pwq5r5&%1ub z?0aofdTyp>IRE`g8`2iDYfNK2AjvRia1p+>48O0geZeW5`-<7ZZoil2(kbzA9C1c7 zm)SMUyY|@oOG{@9=L7Y9at|24#PJtzp8G(x@B-tPExUKVxp!BOO;6IE`Ny*_iv(>G z*YGUhubz7L1*dW{L#@TiSa*L3NoI))TWTz%4m8-+TZmno#x(s;KO>Lh=XaXB`OCZ- zz5ktKXnXTw&Ahu)FS$LK^iSdd$JJNnH)HjlF;D+_YwB;E#IK0i%yK85&d`i%)^QF#a5(io;-X5{xVs0>Iuow`cn%!%He)qIP STU&w2hr!d;&t;ucLK6U(@Y- String: + var out := "" + out += _header("Kamera & Steuerung") + out += _table(_rows([ + ["Mittlere Maustaste ziehen", "Orbit: um die Karte drehen"], + ["Mittlere Maustaste + Umschalt", "Pan: Karte verschieben"], + ["Mausrad", "Zoom"], + ["Rechte Maustaste halten", "Freelook-Flug in jedem Werkzeug: Maus = Umsehen, W/A/S/D = Bewegen, Leertaste hoch, Umschalt runter"], + ["Strg / Alt (im Flug)", "schneller (×3) / langsamer (×0,3); Mausrad ändert die Grundgeschwindigkeit"], + ["Umschalt+F", "Flugmodus dauerhaft an/aus"], + ["F", "Auswahl ins Bild zentrieren"], + ["L", "Höhenlinien fixieren (sonst nur im Terrain-Werkzeug)"], + ["H", "diese Hilfe an/aus (Esc schließt auch)"], + ])) + out += _header("Objekte auswählen & platzieren (F2)") + out += _table(_rows([ + ["Linksklick", "Objekt wählen; Umschalt/Strg+Klick: Mehrfachauswahl"], + ["Rahmen aufziehen", "alle Objekte im Rahmen wählen (Umschalt: hinzufügen)"], + ["Bibliothek: Klick / Doppelklick", "Objekt auswählen / Platzieren starten; Klick in die Karte setzt, Esc bricht ab"], + ["G", "greifen: Objekt hängt an der Maus (Klick setzt, Esc zurück)"], + ["Pfeiltasten", "im 2-m-Raster verschieben"], + ["Bild↑ / Bild↓", "0,25 m anheben / absenken; Strg+Bild↑ = auf den Boden setzen"], + ["Strg halten", "Snap-Zwang auf ganze Meter"], + ["Strg+D", "duplizieren"], + ["Entf", "löschen"], + ["Strg+G / Strg+Umschalt+G", "Gruppieren / Gruppe lösen"], + ["Esc", "abbrechen, dann Auswahl aufheben"], + ])) + out += _header("Objekte verschieben, drehen, kippen (Werkzeugleiste links oben in der 3D-Ansicht)") + out += _table(_rows([ + ["Verschieben", "Pfeile am Objekt ziehen (X rot, Y grün, Z blau); Mausrad ändert die Schrittweite"], + ["Drehen", "Ringe am Objekt ziehen: um alle drei Achsen, in 15°-Schritten; R = 90° um Y (Umschalt+R = −90°)"], + ["Kippen", "Strg+R / Strg+Umschalt+R = um X ±15°; Alt+R / Alt+Umschalt+R = um Z ±15° (auch beim Platzieren)"], + ["Spiegeln", "an der Stelle links↔rechts oder vor↔zurück (Panel Auswahl)"], + ["Strg+Z / Strg+Y", "jeder Zug ist ein Undo-Schritt"], + ])) + out += _header("Terrain formen (F1)") + out += _table(_rows([ + ["1 / 2 / 3", "Heben / Senken / Glätten"], + ["5 / 6", "Einebnen (Höhe vom Strichstart) / Rampe (Start klicken, ziehen, loslassen)"], + ["[ / ]", "Pinselgröße Klein / Mittel / Groß"], + ["Linksklick ziehen", "Boden formen; Strg+Klick = Gegenteil (Heben ↔ Senken)"], + ["Tablet/Controller", "Stärke folgt dem Druck (Maus = voll)"], + ])) + out += _header("Malen (4)") + out += _table(_rows([ + ["Material wählen", "Tab Malen: Kacheln mit Vorschau"], + ["Linksklick ziehen", "Material auf den Boden malen; Strg+Klick malt Steppe zurück"], + ["Kante", "Regler: hart ↔ weich auslaufend"], + ])) + out += _header("Bauen (F3)") + out += _table(_rows([ + ["Teil im Tab Bauen", "wählen, dann in die Karte klicken — Wände rasten an die Zellkante, Böden/Dächer in die Zellmitte"], + ["Klick auf Wandoberkante", "stapelt das nächste Geschoss; Klick auf die Seite ersetzt das Teil (Wand → Tür)"], + ["R / Esc", "Teil umdrehen bzw. drehen / Bauen beenden"], + ["Gebäude", "jedes Haus ist eine Gruppe: „Ganzes Gebäude auswählen“, kopieren, löschen im Tab Bauen"], + ])) + out += _header("Spawn-Zonen (F4) und Test-Start (T)") + out += _table(_rows([ + ["F4: Linksklick", "Zone setzen; Ziehen verschiebt, Entf löscht; Team und Radius im Tab Prüfen"], + ["T: Linksklick", "Test-Startpunkt setzen (nur für F5, kein Spawn)"], + ["F5", "▶ Karte testen"], + ])) + out += _header("Datei & Rückgängig") + out += _table(_rows([ + ["Strg+Z", "Rückgängig"], + ["Strg+Y / Strg+Umschalt+Z", "Wiederherstellen"], + ["Strg+S / Strg+Umschalt+S", "Speichern / Speichern unter"], + ["Strg+O / Strg+N", "Öffnen / Neue Map"], + ["Datei → Hand-Haltung der Waffen", "öffnet das Tool für Hände und Finger pro Waffe (eigenes Fenster)"], + ["Datei → Updates prüfen", "prüft auf eine neue Version; Banner „Jetzt updaten“ lädt und startet neu"], + ])) + return out + + +static func _header(title: String) -> String: + return "\n[color=#8cc9f2][b]%s[/b][/color]\n\n" % title + + +static func _table(rows: String) -> String: + return "[table=2]%s[/table]\n" % rows + + +static func _rows(pairs: Array) -> String: + var out := "" + for pair in pairs: + out += "[cell][b]%s[/b][/cell][cell]%s[/cell]" % [str(pair[0]), str(pair[1])] + return out diff --git a/ui/help_text.gd.uid b/ui/help_text.gd.uid new file mode 100644 index 0000000..c1a819e --- /dev/null +++ b/ui/help_text.gd.uid @@ -0,0 +1 @@ +uid://cmq500ivk0ro2 diff --git a/ui/inspector_panel.gd b/ui/inspector_panel.gd new file mode 100644 index 0000000..629dfa8 --- /dev/null +++ b/ui/inspector_panel.gd @@ -0,0 +1,700 @@ +extends VBoxContainer +## Objekt-Inspektor (Karte t_bb0d11c9) — Godot/Unity-Style Eigenschaften-Panel +## oben im rechten Panel: Position/Drehung/Größe der markierten Objekte +## TIPPBAR (LineEdit) und ZIEHBAR (am Label ziehen, Godot-Konvention). +## +## Verdrahtung (main.gd): der Inspektor wird in _build_right_panel() als +## ERSTER Abschnitt eingehängt; refresh() läuft in _selection_status und +## _sync_selection_panel — damit füllen ALLE Auswahl-Wege das Panel +## (3D-Klick, Rahmen-Ausziehen, Map-Inhalt-Baum). +## +## Regeln der Karte: +## - Änderungen wirken LIVE im 3D-Fenster (Marker direkt umgesetzt, kein Rebuild). +## - JEDE Änderung ist EIN Strg+Z-Schritt: Tippen = ein Schritt beim Bestätigen +## (Enter/Klick woanders), Ziehen = ein Schritt beim Loslassen. +## - Mehrfachauswahl: Änderungen wirken auf ALLE markierten; ungleiche Werte +## zeigen „—“ und werden erst beim Tippen/Ziehen angeglichen. +## - SCALE IST FEST (Karte t_e166e656, Sly-Wunsch „Realismus“): die scale-Zeile +## ist bewusst ENTFERNT — neue Objekte bekommen immer scale 1.0, alte Karten +## laden mit ihrem gespeicherten scale (Format bleibt kompatibel). Hier gibt +## es nur den lesenden Hinweis „Größe fix“. +## - KIPPEN IN SÄMTLICHEN ACHSEN (Karte t_e166e656): das svmap-Feld `rot` +## (Euler x/y/z, OPTIONAL) trägt X/Z-Kippen; fehlt es, gilt rot_y_deg. +## rot/rot_y_deg bleiben über SvmapIO.rot_setzen synchron. +## - X/Z werden an der Map geklemmt, Y an den Match-Grenzen — Versenken UNTER +## die Terrain-Höhe ist ausdrücklich erlaubt (Steine im Boden), die +## Info-Zeile zeigt die Versenk-Tiefe. + +const EPS := 0.005 # Toleranz „gleicher Wert“ (Anzeige-Konsens) +const MIXED := "—" # Anzeige für ungleiche Werte in der Auswahl + + +func _clamp_norm_deg(f: float) -> float: + return fposmod(f + 180.0, 360.0) - 180.0 + + +class DragValue extends HBoxContainer: + ## Eine Zeile „Label + Wert“: am Label ziehen ändert den Wert live + ## (Godot-Inspector-Konvention), ins LineEdit tippen setzt ihn exakt. + ## Die Logik (Wert lesen/anwenden/Undo) liegt beim Inspektor — dieses + ## Widget ist nur die Eingabe-Maschine und ruft die Callables. + var step := 0.05 # Wert-Änderung pro Pixel beim Ziehen + var fmt := "%.2f" # Anzeige-Format + var suffix := "" + var min_v := -1000000.0 # Zieh-Grenzen (Anzeige + Doc werden geklemmt) + var max_v := 1000000.0 + var get_value: Callable # -> float (Wert des ersten markierten Objekts) + var is_mixed: Callable # -> bool (true = Werte in der Auswahl ungleich) + var begin_live: Callable # Undo-Basis merken (Zieh-Start) + var live_apply: Callable # (float) — live anwenden OHNE Undo-Commit + var end_live: Callable # (final: float, original: float) — Commit beim Loslassen + var commit: Callable # (float) — Tippen: Snapshot + anwenden + EIN Commit + + var label: Label + var edit: LineEdit + var _dragging := false + var _drag_base := 0.0 + var _drag_accum := 0.0 + + func _init() -> void: + add_theme_constant_override("separation", 6) + + func build(p_label: String, tip: String, edit_width: int) -> void: + label = Label.new() + label.text = p_label + # KEINE feste Mindestbreite — die kompakte X/Y/Z-Zeile (3 Widgetpaare + # nebeneinander) darf das Panel NICHT breiter drücken als das Fenster + # (Layout-Bruch bei UI-Größe Groß, Beweis-Probe 19.10.). Natürliche + # Breite von „X“/„Grad“/„Faktor“ reicht als Zieh-Fläche. + label.mouse_filter = Control.MOUSE_FILTER_STOP + label.tooltip_text = tip + label.gui_input.connect(_on_label_input) + add_child(label) + edit = LineEdit.new() + edit.custom_minimum_size = Vector2(edit_width, 0) + edit.select_all_on_focus = true + edit.text_submitted.connect(_on_text_submitted) + edit.focus_exited.connect(_on_focus_exited) + add_child(edit) + + func set_shown(v: float) -> void: + edit.text = (fmt % v) + suffix + + func set_mixed() -> void: + edit.text = "—" + + ## Probes/Tests: Ziehen programmgesteuert ausführen (gleicher Pfad wie Maus). + func probe_drag(pixels: float) -> void: + _start_drag() + _drag_accum += pixels + _apply_drag() + _finish_drag() + + func _start_drag() -> void: + _dragging = true + _drag_accum = 0.0 + _drag_base = float(get_value.call()) + begin_live.call() + + func _apply_drag() -> void: + var v := _clamp(_drag_base + _drag_accum * step) + live_apply.call(v) + set_shown(v) + + func _finish_drag() -> void: + if not _dragging: + return + _dragging = false + end_live.call(_clamp(_drag_base + _drag_accum * step), _drag_base) + + func _clamp(f: float) -> float: + return clampf(f, min_v, max_v) + + func _on_label_input(event: InputEvent) -> void: + if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT: + if event.pressed: + _start_drag() + else: + _finish_drag() + elif event is InputEventMouseMotion and _dragging: + _drag_accum += event.relative.x + _apply_drag() + + func _parse(text: String) -> float: + var t := text.strip_edges().replace(",", ".") + if t.is_empty() or not t.is_valid_float(): + return NAN + return t.to_float() + + func _apply_text(text: String) -> void: + var v := _parse(text) + if is_nan(v): + set_shown(float(get_value.call())) # „—“/Müll → Anzeige wiederherstellen + return + commit.call(_clamp(v)) + + func _on_text_submitted(text: String) -> void: + _apply_text(text) + + func _on_focus_exited() -> void: + # Nur nachziehen, wenn der Text NICHT frisch bestätigt wurde (sonst + # würde Enter + Klick woanders DOPPELT committen). + if edit.text.is_empty(): + return + if edit.text.begins_with("—"): + return + # Bestätigte Werte wurden beim submitted bereits gesetzt und neu + # formatiert; weicht der Text noch ab (Klick weg ohne Enter), gilt das + # als bestätigt — EIN Undo-Schritt. + _apply_text(edit.text) + + +var _main # core/ui/main.gd (ungewollt typisiert — dynamisch) +var _head: Label +var _sub: Label +var _grid: GridContainer +var _info: Label +var _hint: Label +var _ground_btn: Button +var _farben_grid: GridContainer # Farbfeld-Raster (Karte t_b0edb807) +var _farbe_reset_btn: Button +var _farbe_status: Label +var _rows := {} # field -> DragValue +var _built := false + + +func setup(p_main) -> void: + _main = p_main + add_theme_constant_override("separation", 6) + + _head = Label.new() + _head.text = "Objekt-Inspektor" + _head.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART + add_child(_head) + + _sub = Label.new() + _sub.text = "" + _sub.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART + add_child(_sub) + + _hint = Label.new() + _hint.text = "Nichts ausgewählt.\nKlicke im Viewport ein Objekt an." + _hint.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART + add_child(_hint) + + _grid = GridContainer.new() + _grid.columns = 1 + _grid.add_theme_constant_override("h_separation", 6) + _grid.add_theme_constant_override("v_separation", 6) + add_child(_grid) + + # --- Position X/Y/Z --- + _grid.add_child(_field("Position")) + var px := _make_row("pos_x", "X", "Position X in Meter — ZIEHEN am Label ändert live, TIPPEN setzt exakt (Enter bestätigt).", 0.05, "%.2f", " m") + var py := _make_row("pos_y", "Y", "Höhe (Fußpunkt) in Meter — ziehen/tippen. UNTER die Terrain-Höhe absenken ist erlaubt (Versenken, Karte t_e166e656), Untergrenze = Match-Grenze.", 0.05, "%.2f", " m") + var pz := _make_row("pos_z", "Z", "Position Z in Meter — ziehen/tippen.", 0.05, "%.2f", " m") + # Zieh-Grenzen grob an der Map orientieren (doc-Apply klemmt exakt). + var half_span: float = 1024.0 + px.min_v = -half_span + px.max_v = half_span + py.min_v = -200.0 # Versenken erlaubt (Karte t_e166e656) — _apply klemmt exakt an bounds.min.y + py.max_v = 80.0 + pz.min_v = -half_span + pz.max_v = half_span + var pos_row := HBoxContainer.new() + pos_row.add_theme_constant_override("separation", 6) + pos_row.add_child(px) + pos_row.add_child(py) + pos_row.add_child(pz) + _grid.add_child(pos_row) + + # --- Drehen & Kippen (Karte t_e166e656) --- + _grid.add_child(_field("Drehen & Kippen")) + _grid.add_child(_make_row("rot_y", "Drehen Y", "Blickrichtung in Grad (−180…180) — ziehen/tippen. Tasten: R (90°), Mausrad (15° fein).", 0.5, "%.1f", "°", -180.0, 180.0)) + _grid.add_child(_make_row("rot_x", "Kippen X", "Kippen um die X-Achse in Grad (−180…180) — vor/zurück neigen. Tasten: Strg+R / Strg+Umschalt+R.", 0.5, "%.1f", "°", -180.0, 180.0)) + _grid.add_child(_make_row("rot_z", "Kippen Z", "Kippen um die Z-Achse in Grad (−180…180) — links/rechts neigen. Tasten: Alt+R / Alt+Umschalt+R.", 0.5, "%.1f", "°", -180.0, 180.0)) + + # --- Größe (FEST, Karte t_e166e656) --- + _grid.add_child(_field("Größe")) + var gross_fix := Label.new() + gross_fix.text = "Größe fix (Original) — Assets bleiben in ihrer echten Größe." + gross_fix.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART + _grid.add_child(gross_fix) + + var btn_row := HBoxContainer.new() + btn_row.add_theme_constant_override("separation", 6) + _ground_btn = Button.new() + _ground_btn.text = "Auf Boden setzen" + _ground_btn.custom_minimum_size = UIScale.v2(0, 40) + _ground_btn.tooltip_text = "Alle markierten Objekte exakt auf die Terrain-Höhe setzen (Strg+Bild↑ geht auch) — EIN Rückgängig-Schritt" + _ground_btn.pressed.connect(_on_ground) + btn_row.add_child(_ground_btn) + _grid.add_child(btn_row) + + # --- Farbe / Material (Karte t_b0edb807) --- + # Feste Palette als Farbfeld-Raster; Klick = Farbe auf ALLE markierten + # Objekte (EIN Undo-Schritt). „Zurücksetzen“ entfernt das tint-Feld → + # wieder die Pack-Farbe (Rückwärtskompatibel, wie vor der Karte). + _grid.add_child(_field("Farbe / Material")) + _farben_grid = GridContainer.new() + _farben_grid.columns = 4 + _farben_grid.add_theme_constant_override("h_separation", 6) + _farben_grid.add_theme_constant_override("v_separation", 6) + _grid.add_child(_farben_grid) + for eintrag in SvmapTint.PALETTE: + _farben_grid.add_child(_swatch(eintrag[1], str(eintrag[0]))) + var farbe_row := HBoxContainer.new() + farbe_row.add_theme_constant_override("separation", 6) + _farbe_reset_btn = Button.new() + _farbe_reset_btn.text = "Zurücksetzen (Pack-Farbe)" + _farbe_reset_btn.custom_minimum_size = UIScale.v2(0, 40) + _farbe_reset_btn.tooltip_text = "Farbe der markierten Objekte entfernen — sie zeigen wieder die Pack-Farbe — EIN Rückgängig-Schritt" + _farbe_reset_btn.pressed.connect(_on_farbe_reset) + farbe_row.add_child(_farbe_reset_btn) + _grid.add_child(farbe_row) + _farbe_status = Label.new() + _farbe_status.text = "" + _grid.add_child(_farbe_status) + + # --- Info (nur lesen) --- + _info = Label.new() + _info.text = "" + _info.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART + add_child(_info) + + # Startzustand: keine Auswahl → nur Hinweis sichtbar (refresh() schaltet um). + _grid.visible = false + _info.visible = false + _ground_btn.visible = false + _built = true + + +func _field(text: String) -> Label: + var l := Label.new() + l.text = text + l.tooltip_text = "Werte gelten für ALLE markierten Objekte. „—“ = Werte sind verschieden und werden erst beim Tippen/Ziehen angeglichen." + return l + + +## Ein Farbfeld-Knopf (Karte t_b0edb807): flacher Farb-Button mit Tooltip. +func _swatch(c: Color, name: String) -> Button: + var btn := Button.new() + btn.custom_minimum_size = UIScale.v2(34, 34) + btn.tooltip_text = "%s — Farbe auf alle markierten Objekte anwenden (EIN Rückgängig-Schritt)" % name + btn.focus_mode = Control.FOCUS_NONE + var sb := StyleBoxFlat.new() + sb.bg_color = c + sb.set_corner_radius_all(6) + btn.add_theme_stylebox_override("normal", sb) + var sb_hover: StyleBoxFlat = sb.duplicate() + sb_hover.bg_color = c.lightened(0.08) # U7: Aufhellung statt Manuell-Mathe + btn.add_theme_stylebox_override("hover", sb_hover) + btn.add_theme_stylebox_override("pressed", sb_hover) + btn.add_theme_stylebox_override("focus", StyleBoxEmpty.new()) + btn.pressed.connect(_on_farbe_gewaehlt.bind(c, name)) + return btn + + +# ------------------------------------------------------------- Farbe/Material --- + +## Palette-Farbe auf ALLE markierten Objekte — EIN Undo-Schritt. +func _on_farbe_gewaehlt(c: Color, name: String) -> void: + var indices := _selected() + if indices.is_empty(): + return + var before: Dictionary = _main.history.snapshot(["objects"]) + var objects: Array = _main.doc.get("objects", []) + var changed := false + for i in indices: + var obj: Dictionary = objects[i] + var alt := SvmapTint.von(obj) + SvmapTint.setze(obj, c) + if not SvmapTint.gleich(alt, c): + changed = true + if not changed: + return # gleiche Farbe erneut → kein Leer-Schritt + _commit_common("Inspektor: Farbe %s" % name, before) + _main.view_builder.call("tint_refresh", indices) + + +## tint-Feld entfernen → Pack-Farbe — EIN Undo-Schritt. +func _on_farbe_reset() -> void: + var indices := _selected() + if indices.is_empty(): + return + var before: Dictionary = _main.history.snapshot(["objects"]) + var objects: Array = _main.doc.get("objects", []) + var changed := false + for i in indices: + var obj: Dictionary = objects[i] + if SvmapTint.hat(obj): + SvmapTint.entferne(obj) + changed = true + if not changed: + return # nichts hatte eine Farbe → kein Leer-Schritt + _commit_common("Inspektor: Farbe zurückgesetzt (Pack-Farbe)", before) + _main.view_builder.call("tint_refresh", indices) + + +## Status-Zeile der Farbsektion: Pack-Farbe / Palettenname / eigene Farbe / +## gemischt (Mehrfachauswahl mit verschiedenen Farben). +func _farbe_text(objs: Array) -> String: + if objs.is_empty(): + return "" + if objs.size() == 1: + var obj: Dictionary = objs[0] + if not SvmapTint.hat(obj): + return "Farbe: Pack-Farbe" + var c := SvmapTint.von(obj) + var pn := SvmapTint.palette_name(c) + return "Farbe: %s" % (pn if pn != "" else "eigene Farbe") + # Mehrfachauswahl: alle ohne Feld = Pack-Farbe, alle gleich = Name, sonst gemischt. + var first_hat := SvmapTint.hat(objs[0]) + var first_c := SvmapTint.von(objs[0]) + for obj in objs: + if SvmapTint.hat(obj) != first_hat: + return "Farbe: gemischt" + if first_hat and not SvmapTint.gleich(SvmapTint.von(obj), first_c): + return "Farbe: gemischt" + if not first_hat: + return "Farbe: Pack-Farbe" + var pn2 := SvmapTint.palette_name(first_c) + return "Farbe: %s" % (pn2 if pn2 != "" else "eigene Farbe") + + +func _make_row(field: String, lbl: String, tip: String, step: float, fmt: String, suffix: String, + min_v := -1000000.0, max_v := 1000000.0) -> DragValue: + var w := DragValue.new() + w.step = step + w.fmt = fmt + w.suffix = suffix + w.min_v = min_v + w.max_v = max_v + w.get_value = _get_value.bind(field) + w.is_mixed = _is_mixed.bind(field) + w.begin_live = _begin_live + w.live_apply = _live_apply.bind(field) + w.end_live = _end_live.bind(field) + w.commit = _commit.bind(field) + w.build(lbl, tip, UIScale.px(64)) + _rows[field] = w + return w + + +# ------------------------------------------------------------- Datenzugriff -- + +func _selected() -> Array: + if _main == null or _main.get("interaction") == null: + return [] + var objects: Array = _main.doc.get("objects", []) + var out: Array = [] + for i in _main.interaction.selected_indices: + if i is int and i >= 0 and i < objects.size(): + out.append(i) + return out + + +func _sel_objects() -> Array: + var objects: Array = _main.doc.get("objects", []) + var out: Array = [] + for i in _selected(): + var obj = objects[i] + if obj is Dictionary: + out.append(obj) + return out + + +func _entry(obj: Dictionary) -> Dictionary: + var manifest: Dictionary = _main.get("manifest") + if manifest == null or manifest.is_empty(): + return {} + var lib: Dictionary = manifest.get("objects", {}) + return lib.get(str(obj.get("id", "")), {}) + + +func _field_value(obj: Dictionary, field: String) -> float: + match field: + "pos_x": + var p: Array = obj.get("pos", [0.0, 0.0, 0.0]) + return float(p[0]) if (p as Array).size() == 3 else 0.0 + "pos_y": + var p: Array = obj.get("pos", [0.0, 0.0, 0.0]) + return float(p[1]) if (p as Array).size() == 3 else 0.0 + "pos_z": + var p: Array = obj.get("pos", [0.0, 0.0, 0.0]) + return float(p[2]) if (p as Array).size() == 3 else 0.0 + "rot_y": + return _clamp_norm_deg(SvmapIO.objekt_rotation(obj).y) + "rot_x": + return _clamp_norm_deg(SvmapIO.objekt_rotation(obj).x) + "rot_z": + return _clamp_norm_deg(SvmapIO.objekt_rotation(obj).z) + return 0.0 + + +func _get_value(field: String) -> float: + var objs := _sel_objects() + if objs.is_empty(): + return 0.0 + return _field_value(objs[0], field) + + +func _is_mixed(field: String) -> bool: + var objs := _sel_objects() + if objs.size() < 2: + return false + var first := _field_value(objs[0], field) + for obj in objs: + if absf(_field_value(obj, field) - first) > EPS: + return true + return false + + +# ------------------------------------------------------------ Anzeige (refresh) -- + +func refresh() -> void: + if not _built or _main == null or _main.doc.is_empty(): + return + var indices := _selected() + var objects: Array = _main.doc.get("objects", []) + var has := not indices.is_empty() + _grid.visible = has + _ground_btn.visible = has + _info.visible = has + _hint.visible = not has + if not has: + _head.text = "Objekt-Inspektor" + _sub.text = "" + return + + var objs := _sel_objects() + var m := objs.size() + # Kopf: Name(n) + ID + Kategorie + „N von M markiert“ + Poly. + var names := PackedStringArray() + for obj in objs: + if names.size() < 3: + names.append(str(LibraryBrowser.object_label(str(obj.get("id", "?"))))) + var more := " … +%d" % (m - 3) if m > 3 else "" + var name_txt := (" · ".join(names) + more) if m > 1 else str(LibraryBrowser.object_label(str(objs[0].get("id", "?")))) + _head.text = name_txt + var kat := "?" + var oid := str((objs[0] as Dictionary).get("id", "")) + var entry: Dictionary = _entry(objs[0]) + if not entry.is_empty(): + kat = str(entry.get("kategorie", "?")) + var poly := 0.0 + for obj in objs: + var e: Dictionary = _entry(obj) + poly += float(e.get("poly", 0)) * float(obj.get("scale", 1.0)) * float(obj.get("scale", 1.0)) + _sub.text = "ID: %s · Kategorie: %s · %d von %d Objekten markiert · Poly: %d" % [ + oid if m == 1 else "%s …" % oid, kat, m, objects.size(), int(poly)] + + for field in ["pos_x", "pos_y", "pos_z", "rot_y", "rot_x", "rot_z"]: + var w: DragValue = _rows[field] + if w.edit.has_focus(): + continue # nicht unter dem tippenden Nutzer wegziehen + if _is_mixed(field): + w.set_mixed() + else: + w.set_shown(_get_value(field)) + + # Farbsektion (Karte t_b0edb807): aktueller Farbstand der Auswahl. + _farbe_status.text = _farbe_text(objs) + + # Info-Block (nur lesen). + var lift := ObjectOps.lift_offset(_main.doc, indices[0]) + var lift_txt: String + if absf(lift) < ObjectOps.FLOAT_EPSILON: + lift_txt = "am Boden" + elif lift > 0.0: + lift_txt = "%+.2f m über dem Boden" % lift + else: + lift_txt = "%.2f m im Boden versenkt" % -lift + var e0: Dictionary = _entry(objs[0]) + var col: Dictionary = e0.get("collision", {}) + var col_size: Array = col.get("size", []) + var col_txt := "—" + if (col_size as Array).size() == 3: + var s := float(objs[0].get("scale", 1.0)) + col_txt = "%s %s × %s × %s m" % [ + ("Box" if str(col.get("shape", "box")) == "box" else str(col.get("shape", "?"))), + ("%.1f" % (float(col_size[0]) * s)), ("%.1f" % (float(col_size[1]) * s)), ("%.1f" % (float(col_size[2]) * s))] + var echt := _echt_modell(indices[0]) + _info.text = "Fußpunkt: y = %.2f m (%s)\nKollision: %s\nEchtes Modell: %s" % [ + float((objs[0] as Dictionary).get("pos", [0.0, 0.0, 0.0])[1]) if ((objs[0] as Dictionary).get("pos", [0.0, 0.0, 0.0]) as Array).size() == 3 else 0.0, + lift_txt, col_txt, "ja" if echt else "nein (Platzhalter)"] + + +func _echt_modell(idx: int) -> bool: + var markers: Array = _main.view_builder.object_markers + if idx < markers.size(): + var marker = markers[idx] + if marker != null and is_instance_valid(marker) and marker.has_meta("glb"): + return bool(marker.get_meta("glb")) + return not str(_entry(_main.doc["objects"][idx]).get("glb", "")).is_empty() + + +# ------------------------------------------------------------ Anwenden + Undo -- + +var _live_before: Dictionary = {} # Undo-Basis während des Ziehens +var _live_changed := false # hat das Ziehen das Doc wirklich geändert? + +func _begin_live() -> void: + _live_before = _main.history.snapshot(["objects"]) + _live_changed = false + +## Achtung Callable.bind hängt die gebundenen Argumente HINTER die +## Aufruf-Argumente: commit.call(v) → _commit(v, field). +func _live_apply(v: float, field: String) -> void: + if _apply(field, v): + _live_changed = true + +func _end_live(final: float, original: float, field: String) -> void: + if not _live_changed or absf(final - original) < 0.0001: + return # Ziehen ohne Änderung → kein Leer-Undo-Schritt + _commit_common("Inspektor: %s" % _desc_for(field, final), _live_before) + +func _commit(v: float, field: String) -> void: + var before: Dictionary = _main.history.snapshot(["objects"]) + if not _apply(field, v): + return # nichts geändert (alles geklemmt/identisch) → kein Leer-Schritt + _commit_common("Inspektor: %s" % _desc_for(field, v), before) + + +func _commit_common(desc: String, before: Dictionary) -> void: + _main.history.commit(desc, before, _main.history.snapshot(["objects"])) + _main.dirty = true + _main.call("_refresh_file_label") + _main.call("_refresh_stats") + _main.call("_refresh_history_buttons") + _main.call("_refresh_spawn_status") + _main.call("_set_status", "%s — Strg+Z macht es in EINEM Schritt rückgängig." % desc) + refresh() + + +func _desc_for(field: String, v: float) -> String: + var n := _sel_objects().size() + var mehr := "%d Objekte: " % n if n > 1 else "" + match field: + "pos_x": + return "%sPosition X = %.2f m" % [mehr, v] + "pos_y": + return "%sHöhe (Y) = %.2f m" % [mehr, v] + "pos_z": + return "%sPosition Z = %.2f m" % [mehr, v] + "rot_y": + return "%sDrehen (Y) = %.1f°" % [mehr, v] + "rot_x": + return "%sKippen (X) = %.1f°" % [mehr, v] + "rot_z": + return "%sKippen (Z) = %.1f°" % [mehr, v] + return "Inspektor-Änderung" + + +## Wert auf ALLE markierten Objekte anwenden + 3D-Ansicht live aktualisieren. +## false = nichts geändert (keine Auswahl / alles geklemmt). +func _apply(field: String, v: float) -> bool: + var indices := _selected() + if indices.is_empty(): + return false + var objects: Array = _main.doc.get("objects", []) + var half: Vector2 = _terrain_half() + var max_y := _max_y() + var min_y := _min_y() + var changed := 0 + # Position-Felder bei Mehrfachauswahl: der eingetippte Wert gilt für das + # ERSTE markierte Objekt (Anker), alle anderen wandern mit DEMSELBEN Delta + # mit → Abstände bleiben erhalten (Relativ-Move, wie beim Greifen). + # Bei 1 Objekt ist das Delta = absoluter Wert → Verhalten unverändert. + var rel_delta := 0.0 + if field == "pos_x" or field == "pos_y" or field == "pos_z": + var anchor_pos: Array = (objects[indices[0]] as Dictionary).get("pos", [0.0, 0.0, 0.0]) + if (anchor_pos as Array).size() == 3: + var comp := 0 if field == "pos_x" else (1 if field == "pos_y" else 2) + rel_delta = v - float(anchor_pos[comp]) + for i in indices: + var obj: Dictionary = objects[i] + var pos: Array = obj.get("pos", [0.0, 0.0, 0.0]) + if (pos as Array).size() != 3: + continue + var x := float(pos[0]) + var y := float(pos[1]) + var z := float(pos[2]) + if field == "rot_y" or field == "rot_x" or field == "rot_z": + # Karte t_e166e656: rot/rot_y_deg bleiben über rot_setzen synchron + # (reines Y → kein rot-Feld in der Datei). Anzeige normalisiert + # auf −180…180, gespeichert wird der Wert wie getippt. + var euler := SvmapIO.objekt_rotation(obj) + var neu := Vector3(euler.x, euler.y, euler.z) + if field == "rot_y": + neu.y = _clamp_norm_deg(v) + elif field == "rot_x": + neu.x = _clamp_norm_deg(v) + else: + neu.z = _clamp_norm_deg(v) + SvmapIO.rot_setzen(obj, neu) + changed += 1 + continue + if field == "pos_x": + x = clampf(float(pos[0]) + rel_delta, -half.x, half.x) + elif field == "pos_y": + # Karte t_e166e656: Versenken erlaubt — Untergrenze ist die + # Match-Grenze (bounds.min.y), NICHT mehr die Terrain-Höhe. + y = clampf(float(pos[1]) + rel_delta, min_y, max_y) + elif field == "pos_z": + z = clampf(float(pos[2]) + rel_delta, -half.y, half.y) + if absf(x - float(pos[0])) > 0.0001 or absf(y - float(pos[1])) > 0.0001 or absf(z - float(pos[2])) > 0.0001: + obj["pos"] = [x, y, z] + changed += 1 + _sync_markers(indices) + return changed > 0 + + +func _terrain_half() -> Vector2: + var terrain: Dictionary = _main.doc.get("terrain", {}) + return Vector2(float(terrain.get("size_x_m", 1024.0)), float(terrain.get("size_z_m", 1024.0))) * 0.5 + + +func _max_y() -> float: + var bounds: Dictionary = _main.doc.get("bounds", {}) + if (bounds.get("max", null) is Array) and ((bounds["max"] as Array).size() == 3): + return float(bounds["max"][1]) + return 80.0 + + +## Untere Match-Grenze (Karte t_e166e656): Versenken im Boden ist erlaubt, +## klemmt an bounds.min.y statt an der Terrain-Höhe. +func _min_y() -> float: + var bounds: Dictionary = _main.doc.get("bounds", {}) + if (bounds.get("min", null) is Array) and ((bounds["min"] as Array).size() == 3): + return float(bounds["min"][1]) + return -80.0 + + +func _sync_markers(indices: Array) -> void: + var markers: Array = _main.view_builder.object_markers + var objects: Array = _main.doc.get("objects", []) + for i in indices: + if i >= markers.size(): + continue + var marker = markers[i] + if marker == null or not is_instance_valid(marker): + continue + var pos: Array = (objects[i] as Dictionary).get("pos", [0.0, 0.0, 0.0]) + if (pos as Array).size() == 3: + marker.position = Vector3(float(pos[0]), float(pos[1]), float(pos[2])) + marker.rotation_degrees = SvmapIO.objekt_rotation(objects[i] as Dictionary) + + +# ------------------------------------------------------------------- Knöpfe -- + +func _on_ground() -> void: + # Bewährte Boden-Logik (interaction.snap_selection_to_floor): snapshotet, + # committet selbst EINEN Schritt und meldet in der Statuszeile. + _main.interaction.call("snap_selection_to_floor") + refresh() + + +## Für Tests/Probes: Widget zu einem Feld holen ("pos_x"…"rot_z"). +func widget(field: String) -> DragValue: + return _rows.get(field) diff --git a/ui/inspector_panel.gd.uid b/ui/inspector_panel.gd.uid new file mode 100644 index 0000000..3076705 --- /dev/null +++ b/ui/inspector_panel.gd.uid @@ -0,0 +1 @@ +uid://dndmcn006xggw diff --git a/ui/main.gd b/ui/main.gd new file mode 100644 index 0000000..8a91d07 --- /dev/null +++ b/ui/main.gd @@ -0,0 +1,2920 @@ +extends Control +## ScopedVR Map-Editor — Hauptfenster (M2 UX-Fundament, Karte t_40d855d0; +## U1-Modularisierung, Karte t_eaccbfed). +## +## U1 (Unity-artiges Layout-Fundament): diese Datei ist jetzt ein DÜNNER +## KOORDINATOR — Dokument/History, Werkzeug-Umschaltung, Shortcuts, Dialoge, +## Update, Playtest. Die Oberflächen-Bereiche wohnen in eigenen Modulen unter +## core/ui/panels/ und melden sich DATENGETRIEBEN in +## core/ui/panels/registry.gd an; das Layout wird ausschließlich aus der +## Registry gebaut (Operator-Vorgabe 20.10. — die Umbau-Karten U2–U7 ändern +## je nur IHR Modul + eine Registry-Zeile, nie wieder main.gd). +## +## Layout (Schaubild in /opt/data/scopedvr/KARTEN_UI_UNITY_vc27.md): +## Toolbar oben · links Tab "Map-Inhalt" · Mitte 3D-Ansicht · +## rechts Tabs (Inspektor/Auswahl/Map/Terrain/Prüfen) · +## unten Assets (Objekt-Bibliothek) · Statuszeile. +## Alles über HSplit/HSplit/VSplit größenverstellbar; die Splitter-Lage +## bleibt in user://scopedvr_editor.cfg ([fenster] Abschnitt) gemerkt. +## +## Farben/Namen kommen aus theme/editor_theme.tres (einzige Farbquelle). +## +## UX-Fundament (Chef-Grundsatz Sly — map-editor-README): +## 1. Undo/Redo (Strg+Z / Strg+Y) über ActionHistory — spätere Werkzeuge +## (Terrain, Spawn-Zonen) melden sich mit snapshot/commit einfach an. +## 2. Ghost-Preview: Platzier-Vorschau schwebt transparent am Cursor +## (interaction.gd), Klick setzt das Objekt. +## 3. Auswahl-Anfassen: Klick wählt, Ziehen verschiebt, +## R ODER Mausrad dreht (15°-Raster), Entf löscht. +## 4. Helfende Meldungen: Klartext + DER NÄCHSTE SCHRITT, keine Godot-Texte. +## 5. Deutsch & groß: Schrift ≥ 14 px, klickbare Flächen ≥ 40 px Höhe. + +const APP_TITLE := "ScopedVR Map-Editor" +# Shortcut-Infrastruktur (Karte t_c46d31c2): InputMap-Actions + Esc-Priorität. +const ShortcutKeys := preload("res://core/editor/shortcut_keys.gd") +const ShortcutPolicy := preload("res://core/editor/shortcut_policy.gd") +# Shortcuts-Mathe Karte 2/3 (t_55257792): Pfeil-Raster + Pinsel-Presets. +const MoveMath := preload("res://core/editor/move_math.gd") +# Kurzhilfe-Overlay Karte 3/3 (t_11b5c25b): Gesamte Tastenliste als BBCode. +const HelpText := preload("res://core/ui/help_text.gd") +# Zentrale UI-Skalierung (Karte t_297221b5): EIN Faktor für Schrift/Panels/Zeilen. +const UIScale := preload("res://core/ui/ui_scale.gd") +# U1 (t_eaccbfed): die Registry ist die EINZIGE Layout-Quelle. +const PanelRegistryScript := preload("res://core/ui/panels/registry.gd") +# Editor-Theme (U1): eine Theme-Ressource als einzige Farbquelle. +const THEME_PATH := "res://core/theme/editor_theme.tres" + +var manifest: Dictionary = {} +var doc: Dictionary = {} # das Map-Dictionary (1:1 svmap-Format) +var current_path := "" # leer = noch nie gespeichert +var dirty := false +var grid_snap := false # Raster-Snap (1 m) an/aus — Objekt-Werkzeuge links + +var history := ActionHistory.new() +var interaction # core/editor/interaction.gd (script-erweitert → untypisiert) +var viewport_toolbar # core/ui/viewport_toolbar.gd (Buttons oben links in der 3D-Ansicht) +var gizmo # core/viewport/gizmo.gd (Achsen-Pfeile, Kind von interaction) +var gizmo_step_m := 0.5 # Gizmo-Schrittweite in m (Panel-Feld; überlebt UI-Rebuilds) +var terrain_tool # core/editor/terrain_tool.gd (Pinsel, Karte t_9aba04f1) +var spawn_tool # core/editor/spawn_tool.gd (Zonen, Karte t_c4162c5d) +var tool_mode := "objects" # "objects" | "terrain" | "spawns" | "teststart" (Bauen = Objekt-Platzieren mit Rastern) + +# Symmetrie-Modus (Karte t_f5935023, M1): Modus + Toolbar-Schalter +# + Statuszeilen-Anzeige. Standard = Punktspiegelung (Sly 20.10.). M1 legt nur +# Modus + Anzeige fest; das Spiegeln selbst kommt mit M2–M4. +var sym_mode: int = SymmetryCore.Mode.POINT + +# UI-Referenzen (Koordinator-Sicht auf die Module — Panels bauen selbst) +var status_label: Label +var file_label: Label +var help_label: Label +var view_builder: Node3D +var camera: Camera3D +var inspector: Control # Objekt-Inspektor (Karte t_bb0d11c9) — im Inspektor-Tab + +# U1-Module (aus der Registry gebaut; Toolbar/Status/Kern-Widget-Referenzen +# bleiben hier, damit Tests/Tools denselben Vertrag sehen wie vorher) +var toolbar_mod # core/ui/panels/toolbar.gd +var status_mod # core/ui/panels/status_bar.gd +var selection_mod # core/ui/panels/selection_panel.gd (nur Logik, kein Tab mehr) +var settings_mod # core/ui/panels/settings_panel.gd (im Einstellungen-Fenster) +var drop_overlay: Control # Ablege-Fläche über der 3D-Ansicht (nur während Drag aktiv) +var settings_dialog: AcceptDialog # Fenster „Einstellungen“ (Knopf in der Kopfleiste) +var sym_mod # core/ui/panels/symmetry_panel.gd (im Map-Tab) +var map_mod # core/ui/panels/map_panel.gd +var terrain_mod # core/ui/panels/terrain_panel.gd +var malen_mod # core/ui/panels/malen_panel.gd (Malen-Tab) +var bauen_mod # core/ui/panels/bauen_panel.gd (Bauen-Tab) +var check_mod # core/ui/panels/check_panel.gd +var tree_mod # core/ui/panels/scene_tree_panel.gd +var assets_mod # core/ui/panels/assets_panel.gd +var content_tree: Tree # weiter in tree_mod (Bequemlichkeits-Referenz) +var stats_objects: Label # weiter in status_mod +var stats_terrain: Label # weiter in status_mod +var tool_label: Label # weiter in status_mod +var sym_label: Label # weiter in status_mod +var undo_btn: Button # weiter in toolbar_mod +var redo_btn: Button # weiter in toolbar_mod +var grid_btn: CheckButton # weiter in settings_mod (Einstellungen-Fenster) +var contours_btn: CheckButton # weiter in settings_mod +var size_menu: OptionButton # weiter in settings_mod +var sym_menu: OptionButton # weiter in settings_mod +var prop_name: LineEdit # weiter in map_mod +var gizmo_step_box: SpinBox # weiter in settings_mod +var library_search: LineEdit # weiter in assets_mod +var library_buttons: Dictionary = {} # weiter in assets_mod (Bequemlichkeit) +var _library_group_rows: Array = [] # weiter in assets_mod (Bequemlichkeit) +var spawn_status: Label # weiter in check_mod +var terrain_info: Label # weiter in map_mod +var terrain_mode_lower: Button # weiter in terrain_mod (Test-Vertrag) +var terrain_size_btn_small: Button # weiter in terrain_mod +var terrain_size_btn_medium: Button # weiter in terrain_mod +var terrain_size_btn_large: Button # weiter in terrain_mod +var terrain_palette: VBoxContainer # weiter in terrain_mod +var terrain_radius_slider: HSlider # weiter in terrain_mod +var terrain_radius_label: Label # weiter in terrain_mod +var terrain_strength_slider: HSlider # weiter in terrain_mod +var terrain_mat_buttons: Array = [] # weiter in terrain_mod (Gras/Sand/Fels) +var library_open_all_btn: Button # weiter in assets_mod +var library_close_all_btn: Button # weiter in assets_mod + +# Toolbar-/Panel-Zustand (gehört dem Koordinator) +var _grid_on := false # Nutzer-Wahl für das Maßstabsgitter +# Höhenlinien (Karte t_89c0ec95): _contours_on ist die NUTZER-Wahl „fixiert +# an“ (L-Taste oder Button). Ohne Fix erscheinen die Linien NUR im +# Terrain-Werkzeug (F1) — Sly-Befund 17.10.: dauerhaft sichtbar störte. +# Effektiv = _contours_fix AN ODER tool_mode == "terrain". +var _contours_on := false + +# --- Test-Start (Karte t_96e3c4ee / T1b) ------------------------------------- +# main hält den ZUSTAND und die Haken (Vertrag mit tests/test_playtest_spawn.gd); +# das Panel-Modul test_start_panel.gd zeigt ihn nur an (U1-Muster). +var test_start_point: Variant = null # Vector3 (nur x/z zählt) oder null +var test_start_tool # core/editor/playtest/test_start_tool.gd +var test_start_panel: Control # core/ui/panels/test_start_panel.gd (von der Prüfsuite erwartet) +var test_start_btn: Button # „🎯 Test-Start" in der Leiste (Umschalter) +var _test_start_active := false +var _loading_ui_values := false # verhindert dirty beim Auffüllen der Felder + +# Rahmen-Ausziehen (Rubberband) — Overlay über dem 3D-Viewport +var rubber_overlay: Control +var rubber_rect := Rect2() # leer = Overlay aus + +# Playtest (Karte t_1cdc1a72) + Lauf-Modus-Panelverweise +var playtest: Node = null # core/editor/playtest/playtest_mode.gd Instanz +var _playtest_tool_mode := "" # gemerkter Werkzeug-Modus für die Rückkehr +var ui_top_bar: Control # Top-Bar (im Lauf-Modus aus) +var ui_left_panel: Control # linke Spalte (im Lauf-Modus aus) +var ui_right_panel: Control # rechte Tab-Spalte (im Lauf-Modus aus) +var ui_status_bar: Control # Statusleiste (im Lauf-Modus aus) +var ui_dock_bottom: Control # Assets-Bereich unten (im Lauf-Modus aus) +var world3d: Node3D # 3D-Wurzel im SubViewport (Spieler lebt hier) + +# Karte 3/3 (t_11b5c25b): Dirty-Schutz + Kurzhilfe + Werkzeug-Statuszeile. +var dirty_dialog: ConfirmationDialog # „Ungespeicherte Änderungen verwerfen?“ +var resign_dialog: ConfirmationDialog # „Trotzdem laden (Prüfsumme erneuern)“ (t_9814f18f) +var _resign_pending_path: String = "" +var _pending_after_dirty := Callable() # was nach „Verwerfen“ ausgeführt wird +var help_overlay: PanelContainer # H-Kurzhilfe (nicht-blockierend) +var help_overlay_title: Label +var help_overlay_text: RichTextLabel + +# Editor-Selbstupdate (Karte t_d95f087a): Start-Check + Banner + „Jetzt updaten“ +var update_banner: PanelContainer # Leiste „🔄 Update verfügbar …“ (versteckt) +var update_label: Label +var update_btn: Button # „Jetzt updaten“ im Banner +var check_thread: Thread # Update-Check im Hintergrund (Start/Menü) +var update_thread: Thread # Update-Ausführung (pull + Import-Lauf) +var _update_check_busy := false +var _hand_pose_thread: Thread = null +var _update_running := false +var _update_result: Dictionary = {} # letzter Check (Status/Banner-Nachfrage) + +# Dialoge +var new_dialog: AcceptDialog +var open_dialog: FileDialog +var save_dialog: FileDialog +var error_dialog: AcceptDialog +var resize_dialog: ConfirmationDialog # „Kartengröße ändern“ (R3, t_c863b93b) +var error_text: Label + +# Map-Check (Karte prüfen) +var check_dialog: AcceptDialog +var check_text: Label + +# Update-Check-Ergebnis (Menü „🔄 Updates prüfen“, Sly 20.10.: nur die +# Statuszeile las sich wie „tut nichts“ → kleines Ergebnis-Fenster). +var update_dialog: AcceptDialog +var update_text: Label + +# Karte testen (Karte t_b84af40f) +var test_btn: Button + +# U1-Dock-Zustand: Splitter-Lagen ([fenster]-Abschnitt, gemerkt) +var _dock_offsets: Dictionary = {} +var _split_lagen_playtest: Dictionary = {} # Playtest: Trenner-Lagen (Sly-Befund 20.10.) + +const GizmoScript := preload("res://core/viewport/gizmo.gd") +const INSPECTOR_PANEL := preload("res://core/ui/inspector_panel.gd") + + +func _ready() -> void: + # InputMap-Actions der Tastatur-Shortcuts (Karte t_c46d31c2) — VOR UI/Kamera, + # damit die Kamera-Polls (Flug W/A/S/D + Leertaste/Shift) sofort kennen. + ShortcutKeys.register() + manifest = _load_manifest() + _build_ui() + _update_tool_label() + # Symmetrie-Anzeige initialisieren (Karte t_f5935023, M1): Standard = Punkt. + _update_sym_ui() + # Fenster-Zustand (Karte t_297221b5): Default MAXIMIERT (kein Vollbild); + # wer auf Fenstergröße umschaltet, bekommt die gemerkte Lage wieder. + # Close-Request selbst behandeln, damit die Lage VOR dem Quit gemerkt wird. + get_tree().set_auto_accept_quit(false) + _apply_window_state() + _load_dock_state() + _start_with_new_map() + _maybe_start_demo_mode() + # Selbst-Update (Karte t_d95f087a): STILLER Start-Check im Hintergrund — + # nur bei „Update verfügbar“ erscheint das Banner; offline/Tunnel weg + # bleibt alles ruhig (kein Banner, keine Meldung). + _startup_update_check() + + +func _load_manifest() -> Dictionary: + var parsed: Variant = JSON.parse_string(FileAccess.get_file_as_string(SvmapIO.MANIFEST_PATH)) + if parsed is Dictionary: + LibraryBrowser.setze_manifest(parsed) + return parsed + push_error("Bibliothek library/objects.json konnte nicht geladen werden!") + return {} + + +# ------------------------------------------------------------------ UI-Bau -- +## Layout aus der Registry (U1, Operator-Vorgabe): Top-Bar → Update-Banner → +## Haupt-WSplit (links Tabs | Mitte 3D | rechts Tabs) → unten Assets → +## Statuszeile. Kein Panel wird hier fest verdrahtet — Registry ändert das +## Layout, main.gd bleibt gleich. + +func _build_ui() -> void: + var theme_res: Theme = load(THEME_PATH) + theme_res.default_font_size = UIScale.font_size() + self.theme = theme_res + + var vbox := VBoxContainer.new() + vbox.set_anchors_preset(Control.PRESET_FULL_RECT) + vbox.add_theme_constant_override("separation", UIScale.px(4)) + add_child(vbox) + + # --- Top-Bar (Modul toolbar.gd) --- + var top := PanelContainer.new() + # _make_module hängt das Modul selbst an den Container (doppelt add_child + # würde „already has a parent“ werfen). + var top_h: Control = _make_module(toolbar_script(), top) + vbox.add_child(top) + ui_top_bar = top # Lauf-Modus (t_1cdc1a72): Top-Bar ausblenden + toolbar_mod = top_h + _pull_toolbar_refs() + _update_banner_build(vbox) + + # --- Hauptbereich: links Tabs | Mitte 3D | rechts Tabs --- + var split := HSplitContainer.new() + split.size_flags_vertical = Control.SIZE_EXPAND_FILL + split.size_flags_horizontal = Control.SIZE_EXPAND_FILL + split.split_offset = UIScale.px(-320) + split.name = "MainSplit" + vbox.add_child(split) + + # Lauf-Modus (t_1cdc1a72): linke/rechte Spalte als Member — werden im + # Lauf-Modus ausgeblendet, die 3D-Ansicht (Mitte) bleibt stehen. + var left_tabs := _build_group_tabs("links") + left_tabs.name = "LeftTabs" + ui_left_panel = left_tabs + split.add_child(left_tabs) + split.add_child(_build_center_viewport()) + var right_tabs := _build_group_tabs("rechts") + right_tabs.name = "RightTabs" + ui_right_panel = right_tabs + right_tabs.tab_changed.connect(_on_right_tab_changed) + split.add_child(right_tabs) + _build_map_sections() + + # --- Assets unten (Registry-Gruppe "unten", U1 Auftragspunkt 4) --- + # Die Objekt-Bibliothek wohnt jetzt UNTER dem Hauptbereich (Unity- + # Projekt-Fenster-Platz). Höhe größenverstellbar über den VSplit und + # gemerkt in [fenster] (dock_unten). + var bottom_wrap := VSplitContainer.new() + bottom_wrap.size_flags_vertical = Control.SIZE_EXPAND_FILL + bottom_wrap.size_flags_horizontal = Control.SIZE_EXPAND_FILL + bottom_wrap.name = "BottomSplit" + # WICHTIG: den Haupt-Split ERST aus der VBox trennen, dann in den VSplit + # hängen — add_child auf ein Kind mit Parent ist ein stiller Baum-Fehler + # (Node hängt dann im Nichts: Slider/Skript-Signale laufen nicht). + vbox.remove_child(split) + # VSplit-Kind 1: der Haupt-Split (links|3D|rechts) — er wächst. + split.size_flags_vertical = Control.SIZE_EXPAND_FILL + bottom_wrap.add_child(split) + # VSplit-Kind 2: die Assets-Tabs. + var bottom_tabs := _build_group_tabs("unten") + bottom_tabs.name = "BottomTabs" + bottom_tabs.custom_minimum_size = UIScale.v2(0, 300) + var bottom_panel := PanelContainer.new() + bottom_panel.add_child(bottom_tabs) + bottom_wrap.add_child(bottom_panel) + # Der VSplit ersetzt den Platz des bisherigen Haupt-Splits in der VBox. + vbox.add_child(bottom_wrap) + ui_dock_bottom = bottom_wrap + + # --- Statusleiste (Modul status_bar.gd) --- + var status_panel := PanelContainer.new() + var status_h: Control = _make_module(status_bar_script(), status_panel) + vbox.add_child(status_panel) + ui_status_bar = status_panel # Lauf-Modus (t_1cdc1a72): Statusleiste aus + status_mod = status_h + _pull_status_refs() + status_label = status_mod.status_label + file_label = toolbar_mod.file_label + + _build_dialogs_and_overlays() + + +func toolbar_script() -> GDScript: + return load("res://core/ui/panels/toolbar.gd") + + +func status_bar_script() -> GDScript: + return load("res://core/ui/panels/status_bar.gd") + + +## Ein Modul (EditorPanel-Ableger) instanziieren und bauen; Rückgabe = das +## Panel selbst (Container). Fehler im Modul-Skript = fette Meldung statt +## stiller null-Referenzen. +func _make_module(script: GDScript, parent: Control) -> Control: + var mod: Control = script.new() + parent.add_child(mod) + if mod.has_method("setup"): + mod.setup(self) + if mod.has_method("build"): + mod.call("build") + return mod + + +func _pull_toolbar_refs() -> void: + undo_btn = toolbar_mod.undo_btn + redo_btn = toolbar_mod.redo_btn + + +func _pull_status_refs() -> void: + stats_objects = status_mod.stats_objects + stats_terrain = status_mod.stats_terrain + tool_label = status_mod.tool_label + sym_label = status_mod.sym_label + status_label = status_mod.status_label + + +## Eine Tab-Gruppe aus der Registry bauen (links/rechts/unten). Jeder Bereich +## erscheint GENAU EINMAL (test_ui_layout prüft das). Die Panels werden per +## preload aus dem Registry-Eintrag erzeugt. +func _build_group_tabs(gruppe: String) -> TabContainer: + var tabs := TabContainer.new() + tabs.size_flags_horizontal = Control.SIZE_EXPAND_FILL + tabs.size_flags_vertical = Control.SIZE_EXPAND_FILL + tabs.add_theme_constant_override("separation", UIScale.px(8)) + var entries: Array = PanelRegistryScript.entries(gruppe) + for entry in entries: + var script: GDScript = load(str(entry["skript"])) + var panel: Control = script.new() + panel.name = str(entry["id"]) + panel.setup(self) + # Der Alt-Inspektor (t_bb0d11c9) baut in setup() — build() ist dort + # nicht vorhanden; neue Module bauen in build(). Beides zulassen. + if panel.has_method("build"): + panel.call("build") + tabs.add_child(panel) + tabs.set_tab_title(panel.get_index(), str(entry["titel"])) + _panel_group_built(gruppe, tabs) + return tabs + + +## Gruppen-Nacharbeit: Referenzen ziehen, sobald ihre Tabs stehen. +func _panel_group_built(gruppe: String, tabs: TabContainer) -> void: + match gruppe: + "rechts": + for child in tabs.get_children(): + match child.name: + "inspektor": + inspector = child + "map": + map_mod = child + "terrain": + terrain_mod = child + "malen": + malen_mod = child + "bauen": + bauen_mod = child + prop_name = map_mod.prop_name + terrain_info = map_mod.terrain_info + # Malen-Widgets wohnen im Malen-Tab; das Terrain-Modul hält die + # alten Namen als Aliase (Tests/Werkzeug-Vertrag). + terrain_mod.terrain_palette = malen_mod.palette + terrain_mod.terrain_mat_buttons = malen_mod.mat_buttons + terrain_mod.terrain_weich_label = malen_mod.weich_label + terrain_mod.terrain_weich_slider = malen_mod.weich_slider + terrain_mod.terrain_paint_hint = malen_mod.paint_hint + # Test-/Werkzeug-Vertrag (wie vor der U1-Aufteilung): die Widgets + # wohnen in den Modulen, der Koordinator hält die alten Namen + # als Bequemlichkeits-Referenzen — nichts wird doppelt gebaut. + terrain_mode_lower = terrain_mod.terrain_mode_lower + terrain_size_btn_small = terrain_mod.terrain_size_btn_small + terrain_size_btn_medium = terrain_mod.terrain_size_btn_medium + terrain_size_btn_large = terrain_mod.terrain_size_btn_large + terrain_palette = terrain_mod.terrain_palette + terrain_radius_slider = terrain_mod.terrain_radius_slider + terrain_radius_label = terrain_mod.terrain_radius_label + terrain_strength_slider = terrain_mod.terrain_strength_slider + terrain_mat_buttons = terrain_mod.terrain_mat_buttons + "links": + for child in tabs.get_children(): + if child.name == "szene": + tree_mod = child + content_tree = tree_mod.content_tree + "unten": + for child in tabs.get_children(): + if child.name == "assets": + assets_mod = child + library_search = assets_mod.library_search + library_buttons = assets_mod.library_buttons + _library_group_rows = assets_mod._library_group_rows + library_open_all_btn = assets_mod.library_open_all_btn + library_close_all_btn = assets_mod.library_close_all_btn + + +## Abschnitte im Map-Tab (Registry-Gruppe "map"): Spawn-Zonen, Test-Start-Info, +## Symmetrie. Sie hängen UNTER den Map-Eigenschaften im selben Scroll-Bereich. +func _build_map_sections() -> void: + var host: Control = map_mod.sections_host() + for entry in PanelRegistryScript.entries("map"): + var script: GDScript = load(str(entry["skript"])) + var panel: Control = script.new() + panel.name = str(entry["id"]) + panel.setup(self) + if panel.has_method("build"): + panel.call("build") + host.add_child(HSeparator.new()) + host.add_child(panel) + match str(entry["id"]): + "check": + check_mod = panel + spawn_status = check_mod.spawn_status + "symmetrie": + sym_mod = panel + + +## Einstellungen-Fenster (Knopf ⚙ in der Kopfleiste): Inhalt kommt aus der +## Registry-Gruppe "dialog". Gitter, Höhenlinien, Symmetrie-Modus, UI-Größe, +## Raster-Snap und Gizmo-Schritt wohnen dort (vorher Kopfleiste / Objekt-Werkzeuge). +func _build_settings_dialog() -> void: + settings_dialog = AcceptDialog.new() + settings_dialog.name = "EinstellungenFenster" + settings_dialog.title = "Einstellungen" + settings_dialog.exclusive = false + settings_dialog.ok_button_text = "Schließen" + settings_dialog.min_size = UIScale.v2i(520, 420) + var scroll := ScrollContainer.new() + scroll.horizontal_scroll_mode = ScrollContainer.SCROLL_MODE_DISABLED + scroll.custom_minimum_size = UIScale.v2(500, 380) + settings_dialog.add_child(scroll) + for entry in PanelRegistryScript.entries("dialog"): + var script: GDScript = load(str(entry["skript"])) + var panel: Control = script.new() + panel.name = str(entry["id"]) + panel.size_flags_horizontal = Control.SIZE_EXPAND_FILL + panel.setup(self) + if panel.has_method("build"): + panel.call("build") + scroll.add_child(panel) + settings_mod = panel + add_child(settings_dialog) + grid_btn = settings_mod.grid_btn + contours_btn = settings_mod.contours_btn + size_menu = settings_mod.size_menu + sym_menu = settings_mod.sym_menu + gizmo_step_box = settings_mod.gizmo_step_box + settings_mod.call("refresh") + + +func _open_settings() -> void: + if settings_dialog == null: + return + settings_mod.call("refresh") + # So groß, dass alles ohne Scrollen sichtbar ist (Inhalt + Titel/Knopf), begrenzt aufs Fenster. + var inhalt: Vector2 = settings_mod.get_combined_minimum_size() + var fenster := Vector2(get_window().size) + var breite := clampf(maxf(inhalt.x + UIScale.px(60), UIScale.px(640)), UIScale.px(640), fenster.x * 0.95) + var hoehe := clampf(inhalt.y + UIScale.px(110), UIScale.px(520), fenster.y * 0.95) + settings_dialog.popup_centered(Vector2i(int(breite), int(hoehe))) + + +func _build_dialogs_and_overlays() -> void: + selection_mod = load("res://core/ui/panels/selection_panel.gd").new() + selection_mod.name = "AuswahlLogik" + selection_mod.setup(self) + add_child(selection_mod) + _build_settings_dialog() + # --- Dialoge --- + new_dialog = preload("res://core/ui/new_map_dialog.gd").new() + new_dialog.confirmed.connect(_on_new_map_confirmed) + add_child(new_dialog) + + # R3 (t_c863b93b): „Kartengröße ändern“ — Preview-Dialog, Ausführen als + # EINE Undo-Einheit in _on_resize_confirmed. + resize_dialog = preload("res://core/ui/resize_map_dialog.gd").new() + resize_dialog.confirmed.connect(_on_resize_confirmed) + add_child(resize_dialog) + + open_dialog = FileDialog.new() + open_dialog.file_mode = FileDialog.FILE_MODE_OPEN_FILE + open_dialog.access = FileDialog.ACCESS_FILESYSTEM + open_dialog.title = "Map öffnen" + open_dialog.filters = PackedStringArray(["*.svmap ; ScopedVR Map"]) + open_dialog.size = UIScale.v2i(800, 560) + open_dialog.file_selected.connect(_on_open_selected) + add_child(open_dialog) + + save_dialog = FileDialog.new() + save_dialog.file_mode = FileDialog.FILE_MODE_SAVE_FILE + save_dialog.access = FileDialog.ACCESS_FILESYSTEM + save_dialog.title = "Map speichern unter" + save_dialog.filters = PackedStringArray(["*.svmap ; ScopedVR Map"]) + save_dialog.size = UIScale.v2i(800, 560) + save_dialog.file_selected.connect(_on_save_selected) + add_child(save_dialog) + + error_dialog = AcceptDialog.new() + error_dialog.title = "Fehler" + error_dialog.ok_button_text = "Alles klar" + error_text = Label.new() + error_text.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART + error_text.custom_minimum_size = UIScale.v2(560, 0) + error_dialog.add_child(error_text) + add_child(error_dialog) + + # Map-Check-Dialog (Karte prüfen, Karte t_c4162c5d). + check_dialog = AcceptDialog.new() + check_dialog.title = "Map-Check" + check_dialog.ok_button_text = "Danke!" + check_text = Label.new() + check_text.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART + check_text.custom_minimum_size = UIScale.v2(620, 0) + check_dialog.add_child(check_text) + add_child(check_dialog) + + # Update-Check-Ergebnis (Sly 20.10.: „tut nichts“ — weil die Rückmeldung + # NUR in der Statuszeile kam und dort schnell wieder weg war). Kleines + # Fenster mit dem Klartext-Ergebnis, Stil wie der Map-Check-Dialog. + update_dialog = AcceptDialog.new() + update_dialog.title = "Update-Check" + update_dialog.ok_button_text = "Alles klar" + update_text = Label.new() + update_text.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART + update_text.custom_minimum_size = UIScale.v2(560, 0) + update_dialog.add_child(update_text) + add_child(update_dialog) + + # Karte 3/3 (t_11b5c25b): Dirty-Schutz vor „Neue Map“ / „Öffnen“ — deutsche + # Klartext-Frage, „Verwerfen“ führt die wartende Aktion aus, „Abbrechen“ tut + # nichts (Map bleibt, wie sie ist). + dirty_dialog = ConfirmationDialog.new() + dirty_dialog.title = "Ungespeicherte Änderungen" + dirty_dialog.dialog_text = "Die Map hat ungespeicherte Änderungen — beim Fortfahren gehen sie verloren.\nJetzt verwerfen und fortfahren?" + dirty_dialog.ok_button_text = "Verwerfen" + dirty_dialog.cancel_button_text = "Abbrechen" + dirty_dialog.confirmed.connect(_on_dirty_confirmed) + add_child(dirty_dialog) + + # Fremdformat-Dialog (t_9814f18f): Lade-Fehler NUR an der Prüfsumme (V13), + # Kern-Validierung grün → „Trotzdem laden (Prüfsumme erneuern)“ statt hartem + # Abbruch; der Editor signiert das Dokument dann mit dem v2-Schema neu. + resign_dialog = ConfirmationDialog.new() + resign_dialog.title = "Prüfsumme stimmt nicht" + resign_dialog.dialog_text = "Der Inhalt der Map ist intakt, aber die Prüfsumme stimmt nicht (die Datei wurde von einem fremden Programm geschrieben oder anders formatiert).\n\nTrotzdem laden? Die Prüfsumme wird beim nächsten Speichern erneuert." + resign_dialog.ok_button_text = "Trotzdem laden (Prüfsumme erneuern)" + resign_dialog.cancel_button_text = "Abbrechen" + resign_dialog.confirmed.connect(_on_resign_confirmed) + add_child(resign_dialog) + + # Kurzhilfe-Overlay (Karte 3/3): H schaltet es an, H/Esc aus. Kein modal + # Dialog — der Editor bleibt bedienbar, das Panel liegt nur obenauf. + help_overlay = PanelContainer.new() + var overlay_style := StyleBoxFlat.new() + # U7: Farben über das Theme (Editor/colors/help_bg, help_border). + overlay_style.bg_color = get_theme_color("help_bg", "Editor") + overlay_style.border_color = get_theme_color("help_border", "Editor") + overlay_style.set_border_width_all(2) + overlay_style.set_corner_radius_all(8) + overlay_style.set_content_margin_all(UIScale.px(14)) + help_overlay.add_theme_stylebox_override("panel", overlay_style) + # Zentriertes Panel statt Vollbild: der Editor bleibt rundherum bedienbar + # (nicht-blockierend), das Panel ist groß genug für die ganze Tabelle. + # Grow BOTH: das Panel wächst SYMMETRISCH um den Mittelpunkt (sonst hängt + # seine linke obere Ecke am Zentrum und es läuft rechts/unten aus dem Bild). + help_overlay.set_anchors_and_offsets_preset(Control.PRESET_CENTER) + help_overlay.grow_horizontal = Control.GROW_DIRECTION_BOTH + help_overlay.grow_vertical = Control.GROW_DIRECTION_BOTH + help_overlay.custom_minimum_size = UIScale.v2(880, 640) + help_overlay.visible = false + var overlay_box := VBoxContainer.new() + overlay_box.add_theme_constant_override("separation", UIScale.px(6)) + help_overlay.add_child(overlay_box) + help_overlay_title = Label.new() + help_overlay_title.text = "Hilfe — Werkzeuge, Steuerung und Tastenkürzel (H oder Esc schließt)" + help_overlay_title.add_theme_font_size_override("font_size", UIScale.heading_font_size()) + help_overlay_title.add_theme_color_override("font_color", get_theme_color("accent", "Editor")) + overlay_box.add_child(help_overlay_title) + help_overlay_text = RichTextLabel.new() + help_overlay_text.bbcode_enabled = true + help_overlay_text.size_flags_vertical = Control.SIZE_EXPAND_FILL + help_overlay_text.custom_minimum_size = UIScale.v2(0, 0) + help_overlay_text.text = HelpText.text() + overlay_box.add_child(help_overlay_text) + add_child(help_overlay) + + +## Ziehen aus der Objekt-Bibliothek: Vorschau folgt der Maus, Loslassen setzt. +func _viewport_can_drop(at_position: Vector2, data: Variant) -> bool: + if not (data is Dictionary) or not (data as Dictionary).has("svr_oid") or doc.is_empty() or assets_mod == null: + return false + assets_mod.drag_hover(str(data["svr_oid"]), at_position) + return true + + +func _viewport_drop(at_position: Vector2, data: Variant) -> void: + if data is Dictionary and (data as Dictionary).has("svr_oid") and assets_mod != null: + assets_mod.drag_drop(str(data["svr_oid"]), at_position) + + +func _build_center_viewport() -> SubViewportContainer: + var container := SubViewportContainer.new() + container.stretch = true + container.size_flags_horizontal = Control.SIZE_EXPAND_FILL + container.size_flags_vertical = Control.SIZE_EXPAND_FILL + # Objekt-Kachel aus der Bibliothek in die Szene ziehen (25.10.). + container.set_drag_forwarding(Callable(), _viewport_can_drop, _viewport_drop) + + var viewport := SubViewport.new() + viewport.own_world_3d = true + viewport.render_target_update_mode = SubViewport.UPDATE_ALWAYS + container.add_child(viewport) + + var world := Node3D.new() + viewport.add_child(world) + world3d = world # Lauf-Modus (t_1cdc1a72): Spieler-Body lebt in diesem Baum + + view_builder = Node3D.new() + view_builder.set_script(load("res://core/viewport/map_view_builder.gd")) + world.add_child(view_builder) + + camera = Camera3D.new() + camera.set_script(load("res://core/viewport/orbit_camera.gd")) + camera.current = true + world.add_child(camera) + + interaction = Node3D.new() + interaction.set_script(load("res://core/editor/interaction.gd")) + world.add_child(interaction) + interaction.setup(self, camera, view_builder) + # Achsen-Gizmo (Karte t_e0120dc2) als KIND von interaction — Kinder + # bekommen _unhandled_input ZUERST, es fängt Pfeil-Klicks ab bevor + # interaction sie sieht. interaction.gd bleibt dadurch unverändert. + gizmo = GizmoScript.new() + gizmo.setup(self, camera, view_builder) + interaction.add_child(gizmo) + camera.set("wheel_filter", Callable(interaction, "wheel_blocked")) + # Freelook-Flug-Verdrahtung (Karte t_c46d31c2): Status-Meldungen der + # Kamera laufen ins Statusfeld. Karte t_2470de89: die rechte Maustaste + # gehört IMMER dem Flug — kein Filter mehr, die Werkzeuge fassen RMB + # nicht mehr an. + camera.set("status_cb", Callable(self, "_set_status")) + + # Terrain-Pinsel (Karte t_9aba04f1) — eigener Eingabe-Knoten im Weltraum. + terrain_tool = Node3D.new() + terrain_tool.set_script(load("res://core/editor/terrain_tool.gd")) + world.add_child(terrain_tool) + terrain_tool.setup(self, camera, view_builder, interaction) + + # Spawn-Zonen-Werkzeug (Karte t_c4162c5d) — ditto eigener Eingabe-Knoten. + spawn_tool = Node3D.new() + spawn_tool.set_script(load("res://core/editor/spawn_tool.gd")) + world.add_child(spawn_tool) + spawn_tool.setup(self, camera, view_builder, interaction) + + + # Test-Start-Werkzeug (T1b, Wiederanbindung 20.10.): Marker in der Karte, + # Klick setzt den Startpunkt. Lebt — wie die übrigen Werkzeuge — in main, + # gelesen wird es von test_start_tool.gd über main.test_start_point. + test_start_tool = Node3D.new() + test_start_tool.set_script(load("res://core/editor/playtest/test_start_tool.gd")) + world.add_child(test_start_tool) + test_start_tool.setup(self, camera, view_builder, interaction) + + # Werkzeugleiste oben links (Verschieben / Drehen & Kippen / Aktionen) + viewport_toolbar = preload("res://core/ui/viewport_toolbar.gd").new() + container.add_child(viewport_toolbar) + viewport_toolbar.setup(self) + + # Ablege-Fläche für Bibliotheks-Kacheln: Godot ruft can_drop/drop NICHT auf einem + # SubViewportContainer auf (Test-Befund 25.10.: Ziehen startete, Loslassen setzte + # nichts — echter Maus-Drag, tests/probe_drag_echt.gd). Eine durchsichtige Fläche + # darüber nimmt den Drop an; sie ist nur WÄHREND eines Ziehens aktiv (sonst + # bleibt die Maus für Kamera/Auswahl frei). + drop_overlay = Control.new() + drop_overlay.name = "AblegeFlaeche" + drop_overlay.set_anchors_preset(Control.PRESET_FULL_RECT) + drop_overlay.mouse_filter = Control.MOUSE_FILTER_IGNORE + drop_overlay.set_drag_forwarding(Callable(), _viewport_can_drop, _viewport_drop) + container.add_child(drop_overlay) + + # Bedien-Hinweis im Viewport (Overlay) + help_label = Label.new() + help_label.text = "Linksklick: auswählen · Rahmen: mehrere · R: drehen · Entf: löschen · H: Hilfe" + help_label.set_anchors_preset(Control.PRESET_BOTTOM_WIDE) + help_label.offset_left = UIScale.px(12) + help_label.offset_bottom = UIScale.px(-8) + help_label.offset_top = UIScale.px(-46) + # U7: Hinweis-Farbe über Theme (Editor/colors/muted) statt modulate. + help_label.add_theme_color_override("font_color", get_theme_color("muted", "Editor")) + # Karte t_297221b5: OHNE Umbruch würde die Mindestbreite des langen Texts + # bei Stufe „Groß“ die 3D-Ansicht breiter zwingen als das Fenster ist — + # die rechte Spalte rutschte aus dem Bildschirm. Mit Umbruch bleibt die + # Mindestbreite klein, der Hinweis legt sich bei Bedarf in mehr Zeilen. + help_label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART + # … und wenn der umgebrochene Text höher wird als der reservierte Streifen, + # wächst er nach OBEN (in die 3D-Ansicht) statt nach unten über die + # Statuszeile (grow-Richtung = das Godot-Mittel gegen Mindestgrößen-Überlauf + # bei Anker-Controls). + help_label.grow_vertical = Control.GROW_DIRECTION_BEGIN + container.add_child(help_label) + + # Rahmen-Ausziehen (Karte t_f6f29d86): halbtransparentes Rechteck über + # dem Viewport — mouse_filter IGNORE, stört keine Maus-Ereignisse. + rubber_overlay = Control.new() + rubber_overlay.set_anchors_preset(Control.PRESET_FULL_RECT) + rubber_overlay.mouse_filter = Control.MOUSE_FILTER_IGNORE + rubber_overlay.draw.connect(_draw_rubberband) + rubber_overlay.visible = false + container.add_child(rubber_overlay) + return container + + +## Rahmen-Rechteck aktualisieren (aus interaction.gd, Viewport-Koordinaten). +func _rubberband_update(start_pos: Vector2, cur_pos: Vector2) -> void: + rubber_rect = SelectionMath.rect_from(start_pos, cur_pos) + rubber_overlay.visible = true + rubber_overlay.queue_redraw() + + +## Rahmen-Overlay ausblenden (Release/Abbruch). +func _rubberband_clear() -> void: + rubber_rect = Rect2() + rubber_overlay.visible = false + rubber_overlay.queue_redraw() + + +func _draw_rubberband() -> void: + if rubber_rect.size.x <= 0.0 or rubber_rect.size.y <= 0.0: + return + # U7: Rubberband-Farben über das Theme (Editor/colors/rubber_fill/_line). + rubber_overlay.draw_rect(rubber_rect, get_theme_color("rubber_fill", "Editor"), true) + rubber_overlay.draw_rect(rubber_rect, get_theme_color("rubber_line", "Editor"), false, 2.0) +# ------------------------------------------------------------ Map-Aktionen -- + +func _start_with_new_map() -> void: + doc = SvmapDocument.create_new("Neue Map", 1024.0, "mittag") + current_path = "" + dirty = false + history.begin(doc) + _refresh_all() + _set_status("Willkommen! Links ein Objekt aus der Bibliothek anklicken, dann kannst du es in der Karte platzieren. Hilfe gibt's unten in dieser Leiste.") + + +func _on_menu_action(id: int) -> void: + match id: + 0: # Neue Map — bei ungespeicherten Änderungen erst NACHFRAGEN (Karte 3/3) + _request_lossy(func() -> void: new_dialog.popup_centered()) + 1: # Öffnen — ditto Dirty-Schutz + _request_lossy(func() -> void: open_dialog.popup_centered()) + 2: # Speichern + _save() + 3: # Speichern unter + save_dialog.popup_centered() + 4: # Beenden (Fensterlage vorher merken, Karte t_297221b5) + _quit_editor() + 5: # Karte testen + _on_test_run() + 6: # Kartengröße ändern (R3, t_c863b93b) + _open_resize_dialog() + 7: # Updates prüfen (Selbst-Update, t_d95f087a) + _on_update_check_menu() + 8: # Hand-Haltung der Waffen (Tool im Client-Projekt) + _on_hand_pose_tool() + + +# --------------------------------------------- UI-Größe + Fenster (t_297221b5) -- + +## Popup-Häkchen auf die aktuelle Stufe setzen. +func _sync_size_menu() -> void: + if size_menu == null or not is_instance_valid(size_menu): + return + size_menu.select(UIScale.step_index()) + + +## Neue Stufe gewählt: speichern, kompletten UI-Neuaufbau mit dem neuen +## Faktor, Statusmeldung. Wirkt SOFORT — kein Neustart nötig. +func _on_ui_size_selected(index: int) -> void: + if index < 0 or index >= UIScale.step_count(): + return + if index == UIScale.step_index(): + return + if _update_running: + _set_status("Während eines Updates kann die UI-Größe nicht umgestellt werden — gleich danach nochmal.", true) + _sync_size_menu() + return + UIScale.set_step_index(index) + var settings_war_offen := settings_dialog != null and settings_dialog.visible + _rebuild_ui_for_scale() + if settings_war_offen: + _open_settings.call_deferred() + _set_status("UI-Größe: %s — sofort wirksam und gespeichert (bleibt auch nach Neustart)." % UIScale.step_label(index)) + + +## Kompletter UI-Neuaufbau mit dem aktuellen UIScale-Faktor. Die Map (doc) +## bleibt als Objekt UNBERÜHRT (Undo-History bleibt gültig); nur die Controls +## werden neu gebaut und der Zustand (Werkzeug, Gitter, Höhenlinien, Auswahl) +## wiederhergestellt. +func _rebuild_ui_for_scale() -> void: + var prev_mode := tool_mode + for child in get_children(): + remove_child(child) + child.queue_free() + _build_ui() + _update_tool_label() + _clear_edit_state() + _refresh_all() + _refresh_history_buttons() + # Nutzer-Wahl Gitter/Höhenlinien wiederherstellen (Neubau setzt Defaults). + grid_btn.set_pressed_no_signal(_grid_on) + _sync_grid_to_builder() + contours_btn.set_pressed_no_signal(_contours_on) + _sync_contours_to_builder() + # Werkzeug-Modus wiederherstellen (Neubau startet bei „objects“). + if prev_mode != "objects": + tool_mode = "objects" + _set_tool_mode(prev_mode) + # Update-Banner-Zustand wiederherstellen (Start-Check kannte das Ergebnis). + if str(_update_result.get("status")) == "update_available": + _show_update_banner(str(_update_result.get("local", "")), str(_update_result.get("remote", ""))) + _sync_size_menu() + + +## Fenster beim Start: maximiert (Default, kein Vollbild-Zwang) oder die +## gemerkte Fensterlage wiederherstellen. Headless-Läufe (Tests) haben kein +## Fenster und springen raus. +func _apply_window_state() -> void: + if DisplayServer.get_name() == "headless": + return + var cfg := ConfigFile.new() + var maximiert := true + var groesse := Vector2i(1600, 900) + var position := Vector2i() + var hat_geom := false + if cfg.load(UIScale.cfg_path()) == OK: + maximiert = bool(cfg.get_value(UIScale.WIN_SECTION, "maximiert", true)) + var g: Variant = cfg.get_value(UIScale.WIN_SECTION, "groesse", null) + if g is Array and (g as Array).size() == 2: + groesse = Vector2i(int((g as Array)[0]), int((g as Array)[1])) + hat_geom = true + var p: Variant = cfg.get_value(UIScale.WIN_SECTION, "position", null) + if p is Array and (p as Array).size() == 2: + position = Vector2i(int((p as Array)[0]), int((p as Array)[1])) + if maximiert: + DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_MAXIMIZED) + else: + DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_WINDOWED) + if hat_geom: + DisplayServer.window_set_size(groesse) + DisplayServer.window_set_position(position) + + +## Fensterlage merken (beim Schließen): Modus + Größe + Position. +func _save_window_state() -> void: + if DisplayServer.get_name() == "headless": + return + var win := get_window() + var cfg := ConfigFile.new() + cfg.load(UIScale.cfg_path()) + cfg.set_value(UIScale.WIN_SECTION, "maximiert", win.mode == Window.MODE_MAXIMIZED) + cfg.set_value(UIScale.WIN_SECTION, "groesse", [win.size.x, win.size.y]) + cfg.set_value(UIScale.WIN_SECTION, "position", [win.position.x, win.position.y]) + cfg.save(UIScale.cfg_path()) + + +## Ein Ausgang für beide Beenden-Wege (Menü + Fenster-X). +func _quit_editor() -> void: + _save_window_state() + _save_dock_state() + get_tree().quit() + + +func _notification(what: int) -> void: + if drop_overlay != null and is_instance_valid(drop_overlay): + if what == NOTIFICATION_DRAG_BEGIN: + drop_overlay.mouse_filter = Control.MOUSE_FILTER_STOP + elif what == NOTIFICATION_DRAG_END: + drop_overlay.mouse_filter = Control.MOUSE_FILTER_IGNORE + if what == NOTIFICATION_WM_CLOSE_REQUEST: + _quit_editor() + + +# ------------------------------------------------- Kartengröße ändern (R3) -- + +## Dialog öffnen: aktueller Stand + Live-Preview (Verlust-Liste/Warnband) füllen. +func _open_resize_dialog() -> void: + if doc.is_empty(): + _set_status("Erst eine Map anlegen (Datei → Neue Map), dann kann die Größe geändert werden.", true) + return + resize_dialog.setup(doc) + resize_dialog.popup_centered() + + +## „Größe ändern“ bestätigt: resize_apply liefert ein FRISCHES Dict (R1/R2 — +## reine Funktion). Der Resize wird als EINE Undo-Einheit in die History +## gehängt: before = kompletter alter doc-Snapshot, after = kompletter neuer. +## Wichtig: doc bleibt dasselbe Dictionary-Objekt (History hält eine Referenz — +## history.begin(doc) nur bei Neu/Laden) — Blöcke werden IN-PLACE ersetzt, +## wie ActionHistory._restore_block es beim Undo macht. +func _on_resize_confirmed() -> void: + var new_x: float = resize_dialog.get_new_size_x() + var new_z: float = resize_dialog.get_new_size_z() + var drop: bool = resize_dialog.get_drop_outside() + var before := history.snapshot(doc.keys()) + var result := SvmapDocument.resize_apply(doc, new_x, new_z, drop) + if result.is_empty(): + _set_status("Kartengröße ändern fehlgeschlagen — die Map wurde nicht verändert.", true) + return + var old_terrain: Dictionary = doc.get("terrain", {}) + _replace_doc_in_place(result) + dirty = true + history.commit("Kartengröße %d × %d m" % [int(new_x), int(new_z)], + before, history.snapshot(doc.keys())) + _after_structure_change() + # Karte K1 (t_950fddaa): nach Resize die GANZE Karte passend einpassen + # (Kartenmitte aus bounds — frame_map ist weg). + var rb: Dictionary = doc.get("bounds", {}) + var rmn: Array = rb.get("min", []) + var rmx: Array = rb.get("max", []) + if rmn.size() == 3 and rmx.size() == 3: + camera.call("fit_to_bounds", + Vector3(rmn[0], rmn[1], rmn[2]), Vector3(rmx[0], rmx[1], rmx[2])) + var old_sx := float(old_terrain.get("size_x_m", 0.0)) + var old_sz := float(old_terrain.get("size_z_m", 0.0)) + var verb := "verkleinert" if (new_x < old_sx or new_z < old_sz) else "vergrößert" + _set_status("Karte auf %d × %d m %s — Strg+Z stellt den alten Zustand komplett her." % [ + int(new_x), int(new_z), verb]) + + +## Kompletten doc-Inhalt IN-PLACE durch ein frisches Ergebnis-Dict ersetzen +## (Identität von doc und seiner Arrays/Dicts bleibt erhalten — History, +## Tests und Ansichten behalten gültige Referenzen; Muster wie +## ActionHistory._restore_block, aber über ALLE Ober-Blöcke). +func _replace_doc_in_place(result: Dictionary) -> void: + for key in doc.keys(): + if not result.has(key): + doc.erase(key) + for key in result.keys(): + var source: Variant = result[key] + if source is Array: + var arr: Array = doc.get(key, []) + arr.clear() + arr.append_array((source as Array).duplicate(true)) + doc[key] = arr + elif source is Dictionary: + var dict: Dictionary = doc.get(key, {}) + dict.clear() + dict.merge((source as Dictionary).duplicate(true)) + doc[key] = dict + else: + doc[key] = source + + +# --------------------------------------------- Selbst-Update (t_d95f087a) ---- + +## Banner „🔄 Update verfügbar“ (unaufdringliche Leiste unter der Top-Bar) — +## nur sichtbar, wenn ein Check einen Update findet. Offline bleibt alles still. +func _update_banner_build(parent: Container) -> void: + update_banner = PanelContainer.new() + var style := StyleBoxFlat.new() + # U7: Banner-Farben über das Theme (Editor/colors/update_bg/_border). + style.bg_color = get_theme_color("update_bg", "Editor") + style.border_color = get_theme_color("update_border", "Editor") + style.set_border_width_all(2) + style.set_content_margin_all(UIScale.px(8)) + style.set_corner_radius_all(6) + update_banner.add_theme_stylebox_override("panel", style) + var h := HBoxContainer.new() + h.add_theme_constant_override("separation", UIScale.px(14)) + update_banner.add_child(h) + update_label = Label.new() + update_label.add_theme_font_size_override("font_size", UIScale.font_size()) + h.add_child(update_label) + var spacer := Control.new() + spacer.size_flags_horizontal = Control.SIZE_EXPAND_FILL + h.add_child(spacer) + update_btn = Button.new() + update_btn.text = "🔄 Jetzt updaten" + update_btn.custom_minimum_size = UIScale.v2(190, 40) + update_btn.tooltip_text = "Lädt die neue Version (git pull), importiert sie und startet den Editor neu. Bei ungespeicherten Änderungen fragt der Editor vorher." + update_btn.pressed.connect(_on_update_now) + h.add_child(update_btn) + update_banner.visible = false + parent.add_child(update_banner) + + +## Still Start-Check (nur Banner bei „Update verfügbar“ — offline: nichts). +func _startup_update_check() -> void: + _updater_check_async(false) + + +## Hand-Haltungs-Tool starten: eigenes Fenster aus dem Client-Projekt. Nach einem +## neuen Client-Stand erst importieren (im Hintergrund, kann dauern), sonst fehlen +## dem Tool neue Modelle. +func _on_hand_pose_tool() -> void: + if _hand_pose_thread != null: + _set_status("Hand-Haltungs-Tool wird schon vorbereitet…") + return + var cfg := TestRun.load_cfg() + var client := TestRun.find_client(ProjectSettings.globalize_path("res://"), cfg) + if client.is_empty(): + _set_status("Client-Ordner nicht gefunden: er muss neben dem Editor liegen (scopedvr-client) oder in den Einstellungen stehen.", true) + return + var godot := TestRun.find_godot(cfg) + if godot.is_empty(): + _set_status("Godot nicht gefunden: bitte in den Einstellungen eintragen.", true) + return + _set_status("Hand-Haltungs-Tool wird vorbereitet…") + _hand_pose_thread = Thread.new() + _hand_pose_thread.start(_hand_pose_prepare.bind(godot, client)) + + +func _hand_pose_prepare(godot: String, client: String) -> void: + var head := EditorUpdater.git_run(EditorUpdater.git_exe(TestRun.load_cfg()), client, PackedStringArray(["rev-parse", "HEAD"])) + var stand := str(head.get("output", "")).strip_edges() + var cfg := TestRun.load_cfg() + if stand.is_empty() or str(cfg.get_value("test", "hand_pose_import", "")) != stand: + var out: Array = [] + OS.execute(godot, TestRun.import_args(client), out, true) + _hand_pose_started.call_deferred(godot, client, stand) + + +func _hand_pose_started(godot: String, client: String, stand: String) -> void: + _hand_pose_thread.wait_to_finish() + _hand_pose_thread = null + var cfg := TestRun.load_cfg() + cfg.set_value("test", "hand_pose_import", stand) + cfg.save(TestRun.CFG_PATH) + var pid := OS.create_process(godot, TestRun.hand_pose_args(client)) + if pid <= 0: + _set_status("Hand-Haltungs-Tool ließ sich nicht starten.", true) + return + _set_status("Hand-Haltungs-Tool läuft in einem eigenen Fenster.") + + +## Datei-Menü „🔄 Updates prüfen“ (ID 7): gleicher Check mit Ergebnis-Meldung. +func _on_update_check_menu() -> void: + if _update_check_busy: + _set_status("Update-Check läuft schon…") + return + _set_status("Prüfe auf Updates…") + _updater_check_async(true) + + +func _updater_check_async(report: bool) -> void: + _update_check_busy = true + check_thread = Thread.new() + check_thread.start(_updater_check_thread.bind(report)) + + +func _updater_check_thread(report: bool) -> void: + var result := EditorUpdater.check_update( + EditorUpdater.git_exe(TestRun.load_cfg()), + ProjectSettings.globalize_path("res://")) + _update_result = result + call_deferred("_updater_check_done", result, report) + + +## Klartext-Ergebnis-Fenster für den manuellen Update-Check (Sly 20.10.: +## Statuszeile allein las sich wie „tut nichts“). Nur bei MANUELLEM Check +## (report=true), der Still-Start-Check bleibt still. +func _show_update_popup(text: String) -> void: + if update_dialog == null or not is_instance_valid(update_dialog): + return # UI wurde gerade neu aufgebaut (UI-Größe) — nichts anfassen + update_text.text = text + update_dialog.popup_centered() + + +func _updater_check_done(result: Dictionary, report: bool) -> void: + _update_check_busy = false + _join(check_thread) + check_thread = null + match str(result.get("status")): + "update_available": + _show_update_banner(str(result["local"]), str(result["remote"])) + if report: + _set_status("🔄 Update verfügbar: %s → %s — im Banner „Jetzt updaten“ klicken." % [ + EditorUpdater.short_sha(str(result["local"])), + EditorUpdater.short_sha(str(result["remote"]))]) + _show_update_popup("🔄 Update verfügbar: %s → %s.\n\nIm Banner oben „Jetzt updaten“ klicken — der Editor holt sich den Stand, baut ihn und startet neu." % [ + EditorUpdater.short_sha(str(result["local"])), + EditorUpdater.short_sha(str(result["remote"]))]) + "up_to_date": + if report: + _set_status("Du bist auf dem neusten Stand (%s)." % EditorUpdater.short_sha(str(result["local"]))) + _show_update_popup("Du bist auf dem neusten Stand (%s).\n\nAktuelle Version ist installiert — es gibt nichts zu tun." % EditorUpdater.short_sha(str(result["local"]))) + "unreachable": + if report: + _set_status("Update-Check nicht erreichbar (offline oder Tunnel weg) — später nochmal probieren.", true) + _show_update_popup("Update-Check nicht erreichbar.\n\nDer Server ist gerade nicht erreichbar (offline oder Tunnel weg) — später nochmal probieren.") + "auth_failed": + # Karte t_1457e935: Zugangsdaten fehlen → klarer Hinweis statt + # GUI-Login-Dialog (Askpass ist im Updater abgeschaltet). + if report: + _set_status(EditorUpdater.AUTH_ERROR_TEXT, true) + _show_update_popup(EditorUpdater.AUTH_ERROR_TEXT) + _: + if report: + _set_status("Update-Check fehlgeschlagen: %s" % str(result.get("error", "")), true) + _show_update_popup("Update-Check fehlgeschlagen:\n%s" % str(result.get("error", ""))) + + +func _show_update_banner(local_sha: String, remote_sha: String) -> void: + if update_banner == null or not is_instance_valid(update_banner): + return # UI wurde gerade neu aufgebaut (UI-Größe) — nichts anfassen + update_label.text = EditorUpdater.banner_text(local_sha, remote_sha) + update_banner.visible = true + + +## Thread sauber einsammeln (Ergebnis kam per call_deferred — der Thread ist +## längst fertig, join ist nur Ordnung). +func _join(thread: Thread) -> void: + if thread != null and thread.is_started(): + thread.wait_to_finish() + + +## Banner-Knopf „Jetzt updaten“: Dirty-Schutz wie Strg+O/Strg+N (derselbe +## deutsche Dialog — „Abbrechen“ bricht das Update ab), dann git pull + +## Import-Lauf + Neustart. Import-Fehler = Abbruch mit Meldung, KEIN Neustart +## (Lektion 17.10.: sonst sieht Sly einen Editor ohne Map-Ansicht). +func _on_update_now() -> void: + if _update_running: + _set_status("Ein Update läuft schon…") + return + _request_lossy(_start_update) + + +func _start_update() -> void: + _update_running = true + update_btn.disabled = true + _set_status("Update läuft — neue Version wird geladen (git pull)…") + update_thread = Thread.new() + update_thread.start(_updater_run_thread) + + +func _updater_run_thread() -> void: + var project_dir := ProjectSettings.globalize_path("res://") + var cfg := TestRun.load_cfg() + var pull := EditorUpdater.pull(EditorUpdater.git_exe(cfg), project_dir) + if not bool(pull["ok"]): + call_deferred("_update_finished", false, "Update abgebrochen — git pull fehlgeschlagen:", pull["errors"]) + return + # Karte t_f73a1cc5: Wenn der Pull eigene Dateien automatisch beiseite- + # gelegt hat, zeigt die Statuszeile den Klartext statt der technischen + # Import-Meldung (KEINE rohe Git-Zeile). + var info := str(pull.get("info", "")) + if info.is_empty(): + info = "Update geladen — Version wird importiert (Godot-Import-Lauf)…" + call_deferred("_set_status", info) + var godot := TestRun.find_godot(cfg) + if godot.is_empty(): + call_deferred("_update_finished", false, "Update abgebrochen — kein Godot-Programm für den Import-Lauf:", [ + "Der Editor läuft nicht über ein Godot-Binary und es ist kein godot_path gesetzt.", + "Trage in scopedvr_editor.cfg (Godot-App-Daten) ein:", + " [test]", + " godot_path=\"/pfad/zu/godot\"", + ]) + return + var imp := EditorUpdater.run_import(godot, project_dir) + if not bool(imp["ok"]): + call_deferred("_update_finished", false, "Update ABGEBROCHEN — der Import ist fehlgeschlagen, es wird NICHT neu gestartet:", imp["errors"]) + return + call_deferred("_update_finished", true, "", []) + + +func _update_finished(ok: bool, title: String, details: Array) -> void: + _update_running = false + if not is_instance_valid(update_btn) or not is_instance_valid(update_banner): + return # UI wurde zwischendurch neu aufgebaut (UI-Größe) — nichts anfassen + update_btn.disabled = false + _join(update_thread) + update_thread = null + if not ok: + update_banner.visible = true + _show_errors(title, details) + _set_status("Update fehlgeschlagen — der Editor bleibt unverändert (es ist nichts kaputt gemacht).", true) + return + var restart := EditorUpdater.resolve_restart(TestRun.load_cfg()) + var project_dir := ProjectSettings.globalize_path("res://") + var pid := -1 + if str(restart["mode"]) == "command": + var argv: PackedStringArray = restart["argv"] + pid = OS.create_process(str(argv[0]), argv.slice(1)) + else: + var godot := TestRun.find_godot(TestRun.load_cfg()) + if godot.is_empty(): + _show_errors("Update installiert — Neustart nicht möglich:", [ + "Der neue Stand ist geladen, aber das Godot-Programm für den Neustart ist unbekannt.", + "Editor einfach einmal selbst neu starten.", + ]) + _set_status("Update installiert — bitte den Editor einmal selbst neu starten.") + return + pid = OS.create_process(godot, EditorUpdater.self_restart_args(project_dir)) + if pid <= 0: + _show_errors("Update installiert — Neustart fehlgeschlagen:", [ + "Der neue Stand ist geladen, aber der Neustart wurde vom System abgelehnt.", + "Editor einfach einmal selbst neu starten.", + ]) + _set_status("Update installiert — bitte den Editor einmal selbst neu starten.") + return + _set_status("Update installiert (%s) — Editor startet neu…" % EditorUpdater.short_sha(str(_update_result.get("remote", "")))) + await get_tree().create_timer(1.0).timeout + get_tree().quit() + + +## „▶ Karte testen" (Karte t_1cdc1a72): Lauf-Modus IM Map-Builder selbst — +## erste Person, WASD + Maus, ohne Client-Ordner/VR/Server (Slys verbindlicher +## Wunsch: der Map-Builder ist überall installierbar und testet die Map ohne +## jegliche ScopedVR-Client-Abhängigkeit). Der ALTE Client-Start (Export nach +## Temp + eigener Client-Prozess, Karte t_b84af40f) bleibt als „alt" in +## core/editor/test_run.gd — der Rückbau kommt in einer späteren Karte. +func _on_test_run() -> void: + if doc.is_empty(): + _set_status("Erst eine Map anlegen (Datei → Neue Map), dann testen.", true) + return + _start_playtest() + + +## Lauf-Modus anwerfen: Werkzeuge einfrieren, Panels ausblenden, Maus einfangen, +## PlaytestMode in der 3D-Welt anlegen (Spieler am ersten Spawnpunkt der Map). +func _start_playtest() -> void: + if playtest != null: + return + # Editor-Zustand einfrieren (ohne Auswahl/Dokument/History anzufassen): + # laufende Ghost-Platzierung zurückrollen, Gizmo-Zug abbrechen (beides + # rollt ohne History-Eintrag zurück), Werkzeug-Modus auf Auswahl umschalten. + interaction.call("cancel_placement") + if gizmo != null and gizmo.has_method("cancel_drag_if_active"): + gizmo.call("cancel_drag_if_active") + _playtest_tool_mode = tool_mode + tool_mode = "objects" + _playtest_set_frozen(true) + Input.mouse_mode = Input.MOUSE_MODE_CAPTURED + playtest = load("res://core/editor/playtest/playtest_mode.gd").new() + playtest.ui_panels = [ui_top_bar, ui_left_panel, ui_right_panel, ui_status_bar] + # Trenner-Lagen JETZT sichern (Sly-Befund 20.10.: beim Verstecken der + # Panels klappen die Trenner zusammen — nach dem Playtest mussten die + # Seitenbereiche neu gezogen werden). Wiederherstellung im Exit-Handler. + _split_lagen_playtest.clear() + for sname in ["MainSplit", "BottomSplit"]: + var sp := _find_split(sname) + if sp != null: + _split_lagen_playtest[sname] = sp.split_offsets.duplicate() + playtest.ui_status = status_label + playtest.help_label = help_label + playtest.exit_requested.connect(_on_playtest_exit_requested) + world3d.add_child(playtest) + camera.current = false # Editor-Orbit abgeben — die Spiel-Kamera übernimmt + # Karte t_96e3c4ee: Fallback-Reihenfolge mit Klartext-Hinweis — gesetzter + # Test-Start → erster Team-Spawnpunkt → Kartenmitte. + var resolved: Dictionary = TestStart.resolve_start(doc, test_start_point) + playtest.enter(doc, view_builder, resolved["pos"]) + _set_status("▶ Testlauf läuft: WASD laufen, Shift rennen, Space springen, Maus umsehen — ESC zurück zum Editor. (%s)" % str(resolved["status"])) + + +## Editor-Input einfrieren/freigeben (Kamera-Flug, Werkzeuge, Gizmo). +## Nur auf die Werkzeug-Nodes — die Sicht (view_builder) bleibt 1:1 stehen. +func _playtest_set_frozen(on: bool) -> void: + for t in [camera, interaction, terrain_tool, spawn_tool, test_start_tool]: + if t == null: + continue + t.set_process_unhandled_input(not on) + t.set_process(not on) + if gizmo != null: + gizmo.set_process_unhandled_input(not on) + gizmo.set_process(not on) + gizmo.visible = not on + + +## ESC im Lauf-Modus: sauber zurück in den Editor — Werkzeuge + Panels wieder +## an, Maus frei, Kamera + Auswahl unverändert, Dokument + Undo-Stapel unverändert. +func _on_playtest_exit_requested() -> void: + if playtest == null: + return + var mode: Node = playtest + playtest = null + mode.exit() + mode.queue_free() + _playtest_set_frozen(false) + Input.mouse_mode = Input.MOUSE_MODE_VISIBLE + camera.current = true + tool_mode = _playtest_tool_mode + _update_tool_label() + _set_status("Testlauf beendet — zurück im Editor (Auswahl und Dokument unverändert).") + # Trenner-Lagen zurücksetzen (Sly-Befund 20.10.): das Re-Layout nach dem + # Wiedereinblenden der Panels setzt die Trenner auf Defaults — die gemerkten + # Lagen deshalb deferred UND im nächsten Frame zurücksetzen (das Layout + # muss die Panels erst neu vermessen haben, sonst clampen sie erneut). + _playtest_split_lagen_zurueck.call_deferred() + get_tree().process_frame.connect(_playtest_split_lagen_zurueck, CONNECT_ONE_SHOT) + + +## Gemerkte Playtest-Trenner-Lagen zurück auf die Splitter schreiben. +func _playtest_split_lagen_zurueck() -> void: + if _split_lagen_playtest.is_empty(): + return + for sname in _split_lagen_playtest.keys(): + var sp := _find_split(str(sname)) + if sp != null: + sp.split_offsets = _split_lagen_playtest[sname] + + +func _on_new_map_confirmed() -> void: + doc = SvmapDocument.create_new(new_dialog.get_map_name(), new_dialog.get_size_m(), new_dialog.get_weather(), new_dialog.get_game_mode()) + current_path = "" + dirty = false + history.begin(doc) + _clear_edit_state() + _refresh_all() + _test_start_reload() # Karte t_96e3c4ee: neue Map → kein Test-Start gesetzt + _set_status("Neue Map „%s“ erstellt (%.0f × %.0f m, Wetter: %s, Modus: %s). Wähle links ein Objekt, um zu bauen!" % [ + new_dialog.get_map_name(), new_dialog.get_size_m(), new_dialog.get_size_m(), new_dialog.get_weather(), + ModusKatalog.MODE_LABELS[new_dialog.get_game_mode()]]) + + +func _on_open_selected(path: String) -> void: + var result := SvmapIO.load_from_file(path) + var migration := {} + if not result["ok"] and SvmapIO.migrierbar(result["errors"]): + # Gelöschte Pack-Objekte (z. B. Pilze): ersetzen/überspringen statt Abbruch. + var migriert := SvmapIO.load_from_file_migriert(path) + if migriert["ok"]: + result = migriert + migration = migriert["migration"] + if not result["ok"]: + # t_9814f18f: NUR die Prüfsumme (V13) schlägt fehl, Kern (V3–V16) grün → + # Dialog „Trotzdem laden (Prüfsumme erneuern)“ statt hartem Abbruch. + if SvmapIO.checksum_only_failure(result["errors"]): + _resign_pending_path = path + resign_dialog.popup_centered() + return + _show_errors("Map konnte NICHT geladen werden:\n(Falls sie in einem anderen Programm geändert wurde, prüfe die Datei.)", result["errors"]) + _set_status("Laden fehlgeschlagen: %s — versuche eine .svmap-Datei aus dem Map-Editor oder vom Server." % path.get_file(), true) + return + doc = result["data"] + # Feines Material-Raster (Karte 24.10.): alte Karten beim Öffnen anheben — + # optisch gleich, ab jetzt ~1 m fein malbar. Die Datei ändert sich erst + # beim nächsten Speichern (deshalb kein dirty). + SvmapIO.upgrade_material_layer(doc.get("terrain", {})) + # Alte Bau-Sektion „gebaeude“ (vor 25.10.) → normale Bauteil-Objekte in einer Gruppe. + var uebernommen := BauOps.migriere_gebaeude(doc) + current_path = path + dirty = uebernommen > 0 or not migration.is_empty() + history.begin(doc) + _clear_edit_state() + _refresh_all() + _test_start_reload() # Karte t_96e3c4ee: Sidecar der geladenen Map lesen + var map_name := str(doc.get("info", {}).get("name", "?")) + if not migration.is_empty() and int(migration.get("gesamt", 0)) > 0: + _set_status("Map „%s“ geladen. Veraltete Objekte angepasst: %s. Bitte prüfen und speichern — vorher bleibt die Datei unverändert." % [ + map_name, SvmapMigration.zusammenfassung(migration, SvmapIO._manifest_or({}).get("objects", {}))]) + elif uebernommen > 0: + _set_status("Map „%s“ geladen. %d alte Bauteile wurden in das neue Bausystem übernommen (Gruppe „Gebäude“) — Wandhöhe ist jetzt 3 m, bitte kurz prüfen und speichern." % [map_name, uebernommen]) + else: + _set_status("Map „%s“ geladen (%d Objekte). Klicke ein Objekt in der Karte an, um es anzupassen." % [map_name, SvmapDocument.object_count(doc)]) + + +func _clear_edit_state() -> void: + if interaction != null: + interaction.call("clear_selection", true) + interaction.call("cancel_placement") + + +func _save() -> void: + if current_path.is_empty(): + save_dialog.popup_centered() + return + _save_to(current_path) + + +func _on_save_selected(path: String) -> void: + if not path.get_extension().is_empty() and path.get_extension() != "svmap": + path += ".svmap" + _save_to(path) + + +func _save_to(path: String) -> void: + # Felder stehen im Dokument (Live-Bindung) — vor dem Speichern noch einmal + # sicherstellen, dass Name/Autor nicht leer sind (verständliche Meldung statt V4-Kauderwelsch). + var name_v := str(doc.get("info", {}).get("name", "")).strip_edges() + if name_v.is_empty(): + _show_errors("Map konnte nicht gespeichert werden:", ["Die Map braucht einen Namen — trag ihn rechts unter „Map-Eigenschaften“ ein."]) + return + var result := SvmapIO.save_to_file(path, doc) + if not result["ok"]: + _show_errors("Map konnte nicht gespeichert werden (ungültige Map-Daten):", result["errors"]) + _set_status("Speichern fehlgeschlagen.", true) + return + current_path = path + dirty = false + _test_start_reload() # Karte t_96e3c4ee: Punkt wandert beim Speichern mit + _refresh_file_label() + _set_status("Map gespeichert: %s" % path) + _refresh_tree() + + +func _show_errors(title: String, errors: Array) -> void: + var lines := "" + for e in errors: + lines += "• %s\n" % str(e) + error_text.text = "%s\n%s" % [title, lines] + error_dialog.title = "Fehler" + error_dialog.popup_centered() + + +# ------------------------------------------- Karte 3/3: Globale Shortcuts --- + +## Verlust-Operation (Neue Map / Öffnen): bei ungespeicherten Änderungen erst +## NACHFRAGEN (deutscher Dialog), sonst direkt ausführen. Die wartende Aktion +## liegt in _pending_after_dirty und läuft bei „Verwerfen“ an. +func _request_lossy(next: Callable) -> void: + if ShortcutPolicy.needs_dirty_confirm(dirty): + _pending_after_dirty = next + dirty_dialog.popup_centered() + return + next.call() + + +## „Verwerfen“ im Dirty-Dialog: die wartende Aktion (Neu/Öffnen) jetzt ausführen. +func _on_dirty_confirmed() -> void: + var next := _pending_after_dirty + _pending_after_dirty = Callable() + if next.is_valid(): + next.call() + + +## Karte 3/3: Dürfen die globalen Tasten (F1–F5, H) gerade wirken? Pure Policy +## in ShortcutPolicy — hier nur die Fakten: Textfeld/SpinBox fokussiert? Ein +## Dialog/Popup offen? (Eigene Fenster des Editors; das Hilfe-Panel ist +## absichtlich KEIN Fenster und zählt nicht.) +func _tool_key_allowed() -> bool: + var focus := get_viewport().gui_get_focus_owner() + var text_focused: bool = focus != null \ + and (focus is LineEdit or focus is TextEdit or focus is SpinBox) + var dialog_open := false + for child in get_children(): + if child is Window and child.visible: + dialog_open = true + break + return ShortcutPolicy.tool_keys_allowed(text_focused, dialog_open) + + +## Kurzhilfe-Overlay umschalten; Statuszeile meldet den Zustand. +func _toggle_help_overlay() -> void: + help_overlay.visible = not help_overlay.visible + if help_overlay.visible: + _set_status("Kurzhilfe an — H oder Esc schließt das Overlay wieder.") + else: + _base_tool_status() + + +## Permanente Werkzeug-Anzeige (Karte 3/3): aktives Werkzeug + Flug-Hint — +## Sly sieht in der Statuszeile immer, wo er ist. +func _update_tool_label() -> void: + if tool_label == null: + return + var names := { + "objects": "Objekte (F2)", + "terrain": "Terrain (F1)", + "spawns": "Spawn-Zonen (F4)", + } + tool_label.text = "Werkzeug: %s" % str(names.get(tool_mode, tool_mode)) + + +## Symmetrie-Schalter (Karte t_f5935023, M1): Modus aus dem Toolbar-Menü übernehmen. +func _on_sym_mode_selected(index: int) -> void: + sym_mode = clampi(index, 0, SymmetryCore.MODE_LABELS.size() - 1) + _update_sym_ui() + if sym_mode == SymmetryCore.Mode.OFF: + _set_status("Symmetrie aus — die Karte wird nicht mehr automatisch gespiegelt.") + else: + _set_status("Symmetrie: %s — Änderungen an einer Seite werden auf die andere übertragen." % + SymmetryCore.mode_label(sym_mode)) + + +## Symmetrie-Status: Toolbar-Text + Haken + Statuszeilen-Label (M1 Fundament). +## Das tatsächliche Spiegeln von Änderungen kommt mit M2–M4. +func _update_sym_ui() -> void: + if sym_menu == null or sym_label == null: + return + var label := "Symmetrie: %s" % SymmetryCore.mode_label(sym_mode) + sym_label.text = label + sym_menu.select(sym_mode) + if sym_mod != null and sym_mod.has_method("refresh_mode"): + sym_mod.call("refresh_mode") + + +# --------------------------------------------------------------- History ---- + +func _do_undo() -> void: + if not history.can_undo(): + _set_status("Nichts zum Rückgängigmachen — die History ist schon am Anfang.") + return + var desc := history.undo() + _after_structure_change() + _set_status("Rückgängig gemacht: %s. Mit Strg+Y kannst du es wiederherstellen." % desc) + + +func _do_redo() -> void: + if not history.can_redo(): + _set_status("Nichts zum Wiederholen — schon am aktuellsten Stand.") + return + var desc := history.redo() + _after_structure_change() + _set_status("Wiederhergestellt: %s." % desc) + + +## F: Auswahl ins Bild zentrieren (Karte t_c46d31c2) — Kamera-Ziel auf den +## Auswahl-Mittelpunkt; im Flugmodus dreht sich nur die Blickrichtung. +func _focus_selection() -> void: + var indices: Array = interaction.selected_indices + if indices.is_empty(): + _set_status("Nichts ausgewählt — F zentriert die Auswahl im Bild. Klicke zuerst ein Objekt an (im Viewport oder im Baum).") + return + var center := SelectionMath.focus_center(view_builder.object_markers, indices) + camera.call("focus_on", center) + _set_status("%d Objekt(e) ins Bild zentriert — Strg+Klick/Strg+LMB markiert weitere dazu, Entf löscht die ganze Auswahl." % indices.size()) + + +## Karte t_2470de89: Der alte Rechtsklick-Filter (_fly_rmb_blocked) ist weg — +## RMB startet den Freelook-Flug in JEDEM Werkzeugzustand (absoluter Vorrang). + + +func _refresh_history_buttons() -> void: + undo_btn.disabled = not history.can_undo() + redo_btn.disabled = not history.can_redo() + undo_btn.tooltip_text = ("Rückgängig machen: %s (Strg+Z)" % history.undo_desc()) if history.can_undo() else "Nichts zum Rückgängigmachen" + redo_btn.tooltip_text = ("Wiederherstellen: %s (Strg+Y)" % history.redo_desc()) if history.can_redo() else "Nichts zum Wiederholen" + + +func _unhandled_key_input(event: InputEvent) -> void: + if not (event is InputEventKey) or not event.is_pressed() or event.is_echo(): + return + var key_evt := event as InputEventKey + var key := key_evt.keycode + # InputEventKey hat KEIN `command_pressed` (Godot-3-API-Relikt — crashete + # bei jeder Taste, GUI-Start-Befund 15.10.). Die Godot-4-Ersatz-API ist + # is_command_or_control_pressed(): Ctrl auf Linux/Windows, Cmd auf macOS. + var ctrl: bool = key_evt.is_command_or_control_pressed() + # Lauf-Modus (t_1cdc1a72): nur ESC behandeln — ALLE anderen Editor-Tasten + # (F1-F5, Undo/Redo, Werkzeuge) sind im Spiel eingefroren. + if playtest != null and playtest.active: + if key == KEY_ESCAPE: + playtest.handle_escape() + get_viewport().set_input_as_handled() + elif key == KEY_T: + # Karte t_96e3c4ee, „jederzeit": T im Testlauf = Test-Start auf den + # Punkt unterm Fadenkreuz setzen + SOFORT dorthin versetzen + # (Augenhöhe 1,70 m, Kollision geprüft). + var tp: Dictionary = playtest.call("teleport_crosshair") + if bool(tp.get("ok")): + _test_start_apply(float(tp.get("x")), float(tp.get("z")), str(tp.get("hinweis"))) + get_viewport().set_input_as_handled() + return + if (key == KEY_PAGEUP or key == KEY_PAGEDOWN) and not ctrl and interaction.placing \ + and BauKatalog.ist_bau(interaction.place_oid): + interaction.bau_geschoss_aendern(1 if key == KEY_PAGEUP else -1) + get_viewport().set_input_as_handled() + return + match key: + KEY_T: + # Karte t_96e3c4ee: T schaltet das Test-Start-Werkzeug um (Editor). + if not ctrl: + _set_tool_mode("teststart" if tool_mode != "teststart" else "objects") + get_viewport().set_input_as_handled() + KEY_Z: + if ctrl: + if event.shift_pressed: + _do_redo() + else: + _do_undo() + get_viewport().set_input_as_handled() + KEY_Y: + if ctrl: + _do_redo() + get_viewport().set_input_as_handled() + KEY_S: + if ctrl: + if event.shift_pressed: + # Strg+Umschalt+S (Karte 3/3): Speichern unter … + save_dialog.popup_centered() + else: + _save() + get_viewport().set_input_as_handled() + KEY_O: + if ctrl: + # Strg+O (Karte 3/3): Map öffnen — bei dirty erst NACHFRAGEN. + _request_lossy(func() -> void: open_dialog.popup_centered()) + get_viewport().set_input_as_handled() + KEY_N: + if ctrl: + # Strg+N (Karte 3/3): Neue Map — bei dirty erst NACHFRAGEN. + _request_lossy(func() -> void: new_dialog.popup_centered()) + get_viewport().set_input_as_handled() + KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5: + # Karte 3/3: Werkzeugwechsel + Test-Platzhalter. NUR wirken, wenn + # kein Textfeld tippt und kein Dialog offen ist (ShortcutPolicy). + if _tool_key_allowed(): + match key: + KEY_F1: + _set_tool_mode("terrain") + KEY_F2: + _set_tool_mode("objects") + KEY_F3: + _open_bauen_tab() + KEY_F4: + _set_tool_mode("spawns") + KEY_F5: + # ▶ Karte testen: der echte Freigabe-/Test-Flow existiert + # (Karte t_b84af40f) — F5 ruft ihn direkt auf. + _on_test_run() + get_viewport().set_input_as_handled() + KEY_H: + # Karte 3/3: Kurzhilfe-Overlay an/aus (Esc schließt ebenfalls). + if _tool_key_allowed(): + _toggle_help_overlay() + get_viewport().set_input_as_handled() + KEY_L: + # Karte t_89c0ec95: Höhenlinien FIXIEREN an/aus — unabhängig vom + # Werkzeug (wer die Linien dauerhaft will, fixiert sie hier). + # Ohne Modifier (kein Strg+L), gleiche Freigabe wie F1–F5/H: + # Tippen in Textfeldern und offene Dialoge gehen vor. + if not ctrl and _tool_key_allowed(): + _on_contours_toggled(not _contours_on) + get_viewport().set_input_as_handled() + KEY_G: + if ctrl: + # Gruppieren/Lösen (Karte t_f6f29d86) + if event.shift_pressed: + interaction.ungroup_selection() + else: + interaction.group_selection() + get_viewport().set_input_as_handled() + elif tool_mode == "objects" and not interaction.placing: + # G = Greifen (Karte t_55257792, Blender-Semantik): Auswahl + # hängt an der Maus, Linksklick setzt neu, Esc bricht ab. + interaction.grab_begin() + get_viewport().set_input_as_handled() + KEY_R: + var r_delta := -90.0 if event.shift_pressed else 90.0 + if ctrl and not event.alt_pressed: + # Strg+R / Strg+Umschalt+R: KIPPEN um X (±15°, Karte t_e166e656 + # — „nicht nur rotieren, sondern auch kippen“). Bauteile werden + # nie gekippt (fest ausgerichtet). + if BauKatalog.ist_bau(interaction.place_oid): + return + var t_delta: float = -interaction.TILT_STEP_DEG if event.shift_pressed else interaction.TILT_STEP_DEG + if interaction.placing: + interaction.place_tilt_x = fposmod(interaction.place_tilt_x + t_delta + 3600.0, 360.0) + interaction._ghost_rotation_anwenden() + else: + interaction.tilt_selected(true, t_delta) + get_viewport().set_input_as_handled() + elif event.alt_pressed and not ctrl: + # Alt+R / Alt+Umschalt+R: KIPPEN um Z (±15°, Karte t_e166e656). + if BauKatalog.ist_bau(interaction.place_oid): + return + var t_delta2: float = -interaction.TILT_STEP_DEG if event.shift_pressed else interaction.TILT_STEP_DEG + if interaction.placing: + interaction.place_tilt_z = fposmod(interaction.place_tilt_z + t_delta2 + 3600.0, 360.0) + interaction._ghost_rotation_anwenden() + else: + interaction.tilt_selected(false, t_delta2) + get_viewport().set_input_as_handled() + elif not ctrl and not event.alt_pressed: + # R = Vierteldrehung 90° (Karte t_55257792): Objekt-Auswahl UND Ghost + # drehen in 90°-Schritten (Umschalt+R = zurück). Feindrehen 15° + # bleibt am Mausrad (Bauteile: 90° pro Rad-Tick). + if interaction.placing: + interaction.place_rot_deg = wrapf(interaction.place_rot_deg + r_delta, 0.0, 360.0) + interaction._ghost_rotation_anwenden() + else: + interaction.rotate_selected(r_delta) + get_viewport().set_input_as_handled() + KEY_F: + if not ctrl: + if event.shift_pressed: + # Umschalt+F: Freelook-Flug dauerhaft an/aus (Karte t_c46d31c2). + camera.call("toggle_fly_lock") + get_viewport().set_input_as_handled() + else: + # F: Auswahl ins Bild zentrieren. + _focus_selection() + get_viewport().set_input_as_handled() + KEY_ESCAPE: + # Karte 3/3: Steht das Hilfe-Overlay offen, gehört Esc IHM (schließen) + # — VOR der normalen Esc-Prioritätskette. + if help_overlay.visible: + _toggle_help_overlay() + get_viewport().set_input_as_handled() + return + # Karte t_e0120dc2: Läuft gerade ein Gizmo-Zug (Achsen-Pfeil), gehört + # Esc IHM — exakt zurückrollen auf die Zug-Startposition (kein + # History-Eintrag), danach NICHT weiter in der Esc-Kette eintauchen. + if gizmo != null and gizmo.cancel_drag_if_active(): + get_viewport().set_input_as_handled() + return + # Esc-Priorität über pure Funktion (Karte t_c46d31c2, testbar): + # Werkzeug verlassen → Greifen zurückrollen → Ghost-Preview + # abbrechen → Auswahl aufheben (Greifen: Karte t_55257792). + var esc := ShortcutPolicy.esc_action(tool_mode, + interaction.placing, + interaction.selected_index != -1 or not interaction.selected_indices.is_empty(), + bool(interaction.get("_grabbing"))) + match esc: + "exit_terrain": + _set_tool_mode("objects") + _set_status("Terrain-Modus beendet — zurück zum Objekt-Werkzeug.") + "exit_spawns": + _set_tool_mode("objects") + _set_status("Spawn-Werkzeug beendet — zurück zum Objekt-Werkzeug.") + "exit_teststart": + # Der gesetzte Test-Start bleibt bestehen (nur Werkzeug aus). + _set_tool_mode("objects") + _set_status("Test-Start-Werkzeug beendet — zurück zum Objekt-Werkzeug.") + "cancel_grab": + interaction.grab_cancel() + "cancel_placement": + interaction.cancel_placement() + _set_status("Platzieren abgebrochen.") + "clear_selection": + interaction.clear_selection() + _set_status("Auswahl aufgehoben.") + if esc != "none": + get_viewport().set_input_as_handled() + KEY_DELETE: + if not ctrl: + if interaction.placing: + return + if tool_mode == "spawns": + spawn_tool.call("delete_selected") + elif tool_mode == "teststart": + # Karte t_96e3c4ee: Entf im Test-Start-Werkzeug = Punkt löschen. + _test_start_delete() + else: + interaction.delete_selected() + get_viewport().set_input_as_handled() + KEY_D: + if ctrl and tool_mode == "objects": + interaction.duplicate_selected() + get_viewport().set_input_as_handled() + KEY_PAGEUP: + if interaction.placing: + return + if ctrl: + # Strg+Bild↑ (Karte t_55257792): Auswahl auf den Boden. + if tool_mode == "objects" and interaction.selected_index >= 0: + interaction.snap_selection_to_floor() + get_viewport().set_input_as_handled() + elif not ctrl: + if tool_mode == "objects" and interaction.selected_index >= 0: + interaction.lift_selected(ObjectOps.LIFT_STEP_M) + get_viewport().set_input_as_handled() + KEY_PAGEDOWN: + if not ctrl and not interaction.placing: + if tool_mode == "objects" and interaction.selected_index >= 0: + interaction.lift_selected(-ObjectOps.LIFT_STEP_M) + get_viewport().set_input_as_handled() + KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT: + # Pfeiltasten (Karte t_55257792): Auswahl im 2-m-Raster verschieben, + # Richtung = Kamera-Ausrichtung nächste Weltachse (MoveMath). Eine + # Zelle pro Tastendruck; beim Platzieren bleibt der Ghost herrschend. + if interaction.placing: + return + var fwd := 0 + var side := 0 + match key: + KEY_UP: + fwd = 1 + KEY_DOWN: + fwd = -1 + KEY_RIGHT: + side = 1 + KEY_LEFT: + side = -1 + var delta := MoveMath.nudge_delta( + float(camera.call("view_yaw_deg")), fwd, side) + if tool_mode == "objects" and interaction.selected_index >= 0: + interaction.nudge_selection(delta) + get_viewport().set_input_as_handled() + KEY_BRACKETLEFT, KEY_BRACKETRIGHT: + # Terrain-Pinsel [ / ] (Karte t_55257792): Größe durch die 3 Presets + # zyklisch — nur im Terrain-Werkzeug (Ziffern-Freiheit, Punkt 6). + if tool_mode == "terrain": + _terrain_brush_size_step(key == KEY_BRACKETRIGHT) + get_viewport().set_input_as_handled() + KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6: + # Terrain-Pinsel-Modi 1–4 (Karte t_55257792): Heben/Senken/Glätten/ + # Malen — NUR im Terrain-Werkzeug (Konfliktfreiheit, Punkt 6; im + # Objekt-/Bauen-Modus bleiben die Ziffern unbenutzt). + if tool_mode == "terrain": + _terrain_brush_mode_key(int(key) - int(KEY_1)) + get_viewport().set_input_as_handled() + + +# --------------------------------------------------------- Bibliothek ------ +# U1: die Bibliothek wohnt im Assets-Bereich unten (assets_panel.gd); die +# Tools rufen weiter main.call("_highlight_library") — dünne Weiterleitung. + +func _on_library_pressed(oid: String) -> void: + assets_mod._on_library_pressed(oid) + + +## U1-Delegation: die Bibliotheks-Logik wohnt in assets_panel.gd — die alten +## main.-Aufrufe (Werkzeuge/Tests) bleiben als dünne Delegaten erhalten. +func _apply_library_filter(query: String) -> void: + assets_mod._apply_library_filter(query) + + +func _on_library_expand_all() -> void: + assets_mod._on_library_expand_all() + + +func _on_library_collapse_all() -> void: + assets_mod._on_library_collapse_all() + + +## Der Bibliothek-Button des aktiven Platzier-Objekts leuchtet auf. +func _highlight_library(oid: String) -> void: + assets_mod.highlight_library(oid) + if bauen_mod != null: + bauen_mod.sync_platzierung() + + +## Bauen-Tab: Gebäude-Info nachziehen (nach Setzen/Löschen/Undo). +func _refresh_bau_info() -> void: + if bauen_mod != null: + bauen_mod.refresh_info() + + +## „Neues Gebäude beginnen“: nächstes Teil startet eine neue Gruppe. +func _bau_neues_gebaeude() -> void: + interaction.call("neues_gebaeude") + _refresh_bau_info() + _set_status("Neues Gebäude: das nächste Bauteil beginnt eine neue Gruppe.") + + +## Alle Teile des Gebäudes wählen, zu dem die Auswahl gehört. +func _bau_gebaeude_waehlen() -> bool: + var sel: Array = interaction.selected_indices + if sel.is_empty(): + _set_status("Nichts markiert — klicke zuerst ein Bauteil des Gebäudes an.", true) + return false + var alle := {} + for i in sel: + for m in BauOps.gebaeude_von(doc, int(i)): + alle[int(m)] = true + var liste: Array = alle.keys() + liste.sort() + interaction.call("select_many", liste, true) + _set_status("Ganzes Gebäude gewählt (%d Teile) — Ziehen verschiebt, R dreht, Strg+D kopiert, Entf löscht." % liste.size()) + return true + + +func _bau_gebaeude_kopieren() -> void: + if _bau_gebaeude_waehlen(): + interaction.call("duplicate_selected") + + +func _bau_gebaeude_loeschen() -> void: + if _bau_gebaeude_waehlen(): + interaction.call("delete_selected") + + +func object_label(oid: String) -> String: + return LibraryBrowser.object_label(oid) + + +## Snap to Ground (1 Klick): ALLE Objekte auf die Terrain-Höhe setzen — +## EIN Undo-Eintrag für die ganze Aktion. +func _on_snap_to_ground() -> void: + var objects: Array = doc.get("objects", []) + if objects.is_empty(): + _set_status("Es gibt noch keine Objekte — platziere zuerst eins aus der Bibliothek links.") + return + var before: Dictionary = history.snapshot(["objects"]) + var changed := ObjectOps.snap_to_ground(doc) + if changed == 0: + _set_status("Alle %d Objekte stehen schon auf dem Boden — nichts zu tun." % objects.size()) + return + history.commit("Alle Objekte auf Boden gesetzt (%d)" % changed, + before, history.snapshot(["objects"])) + _after_structure_change() + _set_status("%d von %d Objekten auf den Boden gesetzt — Strg+Z nimmt es zurück." % [changed, objects.size()]) + + +func _on_grid_snap_changed(pressed: bool) -> void: + grid_snap = pressed + _set_status("Raster-Snap %s — Objekte landen jetzt %s." % [ + "AN" if pressed else "AUS", + "auf ganzen Metern (wie Bauklötze nebeneinander)" if pressed else "dort, wo du hinklickst"]) + + +# ---------------------------------------------------- Werkzeug-Status ------ + +## Standard-Hilfstext, wenn gerade nichts "Im Gange" ist. +func _base_tool_status() -> void: + _set_status("Bereit. Links ein Objekt anklicken zum Platzieren oder in der Karte ein Objekt auswählen.") + + +# ------------------------------------------------------ Terrain-Werkzeug ---- +# (Karte t_9aba04f1 — Höhenfeld heben/senken/glätten) + +## U1-Delegation: die Widgets wohnen in den Modulen (terrain_panel.gd, +## check_panel.gd); der Koordinator hält die Werkzeug-Logik und steuert die +## Modul-Widgets über deren öffentliche Felder. Methoden, die die Tools per +## main.call(...) erreichen (_on_terrain_stroke_committed, _sync_spawn_selection, +## _refresh_spawn_status, _mark_tree_selection…), bleiben unter denselben +## Namen hier (dünne Weiterleitung) — der Werkzeug-Vertrag ist unverändert. + +## Tab Terrain/Malen/Bauen angeklickt → das Werkzeug ist sofort aktiv, kein +## zweiter Klick auf einen Start-Knopf nötig (Befund 25.10.). +func _on_right_tab_changed(idx: int) -> void: + if terrain_mod == null or malen_mod == null or bauen_mod == null or doc.is_empty(): + return + var tab: Node = (ui_right_panel as TabContainer).get_child(idx) + if tab == terrain_mod: + if tool_mode == "terrain" and not terrain_mod.terrain_mode_paint.button_pressed: + return + if terrain_mod.terrain_mode_paint.button_pressed: + terrain_mod.terrain_mode_raise.button_pressed = true + _set_tool_mode("terrain") + elif tab == malen_mod: + if tool_mode == "terrain" and terrain_mod.terrain_mode_paint.button_pressed: + return + terrain_mod.terrain_mode_paint.button_pressed = true + _set_tool_mode("terrain") + elif tab == bauen_mod: + if tool_mode != "objects": + _set_tool_mode("objects") + # Das Verlassen des Terrain-Werkzeugs schaltet den Tab auf Malen/Terrain + # zurück — der Nutzer wollte aber Bauen. + (ui_right_panel as TabContainer).current_tab = bauen_mod.get_index() + + +func _on_terrain_btn_pressed() -> void: + if tool_mode != "terrain": + if terrain_mod.terrain_mode_paint.button_pressed: + terrain_mod.terrain_mode_raise.button_pressed = true + _set_tool_mode("terrain") + else: + _set_tool_mode("objects") + + +## Werkzeug-Modus wechseln: "objects" (Platzieren/Auswahl), "terrain" (Pinsel), +## "spawns" (Spawn-Zonen malen). +func _set_tool_mode(mode: String) -> void: + if mode == tool_mode: + _sync_terrain_button() + _sync_spawn_button() + _sync_test_start_button() + _update_tool_label() + return + if mode == "terrain": + _leave_spawn_mode() + _leave_test_start_mode() + _enter_terrain_mode() + elif mode == "spawns": + _leave_terrain_mode() + _leave_test_start_mode() + _enter_spawn_mode() + elif mode == "teststart": + _leave_terrain_mode() + _leave_spawn_mode() + _enter_test_start_mode() + else: + _leave_terrain_mode() + _leave_spawn_mode() + _leave_test_start_mode() + _enter_objects_mode() + _update_tool_label() + # Karte t_89c0ec95: Werkzeugwechsel = Höhenlinien-Umschalter — nach dem + # Terrain-Werkzeug (F1) wieder aus, bei Terrain-Eintritt wieder an + # (sofern nicht fixiert). Signal-getrieben an diesem EINEN Wechselpunkt, + # kein per-Frame-Poll. + _sync_contours_to_builder() + + +func _enter_terrain_mode() -> void: + interaction.call("cancel_placement") + interaction.call("clear_selection", true) + if not terrain_tool.call("activate"): + # Abgelehnt (z. B. Auflösungs-Limit) — Button zurück, Meldung steht. + _sync_terrain_button() + return + tool_mode = "terrain" + help_label.text = "Linksklick-Ziehen: formen bzw. malen · Strg+Klick: Gegenteil · [ ]: Pinselgröße · H: Hilfe" + terrain_tool.call("set_brush_mode", terrain_mod._selected_terrain_mode()) + terrain_mod.refresh_panels() + _set_status("Terrain-Modus an: LINKSKLICK-Ziehen formt den Boden, im Malen-Modus färbt er das Gelände (Steppe/Sand/Fels …). Regler rechts stellen Pinsel und Stärke ein.") + + +func _leave_terrain_mode() -> void: + if terrain_tool != null: + terrain_tool.call("deactivate") + _sync_terrain_button() + + +func _enter_spawn_mode() -> void: + interaction.call("cancel_placement") + interaction.call("clear_selection", true) + tool_mode = "spawns" + check_mod.spawn_panel.visible = true + help_label.text = "Linksklick: Zone setzen · Ziehen: verschieben · Entf: löschen · H: Hilfe" + check_mod.spawn_edit_btn.button_pressed = true + spawn_tool.call("activate") + spawn_tool.call("set_team", check_mod._selected_spawn_team()) + spawn_tool.call("set_radius", float(check_mod.spawn_radius_slider.value)) + _refresh_spawn_status() + _set_status("Spawn-Modus an: Klicke auf den Boden, um Zonen für %s zu malen. Die Kreis-Vorschau folgt der Maus." % SpawnOps.team_label(check_mod._selected_spawn_team())) + + +func _leave_spawn_mode() -> void: + if spawn_tool != null: + spawn_tool.call("deactivate") + if check_mod != null: + check_mod.spawn_panel.visible = false + _sync_spawn_button() + + +func _enter_objects_mode() -> void: + tool_mode = "objects" + help_label.text = "Linksklick: auswählen · Rahmen: mehrere · R: drehen · Entf: löschen · H: Hilfe" + _base_tool_status() + + +# ------------------------------------------------------------- Bauen ------ +# Bauteile sind normale Bibliotheks-Objekte (bau_*): das Bauen-Panel startet die +# Platzierung in interaction.gd (Ghost rastet über BuildSnap). Kein eigener +# Werkzeug-Modus mehr — Auswahl, Drehen, Kopieren, Löschen, Undo laufen über die +# Objekt-Werkzeuge. + + +## F3 / Menü: Bauen-Tab zeigen (wechselt aus Terrain-/Spawn-Modus zurück zu Objekten). +func _open_bauen_tab() -> void: + if tool_mode != "objects": + _set_tool_mode("objects") + if ui_right_panel is TabContainer and bauen_mod != null: + (ui_right_panel as TabContainer).current_tab = bauen_mod.get_index() + _set_status("Bauen: Bauteil rechts anklicken, dann in die Karte klicken — Wände rasten an Zellkanten, Böden in die Zellmitte, alles aufs 2-m-Raster.") + + +## Bauteil im Bauen-Tab angeklickt → Platzieren mit Snap starten. +func _on_bauteil_gewaehlt(oid: String) -> void: + if tool_mode != "objects": + _set_tool_mode("objects") + interaction.call("start_placement", oid) + + +func _sync_terrain_button() -> void: + terrain_mod.refresh_panels() + + +func _terrain_brush_size_step(up: bool) -> void: + terrain_mod.terrain_brush_size_step(up) + + +func _terrain_brush_mode_key(mode_idx: int) -> void: + var t: Control = terrain_mod + var btn: Button = null + match mode_idx: + 0: + btn = t.terrain_mode_raise + 1: + btn = t.terrain_mode_lower + 2: + btn = t.terrain_mode_smooth + 3: + btn = t.terrain_mode_paint + 4: + btn = t.terrain_mode_flatten + 5: + btn = t.terrain_mode_ramp + if btn == null or terrain_tool == null: + return + btn.set_pressed(true) + var labels := ["Heben", "Senken", "Glätten", "Malen", "Einebnen", "Rampe"] + var extra := "" + if mode_idx == 3: + var mats: Array = SvmapIO.MATERIAL_IDS + extra = " (Material: %s — mit der Palette rechts wechseln)" % str(mats[clampi(int(terrain_tool.get("paint_material")), 0, mats.size() - 1)]) + _set_status("Pinsel-Modus: %s%s — Linksklick-Ziehen formt/malt jetzt so (Ziffern 1–6 wechseln)." % [str(labels[mode_idx]), extra]) + + +## Ein Pinsel-Strich ist fertig (Doc + History schon aktualisiert vom Tool). +func _on_terrain_stroke_committed() -> void: + dirty = true + _refresh_file_label() + _refresh_stats() + _refresh_history_buttons() + view_builder.call("rebuild_terrain_from_doc", doc) + var desc: String = history.undo_desc() + _set_status("%s — Strg+Z macht den ganzen Strich rückgängig." % desc) + + +## Terrain-Modus nach Laden/Neu/Undo mit dem Doc synchron halten (Cache frisch, +## Auflösungs-Limit prüfen — sonst dezenter Rückschalter). +func _recheck_terrain_mode() -> void: + if tool_mode != "terrain" or terrain_tool == null: + return + if not terrain_tool.call("refresh_from_doc"): + terrain_tool.call("deactivate") + tool_mode = "objects" + _sync_terrain_button() + _update_tool_label() + # Karte t_89c0ec95: Dezenter Terrain-Rückschalter = ebenfalls ein + # Werkzeugwechsel — Linien wieder ausblenden (sofern nicht fixiert). + _sync_contours_to_builder() + help_label.text = "Linksklick: auswählen · Rahmen: mehrere · R: drehen · Entf: löschen · H: Hilfe" + _set_status("Terrain-Modus aus: Diese Map passt nicht ins Editor-MVP (Terrain-Auflösung über %d) — die Objekte bleiben normal bearbeitbar." % TerrainField.EDITOR_MAX_RESOLUTION, true) + + +# ---------------------------------------------------- Spawn-Zonen-Werkzeug --- + +func _on_spawn_btn_pressed() -> void: + check_mod._on_spawn_btn_pressed() + + +func _sync_spawn_button() -> void: + check_mod.spawn_edit_btn.button_pressed = tool_mode == "spawns" + + +## Panel-Zeile „Welche Zone ist angewählt?“ — WIRD vom Spawn-Tool gerufen. +func _sync_spawn_selection() -> void: + check_mod.sync_spawn_selection() + + +## LIVE-Validierung (Loader-Regeln) — immer sichtbar, nach JEDEM Struktur-Wechsel. +func _refresh_spawn_status() -> void: + check_mod.refresh_spawn_status() + + +## Map-Fertig-Check (Export-Button-Aktion): Klartext-Liste + Shake, wenn fehlt. +func _on_check_map() -> void: + var report := SpawnOps.ready_report(doc, manifest) + var lines := "" + for line in report["lines"]: + lines += "%s\n" % str(line["text"]) + var hint := str(line.get("hint", "")) + if hint != "": + lines += " → %s\n" % hint + check_text.text = lines + check_dialog.popup_centered() + if report["ok"]: + _set_status("✅ Karte prüfen: Alles bereit zum Export! Speichern erzeugt die signierte .svmap-Datei.") + else: + _shake_button(_registry_toolbar_button("karte_pruefen")) + _set_status("Map ist noch nicht bereit — siehe Warnungen im Map-Check-Fenster.", true) + + +## Kurzes Wackeln des Buttons — AUFMERKSAMKEIT statt Fehlerbombe (Chef-Grundsatz). +func _shake_button(btn: Control) -> void: + var orig: Vector2 = btn.position + var tween := create_tween() + for offset in [-9.0, 9.0, -6.0, 6.0, -3.0, 0.0]: + tween.tween_property(btn, "position", orig + Vector2(offset, 0.0), 0.045) + + +## Toolbar-Button per Registry-ID finden (karte_pruefen / karte_testen …). +func _registry_toolbar_button(id: String) -> Control: + var found: Array = toolbar_mod.find_children(id, "Button", true, false) + return found[0] if not found.is_empty() else null + + +## Baum-Rückrufe wohnen jetzt im Modul (core/ui/panels/scene_tree_panel.gd); +## die Tools rufen weiter main.call("_mark_tree_selection…") — dünne +## Weiterleitungen unten (Registry-Koordinator). +# ------------------------------------------------------- Struktur-Änderung -- + +## Nach undo/redo/platzieren/löschen: Struktur hat sich geändert → Ansicht neu. +func _after_structure_change() -> void: + dirty = true + _refresh_bau_info() + _refresh_file_label() + _refresh_stats() + _refresh_history_buttons() + _refresh_spawn_status() + if interaction != null: + interaction.call("clear_selection", true) + view_builder.call("rebuild", doc, manifest) + _sync_grid_to_builder() + # Karte t_89c0ec95: der Rebuild baut terrain_view NEU (Default-Pref „an“) + # — auch die Höhenlinien brauchen ihren Nacheich (Gitter-Muster). Sonst + # kehrte z. B. nach Strg+Z die Dauersicht zurück, die Sly störte. + _sync_contours_to_builder() + _refresh_tree() + if map_mod != null: + map_mod.refresh_values() # Undo/Redo: Wetter/Himmel-Auswahl nachziehen + _recheck_terrain_mode() + if interaction != null: + interaction.call("refresh_terrain_cache") # t_4092e3a0: Objekt-Cursor trifft das Gelände + if tool_mode == "spawns" and spawn_tool != null: + spawn_tool.call("refresh_from_doc") + +# --------------------------------------------------------------- Anzeige --- + +func _refresh_all() -> void: + _loading_ui_values = true + map_mod.refresh_values() + _loading_ui_values = false + + _refresh_tree() + _refresh_stats() + _refresh_file_label() + _refresh_history_buttons() + _refresh_viewport() + _refresh_spawn_status() + _recheck_terrain_mode() + + +func _refresh_viewport() -> void: + view_builder.call("rebuild", doc, manifest) + _sync_grid_to_builder() + _sync_contours_to_builder() + # Karte K1b (t_eca890c5): Laden/Neu = Ansicht auf den Karten-INHALT + # (Objekte + Bauteile + Spawnpunkte; Terrain zählt nicht) — ohne Inhalt + # wie bisher die ganze Karte. Pos1 (Home) bleibt ganze Karte. + var fb: Dictionary = doc.get("bounds", {}) + var fmn: Array = fb.get("min", []) + var fmx: Array = fb.get("max", []) + if fmn.size() == 3 and fmx.size() == 3: + camera.call("fit_to_document", doc, + Vector3(fmn[0], fmn[1], fmn[2]), Vector3(fmx[0], fmx[1], fmx[2])) + + +# --- Maßstabsgitter (Karte t_7ac70014) ------------------------------------- + +func _on_grid_toggled(pressed: bool) -> void: + _grid_on = pressed + _sync_grid_to_builder() + + +## Nach jedem Viewport-Rebuild: Nutzer-Wahl (bzw. Boden-Referenz ohne Terrain- +## Block) wieder anwenden — der Rebuild setzt das Gitter auf seinen Default. +func _sync_grid_to_builder() -> void: + if view_builder == null: + return + var no_terrain: bool = doc.get("terrain", {}).is_empty() + view_builder.call("set_grid_visible", _grid_on or no_terrain) + if grid_btn != null and grid_btn.button_pressed != _grid_on: + grid_btn.set_pressed_no_signal(_grid_on) + + +# --- Höhenlinien (Karte t_3ebe4086, Werkzeug-Kopplung t_89c0ec95) ------------ + +## Effektive Höhenlinien-Sichtbarkeit: FIX-Anforderung des Nutzers (L/Button) +## ODER das Terrain-Werkzeug (F1) ist aktiv. Bewusst KEIN _process-Poll — +## der Hook hängt am Werkzeug-Wechselpunkt (_set_tool_mode) und am Button/L. +func _contours_effective() -> bool: + return _contours_on or tool_mode == "terrain" + + +func _on_contours_toggled(pressed: bool) -> void: + _contours_on = pressed + _sync_contours_to_builder() + if status_label != null: + _set_status("Höhenlinien %s — %s" % [ + "FIXIERT AN" if _contours_on else "Fix aus", + "jetzt in jedem Werkzeug sichtbar (L oder Button schaltet zurück)." + if _contours_on else + "sichtbar nur noch im Terrain-Werkzeug (F1). L fixiert sie wieder."]) + + +## Nach jedem Viewport-Rebuild und nach JEDEM Werkzeug-Wechsel: die effektive +## Wahl anwenden — der Rebuild baut das Terrain-Mesh (und damit dessen +## Shader-Uniform) neu, der Werkzeugwechsel blendet die Linien ein/aus. +func _sync_contours_to_builder() -> void: + if view_builder == null: + return + var terrain_view = view_builder.get("terrain_view") + if terrain_view != null and is_instance_valid(terrain_view): + terrain_view.call("set_contours", _contours_effective()) + if contours_btn != null and contours_btn.button_pressed != _contours_on: + contours_btn.set_pressed_no_signal(_contours_on) + + +# --- Baum / Auswahl-Sync (U1: Module, dünne Weiterleitung) ------------------- + +func _refresh_tree() -> void: + tree_mod.refresh_tree() + + +## Baum-Klicks kommen im Modul an; die Viewport-Seite (interaction.gd) ruft +## weiter main.call("_mark_tree_selection…") — hier weiterleiten. +func _mark_tree_selection(idx: int) -> void: + tree_mod.mark_tree_selection(idx) + + +func _mark_tree_selection_multi(indices: Array) -> void: + tree_mod.mark_tree_selection_multi(indices) + + +## Rechte Panel-Sektion synchronisieren (wird von interaction.gd gerufen). +func _sync_selection_panel() -> void: + selection_mod.sync_selection() + + +## Hilfs-Meldung zur frischen Auswahl (wird von interaction.gd gerufen). +func _selection_status(idx: int) -> void: + selection_mod.selection_status(idx) + + +func _refresh_stats() -> void: + var count := SvmapDocument.object_count(doc) + var poly := SvmapDocument.poly_usage(doc, manifest) + var budget := int(SvmapIO.MAX_TOTAL_POLY) + var poly_pct := 100.0 * poly / budget + stats_objects.text = "%d Objekte · Poly %.0f %%" % [count, poly_pct] + stats_objects.tooltip_text = "Objekte: %d / 5000\nPoly-Budget: %s / %s (%.0f %%)\nBauteile: %d" % [ + count, _fmt_int(int(poly)), _fmt_int(budget), poly_pct, BauOps.teile_zahl(doc)] + # Nur bei knappem Budget auffällig färben (sonst ruhiger Nebentext). + stats_objects.add_theme_color_override("font_color", get_theme_color( + "warning" if poly_pct >= 90.0 or count >= 4500 else "field", "Editor")) + # GLB-Fehlende Objekte (Karte t_9b50b231): Platzhalter laufen, aber Sly soll + # sehen, WELCHE echten Modelle im Mesh-Lager nachgelegt werden müssen. + if view_builder != null and not (view_builder.get("fehlende_glbs") as Array).is_empty(): + var fehlend: Array = view_builder.get("fehlende_glbs") + var nennung := ", ".join(fehlend.slice(0, 3)) + if fehlend.size() > 3: + nennung += " … (+%d weitere)" % (fehlend.size() - 3) + stats_objects.text += " · ⚠ GLB fehlt: %s" % nennung + # Terrain-Anteil am Quest-3-Budget (res 513 = 524.288 Dreiecke, map_format.md §4) + var tris := 0 + var res := 0 + if view_builder != null and view_builder.get("terrain_view") != null: + tris = int(view_builder.terrain_view.call("triangle_count")) + res = int(view_builder.terrain_view.call("resolution")) + var quest_budget := 524288 + var pct := 100.0 * float(tris) / float(quest_budget) + var fps := Engine.get_frames_per_second() + stats_terrain.text = "Terrain %s² · %d FPS" % [str(res) if res > 0 else "—", fps] + stats_terrain.tooltip_text = "Terrain: %s² Grid, %s Dreiecke (%.0f %% Quest-Budget)" % [ + str(res) if res > 0 else "—", _fmt_int(tris), pct] + + +func _refresh_file_label() -> void: + var map_name := str(doc.get("info", {}).get("name", "Ohne Namen")) + if current_path.is_empty(): + file_label.text = "„%s“ (noch nicht gespeichert)%s" % [map_name, " •" if dirty else ""] + else: + file_label.text = "„%s“ — %s%s" % [map_name, current_path.get_file(), " •" if dirty else ""] + # Karte t_297221b5: bei egalisiertem Label (große Stufe, schmales Fenster) + # steht der volle Name im Tooltip. + file_label.tooltip_text = file_label.text + # U7 (Karte t_2336c58e): ungespeicherte Änderungen auch im FENSTERTITEL — + # so sieht man sie selbst dann, wenn die Datei-Leiste egalisiert ist. + get_window().title = "%s — %s%s" % [APP_TITLE, map_name, + " (ungespeichert)" if dirty else ""] + + +func _set_status(text: String, is_error := false) -> void: + if status_label == null or not is_instance_valid(status_label): + return # UI wurde gerade neu aufgebaut (UI-Größe) — nichts anfassen + status_label.text = text + # U7: Statusfarben über das Theme (Editor/colors/status_error/_ok). + status_label.add_theme_color_override("font_color", + get_theme_color("status_error" if is_error else "status_ok", "Editor")) + + +func _fmt_int(value: int) -> String: + var s := str(value) + var out := "" + while s.length() > 3: + out = "." + s.substr(s.length() - 3) + out + s = s.substr(0, s.length() - 3) + return s + out + + +# ------------------------------------------------------- U1 Dock-Zustand ---- + +## Splitter-Lagen (Assets-Höhe) aus der Config lesen — NACH _build_ui. +func _load_dock_state() -> void: + var cfg := ConfigFile.new() + if cfg.load(UIScale.cfg_path()) == OK: + var l: Variant = cfg.get_value(UIScale.WIN_SECTION, "dock_links", null) + if l is float or l is int: + _dock_offsets["links"] = float(l) + var r: Variant = cfg.get_value(UIScale.WIN_SECTION, "dock_rechts", null) + if r is float or r is int: + _dock_offsets["rechts"] = float(r) + var u: Variant = cfg.get_value(UIScale.WIN_SECTION, "dock_unten", null) + if u is float or u is int: + _dock_offsets["unten"] = float(u) + _apply_dock_state() + + +## Gemerkte Lagen anwenden — deferred, weil das Layout erst nach dem ersten +## Layout-Durchlauf vermessene Größen hat. +func _apply_dock_state() -> void: + if DisplayServer.get_name() == "headless": + return + _apply_dock_state_deferred.call_deferred() + + +func _apply_dock_state_deferred() -> void: + if _dock_offsets.is_empty(): + return + var main_split := _find_split("MainSplit") + if main_split != null and _dock_offsets.has("links"): + main_split.split_offset = UIScale.f(float(_dock_offsets["links"])) + var bottom := _find_split("BottomSplit") + if bottom != null and _dock_offsets.has("unten"): + bottom.split_offset = -UIScale.f(float(_dock_offsets["unten"])) + + +func _find_split(sname: String) -> SplitContainer: + var found := find_children(sname, "SplitContainer", true, false) + return found[0] if not found.is_empty() else null + + +## Splitter-Lagen merken (beim Schließen, neben der Fensterlage). +func _save_dock_state() -> void: + if DisplayServer.get_name() == "headless": + return + var main_split := _find_split("MainSplit") + var bottom := _find_split("BottomSplit") + var cfg := ConfigFile.new() + cfg.load(UIScale.cfg_path()) + if main_split != null: + cfg.set_value(UIScale.WIN_SECTION, "dock_links", main_split.split_offset) + if bottom != null: + cfg.set_value(UIScale.WIN_SECTION, "dock_unten", float(-bottom.split_offset)) + cfg.save(UIScale.cfg_path()) + + +# ---------------------------------------------------- Screenshot-Demo ------- + +## Desktop-Smoke-Hilfe: `godot ... -- --ghost-demo [x z objekt-id]` parkt die +## Platzier-Vorschau sichtbar in der Map und zoomt die Kamera heran, damit ein +## Screenshot die Vorschau zeigen kann (nur für Smoke-Tests). +func _maybe_start_demo_mode() -> void: + var args := OS.get_cmdline_user_args() + if args.has("--terrain-demo"): + _start_terrain_demo(args) + return + if args.has("--library-demo"): + _start_library_demo(args) + return + if args.has("--spawns-demo"): + _start_spawns_demo(args) + return + if args.has("--groups-demo"): + _start_groups_demo(args) + return + if args.has("--bauen-demo"): + _start_bauen_demo(args) + return + if args.has("--ui-demo"): + _start_ui_demo(args) + return + if not args.has("--ghost-demo"): + return + var oid := "box_001" + var x := 0.0 + var z := 0.0 + for i in args.size(): + if args[i] == "--ghost-demo": + if i + 1 < args.size(): + x = float(args[i + 1]) + if i + 2 < args.size(): + z = float(args[i + 2]) + if i + 3 < args.size(): + oid = args[i + 3] + var pos := Vector3(x, SvmapDocument.terrain_height_at(doc, x, z), z) + interaction.demo_park_ghost(pos, oid) + # Demo-Aufbau: zwei Objekte setzen und eins orange auswählen — zeigt + # Ghost-Preview UND Auswahl-Markierung in einem Smoke-Screenshot. + if args.has("--ghost-demo-select"): + var before: Dictionary = history.snapshot(["objects"]) + (doc["objects"] as Array).append({"id": "water_tower_004", "pos": [6.0, 0.0, 0.0], "scale": 1.0, "rot_y_deg": 0.0}) + (doc["objects"] as Array).append({"id": "box_001", "pos": [0.0, 0.0, 0.0], "scale": 1.0, "rot_y_deg": 0.0}) + history.commit("Demo: Objekte gesetzt", before, history.snapshot(["objects"])) + interaction.call("clear_selection", true) + _refresh_all() + interaction.select_object(1, true) + else: + _refresh_history_buttons() + # Kamera nah heran, damit die Vorschau im Screenshot gut sichtbar ist. + camera.target = pos + Vector3(0.0, 0.6, 0.0) + camera.distance = 14.0 + camera.pitch_deg = 32.0 + camera.yaw_deg = 40.0 + camera.call("_apply") + + +# ----------------------------------------------------- UI-Größen-Demo-Screens -- + +## `godot ... -- --ui-demo [ordner] [--ui-demo-res BxH] [--ui-demo-quit]` +## (Karte t_297221b5): fährt ALLE UI-Größen-Stufen programmatisch durch — +## pro Stufe kompletter UI-Neuaufbau (derselbe Pfad wie der Menü-Klick) und +## ein Fenster-Screenshot. Beweist: umschaltbar im Lauf + nichts abgeschnitten. +func _start_ui_demo(args: PackedStringArray) -> void: + var out_dir := "/tmp/scopedvr_ui" + var idx := args.find("--ui-demo") + if idx >= 0 and idx + 1 < args.size() and not args[idx + 1].begins_with("--"): + out_dir = args[idx + 1] + DirAccess.make_dir_recursive_absolute(out_dir) + var res_idx := args.find("--ui-demo-res") + if res_idx >= 0 and res_idx + 1 < args.size(): + var parts := str(args[res_idx + 1]).split("x") + if parts.size() == 2: + # Fenstergröße NICHT zu früh setzen — direkt bei _ready wird der + # Wert von der Projekt-Einstellung überschrieben (xvfb-Befund); + # erst nach dem ersten Frame ist der Resize stabil. + await get_tree().process_frame + DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_WINDOWED) + DisplayServer.window_set_size(Vector2i(int(parts[0]), int(parts[1]))) + get_window().size = Vector2i(int(parts[0]), int(parts[1])) # root-Window setzt durch (xvfb-Befund) + for i in UIScale.step_count(): + UIScale.set_step_index(i) + _rebuild_ui_for_scale() + await get_tree().process_frame + await get_tree().process_frame + _set_status("UI-Größe: %s (%.2f-fach) — Theme-Schrift %d px, Beweis-Screenshot." % [ + UIScale.step_label(i), UIScale.factor(), UIScale.font_size()]) + await _demo_shot(out_dir + "/ui_%s.png" % UIScale.step_key(i)) + print("UI_DEMO: Stufe %s Faktor %.2f Schrift %d" % [UIScale.step_key(i), UIScale.factor(), UIScale.font_size()]) + print("UI_DEMO_OK: %d Stufen, PNGs in %s" % [UIScale.step_count(), out_dir]) + if args.has("--ui-demo-quit"): + get_tree().quit() # Batch-Smoke (xvfb): automatisch beenden nach den Shots + + +# ------------------------------------------------ Terrain-Demo-Screenshots -- + +## `godot ... -- --terrain-demo [ordner]` — Desktop-Smoke (Karte t_9aba04f1): +## fährt die Terrain-Szenarien programmatisch durch und speichert PNGs: +## Hügel heben, Senke senken, glätten, Undo-Roundtrip. Die App bleibt offen +## (Sly sieht das Ergebnis live auf dem Desktop). +func _start_terrain_demo(args: PackedStringArray) -> void: + var out_dir := "/tmp/scopedvr_terrain" + var idx := args.find("--terrain-demo") + if idx >= 0 and idx + 1 < args.size() and not args[idx + 1].begins_with("--"): + out_dir = args[idx + 1] + DirAccess.make_dir_recursive_absolute(out_dir) + + _set_tool_mode("terrain") + terrain_mod.terrain_radius_slider.value = 45.0 + terrain_mod.terrain_strength_slider.value = 10.0 + terrain_mod.terrain_mode_raise.button_pressed = true + + # 1) Hügel heben — Pinsel-Ring bleibt als visueller Beweis im Bild. + terrain_tool.call("demo_stroke", -80.0, -60.0, TerrainField.Mode.RAISE, 1.4) + terrain_tool.call("demo_park_brush", -80.0, -60.0) + _demo_camera(Vector3(-80.0, 12.0, -60.0), 150.0, 32.0, 40.0) + _set_status("Demo 1/5: Hügel GEHOBEN (Radius 45 m, Stärke 10 m/s) — der grüne Ring ist der Pinsel.") + await _demo_shot(out_dir + "/terrain_raise.png") + + # 2) Senke senken (roter Ring). + terrain_mod.terrain_mode_lower.button_pressed = true + terrain_tool.call("demo_stroke", 90.0, 50.0, TerrainField.Mode.LOWER, 1.2) + terrain_tool.call("demo_park_brush", 90.0, 50.0) + _demo_camera(Vector3(90.0, 2.0, 50.0), 150.0, 32.0, -50.0) + _set_status("Demo 2/5: Senke GESSENKT (Strg+Linksklick senkt, ohne umzuschalten).") + await _demo_shot(out_dir + "/terrain_lower.png") + + # 3) Hügelkuppe glätten (blauer Ring). + terrain_mod.terrain_mode_smooth.button_pressed = true + terrain_tool.call("demo_stroke", -70.0, -50.0, TerrainField.Mode.SMOOTH, 0.9) + terrain_tool.call("demo_park_brush", -70.0, -50.0) + _demo_camera(Vector3(-70.0, 10.0, -50.0), 130.0, 35.0, 20.0) + _set_status("Demo 3/5: Kuppe GLÄTTET — rau wird weich, ohne die Form zu zerstören.") + await _demo_shot(out_dir + "/terrain_smooth.png") + + # 4) Undo-Roundtrip: kleiner Strich → Undo → Boden wieder flach. + terrain_mod.terrain_mode_raise.button_pressed = true + terrain_mod.terrain_radius_slider.value = 30.0 + terrain_tool.call("demo_stroke", 0.0, 150.0, TerrainField.Mode.RAISE, 0.9) + terrain_tool.call("demo_park_brush", 0.0, 150.0) + _demo_camera(Vector3(0.0, 8.0, 150.0), 120.0, 35.0, 0.0) + _set_status("Demo 4/5: Test-Hügel für den Undo-Vergleich geformt.") + await _demo_shot(out_dir + "/terrain_before_undo.png") + _do_undo() + _set_status("Demo 5/5: Strg+Z — der GANZE Strich ist zurück, der Boden ist wieder flach.") + await _demo_shot(out_dir + "/terrain_after_undo.png") + + print("TERRAIN_DEMO_OK: 5 Screenshots in %s" % out_dir) + + +func _demo_camera(target: Vector3, dist: float, pitch: float, yaw: float) -> void: + camera.target = target + camera.distance = dist + camera.pitch_deg = pitch + camera.yaw_deg = yaw + camera.call("_apply") + + +func _demo_shot(path: String) -> void: + for i in 5: + await get_tree().process_frame + await RenderingServer.frame_post_draw + var img := get_viewport().get_texture().get_image() + img.save_png(path) + print("DEMO_SHOT: %s (%d×%d)" % [path, img.get_width(), img.get_height()]) + var tv = view_builder.get("terrain_view") + if tv != null and is_instance_valid(tv): + var mi = tv.get("_mi") + if mi != null and is_instance_valid(mi) and mi.mesh != null: + var aabb: AABB = mi.mesh.get_aabb() + print("DEMO_AABB: pos=%s size=%s tris=%d" % [aabb.position, aabb.size, tv.triangle_count()]) + print("DEMO_CAM: cam=%s target=%s" % [camera.global_position, camera.target]) + + +## `godot ... -- --library-demo [ordner]` — Desktop-Smoke (Karte t_3a998ae4): +## Gruppen-Bibliothek + platzierte Objekte + Snap-to-Ground programmatisch +## durchspielen, PNGs speichern. Die App bleibt offen. +func _start_library_demo(args: PackedStringArray) -> void: + var out_dir := "/tmp/scopedvr_library" + var idx := args.find("--library-demo") + if idx >= 0 and idx + 1 < args.size() and not args[idx + 1].begins_with("--"): + out_dir = args[idx + 1] + DirAccess.make_dir_recursive_absolute(out_dir) + + # 1) Bibliothek-Browser: Gruppen sichtbar, Ghost-Preview aktiv. + _set_status("Demo 1/3: Bibliothek in Gruppen — ein Objekt anklicken setzt eine Vorschau in die Karte.") + interaction.demo_park_ghost(Vector3(10.0, SvmapDocument.terrain_height_at(doc, 10.0, 6.0), 6.0), "water_tower_004") + _demo_camera(Vector3(0.0, 2.0, 0.0), 90.0, 35.0, 40.0) + await _demo_shot(out_dir + "/library_browser.png") + + # 2) Objekte platziert (versch. Gruppen), eins orange ausgewählt. + var before: Dictionary = history.snapshot(["objects"]) + (doc["objects"] as Array).append({"id": "water_tower_004", "pos": [10.0, 0.0, 6.0], "scale": 1.0, "rot_y_deg": 30.0}) + (doc["objects"] as Array).append({"id": "box_001", "pos": [-8.0, 0.0, -4.0], "scale": 1.0, "rot_y_deg": 0.0}) + (doc["objects"] as Array).append({"id": "acacia_005", "pos": [-20.0, 0.0, 18.0], "scale": 1.0, "rot_y_deg": 75.0}) + (doc["objects"] as Array).append({"id": "rock_008", "pos": [24.0, 0.0, -18.0], "scale": 1.0, "rot_y_deg": 0.0}) + history.commit("Demo: Objekte gesetzt", before, history.snapshot(["objects"])) + interaction.call("cancel_placement") + _clear_edit_state() + _refresh_all() + interaction.select_object(0, true) + _demo_camera(Vector3(0.0, 2.0, 0.0), 110.0, 40.0, -35.0) + _set_status("Demo 2/3: Objekte platziert (Wachturm orange ausgewählt) — ziehen, drehen, löschen wie gehabt.") + await _demo_shot(out_dir + "/library_placed.png") + + # 3) Snap to Ground: Objekte künstlich in die Luft hängen, dann 1 Klick. + var float_before: Dictionary = history.snapshot(["objects"]) + for obj in (doc["objects"] as Array): + var pos: Array = obj["pos"] + obj["pos"] = [float(pos[0]), float(pos[1]) + 7.0, float(pos[2])] + history.commit("Demo: Objekte schweben", float_before, history.snapshot(["objects"])) + _refresh_all() + _demo_camera(Vector3(0.0, 6.0, 0.0), 110.0, 30.0, -35.0) + _set_status("Demo 3/3a: Objekte SCHWEBEN nach dem Terrain-Formen — ein Klick auf „Alles auf den Boden setzen\" …") + await _demo_shot(out_dir + "/library_floating.png") + _on_snap_to_ground() + _demo_camera(Vector3(0.0, 4.0, 0.0), 110.0, 38.0, -35.0) + _set_status("Demo 3/3b: … und schon stehen ALLE wieder auf dem Boden (Strg+Z nimmt den ganzen Klick zurück).") + await _demo_shot(out_dir + "/library_after_snap.png") + print("LIBRARY_DEMO_OK: 4 Screenshots in %s" % out_dir) + if args.has("--library-demo-quit"): + get_tree().quit() # Batch-Smoke (xvfb): automatisch beenden, sobald die Shots da sind + + +## `godot ... -- --spawns-demo [ordner]` — Desktop-Smoke (Karte t_c4162c5d): +## Spawn-Zonen-Workflow programmatisch durchspielen, PNGs speichern: +## Zonen-Übersicht → Live-Check schlägt Alarm bei fehlenden Zonen → Undo rettet → +## Map-Check-Dialog meldet bereit. Die App bleibt offen (Sly sieht das live). +func _start_spawns_demo(args: PackedStringArray) -> void: + var out_dir := "/tmp/scopedvr_spawns" + var idx := args.find("--spawns-demo") + if idx >= 0 and idx + 1 < args.size() and not args[idx + 1].begins_with("--"): + out_dir = args[idx + 1] + DirAccess.make_dir_recursive_absolute(out_dir) + + # 1) Übersicht: Default-Zonen beider Teams (Kreise) + rote Ghost-Vorschau. + _set_tool_mode("spawns") + check_mod.spawn_team_red.button_pressed = true + spawn_tool.call("demo_park_ghost", 260.0, 120.0, 1, 12.0) + _demo_camera(Vector3(160.0, 140.0, 0.0), 700.0, 48.0, -90.0) + _set_status("Demo 1/4: Spawn-Zonen — blaue Kreise = Team Blau, rote = Team Rot, halbtransparent folgt der Ghost der Maus als Vorschau.") + await _demo_shot(out_dir + "/spawns_zones.png") + + # 2) ALLE roten Zonen löschen → Live-Check springt auf ❌ (BEVOR exportiert wird). + _clear_edit_state() + var before: Dictionary = SpawnOps.snapshot_blocks(history, doc) + for p in SpawnOps.points(doc, 1).duplicate(): + SpawnOps.remove_point(doc, 1, str(p["id"])) + history.commit("Demo: alle roten Zonen gelöscht", before, + SpawnOps.snapshot_blocks(history, doc)) + _after_structure_change() + _set_status("Demo 2/4: ALLE roten Zonen weg — der Spawn-Check (rechts) zeigt sofort ❌: Export wäre blockiert.") + await _demo_shot(out_dir + "/spawns_check.png") + + # 3) Strg+Z — alle vier roten Zonen sind zurück (EIN Undo-Schritt). + _do_undo() + _set_status("Demo 3/4: Strg+Z — alle 4 roten Zonen sind auf EINMAL zurück.") + await _demo_shot(out_dir + "/spawns_undo.png") + + # 4) Karte prüfen: Klartext-Liste im Dialog + Status „Alles bereit“. + _on_check_map() + _set_status("Demo 4/4: „Karte prüfen“ — alles ✅ … beim Speichern wird die .svmap automatisch signiert (sha256).") + await _demo_shot(out_dir + "/spawns_ready.png") + print("SPAWNS_DEMO_OK: 4 Screenshots in %s" % out_dir) + if args.has("--spawns-demo-quit"): + get_tree().quit() # Batch-Smoke (xvfb): automatisch beenden, sobald die Shots da sind + + +## `godot ... -- --groups-demo [ordner]` — Desktop-Smoke (Karte t_f6f29d86): +## Auswahl-System programmatisch durchspielen, PNGs speichern: +## Mehrfachauswahl (Rahmen simuliert) → gruppieren → Gruppe gemeinsam ziehen → +## gemeinsames Drehen → Undo-Nachweis. Die App bleibt offen (Sly sieht live). +func _start_groups_demo(args: PackedStringArray) -> void: + var out_dir := "/tmp/scopedvr_groups" + var idx := args.find("--groups-demo") + if idx >= 0 and idx + 1 < args.size() and not args[idx + 1].begins_with("--"): + out_dir = args[idx + 1] + DirAccess.make_dir_recursive_absolute(out_dir) + + # Aufbau: 4 Objekte in zwei Wohnclustern (2 nahe beieinander = spätere Gruppe). + var before: Dictionary = history.snapshot(["objects"]) + (doc["objects"] as Array).append({"id": "water_tower_004", "pos": [10.0, 0.0, 6.0], "scale": 1.0, "rot_y_deg": 0.0}) + (doc["objects"] as Array).append({"id": "box_001", "pos": [14.0, 0.0, 9.0], "scale": 1.0, "rot_y_deg": 0.0}) + (doc["objects"] as Array).append({"id": "box_002", "pos": [14.0, 0.0, 13.0], "scale": 1.0, "rot_y_deg": 45.0}) + (doc["objects"] as Array).append({"id": "acacia_005", "pos": [-30.0, 0.0, 24.0], "scale": 1.0, "rot_y_deg": 0.0}) + history.commit("Demo: Objekte gesetzt", before, history.snapshot(["objects"])) + _refresh_all() + + # 1) Mehrfachauswahl: Objekte 0–2 markiert (wie nach Rahmen-Ausziehen). + interaction.call("select_many", [0, 1, 2], true) + _demo_camera(Vector3(0.0, 2.0, 0.0), 130.0, 40.0, -35.0) + _set_status("Demo 1/4: Mehrfachauswahl — 3 Objekte orange (Umschalt+Klick oder Rahmen aufziehen). Der Baum links bleibt außen vor.") + await _demo_shot(out_dir + "/groups_select.png") + + # 2) Gruppieren: EIN Klick, die 3 gehören ab jetzt zusammen. + interaction.call("group_selection") + _set_status("Demo 2/4: „Gruppieren“ — die 3 Objekte sind jetzt Gruppe 1. Der Baum links ist NICHT Teil der Gruppe.") + await _demo_shot(out_dir + "/groups_grouped.png") + + # 3) Gruppe gemeinsam ziehen (exakt der Drag-Release-Pfad) + gemeinsames Drehen. + interaction.call("demo_drag_selection", Vector3(24.0, 0.0, -18.0)) + interaction.call("rotate_selected", 30.0) + _demo_camera(Vector3(20.0, 2.0, 0.0), 130.0, 42.0, -20.0) + _set_status("Demo 3/4: Gruppe GEMEINSAM verschoben und um die eigene Mitte gedreht — die Anordnung bleibt erhalten, der Baum stand still.") + await _demo_shot(out_dir + "/groups_moved.png") + + # 4) Undo-Nachweis: Strg+Z nimmt die Drehung zurück (EIN Schritt), die + # zweite Stufe würde den Zug zurücknehmen — jede Aktion = EIN Undo-Schritt. + _do_undo() + _demo_camera(Vector3(20.0, 2.0, 0.0), 130.0, 42.0, -20.0) + _set_status("Demo 4/4: Strg+Z — die Drehung ist zurück (Zug & Drehen sind getrennte Schritte); die Gruppe bleibt gebunden.") + await _demo_shot(out_dir + "/groups_undo.png") + print("GROUPS_DEMO_OK: 4 Screenshots in %s" % out_dir) + if args.has("--groups-demo-quit"): + get_tree().quit() # Batch-Smoke (xvfb): automatisch beenden, sobald die Shots da sind + + +## `godot ... -- --bauen-demo [ordner]` — Desktop-Smoke: baut programmatisch ein +## kleines Haus mit denselben Funktionen wie der Klick (BauSnap + BauOps), zeigt +## Ghost, Gebäude-Auswahl und Weiterbauen nach Speichern/Laden. Die App bleibt +## offen (Sly sieht das Ergebnis live). +func _start_bauen_demo(args: PackedStringArray) -> void: + var out_dir := "/tmp/scopedvr_bauen" + var idx := args.find("--bauen-demo") + if idx >= 0 and idx + 1 < args.size() and not args[idx + 1].begins_with("--"): + out_dir = args[idx + 1] + DirAccess.make_dir_recursive_absolute(out_dir) + _set_tool_mode("objects") + interaction.call("start_placement", "bau_wand") + interaction.call("demo_park_bau", Vector3(2.0, 0.0, 1.0)) + _demo_camera(Vector3(3.0, 2.0, 8.0), 14.0, 32.0, 25.0) + _set_status("Demo 1/3: Bauen — die Vorschau rastet auf die Zellkante ein.") + await _demo_shot(out_dir + "/bauen_ghost.png") + interaction.call("cancel_placement") + var gid := BauOps.haus_demo(doc, history, Vector3(4.0, 0.0, 4.0)) + _after_structure_change() + _demo_camera(Vector3(4.0, 1.5, 4.0), 13.0, 30.0, 35.0) + _set_status("Demo 2/3: Kleines Haus gebaut (Gruppe %d) — Fundament, Wände, Tür, Fenster, Giebel, Dach, Treppe." % (gid + 1)) + await _demo_shot(out_dir + "/bauen_haus.png") + _save_to(out_dir + "/bauen_demo.svmap") + var reload := SvmapIO.load_from_file(out_dir + "/bauen_demo.svmap") + if bool(reload["ok"]): + doc = reload["data"] + history.begin(doc) + _clear_edit_state() + _refresh_all() + _demo_camera(Vector3(4.0, 1.5, 4.0), 13.0, 30.0, 35.0) + _set_status("Demo 3/3: Gespeichert und wieder geladen — das Haus ist als Gruppe erhalten.") + await _demo_shot(out_dir + "/bauen_weiter.png") + print("BAUEN_DEMO_OK: 3 Screenshots in %s (%d Bauteile, Map OK)" % [out_dir, BauOps.teile_zahl(doc)]) + if args.has("--bauen-demo-quit"): + get_tree().quit() # Batch-Smoke (xvfb): automatisch beenden, sobald die Shots da sind + + +## --- Test-Start: Haken (T1b-Vertrag, Operator-Wiederanbindung 20.10.) -------- +## Diese drei Namen erwartet tests/test_playtest_spawn.gd (56 checks) auf main. +## Sie waren beim U1-Umbau verschwunden (Suite brach mit „Nonexistent function +## '_test_start_reload'" ab und hing) — deshalb stehen sie hier bewusst fest. +## Der sichtbare Teil (Info + Löschen) lebt in core/ui/panels/test_start_panel.gd, +## der Zustand hier — genau wie vor dem Umbau. +func _test_start_apply(x: float, z: float, hinweis: String) -> void: + test_start_point = Vector3(x, 0.0, z) + TestStartStore.save_point(current_path, test_start_point) + if test_start_tool != null: + test_start_tool.call("refresh_from_doc") + _refresh_test_start_panel() + # Klartext-Hinweis des Werkzeugs (z.B. „auf dem Boden unter dem Objekt") + # mitnehmen — die Prüfsuite liest ihn aus der Statuszeile. + var ort := " (Höhe automatisch)" if hinweis.is_empty() else " (Höhe automatisch — %s)" % hinweis + _set_status("Test-Start: x=%.0f z=%.0f%s — F5 startet den Testlauf genau dort." % [x, z, ort]) + + +func _test_start_delete() -> void: + if test_start_point == null: + return + test_start_point = null + TestStartStore.clear_point(current_path) + if test_start_tool != null: + test_start_tool.call("refresh_from_doc") + _refresh_test_start_panel() + + +func _test_start_reload() -> void: + test_start_point = TestStartStore.load_point(current_path) + if test_start_tool != null: + test_start_tool.call("refresh_from_doc") + _refresh_test_start_panel() + + +func _refresh_test_start_panel() -> void: + if test_start_panel != null and is_instance_valid(test_start_panel): + test_start_panel.call("refresh_point", test_start_point) + + +## --- Test-Start: Werkzeug-Modus (wie Terrain/Spawns/Bauen) -------------------- +## Die Prüfsuite erwartet tool_mode == "teststart", einen leuchtenden Leisten- +## Knopf (`test_start_btn`) und das erst dann sichtbare Panel (`test_start_panel`). +func _enter_test_start_mode() -> void: + interaction.call("cancel_placement") + tool_mode = "teststart" + if test_start_tool != null: + test_start_tool.call("activate") + _sync_test_start_button() + _sync_test_start_panel_visibility() + + +func _leave_test_start_mode() -> void: + if test_start_tool != null: + test_start_tool.call("deactivate") + # Direkt aus-/einschalten statt über tool_mode: _set_tool_mode ruft die + # _leave_*-Funktionen BEVOR der Zielmodus gesetzt ist — ein Abgleich gegen + # tool_mode ließe das Panel offen (Befund aus test_playtest_spawn). + if test_start_panel != null: + test_start_panel.visible = false + if test_start_btn != null: + test_start_btn.button_pressed = false + + +func _sync_test_start_button() -> void: + if test_start_btn != null: + test_start_btn.button_pressed = (tool_mode == "teststart") + + +func _sync_test_start_panel_visibility() -> void: + if test_start_panel != null: + test_start_panel.visible = (tool_mode == "teststart") + + +## Leisten-Knopf „🎯 Test-Start" (registry.gd ACTIONS) — schaltet das Werkzeug um. +func _on_test_start_tool_pressed() -> void: + _set_tool_mode("objects" if tool_mode == "teststart" else "teststart") + + +# -------------------------------- Fremdformat-Dialog (t_9814f18f) ----------- + +## „Trotzdem laden (Prüfsumme erneuern)“ bestätigt: Datei NUR gegen die +## Kern-Validierung (V3–V16) prüfen, v2-Prüfsumme ins Dokument schreiben und +## normal öffnen. dirty=true: das Dokument weicht von der Datei ab — der +## nächste Speicher-Vorgang schreibt das v2-Schema in die Datei. +func _on_resign_confirmed() -> void: + var result := SvmapIO.load_from_file_resign(_resign_pending_path) + if not result["ok"]: + _show_errors("Map konnte NICHT geladen werden (auch ohne Prüfsummen-Prüfung):", result["errors"]) + _set_status("Laden fehlgeschlagen: %s" % _resign_pending_path.get_file(), true) + return + doc = result["data"] + SvmapIO.upgrade_material_layer(doc.get("terrain", {})) # feines Material-Raster + BauOps.migriere_gebaeude(doc) # alte Bau-Sektion → Bauteil-Objekte + current_path = _resign_pending_path + dirty = true + history.begin(doc) + _clear_edit_state() + _refresh_all() + _test_start_reload() + var map_name := str(doc.get("info", {}).get("name", "?")) + _set_status("Map „%s“ geladen — Prüfsumme erneuert (v2). Speichere die Map, um die neue Prüfsumme zu übernehmen." % map_name) + _refresh_file_label() diff --git a/ui/main.gd.uid b/ui/main.gd.uid new file mode 100644 index 0000000..115239e --- /dev/null +++ b/ui/main.gd.uid @@ -0,0 +1 @@ +uid://c5j3bplirtg6k diff --git a/ui/new_map_dialog.gd b/ui/new_map_dialog.gd new file mode 100644 index 0000000..d092869 --- /dev/null +++ b/ui/new_map_dialog.gd @@ -0,0 +1,94 @@ +extends ConfirmationDialog +## „Neue Map“-Dialog: Name, Größe, Wetter-Preset — bewusst nur 3 Fragen, +## alles Weitere setzt vernünftige Defaults (Chef-Grundsatz: easy). + +const UIScale := preload("res://core/ui/ui_scale.gd") # Karte t_297221b5 + +var name_edit: LineEdit +var size_option: OptionButton +var weather_option: OptionButton +var mode_option: OptionButton + +var _sizes: Array[float] = [512.0, 1024.0, 2048.0] +var _size_labels := ["Klein — 512 × 512 m", "Mittel — 1024 × 1024 m", "Groß — 2048 × 2048 m"] +var _weathers := ["mittag", "abend", "regen", "nacht"] +var _weather_labels := ["Mittag (sonnig, klar)", "Abend (warmes Licht)", "Regen (grau, kühl)", "Nacht (dunkel)"] + + +func _init() -> void: + title = "Neue Map" + ok_button_text = "Map erstellen" + cancel_button_text = "Abbrechen" + min_size = UIScale.v2i(460, 0) + + var vbox := VBoxContainer.new() + vbox.anchors_preset = Control.PRESET_FULL_RECT + vbox.set_anchors_preset(Control.PRESET_FULL_RECT) + vbox.add_theme_constant_override("separation", UIScale.px(12)) + add_child(vbox) + + vbox.add_child(_make_label("Wie soll die Map heißen?")) + name_edit = LineEdit.new() + name_edit.text = "Neue Map" + name_edit.max_length = 64 + name_edit.custom_minimum_size = UIScale.v2(0, 40) + vbox.add_child(name_edit) + + vbox.add_child(_make_label("Wie groß soll das Gelände sein?")) + size_option = OptionButton.new() + for label in _size_labels: + size_option.add_item(label) + size_option.select(1) # Mittel als Default + size_option.custom_minimum_size = UIScale.v2(0, 40) + # U7: Klartext-Tooltips (Karte t_2336c58e). + size_option.tooltip_text = "Kantenlänge des Geländes — größer = mehr Platz zum Bauen" + vbox.add_child(size_option) + + vbox.add_child(_make_label("Welches Wetter soll die Map haben?")) + weather_option = OptionButton.new() + for label in _weather_labels: + weather_option.add_item(label) + weather_option.custom_minimum_size = UIScale.v2(0, 40) + weather_option.tooltip_text = "Licht und Stimmung der Karte (Tag/Abend/Regen/Nacht)" + vbox.add_child(weather_option) + + vbox.add_child(_make_label("Welchen Spielmodus soll die Map haben?")) + mode_option = OptionButton.new() + for m in ModusKatalog.MODES: + mode_option.add_item(ModusKatalog.MODE_LABELS[m]) + mode_option.custom_minimum_size = UIScale.v2(0, 40) + mode_option.tooltip_text = "Team-Deathmatch: Kills zählen. Conquest: Teams nehmen mehrere Zonen ein. King of the Hill: ein Hill, der wandert. Deathmatch: alle gegen alle. Lässt sich später im Map-Tab ändern." + vbox.add_child(mode_option) + + var hint := _make_label("Die Map startet leer mit 4 Spawn-Punkten pro Team\n(Blau im Westen, Rot im Osten) — beides lässt sich später ändern.") + hint.modulate = Color(1, 1, 1, 0.7) + vbox.add_child(hint) + + +func _make_label(text: String) -> Label: + var label := Label.new() + label.text = text + label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART + # FIX 20.10.: autowrap-Label ohne Mindestbreite meldet vor dem ersten + # Layout eine explosionsartige Mindesthöhe (Probe: Fenster 4781 px hoch + # statt ~390) — Popup-Größe wird daraus einmalig übernommen. Mindestbreite + # ~ Dialogbreite verankert den Umbruch an der echten Breite. + label.custom_minimum_size = Vector2(UIScale.px(440), 0) + return label + + +func get_map_name() -> String: + var n := name_edit.text.strip_edges() + return n if not n.is_empty() else "Neue Map" + + +func get_size_m() -> float: + return _sizes[size_option.selected] + + +func get_game_mode() -> String: + return ModusKatalog.MODES[mode_option.selected] + + +func get_weather() -> String: + return _weathers[weather_option.selected] diff --git a/ui/new_map_dialog.gd.uid b/ui/new_map_dialog.gd.uid new file mode 100644 index 0000000..4bc1260 --- /dev/null +++ b/ui/new_map_dialog.gd.uid @@ -0,0 +1 @@ +uid://d1tevsdsnf8ih diff --git a/ui/panels/assets_panel.gd b/ui/panels/assets_panel.gd new file mode 100644 index 0000000..62d223c --- /dev/null +++ b/ui/panels/assets_panel.gd @@ -0,0 +1,782 @@ +extends "res://core/ui/panels/editor_panel.gd" +## Objekt-Bibliothek / Assets-Bereich (aus main.gd ausgezogen, Karte t_eaccbfed; +## Unity-artiger Ausbau Karte t_69687afc/U4): Kategorien-Leiste, Suche, Zuletzt +## benutzt, Vorschau-Kacheln mit Name + ID, Hover vergrößert die ID, fehlende +## Modelle werden markiert (nicht stillschweigend), Klick wählt aus, +## Doppelklick startet das Platzier-Werkzeug wie bisher. +## Der Bereich wohnt UNTEN unter der 3D-Ansicht (Unity-Projekt-Fenster-Platz). +## +## Kompatibilität (main.gd bindet diese Felder — NICHT umbenennen): +## library_search, library_buttons, _library_group_rows, +## library_open_all_btn, library_close_all_btn, +## _on_library_pressed(), _apply_library_filter(), +## _on_library_expand_all(), _on_library_collapse_all(), highlight_library(). +## Die Klapp-Gruppen bleiben als Körper der „Alle"-Ansicht erhalten; die +## Kategorien-Leiste filtert dieselben Zeilen (Mechanik wie die Suche). + +signal object_selected(oid: String) # Klick auf eine Kachel (nur bei Wechsel) +signal object_activated(oid: String) # Doppelklick — Werkzeug-Start (U5 koppelt) + +const LIBRARY_CFG_SECTION := "library" # Abschnitt in user://scopedvr_editor.cfg +const RECENT_CFG_KEY := "zuletzt_benutzt" # selbiger Abschnitt, Liste von IDs +const RECENT_MAX := 12 # gemerkte Objekte (neueste zuerst) +const CAT_ALLE := "alle" # Pseudo-Kategorie: alles +const CAT_ZULETZT := "zuletzt" # Pseudo-Kategorie: zuletzt benutzt + +var library_box: VBoxContainer +var library_buttons: Dictionary = {} # id → Button (Haupt-Grid, kanonisch) +## Bibliothek-Gruppen (t_59fc0f21): Klapp-Zustand + Zeilen für Suche/Alle auf/zu. +var library_search: LineEdit +var library_open_all_btn: Button +var library_close_all_btn: Button +var _library_group_open: Dictionary = {} # Gruppen-Key → auf/zu +var _library_group_rows: Array = [] # {key, header, box, ids} +var _library_bold_font: Font = null + +# --- U4 neu: Kategorien, Zähler, Zuletzt benutzt, Auswahl ------------------- +var library_counter: Label # „N von M sichtbar" +var _cat_chips: HFlowContainer # Kategorien-Leiste +var _cat_buttons: Dictionary = {} # Key → Chip-Button +var _cat_active: String = CAT_ALLE # aktive Kategorie (Chip) +var _recent_box: VBoxContainer # Zuletzt-benutzt-Ansicht (im Scroll) +var _recent_grid: GridContainer +var _recent_tiles: Dictionary = {} # id → Button (Zuletzt-Ansicht, frisch gebaut) +var _recent_ids: Array = [] # Reihenfolge: neueste zuerst +var _drag_oid := "" # Kachel, die gerade gezogen wird +var _drag_started_placement := false # Ziehen hat das Platzieren gestartet +var selected_oid: String = "" # per Klick gewähltes Objekt +var _id_font_normal: int = 0 # ID-Schriftgröße (skaliert), Normalzustand +var _empty_hint: Label # Leerzustand (U7): kein Treffer / leerer Bereich + + +static func spec() -> Dictionary: + return {"titel": "Objekt-Bibliothek", "gruppe": "unten", "order": 10} + + +func panel_title() -> String: + return "Objekt-Bibliothek" + + +## Bau: Überschrift → Suche → Kategorien-Leiste → Alle auf/zu → Zähler → +## Klapp-Gruppen-Körper („Alle") + Zuletzt-benutzt-Ansicht. +func build() -> void: + add_child(_header_label("Objekt-Bibliothek")) + + # Suche (t_59fc0f21): tippen filtert live nach Name/ID — Gruppen mit + # Treffern klappen auf, leere Gruppen verschwinden. Größe ist von + # test_ui_scale gepinnt (36 → 45 bei „Mittel") — nicht ändern. + library_search = LineEdit.new() + library_search.placeholder_text = "Suchen (Name oder ID)…" + library_search.clear_button_enabled = true + library_search.custom_minimum_size = UIScale.v2(0, 36) + library_search.text_changed.connect(_apply_library_filter) + library_search.text_submitted.connect(func(_t: String) -> void: library_search.release_focus()) + add_child(library_search) + + _build_category_chips() + + # „Alle auf" / „Alle zu" (t_59fc0f21): Klapp-Zustand aller Gruppen auf einmal. + var group_btns := HBoxContainer.new() + group_btns.add_theme_constant_override("separation", UIScale.px(8)) # U7-Raster + library_open_all_btn = Button.new() + library_open_all_btn.text = "Alle auf" + library_open_all_btn.size_flags_horizontal = Control.SIZE_EXPAND_FILL + library_open_all_btn.tooltip_text = "Klappt ALLE Gruppen auf" + library_open_all_btn.pressed.connect(_on_library_expand_all) + group_btns.add_child(library_open_all_btn) + library_close_all_btn = Button.new() + library_close_all_btn.text = "Alle zu" + library_close_all_btn.size_flags_horizontal = Control.SIZE_EXPAND_FILL + library_close_all_btn.tooltip_text = "Klappt ALLE Gruppen zu" + library_close_all_btn.pressed.connect(_on_library_collapse_all) + group_btns.add_child(library_close_all_btn) + add_child(group_btns) + + # Zähler „N von M sichtbar" (U4): M = Objekte im aktiven Bereich, N = davon + # durch Suche/Kategorie sichtbar. + library_counter = Label.new() + # U7: Nebentext-Größe + Theme-Farbe (Editor/colors/field). + library_counter.add_theme_font_size_override("font_size", UIScale.small_font_size()) + library_counter.add_theme_color_override("font_color", theme_color("field")) + library_counter.tooltip_text = "Sichtbare Kacheln im aktiven Bereich" + add_child(library_counter) + + var scroll := ScrollContainer.new() + scroll.size_flags_vertical = Control.SIZE_EXPAND_FILL + scroll.custom_minimum_size = UIScale.v2(0, 320) + scroll.horizontal_scroll_mode = ScrollContainer.SCROLL_MODE_DISABLED + add_child(scroll) + library_box = VBoxContainer.new() + library_box.size_flags_horizontal = Control.SIZE_EXPAND_FILL + library_box.add_theme_constant_override("separation", UIScale.px(4)) + scroll.add_child(library_box) + # Leerzustand (U7, „fertig aussehen"): freundlicher Klartext statt + # stummer leerer Fläche — Suchbegriff ohne Treffer oder leerer Bereich. + _empty_hint = Label.new() + _empty_hint.text = "Nichts gefunden — anderen Suchbegriff oder „Alle“ versuchen." + _empty_hint.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART + _empty_hint.add_theme_color_override("font_color", theme_color("muted")) + _empty_hint.visible = false + scroll.add_child(_empty_hint) + _recent_box = VBoxContainer.new() + _recent_box.visible = false + _recent_box.add_theme_constant_override("separation", UIScale.px(4)) + library_box.add_child(_recent_box) + _fill_library() + _recent_ids = _recent_load() + _update_recent_chip() + _apply_library_filter(library_search.text) + + +# ------------------------------------------------------------ Kategorien ---- + +## Kategorien-Leiste (U4): „Alle" + eine Chip je Bibliotheks-Gruppe +## (LibraryBrowser.groups_in_order — KEINE eigene Kategorieliste) + +## „Zuletzt benutzt". Chips zeigen Name + Anzahl; Summe der Gruppen-Chips = +## Gesamtzahl (test_assets_panel rechnet nach). +func _build_category_chips() -> void: + _cat_chips = HFlowContainer.new() + _cat_chips.add_theme_constant_override("h_separation", UIScale.px(4)) + _cat_chips.add_theme_constant_override("v_separation", UIScale.px(4)) + add_child(_cat_chips) + var bg := ButtonGroup.new() + var groups := LibraryBrowser.groups_in_order(main.manifest) + _cat_add_chip(CAT_ALLE, "Alle", _manifest_count(), bg) + for group in groups: + var g_key: String = group["key"] + var g_ids: Array = group["ids"] + if g_ids.is_empty(): + continue + _cat_add_chip(g_key, str(group["label"]), g_ids.size(), bg) + _cat_add_chip(CAT_ZULETZT, "Zuletzt benutzt", 0, bg) + (_cat_buttons[CAT_ZULETZT] as Button).visible = false # taucht auf, sobald benutzt + + +func _manifest_count() -> int: + return (main.manifest.get("objects", {}) as Dictionary).size() + + +func _cat_add_chip(key: String, label: String, count: int, bg: ButtonGroup) -> void: + var chip := Button.new() + chip.toggle_mode = true + chip.button_group = bg + chip.button_pressed = key == _cat_active + chip.text = "%s (%d)" % [label, count] if key != CAT_ZULETZT else label + chip.custom_minimum_size = UIScale.v2(0, 28) + chip.tooltip_text = "Zeigt nur die Gruppe „%s“" % label if key != CAT_ALLE and key != CAT_ZULETZT else "Zeigt alle Objekte" if key == CAT_ALLE else "Die zuletzt ausgewählten/benutzten Objekte" + chip.set_meta("cat_key", key) + chip.set_meta("cat_count", count) + chip.toggled.connect(_on_cat_chip_toggled.bind(key)) + _cat_chips.add_child(chip) + _cat_buttons[key] = chip + + +func _on_cat_chip_toggled(on: bool, key: String) -> void: + if not on: + return # Radio-Gruppe: der neue Chip drückt sich selbst an + _select_category(key) + + +## Kategorie wechseln: Zustand merken (kein Config-Zwang — Chips sind +## Ansichtsfilter, der Klapp-Zustand je Gruppe bleibt in der cfg). +func _select_category(key: String) -> void: + if key != CAT_ZULETZT and not _cat_buttons.has(key): + return + _cat_active = key + for chip_key in _cat_buttons: + var chip := _cat_buttons[chip_key] as Button + chip.set_pressed_no_signal(str(chip_key) == _cat_active) + _apply_library_filter(library_search.text) + + +func _update_recent_chip() -> void: + var chip := _cat_buttons.get(CAT_ZULETZT) as Button + if chip == null: + return + chip.visible = not _recent_ids.is_empty() + chip.text = "Zuletzt benutzt (%d)" % _recent_ids.size() + + +## Objekte des aktiven Bereichs (M im Zähler): Alle → Gesamtkatalog, +## Kategorie → deren IDs, Zuletzt → gemerkte Liste. +func _scope_ids() -> Array: + var lib: Dictionary = main.manifest.get("objects", {}) + if _cat_active == CAT_ALLE: + return lib.keys() + if _cat_active == CAT_ZULETZT: + return _recent_ids.duplicate() + for row in _library_group_rows: + if str(row["key"]) == _cat_active: + return (row["ids"] as Array).duplicate() + return [] + + +# -------------------------------------------------------- Klapp-Gruppen ---- + +func _fill_library() -> void: + library_buttons.clear() + _library_group_rows.clear() + _library_group_open = _library_load_open_states() + # Gruppen-Browser (Karte t_3a998ae4, Überarbeitung t_59fc0f21): + # - Klapp-Überschriften je Gruppe (fett, 18 px, Name + Anzahl), + # - STANDARD EINGEKLAPPT — nur die erste Gruppe ist offen (Übersicht!), + # - Klapp-Zustand je Gruppe wird in user://scopedvr_editor.cfg gemerkt, + # - Objekte als Kacheln mit 96-px-Vorschaubild (2 Spalten je Gruppe). + # U4: der Körper bleibt („Alle“-Ansicht), die Kategorien-Leiste filtert ihn. + var first_open: String = "" + for group in LibraryBrowser.groups_in_order(main.manifest): + var g_key: String = group["key"] + var g_label: String = group["label"] + var g_ids: Array = group["ids"] + if g_ids.is_empty(): + continue + if first_open.is_empty(): + first_open = g_key + var is_open: bool = _library_group_open.get(g_key, g_key == first_open) + _library_group_open[g_key] = is_open + var header := Button.new() + header.text = _library_header_text(is_open, g_label, g_ids.size()) + header.toggle_mode = true + header.button_pressed = is_open + header.alignment = HORIZONTAL_ALIGNMENT_LEFT + header.custom_minimum_size = UIScale.v2(0, 34) + header.tooltip_text = "Gruppe „%s“ auf-/zuklappen" % g_label + header.add_theme_font_size_override("font_size", UIScale.heading_font_size()) + header.add_theme_font_override("font", _library_header_font()) + library_box.add_child(header) + var group_box := VBoxContainer.new() + group_box.add_theme_constant_override("separation", UIScale.px(4)) + group_box.visible = is_open + var grid := GridContainer.new() + grid.columns = 2 + grid.size_flags_horizontal = Control.SIZE_EXPAND_FILL + grid.add_theme_constant_override("h_separation", UIScale.px(8)) # U7-Raster + grid.add_theme_constant_override("v_separation", UIScale.px(8)) # U7-Raster + group_box.add_child(grid) + library_box.add_child(group_box) + header.toggled.connect(_on_library_group_toggled.bind(g_key, g_label, g_ids.size(), header, group_box)) + for oid in g_ids: + _add_library_button(str(oid), grid) + _library_group_rows.append({"key": g_key, "header": header, "box": group_box, "ids": g_ids, "label": g_label, "count": g_ids.size(), "grid": grid}) + if not resized.is_connected(_on_panel_resized): + resized.connect(_on_panel_resized) + _on_panel_resized() + + +## Unity-Projekt-Fenster-Feeling (U4): die Spaltenzahl passt sich der BREITE +## des unteren Bereichs an (schmaler Dock = wenige Spalten, breiter = viele). +## Kachel-Zielbreite ≈ 180 px (skaliert über ui_scale). +func _on_panel_resized() -> void: + _apply_grid_columns(size.x) + + +func _apply_grid_columns(width: float) -> void: + var cols := clampi(int(width / float(UIScale.px(200))), 1, 12) + for row in _library_group_rows: + ((row["grid"] as GridContainer)).columns = cols + if _recent_grid != null: + _recent_grid.columns = cols + + +## Kompletter Neubau des Bibliotheks-Körpers (Probe/Umbau): alte Zeilen frei +## geben, dann frisch füllen und den Filter anwenden. Die Zuletzt-Ansicht +## (_recent_box) überlebt den Neubau — sie wird nur aus dem Baum genommen und +## wieder eingehängt, damit die Referenz NICHT auf ein freigegebenes Objekt +## zeigt (sonst „previously freed" im nächsten Filterlauf). +func _rebuild_library() -> void: + if _recent_box != null and _recent_box.get_parent() == library_box: + library_box.remove_child(_recent_box) + for c in library_box.get_children(): + library_box.remove_child(c) + (c as Node).free() + if _recent_box != null and _recent_box.get_parent() == null: + library_box.add_child(_recent_box) + _fill_library() + _apply_library_filter(library_search.text) + + +func _library_header_text(on: bool, label: String, count: int) -> String: + return "%s %s (%d)" % ["▾" if on else "▸", label, count] + + +func _on_library_group_toggled(on: bool, g_key: String, g_label: String, count: int, header: Button, group_box: VBoxContainer) -> void: + group_box.visible = on + header.text = _library_header_text(on, g_label, count) + _library_group_open[g_key] = on + _library_save_open_state(g_key, on) + + +func _on_library_expand_all() -> void: + for row in _library_group_rows: + var header := row["header"] as Button + header.button_pressed = true + # toggled feuert → box sichtbar; Filter danach neu anwenden, damit + # ein aktiver Kategorie-Filter/Suche nicht weggeblasen wird. + _apply_library_filter(library_search.text) + + +func _on_library_collapse_all() -> void: + for row in _library_group_rows: + var header := row["header"] as Button + header.button_pressed = false + _apply_library_filter(library_search.text) + + +func _library_header_font() -> Font: + if _library_bold_font == null: + var sf := SystemFont.new() + sf.font_names = PackedStringArray(["Noto Sans", "DejaVu Sans", "Ubuntu", "sans-serif"]) + sf.font_weight = 700 + _library_bold_font = sf + return _library_bold_font + + +func _library_load_open_states() -> Dictionary: + var cfg := ConfigFile.new() + cfg.load("user://scopedvr_editor.cfg") + var out := {} + if cfg.has_section(LIBRARY_CFG_SECTION): + for key in cfg.get_section_keys(LIBRARY_CFG_SECTION): + if str(key) == RECENT_CFG_KEY: + continue + # Robustheit (t_efb3d022): cfg-Einträge dieser Sektion müssen Bool- + # Zustände sein. Ein kaputter Eintrag (String/Array/sonstwas) darf + # KEINEN SCRIPT ERROR werfen (bool() ist kein gültiger + # Konstruktor) — sonst brechen die Klapp-Zustände komplett weg. + var val = cfg.get_value(LIBRARY_CFG_SECTION, str(key), true) + if typeof(val) == TYPE_BOOL: + out[str(key)] = val + else: + out[str(key)] = true + return out + + +func _library_save_open_state(g_key: String, on: bool) -> void: + var cfg := ConfigFile.new() + cfg.load("user://scopedvr_editor.cfg") + cfg.set_value(LIBRARY_CFG_SECTION, g_key, on) + cfg.save("user://scopedvr_editor.cfg") + + +# ----------------------------------------------------------------- Suche ---- + +## Live-Filter (t_59fc0f21, U4 erweitert): Suche (Name de/en, ID — case- +## insensitive) geht VOR der Kategorie (sucht im ganzen Katalog); ohne Suche +## zeigt die aktive Kategorie nur ihre Gruppe, „Alle" den Klapp-Zustand wie +## gemerkt, „Zuletzt" die Gemerkten. Danach Zähler „N von M sichtbar". +func _apply_library_filter(query: String) -> void: + var q := query.strip_edges().to_lower() + var searching := not q.is_empty() + var visible_count := 0 + # Suche gilt immer für den GANZEN Katalog; ohne Suche zählt der aktive Bereich. + var scope: int = _manifest_count() if not q.is_empty() else _scope_ids().size() + _recent_box.visible = false + if searching: + for row in _library_group_rows: + var ids: Array = row["ids"] + var any := false + for oid in ids: + var btn := library_buttons.get(str(oid)) as Button + if btn == null: + continue + var vis := _library_oid_matches(str(oid), q) + btn.visible = vis + any = any or vis + if vis: + visible_count += 1 + var header := row["header"] as Button + var box := row["box"] as VBoxContainer + header.visible = any + # Treffer-Gruppen bleiben auf — auch wenn sie zugeklappt waren + # (Pfeil zeigt dann offen, kosmetisch konsistent). + box.visible = any + if any: + header.text = _library_header_text(true, str(row["label"]), int(row["count"])) + elif _cat_active == CAT_ZULETZT: + for row in _library_group_rows: + (row["header"] as Button).visible = false + (row["box"] as VBoxContainer).visible = false + for oid in row["ids"]: + var btn := library_buttons.get(str(oid)) as Button + if btn != null: + btn.visible = false + _fill_recent_box() + _recent_box.visible = true + for oid in _recent_ids: + if _recent_tiles.has(str(oid)): + visible_count += 1 + else: + for row in _library_group_rows: + var in_cat: bool = _cat_active == CAT_ALLE or str(row["key"]) == _cat_active + var ids: Array = row["ids"] + var header := row["header"] as Button + var box := row["box"] as VBoxContainer + header.visible = in_cat + if not in_cat: + box.visible = false + for oid in ids: + var btn := library_buttons.get(str(oid)) as Button + if btn != null: + btn.visible = false + continue + var is_open := bool(_library_group_open.get(str(row["key"]), false)) + if _cat_active != CAT_ALLE: + # Kategorie-Ansicht zeigt DIESE Gruppe geöffnet (wie die + # Suche ihre Treffer-Gruppen öffnet) — ohne den gemerkten + # Klapp-Zustand zu überschreiben. + is_open = true + box.visible = is_open + header.text = _library_header_text(is_open, str(row["label"]), int(row["count"])) + for oid in ids: + var btn := library_buttons.get(str(oid)) as Button + if btn != null: + btn.visible = is_open + if is_open: + visible_count += 1 + if library_counter != null: + library_counter.text = "%d von %d sichtbar" % [visible_count, scope] + # Leerzustand (U7): 0 Treffer → Klartext-Hinweis zeigen statt stummer Fläche. + if _empty_hint != null: + _empty_hint.visible = visible_count == 0 + + +func _library_oid_matches(oid: String, q: String) -> bool: + if oid.to_lower().contains(q): + return true + var entry: Dictionary = (main.manifest.get("objects", {}) as Dictionary).get(oid, {}) + if LibraryBrowser.entry_label(oid, entry).to_lower().contains(q): + return true + if LibraryBrowser.object_label(oid).to_lower().contains(q): + return true + return false + + +# ---------------------------------------------------------------- Kacheln ---- + +## Kachel in ein Grid hängen. canonical = Haupt-Grid (landet in +## library_buttons, wird von interaction/_highlight_library gefunden); +## Zuletzt-benutzt-Kacheln sind eigene frische Buttons (kein Dict-Konflikt). +func _add_library_button(oid: String, parent: Container) -> void: + var btn := _build_tile(oid) + parent.add_child(btn) + library_buttons[oid] = btn + + +func _build_tile(oid: String) -> Button: + var lib: Dictionary = main.manifest.get("objects", {}) + var entry: Dictionary = lib.get(oid, {}) + var poly := int(entry.get("poly", 0)) + var name_txt := LibraryBrowser.entry_label(oid, entry) + var missing := _tile_is_missing(oid, entry) + var btn := Button.new() + btn.toggle_mode = true + btn.button_pressed = false + btn.size_flags_horizontal = Control.SIZE_EXPAND_FILL + btn.custom_minimum_size = UIScale.v2(0, 188) + btn.tooltip_text = "%s · %d Polys · %s" % [name_txt, poly, oid] + if missing: + btn.tooltip_text += " · MODELL FEHLT (Platzhalter-Kiste)" + btn.pressed.connect(_on_tile_pressed.bind(oid)) + btn.gui_input.connect(_on_tile_gui_input.bind(oid)) + # Ziehen & Loslassen (25.10.): Kachel anklicken, gedrückt halten, in die Szene + # ziehen — beim Loslassen wird das Objekt dort gesetzt (Doppelklick geht weiter). + btn.set_drag_forwarding(_tile_drag_data.bind(oid, btn), Callable(), Callable()) + btn.mouse_entered.connect(_on_tile_hover.bind(oid, true)) + btn.mouse_exited.connect(_on_tile_hover.bind(oid, false)) + var tex := LibraryBrowser.load_thumb(oid) + if tex == null: + # Kein Thumbnail → Text-Zeile wie früher (Fehlertoleranz, t_3a998ae4). + btn.text = "%s · %d Polys" % [name_txt, poly] + btn.alignment = HORIZONTAL_ALIGNMENT_LEFT + btn.custom_minimum_size = UIScale.v2(0, 44) + else: + # Kachel (t_59fc0f21 + U4): 96-px-Vorschaubild oben, ID + Name darunter. + # Kinder ignorieren die Maus, damit die Klicks am Button ankommen. + # Reihenfolge Bild → ID → Name: der Name bleibt das LETZTE Label + # (test_library_browser_ui liest das letzte Label als Namen). + var tile := VBoxContainer.new() + tile.mouse_filter = Control.MOUSE_FILTER_IGNORE + tile.set_anchors_preset(Control.PRESET_FULL_RECT) + tile.add_theme_constant_override("separation", UIScale.px(4)) # U7-Raster + btn.add_child(tile) + # Vorschaubild: bleibt DIREKTES Kind der Kachel-VBox (test_library_ + # browser_ui sucht es dort) mit gepinnter Min-Größe (test_ui_scale + # sucht THUMB_DISPLAY_PX × Stufenfaktor). Die „Modell fehlt“-Marke + # hängt als Badge-KIND am TextureRect — der Button ist kein Container, + # eine Extra-Zeile unter dem Bild würde unter die Kachelkante rutschen + # und von der nächsten Reihe überdeckt. + var tr := TextureRect.new() + tr.texture = tex + tr.custom_minimum_size = UIScale.v2(LibraryBrowser.THUMB_DISPLAY_PX, LibraryBrowser.THUMB_DISPLAY_PX) + tr.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED + tr.expand_mode = TextureRect.EXPAND_IGNORE_SIZE + tr.size_flags_horizontal = Control.SIZE_SHRINK_CENTER + tr.mouse_filter = Control.MOUSE_FILTER_IGNORE + tile.add_child(tr) + var id_lbl := Label.new() + id_lbl.text = oid + # U7: Tile-ID als Nebentext-Größe, Farbe über Theme (Editor/colors/title). + _id_font_normal = UIScale.small_font_size() + id_lbl.add_theme_font_size_override("font_size", _id_font_normal) + id_lbl.add_theme_color_override("font_color", theme_color("title")) + id_lbl.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER + id_lbl.clip_text = true + id_lbl.text_overrun_behavior = TextServer.OVERRUN_TRIM_ELLIPSIS + id_lbl.mouse_filter = Control.MOUSE_FILTER_IGNORE + id_lbl.set_meta("tile_id_label", true) + tile.add_child(id_lbl) + var lbl := Label.new() + lbl.text = name_txt + lbl.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER + lbl.clip_text = true + lbl.text_overrun_behavior = TextServer.OVERRUN_TRIM_ELLIPSIS + lbl.mouse_filter = Control.MOUSE_FILTER_IGNORE + tile.add_child(lbl) + if missing: + # Klar sichtbar markieren (U4): Bild abgedunkelt + Warn-Badge + # als Overlay am unteren Bildrand (immer innerhalb der Kachel). + # U7: Abdunkeln nur über Alpha (Farbe bleibt weiß), Badge-Farbe + # über Theme (Editor/colors/warning + badge_outline), Nebentext- + # Größe statt Mikroschrift (U7-Raster: zwei Größen + Überschrift). + tr.modulate.a = 0.45 + tr.clip_contents = true + var warn := Label.new() + warn.text = "Modell fehlt" + warn.set_anchors_preset(Control.PRESET_BOTTOM_WIDE) + warn.offset_top = -UIScale.px(18) + warn.offset_bottom = -UIScale.px(1) + warn.add_theme_font_size_override("font_size", UIScale.small_font_size()) + warn.add_theme_color_override("font_color", theme_color("warning")) + warn.add_theme_color_override("font_outline_color", theme_color("badge_outline")) + warn.add_theme_constant_override("outline_size", UIScale.px(3)) + warn.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER + warn.mouse_filter = Control.MOUSE_FILTER_IGNORE + tr.add_child(warn) + return btn + + +## Fehlendes Modell (U4): nur Katalog-Objekte MIT glb-Eintrag können fehlen; +## kuratierte Primitive (ohne glb) bauen ihren Platzhalter lokal — nie „fehlt". +func _tile_is_missing(oid: String, entry: Dictionary) -> bool: + if str(entry.get("glb", "")).is_empty(): + return false + return GlbMeshStore.fehlt(oid) + + +## Hover (U4): die ID wird GRÖSSER, beim Verlassen wieder normal. +func _on_tile_hover(oid: String, entered: bool) -> void: + _set_tile_hover(oid, entered) + + +func _set_tile_hover(oid: String, on: bool) -> void: + var btn := _tile_button(oid) + if btn == null: + return + var id_lbl := _find_id_label(btn) + if id_lbl == null: + return + # U7-Raster: Hover-Stufe ist die Body-Schrift (klein → body), kein Wert ins Freie. + id_lbl.add_theme_font_size_override("font_size", + UIScale.font_size() if on else _id_font_normal) + + +func _tile_button(oid: String) -> Button: + if library_buttons.has(oid): + return library_buttons[oid] as Button + if _recent_tiles.has(oid): + return _recent_tiles[oid] as Button + return null + + +func _find_id_label(btn: Button) -> Label: + var stack: Array = [btn] + while not stack.is_empty(): + var node: Node = stack.pop_back() + if node is Label and (node as Label).has_meta("tile_id_label"): + return node as Label + for c in node.get_children(): + stack.push_back(c) + return null + + +# --------------------------------------------------- Klick / Doppelklick ---- + +## Klick = auswählen (U4). Das Platzieren selbst startet NICHT mehr hier — +## das übernimmt der Doppelklick (bzw. U5 das Einmal-Platzieren). +func _on_tile_pressed(oid: String) -> void: + _select_tile(oid) + + +## Doppelklick = „gesetzt" haken: Werkzeug startet wie bisher (U4-Vertrag; +## das Einmal-Platzieren kommt in U5). +func _on_tile_gui_input(event: InputEvent, oid: String) -> void: + if event is InputEventMouseButton and event.pressed \ + and event.button_index == MOUSE_BUTTON_LEFT and event.double_click: + _activate_tile(oid) + + +## Ziehen-Start einer Kachel: Vorschau-Etikett an der Maus, Daten = Objekt-ID. +func _tile_drag_data(_at_position: Vector2, oid: String, btn: Button) -> Variant: + if main.doc.is_empty(): + return null + _select_tile(oid) + _drag_oid = oid + var prev := PanelContainer.new() + var box := HBoxContainer.new() + prev.add_child(box) + var tex := LibraryBrowser.load_thumb(oid) + if tex != null: + var tr := TextureRect.new() + tr.texture = tex + tr.custom_minimum_size = UIScale.v2(64, 64) + tr.expand_mode = TextureRect.EXPAND_IGNORE_SIZE + tr.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED + box.add_child(tr) + var lbl := Label.new() + lbl.text = LibraryBrowser.entry_label(oid, (main.manifest.get("objects", {}) as Dictionary).get(oid, {})) + box.add_child(lbl) + prev.modulate.a = 0.85 + btn.set_drag_preview(prev) # gehört in den Drag-Start: gui_is_dragging() ist hier noch false + return {"svr_oid": oid} + + +## Maus mit gezogener Kachel ÜBER der 3D-Ansicht: Platzier-Vorschau folgt der Maus. +func drag_hover(oid: String, viewport_pos: Vector2) -> void: + if str(main.get("tool_mode")) != "objects": + main.call("_set_tool_mode", "objects") + if not (main.interaction.placing and main.interaction.place_oid == oid): + main.interaction.start_placement(oid) + _drag_started_placement = true + main.interaction._ghost_update(viewport_pos) + + +## Loslassen über der 3D-Ansicht: genau wie ein Setz-Klick. +func drag_drop(oid: String, viewport_pos: Vector2) -> void: + drag_hover(oid, viewport_pos) + main.interaction._place_object(viewport_pos, false) + if main.interaction.placing and not BauKatalog.ist_bau(oid): + main.interaction.cancel_placement() # daneben gezielt: Vorschau nicht hängen lassen + _drag_started_placement = false + _drag_oid = "" + + +func _notification(what: int) -> void: + if what != NOTIFICATION_DRAG_END or _drag_oid.is_empty(): + return + # Losgelassen ÜBER der Szene → drag_drop hat aufgeräumt. Sonst (abgebrochen, + # anderswo losgelassen) die Vorschau wieder wegnehmen. + if _drag_started_placement and main != null and main.interaction.placing: + main.interaction.cancel_placement() + _drag_started_placement = false + _drag_oid = "" + + +func _select_tile(oid: String) -> void: + var changed := selected_oid != oid + selected_oid = oid + _apply_tile_selection() + _record_recent(oid) + if changed: + object_selected.emit(oid) + + +## Doppelklick-Aktion: Werkzeug-Start 1:1 wie der alte Bibliotheks-Klick +## (interaction.start_placement, Auto-Rückwechsel auf Objekt-Werkzeug). +func _activate_tile(oid: String) -> void: + _select_tile(oid) + if str(main.get("tool_mode")) != "objects": + main.call("_set_tool_mode", "objects") # Bibliothek-Klick wechselt automatisch zurück + if main.interaction.placing and main.interaction.place_oid == oid: + # Nochmal (Doppel-)geklickt → Modus beenden (An/Aus ohne Umwege). + main.interaction.cancel_placement() + main.call("_set_status", "Platzieren abgebrochen.") + return + main.interaction.start_placement(oid) + object_activated.emit(oid) + + +## Auswahll-Marke je Kachel: ausgewählt = voll hell + Rahmen-Akzent. +func _apply_tile_selection() -> void: + for other_oid in library_buttons: + var btn := library_buttons[other_oid] as Button + btn.button_pressed = str(other_oid) == selected_oid + # U7: Auswahl-Markierung nur über Alpha (Farbe bleibt weiß). + btn.modulate.a = 1.0 if str(other_oid) == selected_oid else 0.85 + for recent_oid in _recent_tiles: + var rbtn := _recent_tiles[recent_oid] as Button + rbtn.button_pressed = str(recent_oid) == selected_oid + rbtn.modulate.a = 1.0 if str(recent_oid) == selected_oid else 0.85 + + +## Der Bibliotheks-Button des aktiven Platzier-Objekts leuchtet auf +## (Weitersenden von interaction.gd — nur Anzeige, KEIN Signal). +func highlight_library(oid: String) -> void: + selected_oid = oid + _apply_tile_selection() + if not oid.is_empty(): + _record_recent(oid) + + +# -------------------------------------------------------- Zuletzt benutzt ---- + +func _recent_load() -> Array: + var cfg := ConfigFile.new() + cfg.load("user://scopedvr_editor.cfg") + var raw: Variant = cfg.get_value(LIBRARY_CFG_SECTION, RECENT_CFG_KEY, []) + var lib: Dictionary = main.manifest.get("objects", {}) + var out: Array = [] + for v in (raw as Array): + var oid := str(v) + if lib.has(oid): # nur IDs, die es wirklich gibt + out.append(oid) + return out + + +func _recent_save() -> void: + var cfg := ConfigFile.new() + cfg.load("user://scopedvr_editor.cfg") + cfg.set_value(LIBRARY_CFG_SECTION, RECENT_CFG_KEY, _recent_ids) + cfg.save("user://scopedvr_editor.cfg") + + +## Auswahl/Benutzung merken (neueste zuerst, Ring mit RECENT_MAX Einträgen). +func _record_recent(oid: String) -> void: + if oid.is_empty(): + return + _recent_ids.erase(oid) + _recent_ids.insert(0, oid) + while _recent_ids.size() > RECENT_MAX: + _recent_ids.pop_back() + _recent_save() + _update_recent_chip() + if _cat_active == CAT_ZULETZT: + _fill_recent_box() + + +func _fill_recent_box() -> void: + if _recent_box == null: + return + for c in _recent_box.get_children(): + (c as Node).queue_free() + _recent_tiles.clear() + var head := Label.new() + head.text = "Zuletzt benutzt" + head.add_theme_font_size_override("font_size", UIScale.heading_font_size()) + head.add_theme_font_override("font", _library_header_font()) + _recent_box.add_child(head) + _recent_grid = GridContainer.new() + _recent_grid.columns = 2 + _recent_grid.size_flags_horizontal = Control.SIZE_EXPAND_FILL + _recent_grid.add_theme_constant_override("h_separation", UIScale.px(8)) # U7-Raster + _recent_grid.add_theme_constant_override("v_separation", UIScale.px(8)) # U7-Raster + _recent_box.add_child(_recent_grid) + var lib: Dictionary = main.manifest.get("objects", {}) + for oid in _recent_ids: + if not lib.has(str(oid)): + continue + var btn := _build_tile(str(oid)) + _recent_grid.add_child(btn) + _recent_tiles[str(oid)] = btn + if str(oid) == selected_oid: + btn.button_pressed = true + btn.modulate.a = 1.0 diff --git a/ui/panels/assets_panel.gd.uid b/ui/panels/assets_panel.gd.uid new file mode 100644 index 0000000..7153a42 --- /dev/null +++ b/ui/panels/assets_panel.gd.uid @@ -0,0 +1 @@ +uid://dxoh6gjklwjna diff --git a/ui/panels/bauen_panel.gd b/ui/panels/bauen_panel.gd new file mode 100644 index 0000000..91f3a68 --- /dev/null +++ b/ui/panels/bauen_panel.gd @@ -0,0 +1,118 @@ +extends "res://core/ui/panels/editor_panel.gd" +## Bauen-Tab: Bauteile für eigene Gebäude (Fundament, Wände, Dach, Treppe). Fertige +## Pack-Objekte (Container, Hangar-Tore, Sperren …) gehören in die Objekt-Bibliothek +## unten, NICHT hierher. Ein Klick auf ein Teil startet +## das Platzieren (Vorschau rastet an Zelle/Kante/Ebene, siehe build_snap.gd); jedes +## gesetzte Teil ist ein normales Objekt und gehört zum laufenden Gebäude (Gruppe). +## Gebäude kopieren/löschen/auswählen läuft über die Knöpfe unten — alles Undo-fähig. + +var bau_buttons: Dictionary = {} # oid → Button +var info_label: Label +var geschoss_label: Label +var _group: ButtonGroup + + +static func spec() -> Dictionary: + return {"titel": "Bauen", "gruppe": "rechts", "order": 47} + + +func panel_title() -> String: + return "Bauen" + + +func build() -> void: + _group = ButtonGroup.new() + _group.allow_unpress = true + add_child(_muted_label("Wähle ein Teil und klicke in die Karte. Wände rasten an die nächste Zellkante, Böden und Dächer in die Zellmitte (Raster 2 m). Klick auf die Oberkante einer Wand stapelt das nächste Geschoss (oder Bild↑/Bild↓: festes Geschoss, dann sitzen Decken mitten im Raum), Klick auf die Seite ersetzt das Teil (z. B. Wand → Tür). R dreht, Esc beendet.")) + for gruppe in BauKatalog.GRUPPEN: + add_child(_field_label(str(gruppe["label"]))) + add_child(_knopf_raster(gruppe["oids"] as Array)) + add_child(_separator()) + add_child(_header_label("Höhe / Geschoss")) + geschoss_label = _muted_label(main.interaction.call("bau_geschoss_text")) + add_child(geschoss_label) + var hoehe := HBoxContainer.new() + hoehe.add_theme_constant_override("separation", UIScale.px(8)) + for spec in [["▲ Höher (Bild↑)", 1], ["▼ Tiefer (Bild↓)", -1]]: + var hb := _aktion(str(spec[0]), "Festes Geschoss wählen: Böden und Decken sitzen dann überall im Raum auf dieser Höhe (je 3 m). Ganz unten = automatisch.", + func() -> void: + main.interaction.call("bau_geschoss_aendern", int(spec[1])) + geschoss_label.text = main.interaction.call("bau_geschoss_text")) + hb.size_flags_horizontal = Control.SIZE_EXPAND_FILL + hoehe.add_child(hb) + add_child(hoehe) + add_child(_separator()) + add_child(_header_label("Gebäude")) + info_label = _muted_label("") + add_child(info_label) + add_child(_aktion("🏠 Neues Gebäude beginnen", "Das nächste Teil gehört zu einem neuen Gebäude (neue Gruppe).", + func() -> void: main.call("_bau_neues_gebaeude"))) + add_child(_aktion("🔲 Ganzes Gebäude auswählen", "Wählt alle Teile des Gebäudes, zu dem das markierte Teil gehört — zum Verschieben, Drehen, Kopieren.", + func() -> void: main.call("_bau_gebaeude_waehlen"))) + add_child(_aktion("📄 Gebäude kopieren", "Kopiert das ganze Gebäude als neues Gebäude (Strg+Z nimmt es zurück).", + func() -> void: main.call("_bau_gebaeude_kopieren"))) + add_child(_aktion("🗑 Gebäude löschen", "Löscht alle Teile des Gebäudes (Strg+Z holt es zurück).", + func() -> void: main.call("_bau_gebaeude_loeschen"))) + refresh_info() + wrap_in_scroll() + + +func _knopf_raster(oids: Array) -> GridContainer: + var grid := GridContainer.new() + grid.columns = 2 + grid.add_theme_constant_override("h_separation", UIScale.px(8)) + grid.add_theme_constant_override("v_separation", UIScale.px(8)) + var lib: Dictionary = main.manifest.get("objects", {}) + for oid in oids: + var btn := Button.new() + btn.toggle_mode = true + btn.button_group = _group + btn.custom_minimum_size = UIScale.v2(148, 44) + btn.clip_text = true + var poly := int((lib.get(oid, {}) as Dictionary).get("poly", 0)) + btn.text = BauKatalog.label(oid) + btn.tooltip_text = "%s — %s\n%d Dreiecke" % [BauKatalog.label(oid), + str((BauKatalog.KINDS[oid] as Dictionary).get("info", "")), poly] + btn.pressed.connect(_on_teil_gedrueckt.bind(str(oid), btn)) + bau_buttons[str(oid)] = btn + grid.add_child(btn) + return grid + + +func _aktion(text: String, tip: String, cb: Callable) -> Button: + var b := Button.new() + b.text = text + b.tooltip_text = tip + b.custom_minimum_size = UIScale.v2(0, 44) + b.pressed.connect(cb) + return b + + +func _on_teil_gedrueckt(oid: String, btn: Button) -> void: + if not btn.button_pressed: + main.interaction.call("cancel_placement") + return + main.call("_on_bauteil_gewaehlt", oid) + + +## Teil-Markierung an den laufenden Platzier-Zustand koppeln (Esc/Abbruch löst sie). +func sync_platzierung() -> void: + var aktiv := str(main.interaction.get("place_oid")) if bool(main.interaction.get("placing")) else "" + for oid in bau_buttons: + (bau_buttons[oid] as Button).set_pressed_no_signal(oid == aktiv) + + +## Info-Zeile: aktuelles Gebäude (Name, Teile, Dreiecke) bzw. Gesamtzahl. +func refresh_info() -> void: + if info_label == null or main == null or main.doc.is_empty(): + return + var gebaeude := BauOps.gebaeude_gruppen(main.doc) + if geschoss_label != null: + geschoss_label.text = main.interaction.call("bau_geschoss_text") + var text := "%d Gebäude, %d Bauteile in der Map." % [gebaeude.size(), BauOps.teile_zahl(main.doc)] + var gid := int(main.interaction.get("build_group_id")) + for g in gebaeude: + if int(g["gid"]) == gid: + text = "Aktuell: %s — %d Teile, %d Dreiecke.\n%s" % [g["name"], (g["indizes"] as Array).size(), int(g["dreiecke"]), text] + break + info_label.text = text diff --git a/ui/panels/bauen_panel.gd.uid b/ui/panels/bauen_panel.gd.uid new file mode 100644 index 0000000..60f27df --- /dev/null +++ b/ui/panels/bauen_panel.gd.uid @@ -0,0 +1 @@ +uid://ctxc87eisoda6 diff --git a/ui/panels/check_panel.gd b/ui/panels/check_panel.gd new file mode 100644 index 0000000..4450275 --- /dev/null +++ b/ui/panels/check_panel.gd @@ -0,0 +1,176 @@ +extends "res://core/ui/panels/editor_panel.gd" +## Spawn-Check + Spawn-Zonen-Werkzeug-Panel (aus main.gd ausgezogen, Karte +## t_eaccbfed U1 — Logik unverändert, Karte t_c4162c5d): Live-Validierung +## (Loader-Regeln, IMMER sichtbar) + großer Werkzeug-Button + Team/Radius/ +## Löschen. Werkzeug-Ein/Aus bleibt im Koordinator (main.gd). + +var spawn_edit_btn: Button +var spawn_panel: VBoxContainer +var spawn_team_blue: Button +var spawn_team_red: Button +var spawn_radius_slider: HSlider +var spawn_radius_label: Label +var spawn_status: Label # Live-Validierung (IMMER sichtbar, Loader-Regeln) +var spawn_sel_label: Label # Welche Zone ist an? +var spawn_delete_btn: Button +var spawn_yaw_row: HBoxContainer +var spawn_yaw_spin: SpinBox +var spawn_yaw_reset: Button + + +static func spec() -> Dictionary: + return {"titel": "Spawn-Zonen", "gruppe": "map", "order": 10} + + +func panel_title() -> String: + return "Prüfen" + + +## Bau (aus der alten main.gd/_build_right_panel übernommen, Logik identisch): +## Live-Status IMMER sichtbar + Werkzeug-Button + Bedien-Panel (Team/Radius/ +## Auswahl/Löschen). Ein/Aus des Werkzeugs bleibt beim Koordinator (main.gd). +func build() -> void: + add_child(_header_label("Spawn-Zonen")) + # --- Spawn-Zonen (Karte t_c4162c5d): Live-Status IMMER sichtbar --- + spawn_status = Label.new() + spawn_status.text = "" + spawn_status.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART + spawn_status.custom_minimum_size = UIScale.v2(0, 44) + add_child(spawn_status) + + # --- Spawn-Zonen-Werkzeug: großer Button + Bedien-Panel --- + spawn_edit_btn = Button.new() + spawn_edit_btn.text = "🚩 Spawn-Zonen malen" + spawn_edit_btn.custom_minimum_size = UIScale.v2(0, 48) + spawn_edit_btn.toggle_mode = true + spawn_edit_btn.tooltip_text = "Startzonen für Team Blau und Rot auf den Boden malen (TDM)" + spawn_edit_btn.pressed.connect(_on_spawn_btn_pressed) + add_child(spawn_edit_btn) + + spawn_panel = VBoxContainer.new() + spawn_panel.add_theme_constant_override("separation", UIScale.px(8)) # U7-Raster + spawn_panel.visible = false + add_child(spawn_panel) + + spawn_panel.add_child(_field_label("Team:")) + var team_row := HBoxContainer.new() + team_row.add_theme_constant_override("separation", UIScale.px(8)) # U7-Raster + spawn_panel.add_child(team_row) + var team_group := ButtonGroup.new() + spawn_team_blue = _spawn_team_button("🔵 Team Blau", team_group, 0) + spawn_team_red = _spawn_team_button("🔴 Team Rot", team_group, 1) + spawn_team_blue.button_pressed = true + team_row.add_child(spawn_team_blue) + team_row.add_child(spawn_team_red) + + spawn_radius_label = _field_label("Zonen-Radius: 6 m") + spawn_panel.add_child(spawn_radius_label) + spawn_radius_slider = HSlider.new() + spawn_radius_slider.min_value = SpawnOps.MIN_ZONE_RADIUS + spawn_radius_slider.max_value = SpawnOps.MAX_ZONE_RADIUS + spawn_radius_slider.step = 1.0 + spawn_radius_slider.value = SpawnOps.DEFAULT_ZONE_RADIUS + spawn_radius_slider.custom_minimum_size = UIScale.v2(0, 32) + spawn_radius_slider.value_changed.connect(_on_spawn_radius_changed) + spawn_panel.add_child(spawn_radius_slider) + + spawn_sel_label = Label.new() + spawn_sel_label.text = "Keine Zone ausgewählt." + spawn_sel_label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART + spawn_panel.add_child(spawn_sel_label) + spawn_yaw_row = HBoxContainer.new() + spawn_yaw_row.add_theme_constant_override("separation", UIScale.px(8)) + spawn_yaw_row.add_child(_field_label("Blickrichtung °")) + spawn_yaw_spin = SpinBox.new() + spawn_yaw_spin.min_value = 0.0 + spawn_yaw_spin.max_value = 359.0 + spawn_yaw_spin.step = 1.0 + spawn_yaw_spin.tooltip_text = "Wohin Spieler und Bots hier beim Spawnen schauen. Geht auch im Bild: Pfeilspitze ziehen." + spawn_yaw_spin.size_flags_horizontal = Control.SIZE_EXPAND_FILL + spawn_yaw_spin.value_changed.connect(_on_spawn_yaw_changed) + spawn_yaw_row.add_child(spawn_yaw_spin) + spawn_yaw_reset = Button.new() + spawn_yaw_reset.text = "Standard" + spawn_yaw_reset.tooltip_text = "Keine feste Richtung: Spieler schauen zur Kartenmitte, Bots zum Gegner (grauer Pfeil)" + spawn_yaw_reset.pressed.connect(func() -> void: main.spawn_tool.call("set_selected_yaw", null)) + spawn_yaw_row.add_child(spawn_yaw_reset) + spawn_panel.add_child(spawn_yaw_row) + spawn_delete_btn = Button.new() + spawn_delete_btn.text = "Zone löschen (Entf)" + spawn_delete_btn.custom_minimum_size = UIScale.v2(0, 40) + spawn_delete_btn.tooltip_text = "Die ausgewählte Spawn-Zone löschen (Strg+Z holt sie zurück)" + spawn_delete_btn.pressed.connect(_on_spawn_delete_pressed) + spawn_panel.add_child(spawn_delete_btn) + + + +func _spawn_team_button(text: String, group: ButtonGroup, team: int) -> Button: + var btn := Button.new() + btn.text = text + btn.toggle_mode = true + btn.button_group = group + btn.custom_minimum_size = UIScale.v2(0, 40) + # U7: Werkzeugname im Tooltip (Team, in das neue Zonen gemalt werden). + btn.tooltip_text = "Zonen für %s malen" % ("Team Blau" if team == 0 else "Team Rot") + btn.pressed.connect(_on_spawn_team_changed.bind(team)) + return btn + + +func _on_spawn_btn_pressed() -> void: + if spawn_edit_btn.button_pressed: + main.call("_set_tool_mode", "spawns") + else: + main.call("_set_tool_mode", "objects") + + +func _selected_spawn_team() -> int: + return 1 if spawn_team_red.button_pressed else 0 + + +func _on_spawn_team_changed(team: int) -> void: + if main.spawn_tool != null and str(main.get("tool_mode")) == "spawns": + main.spawn_tool.call("set_team", team) + + +func _on_spawn_radius_changed(value: float) -> void: + spawn_radius_label.text = "Zonen-Radius: %d m" % int(value) + if main.spawn_tool != null and str(main.get("tool_mode")) == "spawns": + main.spawn_tool.call("set_radius", value) + + +func _on_spawn_yaw_changed(value: float) -> void: + if str(main.get("tool_mode")) == "spawns": + main.spawn_tool.call("set_selected_yaw", value) + + +func _on_spawn_delete_pressed() -> void: + if str(main.get("tool_mode")) == "spawns": + main.spawn_tool.call("delete_selected") + + +## Panel-Zeile „Welche Zone ist angewählt?“ — WIRD vom Spawn-Tool gerufen. +func sync_spawn_selection() -> void: + if main.spawn_tool == null: + return + var team: int = main.spawn_tool.get("selected_team") + var pid: String = str(main.spawn_tool.get("selected_id")) + if team < 0 or pid == "": + spawn_sel_label.text = "Keine Zone ausgewählt.\nKlicke im Viewport auf einen Kreis." + spawn_delete_btn.disabled = true + spawn_yaw_row.visible = false + return + spawn_yaw_row.visible = true + for p in SpawnOps.points(main.doc, team): + if p is Dictionary and str(p.get("id", "")) == pid: + spawn_yaw_spin.set_value_no_signal(SpawnOps.effective_yaw(main.doc, p)) + spawn_yaw_reset.disabled = not SpawnOps.has_yaw(p) + spawn_sel_label.text = "Ausgewählt: %s (%s)\nVerschieben: klicken+ziehen · Radius: Regler oben" % [ + pid, SpawnOps.team_label(team)] + spawn_delete_btn.disabled = false + + +## LIVE-Validierung (Loader-Regeln) — immer sichtbar, nach JEDEM Struktur-Wechsel. +func refresh_spawn_status() -> void: + if main.doc.is_empty() or spawn_status == null: + return + spawn_status.text = SpawnOps.live_status(main.doc, main.manifest) diff --git a/ui/panels/check_panel.gd.uid b/ui/panels/check_panel.gd.uid new file mode 100644 index 0000000..6e2389a --- /dev/null +++ b/ui/panels/check_panel.gd.uid @@ -0,0 +1 @@ +uid://b84fxjtuhejui diff --git a/ui/panels/editor_panel.gd b/ui/panels/editor_panel.gd new file mode 100644 index 0000000..1f10761 --- /dev/null +++ b/ui/panels/editor_panel.gd @@ -0,0 +1,89 @@ +extends VBoxContainer +class_name EditorPanel + +## Basis-Klasse aller Registry-Panels (Karte t_eaccbfed). Jedes Modul baut +## seinen eigenen Inhalt in setup(main) und wird von main.gd NUR über die +## Registry (core/ui/panels/registry.gd) in den Baum gehängt — main.gd kennt +## keine Panel-Interna mehr. +## +## Datenfluss (bewusst 1:1 wie vorher): Module greifen über `main` auf das +## Dokument/History/Werkzeuge zu und rufen die Koordinator-Helfer über +## main.call(...) — der Aufruf-Vertrag zu den Tools (interaction.gd etc.) +## bleibt unverändert, die Methoden wohnen jetzt nur in den Modulen. + +var main # core/ui/main.gd (script-erweitert → untypisiert) + + +func setup(p_main) -> void: + main = p_main + # U7-Abstands-Raster (4/8 px, über ui_scale skaliert): Panel-Grundabstand. + add_theme_constant_override("separation", UIScale.px(8)) + + +## Titel der Sektions-Überschrift (Registry-Titel als Default). +func panel_title() -> String: + return "Panel" + + +## Lange Tabs (Map, Bauen): den ganzen Inhalt in einen senkrechten Scroll-Bereich +## legen, damit die rechte Spalte nicht mit dem Inhalt wächst. Rückgabe = die +## innere Box (dort hängen spätere Abschnitte an). +func wrap_in_scroll() -> VBoxContainer: + var scroll := ScrollContainer.new() + scroll.name = "%sScroll" % name + scroll.size_flags_vertical = Control.SIZE_EXPAND_FILL + scroll.size_flags_horizontal = Control.SIZE_EXPAND_FILL + scroll.horizontal_scroll_mode = ScrollContainer.SCROLL_MODE_DISABLED + var inner := VBoxContainer.new() + inner.name = "%sInhalt" % name + inner.size_flags_horizontal = Control.SIZE_EXPAND_FILL + inner.add_theme_constant_override("separation", UIScale.px(8)) + for child in get_children(): + remove_child(child) + inner.add_child(child) + scroll.add_child(inner) + add_child(scroll) + return inner + + +# --- Farb-Zugriff NUR über das Theme (Karte t_2336c58e/U7) ------------------ +## Farben kommen ausschließlich aus theme/editor_theme.tres (Abschnitt +## Editor/colors/…) — keine Farbwerte mehr im Panel-Code. Der Wert liest +## sich vom angeschlossenen Theme-Baum (main hängt theme auf das Fenster). + +func theme_color(cname: String) -> Color: + # Befund 25.10. („Texte kaum lesbar“): Panels werden gebaut, BEVOR sie im + # Baum hängen — get_theme_color liefert dort Schwarz statt der Theme-Farbe. + # Darum direkt aus dem Theme des Hauptfensters lesen. + if main != null and main.theme != null and main.theme.has_color(cname, "Editor"): + return main.theme.get_color(cname, "Editor") + return get_theme_color(cname, "Editor") + + +# --- Gemeinsame Bau-Helfer (aus main.gd übernommen, Logik identisch) -------- + +func _header_label(text: String) -> Label: + var label := Label.new() + label.text = text + label.add_theme_font_size_override("font_size", UIScale.heading_font_size()) + label.add_theme_color_override("font_color", theme_color("accent")) + return label + + +func _field_label(text: String) -> Label: + var label := Label.new() + label.text = text + label.add_theme_color_override("font_color", theme_color("field")) + return label + + +func _muted_label(text: String) -> Label: + var label := Label.new() + label.text = text + label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART + label.add_theme_color_override("font_color", theme_color("muted")) + return label + + +func _separator() -> HSeparator: + return HSeparator.new() diff --git a/ui/panels/editor_panel.gd.uid b/ui/panels/editor_panel.gd.uid new file mode 100644 index 0000000..902fabd --- /dev/null +++ b/ui/panels/editor_panel.gd.uid @@ -0,0 +1 @@ +uid://cu0oq4cx0oy60 diff --git a/ui/panels/loadout_panel.gd b/ui/panels/loadout_panel.gd new file mode 100644 index 0000000..cd0de39 --- /dev/null +++ b/ui/panels/loadout_panel.gd @@ -0,0 +1,329 @@ +extends "res://core/ui/panels/editor_panel.gd" +## Loadout-Bereich im Map-Tab (Karte „Loadout pro Map"): pro Map wählbar, ob die +## Spieler ihr eigenes Lobby-Loadout mitbringen oder die Map ein festes Loadout +## (Primär-/Sekundärwaffe + Aufsätze) vorschreibt. Gespeichert als optionaler +## Block doc["loadout"] (Regeln: core/svmap/loadout_katalog.gd, V18). Der Server +## setzt ein festes Loadout durch, der Client zeigt es an. In beiden Modi lässt +## sich zusätzlich der Granaten-/Minen-Vorrat pro Leben festlegen (auch für Bots). +## +## Jede Änderung ist ein Undo-Schritt (History-Block "loadout"; fehlt der Block, +## ist das Spieler-Loadout gemeint). + +const KEINE := "" + +var mode_option: OptionButton +var primary_option: OptionButton +var secondary_option: OptionButton +var fixed_box: VBoxContainer +var attach_box: VBoxContainer +var hint_label: Label +var vorrat_check: CheckBox +var vorrat_box: VBoxContainer +var granaten_spins: Dictionary = {} # Granaten-ID -> SpinBox +var minen_spin: SpinBox + +var _loading := false +var _ids: Array[String] = [] + + +static func spec() -> Dictionary: + return {"titel": "Loadout", "gruppe": "map", "order": 25} + + +func panel_title() -> String: + return "Loadout" + + +func build() -> void: + add_child(_header_label("Loadout")) + add_child(_muted_label("Legt fest, mit welchen Waffen die Spieler diese Karte spielen.")) + + mode_option = OptionButton.new() + mode_option.tooltip_text = "Eigenes Loadout: Spieler nehmen ihre Auswahl aus der Lobby mit. Festes Loadout: alle bekommen genau diese Waffen, der Server setzt das durch." + mode_option.add_item("Eigenes Loadout der Spieler (Lobby)") + mode_option.add_item("Festes Map-Loadout") + add_child(mode_option) + + fixed_box = VBoxContainer.new() + fixed_box.add_theme_constant_override("separation", UIScale.px(8)) + add_child(fixed_box) + + fixed_box.add_child(_field_label("Primärwaffe (Rücken)")) + primary_option = OptionButton.new() + fixed_box.add_child(primary_option) + fixed_box.add_child(_field_label("Sekundärwaffe (Hüfte)")) + secondary_option = OptionButton.new() + fixed_box.add_child(secondary_option) + + _ids = LoadoutKatalog.waffen_ids() + for id in _ids: + primary_option.add_item(LoadoutKatalog.anzeigename(id)) + secondary_option.add_item(LoadoutKatalog.anzeigename(id)) + secondary_option.add_item("— keine —") + + attach_box = VBoxContainer.new() + attach_box.add_theme_constant_override("separation", UIScale.px(6)) + fixed_box.add_child(attach_box) + + hint_label = _muted_label("Messer bleiben unverändert.") + fixed_box.add_child(hint_label) + + add_child(_header_label("Granaten und Minen")) + vorrat_check = CheckBox.new() + vorrat_check.text = "Anzahl für diese Karte festlegen" + vorrat_check.tooltip_text = "Aus: es gilt der Standard des Servers. An: Spieler und Bots bekommen pro Leben genau diese Anzahl." + vorrat_check.toggled.connect(func(an: bool) -> void: + if not _loading: + set_vorrat_aktiv(an)) + add_child(vorrat_check) + vorrat_box = VBoxContainer.new() + vorrat_box.add_theme_constant_override("separation", UIScale.px(6)) + add_child(vorrat_box) + for gid in LoadoutKatalog.GRANATEN_PANEL: + var spin := _anzahl_zeile(str(LoadoutKatalog.GRANATEN[gid]), LoadoutKatalog.MAX_GRANATEN_JE_ART) + spin.value_changed.connect(func(v: float) -> void: + if not _loading: + set_granaten(gid, int(v))) + granaten_spins[gid] = spin + minen_spin = _anzahl_zeile("Minen", LoadoutKatalog.MAX_MINEN) + minen_spin.value_changed.connect(func(v: float) -> void: + if not _loading: + set_minen(int(v))) + + mode_option.item_selected.connect(func(i: int) -> void: set_fixed(i == 1)) + primary_option.item_selected.connect(func(i: int) -> void: + set_weapons(_ids[i], _secondary_id())) + secondary_option.item_selected.connect(func(_i: int) -> void: + set_weapons(_primary_id(), _secondary_id())) + refresh_values() + + +func _anzahl_zeile(titel: String, max_n: int) -> SpinBox: + var row := HBoxContainer.new() + var lab := _field_label(titel) + lab.size_flags_horizontal = Control.SIZE_EXPAND_FILL + row.add_child(lab) + var spin := SpinBox.new() + spin.min_value = 0 + spin.max_value = max_n + spin.step = 1 + row.add_child(spin) + vorrat_box.add_child(row) + return spin + + +# ------------------------------------------------------------- Lesen ------- + +func _primary_id() -> String: + return _ids[primary_option.selected] if primary_option.selected >= 0 else "" + + +func _secondary_id() -> String: + var i := secondary_option.selected + return _ids[i] if i >= 0 and i < _ids.size() else KEINE + + +func current() -> Dictionary: + return main.doc.get("loadout", {}) if main != null and not main.doc.is_empty() else {} + + +func is_fixed() -> bool: + return str(current().get("mode", LoadoutKatalog.MODE_PLAYER)) == LoadoutKatalog.MODE_FIXED + + +# ------------------------------------------------------------- Ändern ------ + +## Modus wechseln. Auf „fest" ohne vorherige Wahl: M40 + Pistole 1 als Start. +func set_fixed(fixed: bool) -> void: + if main.doc.is_empty(): + return + if not fixed: + _commit(_nur_vorrat(current()), "Loadout: Spieler-Loadout") + return + var cur := current() + if cur.get("mode", "") == LoadoutKatalog.MODE_FIXED: + return + var prim := "m40" if LoadoutKatalog.hat_waffe("m40") else (_ids[0] if not _ids.is_empty() else "") + var sec := "pistol1" if LoadoutKatalog.hat_waffe("pistol1") else KEINE + var neu := {"mode": LoadoutKatalog.MODE_FIXED, "primary": prim, "secondary": sec, "attachments": {}} + var vorrat: Variant = _nur_vorrat(cur) + if vorrat != null: + neu.merge(vorrat as Dictionary, false) + _commit(neu, "Loadout: festes Map-Loadout") + + +## Spieler-Loadout mit Vorrat bleibt als Block erhalten; ohne Vorrat kein Block. +func _nur_vorrat(lo: Dictionary) -> Variant: + if not lo.has("grenades") and not lo.has("mines"): + return null + var out := {"mode": LoadoutKatalog.MODE_PLAYER} + for key in ["grenades", "mines"]: + if lo.has(key): + out[key] = lo[key] + return out + + +func hat_vorrat() -> bool: + return current().has("grenades") or current().has("mines") + + +## Vorrat festlegen (Start = Server-Standard) oder wieder dem Server überlassen. +func set_vorrat_aktiv(an: bool) -> void: + if main.doc.is_empty() or an == hat_vorrat(): + return + var lo := current().duplicate(true) + if an: + if lo.is_empty(): + lo["mode"] = LoadoutKatalog.MODE_PLAYER + lo["grenades"] = {"he1": 1, "blend1": 1, "smoke1": 1} + lo["mines"] = LoadoutKatalog.STANDARD_MINEN + _commit(lo, "Loadout: Granaten und Minen festgelegt") + return + lo.erase("grenades") + lo.erase("mines") + var leer := str(lo.get("mode", LoadoutKatalog.MODE_PLAYER)) == LoadoutKatalog.MODE_PLAYER + _commit(null if leer else lo, "Loadout: Granaten und Minen wie Server") + + +func set_granaten(gid: String, anzahl: int) -> void: + if main.doc.is_empty() or not hat_vorrat() or not LoadoutKatalog.GRANATEN.has(gid): + return + var lo := current().duplicate(true) + var g: Dictionary = lo.get("grenades", {}) + if anzahl > 0: + g[gid] = clampi(anzahl, 0, LoadoutKatalog.MAX_GRANATEN_JE_ART) + else: + g.erase(gid) + lo["grenades"] = g + _commit(lo, "Loadout: %s" % str(LoadoutKatalog.GRANATEN[gid])) + + +func set_minen(anzahl: int) -> void: + if main.doc.is_empty() or not hat_vorrat(): + return + var lo := current().duplicate(true) + lo["mines"] = clampi(anzahl, 0, LoadoutKatalog.MAX_MINEN) + _commit(lo, "Loadout: Minen") + + +## Waffen setzen. Aufsätze von Waffen, die nicht mehr im Loadout sind, fallen weg. +func set_weapons(primary: String, secondary: String) -> void: + if main.doc.is_empty() or not is_fixed(): + return + if not LoadoutKatalog.hat_waffe(primary) or (secondary != KEINE and not LoadoutKatalog.hat_waffe(secondary)): + return + var lo := current().duplicate(true) + lo["primary"] = primary + lo["secondary"] = secondary + var att: Dictionary = lo.get("attachments", {}) + for w in att.keys(): + if w != primary and w != secondary: + att.erase(w) + lo["attachments"] = att + _commit(lo, "Loadout: %s / %s" % [LoadoutKatalog.anzeigename(primary), + LoadoutKatalog.anzeigename(secondary) if secondary != KEINE else "keine"]) + + +## Ein Aufsatz-Slot einer Loadout-Waffe setzen (part = Teil-ID, "" = nichts). +func set_part(weapon: String, slot: String, part: String) -> void: + if main.doc.is_empty() or not is_fixed(): + return + var lo := current().duplicate(true) + if weapon != str(lo.get("primary", "")) and weapon != str(lo.get("secondary", "")): + return + var att: Dictionary = lo.get("attachments", {}) + var sel := LoadoutKatalog.auswahl(weapon, str(att.get(weapon, ""))) + if not sel.has(slot): + return + sel[slot] = part + var wire := LoadoutKatalog.encode(weapon, sel) + if LoadoutKatalog.pruefe_aufsaetze(weapon, wire) != "": + return + if wire.is_empty(): + att.erase(weapon) + else: + att[weapon] = wire + lo["attachments"] = att + _commit(lo, "Loadout: Aufsatz %s" % slot) + + +func _commit(neu: Variant, text: String) -> void: + var alt: Variant = main.doc.get("loadout", null) + if alt != null: + alt = (alt as Dictionary).duplicate(true) + if neu == null: + main.doc.erase("loadout") + else: + main.doc["loadout"] = (neu as Dictionary).duplicate(true) + var danach: Variant = main.doc.get("loadout", null) + if danach != null: + danach = (danach as Dictionary).duplicate(true) + if alt == danach: + return + main.history.commit(text, {"loadout": alt}, {"loadout": danach}) + main.dirty = true + main.call("_refresh_file_label") + main.call("_refresh_history_buttons") + refresh_values() + main.call("_set_status", "%s." % text) + + +# ------------------------------------------------------------ Anzeige ------ + +## UI aus dem doc auffüllen (Laden, Undo/Redo) — löst keinen Schreibzugriff aus. +func refresh_values() -> void: + if mode_option == null or main == null: + return + _loading = true + var lo := current() + var fixed := is_fixed() + mode_option.select(1 if fixed else 0) + fixed_box.visible = fixed + if fixed: + var prim := str(lo.get("primary", "")) + var sec := str(lo.get("secondary", "")) + primary_option.select(maxi(0, _ids.find(prim))) + secondary_option.select(_ids.find(sec) if sec != KEINE and _ids.has(sec) else _ids.size()) + _rebuild_attachments(prim, sec, lo.get("attachments", {})) + var vorrat := hat_vorrat() + vorrat_check.button_pressed = vorrat + vorrat_box.visible = vorrat + for gid in granaten_spins: + (granaten_spins[gid] as SpinBox).value = int((lo.get("grenades", {}) as Dictionary).get(gid, 0)) + minen_spin.value = int(lo.get("mines", LoadoutKatalog.STANDARD_MINEN)) + _loading = false + + +func _rebuild_attachments(prim: String, sec: String, att: Dictionary) -> void: + for c in attach_box.get_children(): + attach_box.remove_child(c) + c.queue_free() + for w in [prim, sec]: + if w == "" or LoadoutKatalog.slots(w).is_empty(): + continue + attach_box.add_child(_header_label("Aufsätze: %s" % LoadoutKatalog.anzeigename(w))) + var sel := LoadoutKatalog.auswahl(w, str(att.get(w, ""))) + var sl := LoadoutKatalog.slots(w) + var slot_names: Array = sl.keys() + slot_names.sort() + for s in slot_names: + var sd: Dictionary = sl[s] + var row := HBoxContainer.new() + var lab := _field_label(str(s).replace("_", " ")) + lab.custom_minimum_size = UIScale.v2(90, 0) + row.add_child(lab) + var ob := OptionButton.new() + ob.name = "Teil_%s_%s" % [w, s] + ob.size_flags_horizontal = Control.SIZE_EXPAND_FILL + var parts: Array = [] + if bool(sd.get("optional", false)): + parts.append("") + parts.append_array(sd.get("options", [])) + for p in parts: + ob.add_item(LoadoutKatalog.teil_name(str(p))) + ob.select(maxi(0, parts.find(sel.get(s, "")))) + ob.item_selected.connect(func(i: int) -> void: + if not _loading: + set_part(w, str(s), str(parts[i]))) + row.add_child(ob) + attach_box.add_child(row) diff --git a/ui/panels/loadout_panel.gd.uid b/ui/panels/loadout_panel.gd.uid new file mode 100644 index 0000000..dfc7fac --- /dev/null +++ b/ui/panels/loadout_panel.gd.uid @@ -0,0 +1 @@ +uid://t00n1cb8be2w diff --git a/ui/panels/malen_panel.gd b/ui/panels/malen_panel.gd new file mode 100644 index 0000000..36772df --- /dev/null +++ b/ui/panels/malen_panel.gd @@ -0,0 +1,170 @@ +extends "res://core/ui/panels/editor_panel.gd" +## Malen-Tab (25.10., UI-Aufräumen): Material-Palette mit Vorschau-Kacheln, +## Pinselgröße und Kante. Malen ist technisch weiter der Pinsel-Modus PAINT des +## Terrain-Werkzeugs (terrain_tool.gd) — die Mode-Buttons und die Pinsel-Logik +## wohnen in terrain_panel.gd, dieses Panel hält nur die Mal-Widgets. main.gd +## reicht die Felder unter den alten Namen (terrain_palette …) weiter. + +const ARRAYS_PATH := "res://assets/textures/terrain/terrain_arrays.res" +const MATERIAL_NAMES: Array[String] = [ + "Steppe", "Sand", "Fels", "Sattgras", "Vertrocknet", "Moos", "Erde", + "Pfad", "Umgegraben", "Schotter", "Lehm", "Sand hell", "Sand rost", + "Basalt", "Geröll", "Schlamm", "Schnee", "Matschschnee", "Asche", "Stoppeln", +] + +var malen_edit_btn: Button +var malen_panel: VBoxContainer +var palette: VBoxContainer +var mat_buttons: Array = [] +var radius_label: Label +var radius_slider: HSlider +var weich_label: Label +var weich_slider: HSlider +var paint_hint: Label +var _syncing := false + + +static func spec() -> Dictionary: + return {"titel": "Malen", "gruppe": "rechts", "order": 45} + + +func panel_title() -> String: + return "Malen" + + +func build() -> void: + malen_edit_btn = Button.new() + malen_edit_btn.text = "🖌 Malen" + malen_edit_btn.custom_minimum_size = UIScale.v2(0, 48) + malen_edit_btn.toggle_mode = true + malen_edit_btn.tooltip_text = "Material auf den Boden malen (Taste 4)" + malen_edit_btn.pressed.connect(_on_malen_btn_pressed) + add_child(malen_edit_btn) + + malen_panel = VBoxContainer.new() + malen_panel.add_theme_constant_override("separation", UIScale.px(8)) + add_child(malen_panel) + + palette = VBoxContainer.new() + palette.add_theme_constant_override("separation", UIScale.px(4)) + palette.visible = false + malen_panel.add_child(palette) + palette.add_child(_field_label("Material:")) + var grid := GridContainer.new() + grid.columns = 3 + grid.size_flags_horizontal = Control.SIZE_EXPAND_FILL + grid.add_theme_constant_override("h_separation", UIScale.px(6)) + grid.add_theme_constant_override("v_separation", UIScale.px(6)) + var scroll := ScrollContainer.new() + scroll.custom_minimum_size = UIScale.v2(0, 340) + scroll.size_flags_vertical = Control.SIZE_EXPAND_FILL + scroll.horizontal_scroll_mode = ScrollContainer.SCROLL_MODE_DISABLED + grid.size_flags_horizontal = Control.SIZE_EXPAND_FILL + scroll.add_child(grid) + palette.add_child(scroll) + var previews := _material_previews() + var group := ButtonGroup.new() + for mat_id in SvmapIO.MATERIAL_IDS.size(): + var btn := Button.new() + btn.text = MATERIAL_NAMES[mat_id] if mat_id < MATERIAL_NAMES.size() else str(SvmapIO.MATERIAL_IDS[mat_id]) + btn.custom_minimum_size = UIScale.v2(92, 104) + btn.size_flags_horizontal = Control.SIZE_EXPAND_FILL + btn.toggle_mode = true + btn.button_group = group + btn.clip_text = true + btn.icon_alignment = HORIZONTAL_ALIGNMENT_CENTER + btn.vertical_icon_alignment = VERTICAL_ALIGNMENT_TOP + btn.expand_icon = true + btn.add_theme_constant_override("icon_max_width", UIScale.px(76)) + if mat_id < previews.size() and previews[mat_id] != null: + btn.icon = previews[mat_id] + btn.tooltip_text = "Malen: %s" % btn.text + if mat_id == 0: + btn.button_pressed = true + btn.toggled.connect(_on_material_changed.bind(mat_id)) + mat_buttons.append(btn) + grid.add_child(btn) + + radius_label = _field_label("Pinsel-Größe: 12 m") + malen_panel.add_child(radius_label) + radius_slider = HSlider.new() + radius_slider.min_value = 1.0 + radius_slider.max_value = 64.0 + radius_slider.step = 1.0 + radius_slider.value = 12.0 + radius_slider.custom_minimum_size = UIScale.v2(0, 32) + radius_slider.value_changed.connect(_on_radius_changed) + malen_panel.add_child(radius_slider) + + weich_label = _field_label("Kante: 40 % weich") + malen_panel.add_child(weich_label) + weich_slider = HSlider.new() + weich_slider.min_value = 0.0 + weich_slider.max_value = 100.0 + weich_slider.step = 5.0 + weich_slider.value = 40.0 + weich_slider.custom_minimum_size = UIScale.v2(0, 32) + weich_slider.tooltip_text = "Links = harte Kante, rechts = weicher Übergang" + weich_slider.value_changed.connect(_on_weich_changed) + malen_panel.add_child(weich_slider) + + paint_hint = _muted_label("") + malen_panel.add_child(paint_hint) + + +## Vorschaubilder der 20 Materialien aus dem Textur-Array (Albedo-Layer). +## Fehlt das Array oder ein Layer: Kachel bleibt ohne Bild (nie ein Absturz). +func _material_previews() -> Array: + var out: Array = [] + if not ResourceLoader.exists(ARRAYS_PATH): + return out + var arr = load(ARRAYS_PATH) + if arr == null or not ("albedo_images" in arr): + return out + for img in arr.albedo_images: + var tex: Texture2D = null + if img is Image and not (img as Image).is_empty(): + var copy: Image = (img as Image).duplicate() + if copy.is_compressed(): + copy.decompress() + copy.resize(96, 96, Image.INTERPOLATE_BILINEAR) + tex = ImageTexture.create_from_image(copy) + out.append(tex) + return out + + +func _on_malen_btn_pressed() -> void: + var t = main.terrain_mod + if malen_edit_btn.button_pressed: + t.terrain_mode_paint.button_pressed = true + main.call("_set_tool_mode", "terrain") + t.refresh_panels() + else: + main.call("_set_tool_mode", "objects") + + +func _on_material_changed(pressed: bool, mat_id: int) -> void: + if pressed and main.terrain_tool != null: + main.terrain_tool.call("set_paint_material", mat_id) + + +func _on_radius_changed(value: float) -> void: + radius_label.text = "Pinsel-Größe: %d m" % int(value) + if _syncing: + return + var t = main.terrain_mod + if t != null and t.terrain_radius_slider != null: + t.terrain_radius_slider.value = value # → set_radius über dessen Handler + + +## Terrain-Tab → Malen: Radius spiegeln, ohne Rückkopplung. +func set_radius_silent(value: float) -> void: + _syncing = true + radius_slider.value = value + _syncing = false + + +func _on_weich_changed(value: float) -> void: + weich_label.text = "Kante: %d %% weich" % int(value) if value > 0.0 else "Kante: hart" + if main.terrain_tool != null: + main.terrain_tool.call("set_weichheit", value / 100.0) diff --git a/ui/panels/malen_panel.gd.uid b/ui/panels/malen_panel.gd.uid new file mode 100644 index 0000000..12230fd --- /dev/null +++ b/ui/panels/malen_panel.gd.uid @@ -0,0 +1 @@ +uid://1cuxg4r1bmls diff --git a/ui/panels/map_panel.gd b/ui/panels/map_panel.gd new file mode 100644 index 0000000..bce6af5 --- /dev/null +++ b/ui/panels/map_panel.gd @@ -0,0 +1,264 @@ +extends "res://core/ui/panels/editor_panel.gd" +## Map-Eigenschaften (aus main.gd ausgezogen, Karte t_eaccbfed U1 — Logik +## unverändert): Name/Autor/Beschreibung/Version/Wetter + Terrain-Info. +## Eingaben schreiben LIVE ins doc (Live-Bindung wie vorher) und markieren +## dirty — die Signale wurden vorher in _build_right_panel verdrahtet, sie +## hängen jetzt hier. + +var prop_name: LineEdit +var prop_author: LineEdit +var prop_desc: LineEdit +var prop_version: SpinBox +var prop_weather: OptionButton +var prop_sky: OptionButton +var sky_preview: TextureRect # Vorschau der gewählten Skybox (obere Panorama-Hälfte) +var prop_water: HSlider +var terrain_info: Label + +var _sections: VBoxContainer # Inhalt des Map-Tabs (im Scroll-Bereich) +var _loading_ui_values := false # verhindert dirty beim Auffüllen der Felder + +## Karte t_28fdef03: Slider-Stellung für „Kein Wasser“ (Meta-Vertrag für +## Tests/Verdrahtung). Slider unterhalb davon (−10 m) = Wasser AUS — das doc- +## Feld wird dann ENTFERNT (Legacy-sauber, kein Wert 0 versehentlich gespeichert). +const KEIN_WASSER_WERT := -10.0 + + +static func spec() -> Dictionary: + return {"titel": "Map", "gruppe": "rechts", "order": 30} + + +func panel_title() -> String: + return "Map-Eigenschaften" + + +## Bau (aus der alten main.gd/_build_right_panel übernommen, Logik identisch): +## Name/Autor/Beschreibung/Version/Wetter + Terrain-Info. Die Signale hängen +## jetzt hier (statt in main.gd) — der doc-Datenfluss ist derselbe. +func build() -> void: + add_child(_field_label("Name")) + prop_name = LineEdit.new() + prop_name.max_length = 64 + add_child(prop_name) + + add_child(_field_label("Autor")) + prop_author = LineEdit.new() + add_child(prop_author) + + add_child(_field_label("Beschreibung")) + prop_desc = LineEdit.new() + add_child(prop_desc) + + add_child(_field_label("Version")) + prop_version = SpinBox.new() + prop_version.min_value = 1 + prop_version.max_value = 99999 + prop_version.step = 1 + add_child(prop_version) + + add_child(_field_label("Wetter")) + prop_weather = OptionButton.new() + # U7: Klartext-Tooltip am Wetter-Auswahlfeld. + prop_weather.tooltip_text = "Licht und Stimmung der Karte (Tag/Abend/Regen/Nacht)" + prop_weather.add_item("Mittag (sonnig, klar)") + prop_weather.add_item("Abend (warmes Licht)") + prop_weather.add_item("Regen (grau, kühl)") + prop_weather.add_item("Nacht (dunkel)") + add_child(prop_weather) + + add_child(_field_label("Himmel")) + prop_sky = OptionButton.new() + # Karte Atmosphäre/Skybox: Panorama-Skybox aus dem Pack als Map-Option. + prop_sky.tooltip_text = "Himmel der Karte: Prozedural (Standard, lässt die Karte unverändert) oder eine Skybox aus dem Katalog. Der Viewport zeigt sie sofort; Strg+Z macht die Wahl rückgängig." + prop_sky.add_item("Prozedural (Standard)") + for e in SkyboxKatalog.EINTRAEGE: + prop_sky.add_item(str(e["name"])) + add_child(prop_sky) + sky_preview = TextureRect.new() + sky_preview.custom_minimum_size = Vector2(0, 80) + sky_preview.expand_mode = TextureRect.EXPAND_IGNORE_SIZE + sky_preview.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_COVERED + sky_preview.tooltip_text = "Vorschau: oberer Teil der gewählten Skybox" + add_child(sky_preview) + + # Wasser (Karte t_28fdef03): Wasserhöhe der Map — Senken unter der Höhe + # füllen sich automatisch. Ganz links = „Kein Wasser“ (Feld entfernen, + # alte Maps unverändert). Die Live-Vorschau nutzt dasselbe Material wie + # der Client (SvmapWasser.make_material — Identitäts-Vertrag). + add_child(_field_label("Wasserhöhe")) + prop_water = HSlider.new() + prop_water.min_value = -10.0 + prop_water.max_value = 100.0 + prop_water.step = 0.25 + prop_water.value = KEIN_WASSER_WERT + prop_water.custom_minimum_size = UIScale.v2(0, 32) + prop_water.tooltip_text = "Wasser: ganz links = kein Wasser, sonst Höhe der Wasseroberfläche über dem Terrain. Senken unter dieser Höhe füllen sich mit Wasser." + prop_water.set_meta("kein_wasser_value", KEIN_WASSER_WERT) + add_child(prop_water) + + add_child(_separator()) + add_child(_header_label("Terrain")) + terrain_info = Label.new() + terrain_info.text = "" + terrain_info.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART + add_child(terrain_info) + + # Signale (Änderungen → Dokument + Ansicht) — wie vorher in main.gd. + prop_name.text_changed.connect(_on_prop_changed.bind("name")) + prop_author.text_changed.connect(_on_prop_changed.bind("author")) + prop_desc.text_changed.connect(_on_prop_changed.bind("description")) + prop_version.value_changed.connect(_on_version_changed) + prop_weather.item_selected.connect(_on_weather_changed) + prop_sky.item_selected.connect(_on_sky_changed) + prop_water.value_changed.connect(_on_water_changed) + _sections = wrap_in_scroll() + + +## Hier hängen die Abschnitte der Registry-Gruppe "map" (Spawn-Zonen, Test-Start, +## Symmetrie) unter den Map-Eigenschaften. +func sections_host() -> Control: + return _sections + + +func _on_prop_changed(text: String, field: String) -> void: + if _loading_ui_values or main.doc.is_empty(): + return + var info: Dictionary = main.doc["info"] + match field: + "name": + info["name"] = text + "author": + info["author"] = text + "description": + info["description"] = text + main.dirty = true + main.call("_refresh_file_label") + + +func _on_version_changed(value: float) -> void: + if _loading_ui_values or main.doc.is_empty(): + return + main.doc["info"]["version"] = int(value) + main.dirty = true + main.call("_refresh_file_label") + + +func _on_weather_changed(index: int) -> void: + if _loading_ui_values or main.doc.is_empty(): + return + var weathers := ["mittag", "abend", "regen", "nacht"] + main.doc["weather"] = weathers[index] + main.dirty = true + main.call("_refresh_file_label") + # Licht/Stimmung im Viewport sofort anpassen + main.view_builder.call("rebuild", main.doc, main.manifest) + main.call("_sync_grid_to_builder") + main.call("_set_status", "Wetter geändert auf „%s“." % weathers[index]) + + +## Skybox-Auswahl: Eintrag → doc["weather_sky"] = Katalog-ID (ein Speicherfeld, +## checksum-neutral wie tint/gebaeude). „Prozedural (Standard)“ = Index 0 → Feld +## ENTFERNEN (alte Maps unverändert). Mit Undo/Redo (History-Block weather_sky). +## Sofort-Neuaufbau wie Wetter — der Viewport zeigt exakt, was der Client zeigt. +func _on_sky_changed(index: int) -> void: + if _loading_ui_values or main.doc.is_empty(): + return + var neu := "" if index <= 0 else str(SkyboxKatalog.EINTRAEGE[index - 1]["id"]) + var alt := str(main.doc.get("weather_sky", "")) + if neu == alt: + return + var before := {"weather_sky": (alt if main.doc.has("weather_sky") else null)} + if neu == "": + main.doc.erase("weather_sky") + else: + main.doc["weather_sky"] = neu + var after := {"weather_sky": (neu if neu != "" else null)} + var name := "Prozedural (Standard)" if neu == "" else str(SkyboxKatalog.eintrag(neu)["name"]) + main.history.commit("Himmel: %s" % name, before, after) + main.dirty = true + main.call("_refresh_file_label") + main.call("_refresh_history_buttons") + main.view_builder.call("rebuild", main.doc, main.manifest) + main.call("_sync_grid_to_builder") + _update_sky_preview(neu) + var hinweis := "" + if neu != "" and SkyboxKatalog.panorama_textur(neu) == null: + hinweis = " Achtung: Textur nicht gefunden (Client-Ordner neben dem Editor fehlt) — Vorschau zeigt den Standard-Himmel." + main.call("_set_status", "Himmel geändert auf „%s“.%s" % [name, hinweis]) + + +func _update_sky_preview(id: String) -> void: + sky_preview.texture = SkyboxKatalog.vorschau(id) if id != "" else null + sky_preview.visible = sky_preview.texture != null + + +## Wasser (Karte t_28fdef03): Slider → doc["water_level"]. Ganz links +## („Kein Wasser“, KEIN_WASSER_WERT) = Feld ENTFERNEN (Legacy-sauber). +## Sofort-Neuaufbau wie Wetter/Himmel — die Vorschau zeigt die Fläche live +## (dasselbe Material wie der Client). +func _on_water_changed(value: float) -> void: + if _loading_ui_values or main.doc.is_empty(): + return + if value <= KEIN_WASSER_WERT + 0.0001: + main.doc.erase("water_level") + main.call("_set_status", "Wasser entfernt (kein Wasser in dieser Karte).") + else: + var terrain: Dictionary = main.doc.get("terrain", {}) + var ok := true + if not terrain.is_empty(): + # Range-Bewacher (V20-Band): sinnlose Werte gar nicht erst + # ins doc schreiben — der Slider klemmt am Höhenbereich. + var hmin := float(terrain.get("min_height_m", -5.0)) + var hmax := float(terrain.get("max_height_m", 500.0)) + var geklemmt := clampf(value, hmin - 10.0, hmax + 10.0) + if geklemmt != value: + ok = false + value = geklemmt + prop_water.set_value_no_signal(geklemmt) + main.call("_set_status", "Wasserhöhe an den Terrain-Höhenbereich geklemmt (%.1f m)." % geklemmt) + if ok or value != KEIN_WASSER_WERT: + main.doc["water_level"] = value + main.dirty = true + main.call("_refresh_file_label") + main.view_builder.call("rebuild", main.doc, main.manifest) + main.call("_sync_grid_to_builder") + + +## Felder aus dem doc auffüllen (aus main.gd _refresh_all-Anfang ausgezogen). +func refresh_values() -> void: + _loading_ui_values = true + var info: Dictionary = main.doc.get("info", {}) + prop_name.text = str(info.get("name", "")) + prop_author.text = str(info.get("author", "")) + prop_desc.text = str(info.get("description", "")) + prop_version.value = float(info.get("version", 1)) + var weathers := ["mittag", "abend", "regen", "nacht"] + var weather := str(main.doc.get("weather", "mittag")) + prop_weather.select(maxi(0, weathers.find(weather))) + # Himmel: Auswahl ↔ doc["weather_sky"] (Katalog-ID; unbekannt/leer → Standard). + var sky_id := str(main.doc.get("weather_sky", "")) + var sky_idx := 0 + for i in SkyboxKatalog.EINTRAEGE.size(): + if SkyboxKatalog.EINTRAEGE[i]["id"] == sky_id: + sky_idx = i + 1 + prop_sky.select(sky_idx) + _update_sky_preview(sky_id if sky_idx > 0 else "") + + var terrain: Dictionary = main.doc.get("terrain", {}) + terrain_info.text = "Größe: %.0f × %.0f m\nAuflösung: %d × %d Höhenpunkte\nHöhenbereich: %.0f bis %.0f m" % [ + float(terrain.get("size_x_m", 0.0)), float(terrain.get("size_z_m", 0.0)), + int(terrain.get("resolution", 0)), + int(terrain.get("resolution", 0)), + float(terrain.get("min_height_m", 0.0)), float(terrain.get("max_height_m", 0.0))] + # Wasser (Karte t_28fdef03): Regler aus dem doc füllen (ohne dirty). + var wl: Variant = main.doc.get("water_level", null) + prop_water.set_value_no_signal( + float(wl) if (wl is float or wl is int) else KEIN_WASSER_WERT) + # Loadout-Bereich (Registry-Gruppe "map") aus dem doc nachziehen. + var modus_panel: Node = _sections.get_node_or_null("modus") if _sections != null else null + if modus_panel != null: + modus_panel.call("refresh_values") + var loadout_panel: Node = _sections.get_node_or_null("loadout") if _sections != null else null + if loadout_panel != null: + loadout_panel.call("refresh_values") + _loading_ui_values = false diff --git a/ui/panels/map_panel.gd.uid b/ui/panels/map_panel.gd.uid new file mode 100644 index 0000000..41e082d --- /dev/null +++ b/ui/panels/map_panel.gd.uid @@ -0,0 +1 @@ +uid://dihu04ppa406d diff --git a/ui/panels/modus_panel.gd b/ui/panels/modus_panel.gd new file mode 100644 index 0000000..886e79c --- /dev/null +++ b/ui/panels/modus_panel.gd @@ -0,0 +1,413 @@ +extends "res://core/ui/panels/editor_panel.gd" +## Spielmodus-Bereich im Map-Tab (28.10.): Modus der Map wählen (Team-Deathmatch / +## Conquest / King of the Hill / Deathmatch), Zonen bzw. Hills setzen und eigene +## Spawns je Modus anlegen. Zonen erscheinen als farbige Kreise im 3D-Bild. +## Gespeichert als optionale Felder doc["game_mode"], doc["conquest_zones"], +## doc["hills"], doc["mode_spawns"] (Regeln: core/svmap/modus_katalog.gd). +## +## Jede Änderung ist ein Undo-Schritt (History-Blöcke; fehlt ein Block, gilt der +## Standard: TDM, keine Zonen, keine eigenen Spawns). + +var mode_option: OptionButton +var cp_box: VBoxContainer # Zonen-/Hill-Bereich (nur Conquest und KotH) +var zones_title: Label +var rows_box: VBoxContainer +var add_button: Button +var hint_label: Label +var spawn_option: OptionButton # Spawn-Satz, der mit dem Spawn-Werkzeug bearbeitet wird +var spawn_create: Button +var spawn_remove: Button +var spawn_hint: Label + +var _loading := false + + +static func spec() -> Dictionary: + return {"titel": "Spielmodus", "gruppe": "map", "order": 22} + + +func panel_title() -> String: + return "Spielmodus" + + +func build() -> void: + add_child(_header_label("Spielmodus")) + add_child(_muted_label("Legt fest, wie auf dieser Karte gewonnen wird.")) + + mode_option = OptionButton.new() + mode_option.name = "ModusAuswahl" + mode_option.tooltip_text = "Team-Deathmatch: Kills zählen. Conquest: Teams nehmen mehrere Zonen ein. King of the Hill: ein Hill, der wandert. Deathmatch: alle gegen alle." + for m in ModusKatalog.MODES: + mode_option.add_item(ModusKatalog.MODE_LABELS[m]) + add_child(mode_option) + + cp_box = VBoxContainer.new() + cp_box.add_theme_constant_override("separation", UIScale.px(8)) + add_child(cp_box) + + zones_title = _field_label("Zonen") + cp_box.add_child(zones_title) + rows_box = VBoxContainer.new() + rows_box.add_theme_constant_override("separation", UIScale.px(6)) + cp_box.add_child(rows_box) + + add_button = Button.new() + add_button.name = "ZoneNeu" + add_button.text = "+ Zone in Bildmitte setzen" + add_button.tooltip_text = "Setzt eine neue Zone dorthin, wo die Kamera hinschaut. Position und Größe lassen sich darunter ändern." + cp_box.add_child(add_button) + + hint_label = _muted_label("Mindestens eine Zone nötig.") + cp_box.add_child(hint_label) + + # Spawns je Modus + add_child(_field_label("Spawns bearbeiten für")) + spawn_option = OptionButton.new() + spawn_option.name = "SpawnSatz" + spawn_option.tooltip_text = "Welche Spawn-Punkte das Spawn-Werkzeug gerade zeigt und ändert. Ohne eigene Spawns nutzt ein Modus die Basis-Spawns." + add_child(spawn_option) + spawn_create = Button.new() + spawn_create.name = "SpawnSatzNeu" + spawn_create.tooltip_text = "Legt eigene Spawn-Punkte für diesen Modus an (Kopie der Basis-Spawns) — danach mit dem Spawn-Werkzeug anpassen." + add_child(spawn_create) + spawn_remove = Button.new() + spawn_remove.name = "SpawnSatzWeg" + spawn_remove.text = "Eigene Spawns löschen" + spawn_remove.tooltip_text = "Entfernt die eigenen Spawns dieses Modus — er nutzt danach wieder die Basis-Spawns." + add_child(spawn_remove) + spawn_hint = _muted_label("") + add_child(spawn_hint) + + mode_option.item_selected.connect(func(i: int) -> void: + if not _loading: + set_mode(ModusKatalog.MODES[i])) + add_button.pressed.connect(func() -> void: add_zone_at_view()) + spawn_option.item_selected.connect(func(i: int) -> void: + if not _loading: + select_spawn_set(_spawn_set_ids()[i])) + spawn_create.pressed.connect(func() -> void: create_spawns(SpawnOps.edit_set)) + spawn_remove.pressed.connect(func() -> void: remove_spawns(SpawnOps.edit_set)) + refresh_values() + + +# ------------------------------------------------------------- Ändern ------ + +func set_mode(mode: String) -> void: + if main.doc.is_empty() or not ModusKatalog.MODES.has(mode) or ModusKatalog.mode_of(main.doc) == mode: + return + var before := _snap() + if mode == ModusKatalog.MODE_TDM: + main.doc.erase("game_mode") + else: + main.doc["game_mode"] = mode + if ModusKatalog.has_zones(mode) and ModusKatalog.zones(main.doc, mode).is_empty(): + main.doc[ModusKatalog.ZONE_KEYS[mode]] = ModusKatalog.default_zones(main.doc, mode) + _commit(before, "Spielmodus: %s" % ModusKatalog.MODE_SHORT[mode]) + + +func _zone_key() -> String: + return str(ModusKatalog.ZONE_KEYS.get(ModusKatalog.mode_of(main.doc), "")) + + +func add_zone_at_view() -> void: + if main.doc.is_empty() or _zone_key() == "": + return + var at := Vector3.ZERO + if main.camera != null and "target" in main.camera: + at = main.camera.target + var half := _half() + add_zone(clampf(at.x, -half.x, half.x), clampf(at.z, -half.y, half.y)) + + +func add_zone(x: float, z: float) -> String: + var mode := ModusKatalog.mode_of(main.doc) + var key := _zone_key() + if key == "": + return "" + var before := _snap() + var zone := ModusKatalog.make_zone(main.doc, mode, x, z) + var list: Array = ModusKatalog.zones(main.doc, mode).duplicate(true) + list.append(zone) + main.doc[key] = list + _commit(before, "%s %s gesetzt" % [ModusKatalog.ZONE_NAMES[mode], zone["id"]]) + return str(zone["id"]) + + +func remove_zone(id: String) -> void: + var mode := ModusKatalog.mode_of(main.doc) + var key := _zone_key() + if key == "": + return + var before := _snap() + var list: Array = [] + for c in ModusKatalog.zones(main.doc, mode): + if str(c.get("id", "")) != id: + list.append((c as Dictionary).duplicate(true)) + if list.size() == ModusKatalog.zones(main.doc, mode).size(): + return + if list.is_empty(): + main.doc.erase(key) + else: + main.doc[key] = list + _commit(before, "%s %s gelöscht" % [ModusKatalog.ZONE_NAMES[mode], id]) + + +## King of the Hill: Reihenfolge der Hills ändern (dir = -1 hoch, +1 runter). +func move_zone(id: String, dir: int) -> void: + var mode := ModusKatalog.mode_of(main.doc) + var key := _zone_key() + if key == "": + return + var list: Array = ModusKatalog.zones(main.doc, mode).duplicate(true) + var idx := -1 + for i in list.size(): + if str(list[i].get("id", "")) == id: + idx = i + var to := idx + dir + if idx < 0 or to < 0 or to >= list.size(): + return + var before := _snap() + var tmp: Variant = list[idx] + list[idx] = list[to] + list[to] = tmp + main.doc[key] = list + _commit(before, "%s %s verschoben (Reihenfolge)" % [ModusKatalog.ZONE_NAMES[mode], id]) + + +## Name / Position / Radius einer Zone ändern (nur übergebene Felder). +func edit_zone(id: String, fields: Dictionary) -> void: + var mode := ModusKatalog.mode_of(main.doc) + var key := _zone_key() + if key == "": + return + var before := _snap() + var list: Array = ModusKatalog.zones(main.doc, mode).duplicate(true) + for c in list: + if str(c.get("id", "")) != id: + continue + if fields.has("label"): + c["label"] = str(fields["label"]).strip_edges().substr(0, 32) + if fields.has("radius_m"): + c["radius_m"] = clampf(float(fields["radius_m"]), ModusKatalog.MIN_RADIUS, ModusKatalog.MAX_RADIUS) + if fields.has("x") or fields.has("z"): + var half := _half() + var p: Array = c["pos"] + var nx := clampf(float(fields.get("x", p[0])), -half.x, half.x) + var nz := clampf(float(fields.get("z", p[2])), -half.y, half.y) + c["pos"] = [nx, SvmapDocument.terrain_height_at(main.doc, nx, nz), nz] + if fields.has(SpawnOps.YAW_KEY): + SpawnOps.write_yaw(c, fields[SpawnOps.YAW_KEY]) + main.doc[key] = list + _commit(before, "%s %s geändert" % [ModusKatalog.ZONE_NAMES[mode], id], "cp_%s" % id if fields.has("x") or fields.has("z") or fields.has("radius_m") or fields.has(SpawnOps.YAW_KEY) else "") + + +# ---- Spawn-Sätze ---- + +func _spawn_set_ids() -> Array: + var out: Array = [ModusKatalog.SPAWN_SET_BASE] + out.append_array(ModusKatalog.MODES) + return out + + +func select_spawn_set(set_id: String) -> void: + if not _spawn_set_ids().has(set_id): + return + SpawnOps.edit_set = set_id + _refresh_spawn_view() + refresh_values() + main.call("_set_status", "Spawn-Satz: %s." % _set_label(set_id)) + + +func create_spawns(mode: String) -> void: + if main.doc.is_empty() or mode == ModusKatalog.SPAWN_SET_BASE or ModusKatalog.has_own_spawns(main.doc, mode): + return + var before := _snap() + ModusKatalog.create_spawn_set(main.doc, mode) + _commit(before, "Eigene Spawns für %s angelegt" % ModusKatalog.MODE_SHORT[mode]) + _refresh_spawn_view() + + +func remove_spawns(mode: String) -> void: + if main.doc.is_empty() or mode == ModusKatalog.SPAWN_SET_BASE or not ModusKatalog.has_own_spawns(main.doc, mode): + return + var before := _snap() + ModusKatalog.remove_spawn_set(main.doc, mode) + SpawnOps.edit_set = ModusKatalog.SPAWN_SET_BASE + _commit(before, "Eigene Spawns für %s gelöscht" % ModusKatalog.MODE_SHORT[mode]) + _refresh_spawn_view() + + +func _refresh_spawn_view() -> void: + if main.view_builder != null: + main.view_builder.call("_rebuild_spawn_markers", main.doc) + if "spawn_tool" in main and main.spawn_tool != null: + main.spawn_tool.call("refresh_from_doc") + + +func _set_label(set_id: String) -> String: + if set_id == ModusKatalog.SPAWN_SET_BASE: + return "Basis (für alle Modi ohne eigene Spawns)" + return "%s%s" % [ModusKatalog.MODE_SHORT[set_id], " ✔ eigene" if ModusKatalog.has_own_spawns(main.doc, set_id) else ""] + + +func _half() -> Vector2: + var t: Dictionary = main.doc.get("terrain", {}) + return Vector2(float(t.get("size_x_m", 1024.0)) * 0.5, float(t.get("size_z_m", 1024.0)) * 0.5) + + +func _snap() -> Dictionary: + var out := {} + for key in ["game_mode", "conquest_zones", "hills", "mode_spawns"]: + var v: Variant = main.doc.get(key, null) + out[key] = v.duplicate(true) if v is Array or v is Dictionary else v + return out + + +func _commit(before: Dictionary, text: String, merge_tag := "") -> void: + var after := _snap() + if before == after: + return + main.history.commit(text, before, after, merge_tag) + main.dirty = true + main.call("_refresh_file_label") + main.call("_refresh_history_buttons") + if main.view_builder != null: + main.view_builder.call("rebuild_zone_markers", main.doc) + refresh_values() + main.call("_set_status", "%s." % text) + + +# ------------------------------------------------------------ Anzeige ------ + +## UI aus dem doc auffüllen (Laden, Undo/Redo) — löst keinen Schreibzugriff aus. +func refresh_values() -> void: + if mode_option == null or main == null or main.doc.is_empty(): + return + _loading = true + var mode := ModusKatalog.mode_of(main.doc) + mode_option.select(ModusKatalog.MODES.find(mode)) + cp_box.visible = ModusKatalog.has_zones(mode) + if cp_box.visible: + var nm: String = ModusKatalog.ZONE_NAMES[mode] + zones_title.text = "Hills (Reihenfolge = Wanderreihenfolge)" if mode == ModusKatalog.MODE_KOTH else "Zonen" + add_button.text = "+ %s in Bildmitte setzen" % nm + hint_label.text = "Mindestens %s nötig. %s" % [ + "einen Hill" if mode == ModusKatalog.MODE_KOTH else "eine Zone", + "Der Server wechselt nach der eingestellten Zeit zum nächsten Hill (oder zufällig)." if mode == ModusKatalog.MODE_KOTH + else "Spieler spawnen zusätzlich an Zonen ihres Teams."] + for c in rows_box.get_children(): + rows_box.remove_child(c) + c.queue_free() + var zl := ModusKatalog.zones(main.doc, mode) + for i in zl.size(): + if zl[i] is Dictionary: + rows_box.add_child(_row(zl[i], i, zl.size(), mode)) + hint_label.visible = zl.is_empty() + # Spawn-Sätze + if not _spawn_set_ids().has(SpawnOps.edit_set): + SpawnOps.edit_set = ModusKatalog.SPAWN_SET_BASE + spawn_option.clear() + for sid in _spawn_set_ids(): + spawn_option.add_item(_set_label(sid)) + spawn_option.select(_spawn_set_ids().find(SpawnOps.edit_set)) + var base := SpawnOps.edit_set == ModusKatalog.SPAWN_SET_BASE + var own := not base and ModusKatalog.has_own_spawns(main.doc, SpawnOps.edit_set) + spawn_create.visible = not base and not own + spawn_create.text = "Eigene Spawns für %s anlegen" % (ModusKatalog.MODE_SHORT[SpawnOps.edit_set] if not base else "") + spawn_remove.visible = own + if base: + spawn_hint.text = "Basis-Spawns gelten für jeden Modus ohne eigene Spawns." + elif own: + spawn_hint.text = "Das Spawn-Werkzeug ändert jetzt die eigenen Spawns dieses Modus." + else: + spawn_hint.text = "%s nutzt noch die Basis-Spawns. Mit dem Knopf legst du eigene an." % ModusKatalog.MODE_SHORT[SpawnOps.edit_set] + if SpawnOps.edit_set == ModusKatalog.MODE_DM and own: + spawn_hint.text += " Deathmatch hat keine Teams — alle Punkte gelten für alle." + _loading = false + + +func _row(cp: Dictionary, index := 0, count := 1, mode := "conquest") -> Control: + var id := str(cp.get("id", "")) + var pos: Array = cp.get("pos", [0, 0, 0]) + var half := _half() + var box := VBoxContainer.new() + box.name = "Z_%s" % id + box.add_theme_constant_override("separation", UIScale.px(4)) + + var top := HBoxContainer.new() + var idl := _field_label("%d·%s" % [index + 1, id] if mode == ModusKatalog.MODE_KOTH else id) + idl.custom_minimum_size = UIScale.v2(32, 0) + top.add_child(idl) + var name_edit := LineEdit.new() + name_edit.name = "Name" + name_edit.text = str(cp.get("label", id)) + name_edit.max_length = 32 + name_edit.size_flags_horizontal = Control.SIZE_EXPAND_FILL + name_edit.text_submitted.connect(func(t: String) -> void: + if not _loading: + edit_zone(id, {"label": t})) + name_edit.focus_exited.connect(func() -> void: + if not _loading and name_edit.text != str(cp.get("label", id)): + edit_zone(id, {"label": name_edit.text})) + top.add_child(name_edit) + if mode == ModusKatalog.MODE_KOTH: + var up := Button.new() + up.name = "Hoch" + up.text = "▲" + up.tooltip_text = "Früher drankommen" + up.disabled = index == 0 + up.pressed.connect(func() -> void: move_zone(id, -1)) + top.add_child(up) + var dn := Button.new() + dn.name = "Runter" + dn.text = "▼" + dn.tooltip_text = "Später drankommen" + dn.disabled = index >= count - 1 + dn.pressed.connect(func() -> void: move_zone(id, 1)) + top.add_child(dn) + var del := Button.new() + del.name = "Loeschen" + del.text = "✕" + del.tooltip_text = "Löschen" + del.pressed.connect(func() -> void: remove_zone(id)) + top.add_child(del) + box.add_child(top) + + var nums := HBoxContainer.new() + nums.add_theme_constant_override("separation", UIScale.px(4)) + nums.add_child(_spin("X", "x", id, float(pos[0]), -half.x, half.x, 1.0)) + nums.add_child(_spin("Z", "z", id, float(pos[2]), -half.y, half.y, 1.0)) + nums.add_child(_spin("Radius", "radius_m", id, float(cp.get("radius_m", ModusKatalog.DEFAULT_RADIUS)), + ModusKatalog.MIN_RADIUS, ModusKatalog.MAX_RADIUS, 1.0)) + box.add_child(nums) + if mode == ModusKatalog.MODE_CONQUEST: + var facing := HBoxContainer.new() + facing.add_theme_constant_override("separation", UIScale.px(4)) + facing.add_child(_spin("Blickrichtung °", SpawnOps.YAW_KEY, id, SpawnOps.effective_yaw(main.doc, cp), 0.0, 359.0, 1.0)) + var reset := Button.new() + reset.name = "BlickStandard" + reset.text = "Standard" + reset.tooltip_text = "Keine feste Richtung: Spieler schauen zur Kartenmitte, Bots zum Gegner. Im Spawn-Werkzeug geht's auch per Pfeilspitze." + reset.disabled = not SpawnOps.has_yaw(cp) + reset.pressed.connect(func() -> void: edit_zone(id, {SpawnOps.YAW_KEY: null})) + facing.add_child(reset) + box.add_child(facing) + return box + + +func _spin(label: String, field: String, id: String, value: float, mn: float, mx: float, step: float) -> Control: + var h := HBoxContainer.new() + h.size_flags_horizontal = Control.SIZE_EXPAND_FILL + h.add_child(_field_label(label)) + var sb := SpinBox.new() + sb.name = field + sb.min_value = mn + sb.max_value = mx + sb.step = step + sb.set_value_no_signal(value) + sb.size_flags_horizontal = Control.SIZE_EXPAND_FILL + sb.value_changed.connect(func(v: float) -> void: + if not _loading: + edit_zone(id, {field: v})) + h.add_child(sb) + return h diff --git a/ui/panels/modus_panel.gd.uid b/ui/panels/modus_panel.gd.uid new file mode 100644 index 0000000..ad8aa37 --- /dev/null +++ b/ui/panels/modus_panel.gd.uid @@ -0,0 +1 @@ +uid://dd6aphlxfvcha diff --git a/ui/panels/registry.gd b/ui/panels/registry.gd new file mode 100644 index 0000000..dce3e73 --- /dev/null +++ b/ui/panels/registry.gd @@ -0,0 +1,109 @@ +class_name PanelRegistry +extends RefCounted + +## Zentrale, DATENGETRIEBENE Anmeldung aller Editor-Bereiche (Karte t_eaccbfed, +## Operator-Vorgabe 20.10.). main.gd baut das Layout AUSSCHLIESSLICH aus dieser +## Registry — keine Panel-Erzeugung mehr fest verdrahtet. +## +## Warum: Die Umbau-Karten U2 (Szenen-Baum), U3 (Gruppen), U4 (Assets), +## U5 (Platzieren nur einmal), U6 (dezente Auswahl) und U7 (Feinschliff) ändern +## danach NUR ihr eigenes Modul und melden sich HIER an (einzeiliger Eintrag) +## — ohne main.gd anzufassen. Dadurch kollidieren parallele Karten nicht mehr +## in derselben Datei (gleiche Falle wie früher bei match_hud.gd). +## +## Struktur je Eintrag: titel (Tab-/Überschrift), gruppe ("rechts" = rechtes +## TabControl, "links" = linke Spalte, "unten" = Assets-Bereich, "map" = Abschnitte im Map-Tab, "dialog" = Einstellungen-Fenster, "toolbar" / +## "status" = Leisten-Aktionen), order (Sortier-Schlüssel), skript (preload-Pfad +## des Panel-Moduls). Ein Bereich erscheint GENAU EINMAL im Baum (test_ui_layout +## prüft das gegen Doppel-Namen). + +const TITLE_TOOLBAR := "Werkzeuge" +const TITLE_STATUS := "Statuszeile" + +## Die Bereiche in fester Reihenfolge. skript = preload-Pfad; jeder +## Panel-Eintrag muss in seinem Skript `static func spec()` haben, das +## mindestens {"titel", "gruppe", "order"} liefert (die Werte hier sind die +## Authorität — spec() wird von test_ui_layout GEGEN diese Tabelle geprüft). +const PANELS: Array = [ + # --- rechts: Tab-Gruppe (Unity-Inspector-Spalte) --- + {"id": "inspektor", "titel": "Inspektor", "gruppe": "rechts", "order": 10, + "skript": "res://core/ui/inspector_panel.gd"}, + {"id": "map", "titel": "Map", "gruppe": "rechts", "order": 30, + "skript": "res://core/ui/panels/map_panel.gd"}, + {"id": "terrain", "titel": "Terrain", "gruppe": "rechts", "order": 40, + "skript": "res://core/ui/panels/terrain_panel.gd"}, + # 25.10. UI-Aufräumen: Malen und Bauen hängen nicht mehr im Terrain-Tab. + {"id": "malen", "titel": "Malen", "gruppe": "rechts", "order": 45, + "skript": "res://core/ui/panels/malen_panel.gd"}, + {"id": "bauen", "titel": "Bauen", "gruppe": "rechts", "order": 47, + "skript": "res://core/ui/panels/bauen_panel.gd"}, + # Etappe 3: Server-Verwaltung (Admin-API des Match-Servers). + {"id": "server", "titel": "Server", "gruppe": "rechts", "order": 50, + "skript": "res://core/ui/panels/server_panel.gd"}, + # --- map: Abschnitte UNTER den Map-Eigenschaften (Tab „Map“) --- + # 25.10. (Test-Befund): Prüfen/Test-Start/Symmetrie sind keine eigenen Tabs + # mehr. Spawn-Zonen, Test-Start-Info und Symmetrie wohnen im Map-Tab. + {"id": "check", "titel": "Spawn-Zonen", "gruppe": "map", "order": 10, + "skript": "res://core/ui/panels/check_panel.gd"}, + {"id": "teststart", "titel": "Test-Start", "gruppe": "map", "order": 20, + "skript": "res://core/ui/panels/test_start_panel.gd"}, + {"id": "loadout", "titel": "Loadout", "gruppe": "map", "order": 25, + "skript": "res://core/ui/panels/loadout_panel.gd"}, + {"id": "modus", "titel": "Spielmodus", "gruppe": "map", "order": 22, + "skript": "res://core/ui/panels/modus_panel.gd"}, + {"id": "symmetrie", "titel": "Symmetrie", "gruppe": "map", "order": 30, + "skript": "res://core/ui/panels/symmetry_panel.gd"}, + # --- dialog: Inhalt des Einstellungen-Fensters (Knopf in der Kopfleiste) --- + # T3 Komfort (Karte t_aaff5dcc) + 25.10.: Gitter, Höhenlinien, Symmetrie- + # Modus, UI-Größe, Raster-Snap, Gizmo-Schritt, Karte prüfen. + {"id": "einstellungen", "titel": "Einstellungen", "gruppe": "dialog", "order": 10, + "skript": "res://core/ui/panels/settings_panel.gd"}, + # --- links: Vorbereitet für U2 (Szenen-Baum); Bibliothek ist UNTEN --- + {"id": "szene", "titel": "Map-Inhalt", "gruppe": "links", "order": 10, + "skript": "res://core/ui/panels/scene_tree_panel.gd"}, + # --- unten: Objekt-Bibliothek / Assets (Unity-Projekt-Fenster-Platz) --- + {"id": "assets", "titel": "Objekt-Bibliothek", "gruppe": "unten", "order": 10, + "skript": "res://core/ui/panels/assets_panel.gd"}, +] + +## Leisten-Aktionen (Toolbar-Buttons/Menüs — KEINE Panels, melden sich ditto +## datengetrieben an, damit T1s Lauf-Modus und künftige Aktionen main.gd +## nicht mehr anfassen). action = Methodenname an main (Callable wird gebunden). +const ACTIONS: Array = [ + {"id": "karte_pruefen", "titel": "✅ Karte prüfen", "gruppe": "toolbar", + "order": 10, "action": "_on_check_map"}, + {"id": "karte_testen", "titel": "▶ Karte testen", "gruppe": "toolbar", + "order": 20, "action": "_on_test_run"}, + # Wiederanbindung 20.10. (T1b, Karte t_96e3c4ee): der Test-Start-Knopf war + # beim U1-Umbau aus der Leiste verschwunden. + {"id": "teststart", "titel": "🎯 Test-Start", "gruppe": "toolbar", + "order": 30, "action": "_on_test_start_tool_pressed"}, +] + + +## Panel-Einträge einer Gruppe, nach order sortiert (Reihenfolge = Tab-Reihenfolge). +static func entries(gruppe: String) -> Array: + var out: Array = [] + for e in PANELS: + if str(e["gruppe"]) == gruppe: + out.append(e) + out.sort_custom(func(a, b) -> bool: return int(a["order"]) < int(b["order"])) + return out + + +## Toolbar-Aktionen, nach order sortiert. +static func toolbar_actions() -> Array: + var out: Array = [] + for e in ACTIONS: + if str(e["gruppe"]) == "toolbar": + out.append(e) + out.sort_custom(func(a, b) -> bool: return int(a["order"]) < int(b["order"])) + return out + + +## Eintrag per ID (für Tests/Probes). +static func entry(id: String) -> Dictionary: + for e in PANELS: + if str(e["id"]) == id: + return e + return {} diff --git a/ui/panels/registry.gd.uid b/ui/panels/registry.gd.uid new file mode 100644 index 0000000..78557b8 --- /dev/null +++ b/ui/panels/registry.gd.uid @@ -0,0 +1 @@ +uid://cmom62lxsqgef diff --git a/ui/panels/scene_tree_panel.gd b/ui/panels/scene_tree_panel.gd new file mode 100644 index 0000000..dccc376 --- /dev/null +++ b/ui/panels/scene_tree_panel.gd @@ -0,0 +1,590 @@ +extends "res://core/ui/panels/editor_panel.gd" +## Map-Inhalt-Baum (aus main.gd ausgezogen, Karte t_eaccbfed U1 — Logik +## unverändert). U2 baut hier den hierarchischen Szenen-Baum aus; diese Karte +## zieht nur um: Der Baum lebt jetzt im LINKEN TabContainer (Registry-Gruppe +## "links"), Zustand/Signale wie vorher. + +var content_tree: Tree +var group_btn: Button +var ungroup_btn: Button +var _tree_select_lock := false # verhindert Rückkopplung Auswahl ↔ Baum +var _tree_select_pending := false # multi_selected gesammelt, Auswertung steht aus +var _obj_index_map: Dictionary = {} # obj_index -> TreeItem (schnelle Zwei-Wege-Kopplung) + +# U3 (Karte t_a4bf9b8c): Kontextmenü, Umbenennen, Lösch-Rückfrage, Drag&Drop. +var _context_menu: PopupMenu +var _rename_dialog: AcceptDialog +var _rename_field: LineEdit +var _rename_gid := -1 # Gruppe, die das Umbenennen-Dialogfeld betrifft +var _confirm_delete: ConfirmationDialog +var _confirm_gid := -1 # Gruppe, die das Lösch-Rückfragen betrifft + + +static func spec() -> Dictionary: + return {"titel": "Map-Inhalt", "gruppe": "links", "order": 10} + + +func build() -> void: + add_child(_header_label("Map-Inhalt")) + + content_tree = Tree.new() + content_tree.size_flags_vertical = Control.SIZE_EXPAND_FILL + content_tree.custom_minimum_size = UIScale.v2(0, 160) + content_tree.allow_reselect = true + content_tree.select_mode = Tree.SELECT_MULTI # Strg+Klick im Baum = Mehrfachauswahl (t_c46d31c2) + content_tree.hide_root = true + # FIX 25.10. (Test-Befund „Liste anklicken wählt in der Szene nichts aus“): + # Im Modus SELECT_MULTI feuert Godot NIE item_selected, sondern nur + # multi_selected (pro Zeile). Beide anschließen; das Sammeln übernimmt der + # Aufrufer-Merker, damit ein Klick mit mehreren Signalen nur EINMAL wirkt. + content_tree.item_selected.connect(_on_tree_selected) + content_tree.multi_selected.connect(_on_tree_multi_selected) + add_child(content_tree) + + # Gruppen verwalten (25.10.: der Tab „Auswahl“ ist weg): mehrere Objekte in der + # Liste (Strg+Klick) oder in der Szene markieren, dann hier gruppieren/lösen. + # Rechtsklick auf eine Zeile bietet dieselben Aktionen. + var group_row := HBoxContainer.new() + group_row.add_theme_constant_override("separation", UIScale.px(8)) + add_child(group_row) + group_btn = Button.new() + group_btn.text = "🔗 Gruppieren" + group_btn.size_flags_horizontal = Control.SIZE_EXPAND_FILL + group_btn.custom_minimum_size = UIScale.v2(0, 40) + group_btn.tooltip_text = "Markierte Objekte zu einer Gruppe verbinden (Strg+G) — sie ziehen und drehen dann gemeinsam. Mehrere markieren: Strg+Klick in der Liste oder Rahmen in der Szene." + group_btn.pressed.connect(func() -> void: main.interaction.group_selection()) + group_row.add_child(group_btn) + ungroup_btn = Button.new() + ungroup_btn.text = "⛓ Gruppe lösen" + ungroup_btn.size_flags_horizontal = Control.SIZE_EXPAND_FILL + ungroup_btn.custom_minimum_size = UIScale.v2(0, 40) + ungroup_btn.tooltip_text = "Die Gruppe der Auswahl auflösen (Strg+Umschalt+G) — die Objekte bleiben, nur die Bindung löst sich" + ungroup_btn.pressed.connect(func() -> void: main.interaction.ungroup_selection()) + group_row.add_child(ungroup_btn) + + # U3 (Karte t_a4bf9b8c): Rechtsklick-Kontextmenü + Drag&Drop für Gruppen. + content_tree.gui_input.connect(_on_tree_gui_input) + # Tree.set_drag_forwarding: die drei Virtuals (_get_drag_data/_can_drop_data/ + # _drop_data) wohnen am Tree selbst — hier per Callables weitergeleitet. + content_tree.set_drag_forwarding(_tree_drag_data, _tree_can_drop, _tree_drop) + _context_menu = PopupMenu.new() + _context_menu.hide_on_item_selection = true + _context_menu.id_pressed.connect(_on_menu_action) + add_child(_context_menu) + _rename_dialog = AcceptDialog.new() + _rename_dialog.title = "Gruppe umbenennen" + _rename_dialog.ok_button_text = "Übernehmen" + # Hinweis: AcceptDialog kennt in Godot 4.7 weder cancel_button_text noch + # get_cancel_button() — der Default-Abbrechen-Button bleibt, wie er ist. + _rename_field = LineEdit.new() + _rename_field.placeholder_text = "Gruppenname" + _rename_dialog.add_child(_rename_field) + _rename_dialog.confirmed.connect(_on_rename_confirmed) + add_child(_rename_dialog) + _confirm_delete = ConfirmationDialog.new() + _confirm_delete.title = "Gruppe löschen" + _confirm_delete.ok_button_text = "Löschen" + _confirm_delete.cancel_button_text = "Abbrechen" + _confirm_delete.confirmed.connect(_on_delete_confirmed) + add_child(_confirm_delete) + add_child(_separator()) + + +## multi_selected kommt je Zeile (auch beim Abwählen): die Auswahl EINMAL pro +## Frame auswerten, nicht pro Signal. +func _on_tree_multi_selected(_item: TreeItem, _column: int, _selected: bool) -> void: + if _tree_select_lock or _tree_select_pending: + return + _tree_select_pending = true + _apply_tree_selection.call_deferred() + + +func _apply_tree_selection() -> void: + _tree_select_pending = false + _on_tree_selected() + + +## Der Baum ruft zurück, wenn der Nutzer dort ein Objekt auswählt. +## SELECT_MULTI (Karte t_c46d31c2): einfacher Klick = Ersatz-Auswahl, +## Strg+Klick addiert/entfernt nativ — ALLE markierten Objekt-Zeilen spiegeln +## sich in die Viewport-Auswahl (Baum und Szene sind immer synchron). +func _on_tree_selected() -> void: + if _tree_select_lock: + return + var item := content_tree.get_selected() + if item == null: + return + # Gruppe geklickt (Karte t_e3c0310a U2): alle Mitglieder auswählen. + if item.has_meta("group_id"): + var g_indices: Array = [] + var walk_g := item.get_first_child() + while walk_g != null: + if walk_g.has_meta("obj_index"): + g_indices.append(int(walk_g.get_meta("obj_index"))) + walk_g = walk_g.get_next() + if not g_indices.is_empty(): + _tree_select_lock = true + main.interaction.select_many(g_indices) + _tree_select_lock = false + main.call("_set_status", "Gruppe %d ausgewählt (%d Objekte) — gemeinsam verschieben/drehen/duplizieren." % [int(item.get_meta("group_id")), g_indices.size()]) + return + var indices: Array = [] + var walk := content_tree.get_next_selected(null) + while walk != null: + if walk.has_meta("obj_index"): + indices.append(int(walk.get_meta("obj_index"))) + walk = content_tree.get_next_selected(walk) + if indices.is_empty(): + return + var objects: Array = main.doc.get("objects", []) + var valid: Array = [] + for idx in indices: + if idx >= 0 and idx < objects.size(): + valid.append(idx) + if valid.is_empty(): + return + if valid.size() == 1: + main.interaction.select_object(valid[0], true) + main.call("_set_status", "%s ausgewählt — ziehen zum Verschieben, R/Mausrad zum Drehen, Entf zum Löschen. Strg+Klick markiert weitere dazu." % main.object_label(str(objects[valid[0]].get("id", "")))) + else: + main.interaction.select_many(valid) + main.call("_set_status", "%d Objekte im Baum markiert — Entf löscht ALLE, Strg+D dupliziert ALLE (jeweils EIN Undo-Schritt)." % valid.size()) + + +func mark_tree_selection(idx: int) -> void: + mark_tree_selection_multi([idx]) + + +func mark_tree_selection_multi(indices: Array) -> void: + _tree_select_lock = true + var wanted := {} + for i in indices: + wanted[int(i)] = true + # Zwei-Wege-Kopplung (Karte t_e3c0310a U2): die Auswahl in 3D spiegelt + # sich im Baum — über die Index-Karte O(1) statt Voll-Suche. + for idx in wanted.keys(): + if _obj_index_map.has(idx): + var item: TreeItem = _obj_index_map[idx] + item.select(0) + # Abwählen: alle übrigen markierten Objekt-Zeilen deselektieren. + var walk := content_tree.get_next_selected(null) + while walk != null: + if walk.has_meta("obj_index") and not wanted.has(int(walk.get_meta("obj_index"))): + walk.deselect(0) + walk = content_tree.get_next_selected(walk) + var primary: Variant = main.interaction.get("selected_index") if main.interaction != null else -1 + if primary is int and primary >= 0 and _obj_index_map.has(primary): + _ensure_tree_visible(content_tree.get_root(), primary) + _tree_select_lock = false + + +func _ensure_tree_visible(item: TreeItem, idx: int) -> void: + if item == null: + return + if item.has_meta("obj_index") and int(item.get_meta("obj_index")) == idx: + # Fix (beim Inspektor-Einbau gefunden, Vorbestand t_f6f29d86): Tree + # und TreeItem haben KEIN ensure_visible — die Godot-4-API heißt + # Tree.scroll_to_item. Der alte Ruf warf bei JEDER Auswahl einen + # SCRIPT ERROR und scrollte den Baum nie zur Auswahl. + content_tree.scroll_to_item(item) + return + for child in item.get_children(): + _ensure_tree_visible(child, idx) + + +func refresh_tree() -> void: + content_tree.clear() + _obj_index_map.clear() + var root := content_tree.create_item() + var objects: Array = main.doc.get("objects", []) + var zones: Dictionary = main.doc.get("spawn_zones", {}) + var group_ids: Array = GroupOps.active_group_ids(main.doc) + + # Leerer Zustand (Karte t_e3c0310a U2): Klartext-Hinweis statt leere Gruppen. + if objects.is_empty() and zones.is_empty() and group_ids.is_empty(): + var empty_item := content_tree.create_item(root) + empty_item.set_text(0, "Noch keine Objekte — links in der Objekt-Bibliothek wählen") + empty_item.set_selectable(0, false) + return + + # Objekte: Kategorie → Objekte (Karte t_e3c0310a U2 — z. B. Mauern, Barrieren). + var obj_item := content_tree.create_item(root) + obj_item.set_text(0, "Objekte (%d)" % objects.size()) + obj_item.set_meta("objekte_kopf", true) # Drag-Ziel „aus Gruppe herauslösen“ (U3) + var kat_map: Dictionary = {} + for i in objects.size(): + var obj = objects[i] + if obj is Dictionary: + var oid := str(obj.get("id", "?")) + var kat := LibraryBrowser.group_of(oid) + if not kat_map.has(kat): + kat_map[kat] = [] + kat_map[kat].append({"idx": i, "obj": obj}) + for kat in kat_map.keys(): + var kat_item := content_tree.create_item(obj_item) + kat_item.set_text(0, "%s (%d)" % [_kat_label(kat), (kat_map[kat] as Array).size()]) + for data in kat_map[kat]: + var idx: int = int(data["idx"]) + var obj: Dictionary = data["obj"] + var is_visible: bool = bool(obj.get("visible", true)) + var item := content_tree.create_item(kat_item) + item.set_text(0, ("👁 " if is_visible else "🚫 ") + "%s #%d" % [main.object_label(str(obj.get("id", "?"))), idx + 1]) + item.set_meta("obj_index", idx) + item.set_meta("visible", is_visible) + _obj_index_map[idx] = item + + # Spawn-Zonen: Team A/B (Karte t_e3c0310a U2 — aus der alten Struktur). + if not zones.is_empty(): + var spawn_item := content_tree.create_item(root) + spawn_item.set_text(0, "Spawn-Zonen") + for team_key in ["0", "1"]: + if not zones.has(team_key): + continue + var zone: Dictionary = zones[team_key] + var team_item := content_tree.create_item(spawn_item) + var team_name := "Team Blau" if team_key == "0" else "Team Rot" + team_item.set_text(0, "%s (%d Punkte)" % [team_name, (zone.get("points", []) as Array).size()]) + for p in (zone.get("points", []) as Array): + if p is Dictionary: + var point_item := content_tree.create_item(team_item) + point_item.set_text(0, "%s (%.0f, %.0f)" % [ + str(p.get("id", "?")), float(p.get("pos", [0, 0, 0])[0]), float(p.get("pos", [0, 0, 0])[2])]) + + # Gruppen (Karte t_e3c0310a U2): aktive Gruppen als eigene Ebene im Baum. + # Klick auf eine Gruppe wählt ALLE Mitglieder in der 3D-Szene (Zwei-Wege). + if not group_ids.is_empty(): + var grp_item := content_tree.create_item(root) + grp_item.set_text(0, "Gruppen (%d)" % group_ids.size()) + grp_item.set_meta("objekte_kopf", true) # Drag-Ziel „herauslösen“ (U3) + for gid in group_ids: + var member_indices: Array = GroupOps.members_of(main.doc, gid) + # U3 (Karte t_a4bf9b8c): gespeicherter Name voran, Fallback "Gruppe N". + var g_node := content_tree.create_item(grp_item) + g_node.set_text(0, "%s (%d Objekte)" % [GroupState.display_name(main.doc, int(gid)), member_indices.size()]) + g_node.set_meta("group_id", int(gid)) + for mi in member_indices: + var obj: Dictionary = main.doc["objects"][int(mi)] + var m_item := content_tree.create_item(g_node) + m_item.set_text(0, " %s" % main.object_label(str(obj.get("id", "?")))) + m_item.set_meta("obj_index", int(mi)) + + +## Kategorie-Schlüssel (z. B. "mauern") in Anzeige-Label (z. B. "Mauern") — +## Karte t_e3c0310a U2. Nutzt KAT_GROUPS aus LibraryBrowser. +static func _kat_label(key: String) -> String: + for kat_name in LibraryBrowser.KAT_GROUPS: + var g: Dictionary = LibraryBrowser.KAT_GROUPS[kat_name] + if str(g["key"]) == key: + return str(g["label"]) + return key.capitalize() + + +# ================= U3: Gruppen im Baum (Karte t_a4bf9b8c) ==================== +# Gruppen direkt im Szenen-Baum bilden: Rechtsklick-Menü (Gruppieren/Auflösen/ +# Umbenennen/Löschen), Drag&Drop für die Mitgliedschaft, Gruppennamen im +# Dokument (GroupState, additiv). Jede Aktion = EIN Undo-Schritt über +# main.history — die Mehrfachauswahl-Logik (interaction.gd) wird benutzt, +# nicht kopiert; object_ops.gd nur LESEND. + + +## Rechtsklick im Baum: Zeile unter der Maus finden → Kontextmenü aufmachen. +func _on_tree_gui_input(event: InputEvent) -> void: + if not (event is InputEventMouseButton): + return + var mb := event as InputEventMouseButton + if not mb.pressed or mb.button_index != MOUSE_BUTTON_RIGHT: + return + var item: TreeItem = content_tree.get_item_at_position(mb.position) + if item == null: + return + # Rechtsklick auf eine (noch nicht markierte) Zeile wählt sie an — wie in + # Unity/Godot: das Menü gehört zur angeklickten Zeile. Direkter Ruf von + # _on_tree_selected (item_selected feuert bei .select() nicht selbst). + if item.has_meta("obj_index") and not item.is_selected(0): + content_tree.deselect_all() + item.select(0) + _on_tree_selected() + _open_context_menu(item, Vector2i(content_tree.get_screen_transform() * mb.position)) + + +## Kontextmenü je Zeilen-Typ aufbauen (Klartext-Einträge, je Aktion eine ID). +func _open_context_menu(item: TreeItem, at_screen: Vector2i) -> void: + _context_menu.clear() + var has_entries := false + # Gruppen-Knoten: Auflösen / Umbenennen / Löschen (Rückfrage bei > 1 Objekt). + if item.has_meta("group_id"): + var gid := int(item.get_meta("group_id")) + _context_menu.add_item("⛓ Gruppe auflösen", 1) + _context_menu.set_item_metadata(_context_menu.item_count - 1, {"aktion": "loesen_gruppe", "gid": gid}) + _context_menu.add_item("✂ Umbenennen…", 2) + _context_menu.set_item_metadata(_context_menu.item_count - 1, {"aktion": "umbenennen", "gid": gid}) + _context_menu.add_item("🗑 Gruppe löschen…", 3) + _context_menu.set_item_metadata(_context_menu.item_count - 1, {"aktion": "loeschen_gruppe", "gid": gid}) + has_entries = true + # Objekt-Zeile: Gruppieren (wenn ≥ 2 markiert), Aus Gruppe lösen, Löschen. + if item.has_meta("obj_index"): + var sel: Array = main.interaction.selected_indices + if sel.size() >= 2: + _context_menu.add_item("🔗 Gruppieren (%d Objekte)" % sel.size(), 10) + _context_menu.set_item_metadata(_context_menu.item_count - 1, {"aktion": "gruppieren"}) + has_entries = true + var objects: Array = main.doc.get("objects", []) + var idx := int(item.get_meta("obj_index")) + if idx >= 0 and idx < objects.size() and GroupOps.group_id(objects[idx]) != GroupOps.UNGROUPED: + _context_menu.add_item("⛓ Aus Gruppe lösen", 1) + _context_menu.set_item_metadata(_context_menu.item_count - 1, {"aktion": "loesen_einzeln", "idx": idx}) + has_entries = true + _context_menu.add_item("🗑 Löschen", 3) + _context_menu.set_item_metadata(_context_menu.item_count - 1, {"aktion": "loeschen_einzeln", "idx": idx}) + has_entries = true + if not has_entries: + return + _context_menu.position = at_screen + _context_menu.popup() + + +## Menü-Auswahl → Aktion (Metadaten tragen Ziel; ID → Zeile über get_item_index, +## robust auch nachdem das Menü sich bei hide_on_item_selection schon versteckt). +func _on_menu_action(id: int) -> void: + var menu_index := _context_menu.get_item_index(id) + if menu_index < 0: + return + var meta: Variant = _context_menu.get_item_metadata(menu_index) + if not (meta is Dictionary): + return + var m := meta as Dictionary + match str(m.get("aktion", "")): + "gruppieren": + group_selected() + "loesen_gruppe": + ungroup_group(int(m.get("gid", -1))) + "loesen_einzeln": + ungroup_indices([int(m.get("idx", -1))]) + "umbenennen": + open_rename_dialog(int(m.get("gid", -1))) + "loeschen_gruppe": + delete_group(int(m.get("gid", -1))) + "loeschen_einzeln": + _select_for_action([int(m.get("idx", -1))]) + main.interaction.delete_selected() + + +## Auswahl für eine Aktion setzen (Baum-Markierung + 3D synchron). +func _select_for_action(indices: Array) -> void: + _tree_select_lock = true + main.interaction.select_many(indices) + _tree_select_lock = false + + +## Mehrfachauswahl → Gruppe (nutzt die bestehende interaction-Logik, EIN Undo). +func group_selected() -> void: + var sel: Array = main.interaction.selected_indices + if sel.size() < 2: + main.call("_set_status", "Gruppieren braucht mindestens 2 markierte Objekte — Strg+Klick im Baum oder im Viewport.", true) + return + main.interaction.group_selection() + _refresh_after_group_change() + _select_for_action(sel) # Gruppe bleibt markiert (Mitglieder hängen jetzt unter dem Gruppen-Knoten) + + +## GANZE Gruppe auflösen: Mitglieder anwählen → bestehende Löse-Logik. +func ungroup_group(gid: int) -> void: + var members: Array = GroupOps.members_of(main.doc, gid) + if members.is_empty(): + main.call("_set_status", "Gruppe %d existiert nicht mehr." % (gid + 1), true) + return + _select_for_action(members) + main.interaction.ungroup_selection() + _refresh_after_group_change() + + +## Objekte aus ihrer Gruppe herauslösen (NUR diese Indizes — Drag-out-Pfad). +## EIN Undo-Schritt: snapshot ["objects", "group_names"] vor/nach (verwaiste +## Namen-Einträge werden im selben Schritt mitgeräumt). +func ungroup_indices(indices: Array) -> void: + var before := _snapshot_group_blocks() + var freed := GroupState.clear_group_fields(main.doc, indices) + if freed == 0: + main.call("_set_status", "Die markierten Objekte stecken in keiner Gruppe.") + return + GroupState.prune_orphans(main.doc) + main.history.commit("Objekt aus Gruppe gelöst (%d)" % freed, + before, _snapshot_group_blocks()) + main.call("_refresh_history_buttons") + _refresh_after_group_change() + + +## Snapshot für Gruppen-Undo-Schritte: ["objects", "group_names"]. Fehlt der +## Namen-Block im Dokument (alte Maps), wird er als null SEEDED — ActionHistory +## wendet nur Schlüssel an, die im Snapshot stehen; ohne Seed bliebe der Name +## nach Undo als Leiche stehen (Restore von null löscht den Block sauber). +func _snapshot_group_blocks() -> Dictionary: + var out: Dictionary = main.history.snapshot(["objects", "group_names"]) + if not out.has(GroupState.NAMES_KEY): + out[GroupState.NAMES_KEY] = null + return out + + +## Umbenennen-Kern (testbar ohne Dialog): Name im Dokument setzen, EIN Undo. +func rename_group(gid: int, new_name: String) -> bool: + if gid < 0: + return false + var clean := new_name.strip_edges() + if GroupState.group_name(main.doc, gid) == clean: + return false # Name unverändert — kein leerer Undo-Eintrag + var before := _snapshot_group_blocks() + GroupState.set_group_name(main.doc, gid, new_name) + GroupState.prune_orphans(main.doc) + var after := _snapshot_group_blocks() + var label := ("Gruppe umbenannt in „%s“" % clean) if not clean.is_empty() \ + else ("Gruppenname entfernt (Gruppe %d)" % (gid + 1)) + main.history.commit(label, before, after) + main.call("_refresh_history_buttons") + _refresh_after_group_change() + return true + + +## Umbenennen-Dialog (Rechtsklick am Gruppen-Knoten). +func open_rename_dialog(gid: int) -> void: + var members: Array = GroupOps.members_of(main.doc, gid) + if members.is_empty(): + main.call("_set_status", "Gruppe %d existiert nicht mehr." % (gid + 1), true) + return + _rename_gid = gid + _rename_field.text = GroupState.group_name(main.doc, gid) + _rename_dialog.dialog_text = "Neuer Name für die Gruppe (leer = wieder „Gruppe %d“):" % (gid + 1) + _rename_field.grab_focus() + _rename_dialog.popup_centered(Vector2i(360, 100)) + + +func _on_rename_confirmed() -> void: + if _rename_gid >= 0: + rename_group(_rename_gid, _rename_field.text) + _rename_gid = -1 + + +## Gruppe löschen: Rückfrage bei > 1 Objekt, dann bestehende Lösch-Logik +## (interaction.delete_selected — EIN Undo-Schritt, Marker/3D räumen mit auf). +func delete_group(gid: int) -> void: + var members: Array = GroupOps.members_of(main.doc, gid) + if members.is_empty(): + main.call("_set_status", "Gruppe %d existiert nicht mehr." % (gid + 1), true) + return + if members.size() > 1: + _confirm_gid = gid + _confirm_delete.dialog_text = "Gruppe „%s“ löschen? Die %d Objekte darin werden ALLE gelöscht — Strg+Z holt sie zurück." % [GroupState.display_name(main.doc, gid), members.size()] + _confirm_delete.popup_centered(Vector2i(480, 140)) + return + delete_group_confirmed(gid) + + +## Lösch-Kern NACH der Rückfrage (auch direkt aufrufbar — Tests). +func delete_group_confirmed(gid: int) -> void: + var members: Array = GroupOps.members_of(main.doc, gid) + if members.is_empty(): + return + _select_for_action(members) + main.interaction.delete_selected() # ruft selbst _after_structure_change → Baum neu + + +func _on_delete_confirmed() -> void: + if _confirm_gid >= 0: + delete_group_confirmed(_confirm_gid) + _confirm_gid = -1 + + +# --- Drag & Drop (Mitgliedschaft ändern) ------------------------------------- + +## Zieh-Menge bestimmen: gezogene Zeile ist Teil der Markierung → die GANZE +## Markierung wandert mit; sonst nur die gezogene Zeile. (Testbar ohne echten +## Drag — _tree_drag_data ruft nur dies + set_drag_preview.) +func _collect_drag_indices(item: TreeItem) -> Array: + if item == null or not item.has_meta("obj_index"): + return [] + var idx := int(item.get_meta("obj_index")) + var sel: Array = main.interaction.selected_indices + if idx in sel: + var out: Array = [] + for i in sel: + if i is int: + out.append(int(i)) + return out + return [idx] + + +## Tree-Drag-Start (set_drag_forwarding-Callable): Datenpaket für Drop-Ziele. +## Vorschau-Control wird NICHT in den Baum gehängt (set_drag_preview verlangt +## ein Control außerhalb des Baums). +func _tree_drag_data(from_position: Vector2) -> Variant: + var item: TreeItem = content_tree.get_item_at_position(from_position) + var indices := _collect_drag_indices(item) + if indices.is_empty(): + return null + var label := Label.new() + label.text = "%d Objekt(e) ziehen" % indices.size() + content_tree.set_drag_preview(label) + return {"svmap_tree_objekte": indices} + + +## Drop erlaubt: AUF einen Gruppen-Knoten (aufnehmen) oder AUF den Objekte-Kopf/ +## eine Kategorie-Zeile (herauslösen — nur wenn mindestens ein gezogenes Objekt +## überhaupt gruppiert ist). +func _tree_can_drop(at_position: Vector2, data: Variant) -> bool: + if not (data is Dictionary) or not (data as Dictionary).has("svmap_tree_objekte"): + return false + var item: TreeItem = content_tree.get_item_at_position(at_position) + if item == null: + return false + if item.has_meta("group_id"): + return true + if item.has_meta("objekte_kopf"): + var objects: Array = main.doc.get("objects", []) + for i in (data["svmap_tree_objekte"] as Array): + if i is int and i >= 0 and i < objects.size() \ + and GroupOps.group_id(objects[i]) != GroupOps.UNGROUPED: + return true + return false + + +## Drop ausführen → Mitgliedschaft ändern (EIN Undo-Schritt), Baum/Auswahl neu. +func _tree_drop(at_position: Vector2, data: Variant) -> void: + var item: TreeItem = content_tree.get_item_at_position(at_position) + if item == null: + return + var indices: Array = (data as Dictionary).get("svmap_tree_objekte", []) + if item.has_meta("group_id"): + _apply_membership_drop(indices, int(item.get_meta("group_id"))) + elif item.has_meta("objekte_kopf"): + _apply_membership_drop(indices, -1) + + +## Mitgliedschafts-Kern (testbar): gid ≥ 0 = aufnehmen, gid < 0 = herauslösen. +func _apply_membership_drop(indices: Array, gid: int) -> void: + var before := _snapshot_group_blocks() + var changed := 0 + var label := "" + if gid >= 0: + changed = GroupState.assign_group(main.doc, indices, gid) + label = "%d Objekt(e) in „%s“ gezogen" % [changed, GroupState.display_name(main.doc, gid)] + else: + changed = GroupState.clear_group_fields(main.doc, indices) + label = "%d Objekt(e) aus der Gruppe herausgelöst" % changed + if changed == 0: + main.call("_set_status", "Nichts zu ändern — die Objekte gehören schon genau so zur Gruppe.") + return + GroupState.prune_orphans(main.doc) + main.history.commit(label, before, _snapshot_group_blocks()) + main.call("_refresh_history_buttons") + _refresh_after_group_change() + _select_for_action(indices) # gezogene Objekte bleiben sichtbar markiert + + +## Nach jeder Gruppen-Änderung: Baum neu + Panels synchron (kein 3D-Rebuild — +## Positionen ändern sich beim Gruppieren/Umbenennen/Zuordnen nicht). +func _refresh_after_group_change() -> void: + main.call("_refresh_tree") + var sel: Array = main.interaction.selected_indices + _tree_select_lock = true + mark_tree_selection_multi(sel) + _tree_select_lock = false + main.call("_sync_selection_panel") diff --git a/ui/panels/scene_tree_panel.gd.uid b/ui/panels/scene_tree_panel.gd.uid new file mode 100644 index 0000000..a7e6184 --- /dev/null +++ b/ui/panels/scene_tree_panel.gd.uid @@ -0,0 +1 @@ +uid://bpbw3vo36ohv1 diff --git a/ui/panels/selection_panel.gd b/ui/panels/selection_panel.gd new file mode 100644 index 0000000..2e87c83 --- /dev/null +++ b/ui/panels/selection_panel.gd @@ -0,0 +1,67 @@ +extends Node +## Auswahl-Logik (U1, Karte t_eaccbfed — aus main.gd ausgezogen). Seit 25.10. +## KEIN Tab mehr (Test-Befund): Drehen/Anheben/Duplizieren/Löschen laufen in der +## 3D-Ansicht (Werkzeugleiste, Gizmo, Tasten), Gruppen im Map-Inhalt links, die +## Gizmo-Schrittweite im Einstellungen-Fenster. Übrig bleibt die Synchronisation: +## Inspektor nachziehen, Gizmo-Schrittweite-Feld folgen, Statuszeile zur frischen +## Auswahl (Klartext + Poly-Budget-Warnung). +## +## Verdrahtung: main.gd ruft sync_selection() an allen Auswahl-Wegen +## (vorher: _sync_selection_panel) und selection_status(idx) bei frischer +## Auswahl (vorher: _selection_status). Alle Objekt-Operationen laufen über +## main.interaction — der Vertrag zu interaction.gd bleibt identisch. + +var main # core/ui/main.gd (script-erweitert → untypisiert) + + +func setup(p_main) -> void: + main = p_main + + +## Objekt-Inspektor + Auswahl-Panel synchron halten (vorher +## main.gd/_sync_selection_panel — Logik unverändert). +func sync_selection() -> void: + # Objekt-Inspektor mit allen Auswahl-Wege synchron halten (Karte t_bb0d11c9). + if main.inspector != null: + main.inspector.call("refresh") + # Gizmo-Schrittweite-Feld mitziehen (Karte t_e0120dc2): Das Mausrad + # WÄHREND eines Zugs kann sie im Gizmo ändern (cycle_step) — das Panel- + # Feld folgt ohne eigene value_changed-Rückkopplung (set_value_no_signal). + var step_box: SpinBox = main.gizmo_step_box + if step_box != null and is_instance_valid(step_box) and not step_box.has_focus(): + step_box.set_value_no_signal(main.gizmo_step_m) + + +## Hilfs-Meldung zur frischen Auswahl (Klartext + Budget-Warnung + nächster +## Schritt) — vorher main.gd/_selection_status, Logik unverändert. +func selection_status(idx: int) -> void: + # Objekt-Inspektor füllen (Karte t_bb0d11c9) — dieser Weg läuft bei + # 3D-Klick, Rahmen-Ausziehen und Map-Inhalt-Baum. + if main.inspector != null: + main.inspector.call("refresh") + # sync_selection ändert bewusst KEINEN Statuszeilen-Text (Stummsync). + sync_selection() + var doc: Dictionary = main.doc + var objects: Array = doc.get("objects", []) + var sel: Array = main.interaction.selected_indices + if (idx < 0 or idx >= objects.size()) and sel.is_empty(): + main._base_tool_status() + return + var used := int(SvmapDocument.poly_usage(doc, main.manifest)) + var budget := int(SvmapIO.MAX_TOTAL_POLY) + var budget_warning := "" + if used > budget * 80 / 100: + budget_warning = " ⚠ Poly-Budget zu %.0f %% voll — bald passt kein Objekt mehr rein." % (100.0 * used / budget) + if sel.size() > 1: + main._set_status("%d Objekte ausgewählt — ziehen bewegt ALLE gemeinsam, R/Mausrad dreht sie um die Mitte, Entf löscht alle, Strg+G gruppiert.%s" % [sel.size(), budget_warning]) + return + if idx < 0 or idx >= objects.size(): + main._base_tool_status() + return + var obj: Dictionary = objects[idx] + var gid := GroupOps.group_id(obj) + var group_hint := "" + if gid != GroupOps.UNGROUPED: + group_hint = " (Gruppe %d — die zieht GEMEINSAM)" % (gid + 1) + main._set_status("%s%s ausgewählt — ziehen zum Verschieben, R oder Mausrad zum Drehen, Bild↑/↓ anheben/absenken, Strg+D duplizieren, Entf zum Löschen.%s" % [ + main.object_label(str(obj.get("id", ""))), group_hint, budget_warning]) \ No newline at end of file diff --git a/ui/panels/selection_panel.gd.uid b/ui/panels/selection_panel.gd.uid new file mode 100644 index 0000000..80c9c4d --- /dev/null +++ b/ui/panels/selection_panel.gd.uid @@ -0,0 +1 @@ +uid://dwp3df5nsfl3s diff --git a/ui/panels/server_panel.gd b/ui/panels/server_panel.gd new file mode 100644 index 0000000..655c1d2 --- /dev/null +++ b/ui/panels/server_panel.gd @@ -0,0 +1,687 @@ +extends "res://core/ui/panels/editor_panel.gd" +## Tab „Server“ (Etappe 3 „Server-Verwaltung“): Client der Match-Server-Admin-API. +## Mehrere Server speichern, verbinden, Status, Einstellungen, Spieler, Maps, +## Rotation, Logs und „Aktuelle Map auf den Server pushen“ – alles per Klick. +## Logik: core/server/ (AdminClient, ServerStore, AdminTexte, MapPush). + +var store: ServerStore +var store_path := ServerStore.DEFAULT_PATH # Tests lenken um +var client: AdminClient +var current_id := "" +var last_notice := "" # letzte Meldung (Tests) +var connected := false +var restart_wait_s := 120.0 # so lange wartet „Server neu starten“ (Tests verkürzen) +var restart_poll_s := 2.0 + +var _sel: OptionButton +var _conn_label: Label +var _notice: Label +var _status_label: Label +var _live_box: VBoxContainer # alles, was einen verbundenen Server braucht +var _push_name: LineEdit +var _push_rot: CheckBox +var _push_result: Label +var _settings_box: VBoxContainer +var _settings_editors: Dictionary = {} # key -> Control +var _settings_loaded: Dictionary = {} +var _settings_spec: Dictionary = {} +var _settings_result: Label +var _players_box: VBoxContainer +var _bans_box: VBoxContainer +var _ban_minutes: OptionButton +var _maps_box: VBoxContainer +var _rotation_checks: Dictionary = {} # map id -> CheckBox +var _log_filter: LineEdit +var _log_text: TextEdit +var _confirm: ConfirmationDialog +var _confirm_action: Callable +var _edit_dialog: ConfirmationDialog +var _edit_fields: Dictionary = {} +var _edit_id := "" + +const BAN_DAUER := [[10, "10 Minuten"], [60, "1 Stunde"], [1440, "1 Tag"], [10080, "1 Woche"], [0, "Dauerhaft"]] + + +static func spec() -> Dictionary: + return {"titel": "Server", "gruppe": "rechts", "order": 50} + + +func panel_title() -> String: + return "Server" + + +func build() -> void: + store = ServerStore.new(store_path) + store.load_store() + client = AdminClient.new() + client.name = "AdminClient" + add_child(client) + + add_child(_header_label("Server verwalten")) + add_child(_muted_label("Verbinde den Editor mit deinem Match-Server (Admin-API), um Maps hochzuladen und den Server zu steuern.")) + var hint := _muted_label(AdminTexte.TUNNEL_HINWEIS) + hint.visible = false + var hint_btn := Button.new() + hint_btn.text = "❓ Wie erreiche ich meinen Server sicher?" + hint_btn.flat = true + hint_btn.pressed.connect(func() -> void: hint.visible = not hint.visible) + add_child(hint_btn) + add_child(hint) + + _sel = OptionButton.new() + _sel.custom_minimum_size = UIScale.v2(0, 36) + _sel.item_selected.connect(func(_i: int) -> void: _on_selected()) + add_child(_sel) + var row := HBoxContainer.new() + add_child(row) + row.add_child(_btn("➕ Neu", _on_add)) + row.add_child(_btn("✏ Bearbeiten", _on_edit)) + row.add_child(_btn("🗑 Entfernen", _on_remove)) + var conn_row := HBoxContainer.new() + add_child(conn_row) + conn_row.add_child(_btn("🔌 Verbinden", func() -> void: connect_selected())) + _conn_label = Label.new() + _conn_label.text = "Nicht verbunden" + _conn_label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART + _conn_label.size_flags_horizontal = Control.SIZE_EXPAND_FILL + conn_row.add_child(_conn_label) + _notice = _muted_label("") + add_child(_notice) + + _live_box = VBoxContainer.new() + _live_box.add_theme_constant_override("separation", UIScale.px(8)) + _live_box.visible = false + add_child(_live_box) + _build_live() + _build_dialogs() + _refresh_selector() + wrap_in_scroll() + + +func _btn(text: String, cb: Callable) -> Button: + var b := Button.new() + b.text = text + b.custom_minimum_size = UIScale.v2(0, 36) + b.pressed.connect(cb) + return b + + +func _section(title: String) -> void: + _live_box.add_child(_separator()) + _live_box.add_child(_header_label(title)) + + +func _build_live() -> void: + _section("Übersicht") + _status_label = Label.new() + _status_label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART + _live_box.add_child(_status_label) + _live_box.add_child(_btn("🔄 Alles aktualisieren", func() -> void: refresh_all())) + + _section("Map auf Server pushen") + _live_box.add_child(_muted_label("Prüft die Map im Editor und lädt sie hoch. Der Server prüft sie noch einmal.")) + _push_name = LineEdit.new() + _push_name.placeholder_text = "Dateiname (leer = Map-Name)" + _live_box.add_child(_push_name) + _push_rot = CheckBox.new() + _push_rot.text = "In die Rotation aufnehmen" + _live_box.add_child(_push_rot) + var pb := _btn("⬆ Aktuelle Map hochladen", func() -> void: push_current_map()) + pb.custom_minimum_size = UIScale.v2(0, 44) + _live_box.add_child(pb) + _push_result = Label.new() + _push_result.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART + _live_box.add_child(_push_result) + + _section("Einstellungen") + _settings_box = VBoxContainer.new() + _live_box.add_child(_settings_box) + var srow := HBoxContainer.new() + _live_box.add_child(srow) + srow.add_child(_btn("💾 Speichern", func() -> void: save_settings())) + srow.add_child(_btn("↩ Zurücksetzen", func() -> void: _fill_settings_editors())) + _settings_result = _muted_label("") + _live_box.add_child(_settings_result) + + _section("Spieler") + _players_box = VBoxContainer.new() + _live_box.add_child(_players_box) + var brow := HBoxContainer.new() + _live_box.add_child(brow) + brow.add_child(_muted_label("Sperrdauer:")) + _ban_minutes = OptionButton.new() + for d in BAN_DAUER: + _ban_minutes.add_item(d[1]) + _ban_minutes.select(1) + brow.add_child(_ban_minutes) + _live_box.add_child(_muted_label("Gesperrt:")) + _bans_box = VBoxContainer.new() + _live_box.add_child(_bans_box) + + _section("Match & Maps") + _live_box.add_child(_btn("🔁 Match neu starten", func() -> void: _ask("Match auf dem Server neu starten? Alle Spieler beginnen die Runde von vorn.", _do_restart))) + _maps_box = VBoxContainer.new() + _live_box.add_child(_maps_box) + _live_box.add_child(_btn("💾 Rotation speichern", func() -> void: save_rotation())) + + _section("Server") + _live_box.add_child(_btn("⏻ Server neu starten", func() -> void: _ask("Server komplett neu starten? Alle Spieler werden getrennt und die laufende Runde endet.", func() -> void: await restart_server()))) + + _section("Server-Log") + _log_filter = LineEdit.new() + _log_filter.placeholder_text = "Filter (z. B. Admin, Join, FEHLER)" + _live_box.add_child(_log_filter) + _live_box.add_child(_btn("📜 Log laden", func() -> void: load_logs())) + _log_text = TextEdit.new() + _log_text.editable = false + _log_text.custom_minimum_size = UIScale.v2(0, 220) + _log_text.wrap_mode = TextEdit.LINE_WRAPPING_BOUNDARY + _live_box.add_child(_log_text) + + +func _build_dialogs() -> void: + _confirm = ConfirmationDialog.new() + _confirm.ok_button_text = "Ja" + _confirm.cancel_button_text = "Abbrechen" + _confirm.confirmed.connect(func() -> void: + if _confirm_action.is_valid(): + _confirm_action.call()) + add_child(_confirm) + + _edit_dialog = ConfirmationDialog.new() + _edit_dialog.title = "Server" + _edit_dialog.ok_button_text = "Speichern" + _edit_dialog.cancel_button_text = "Abbrechen" + var box := VBoxContainer.new() + _edit_dialog.add_child(box) + for f in [["name", "Name (frei wählbar)", "Mein Server"], ["host", "Adresse (IP oder Name)", "127.0.0.1"], + ["port", "Port der Admin-API", str(ServerStore.DEFAULT_PORT)], ["token", "Admin-Token", ""]]: + box.add_child(_field_label(f[1])) + var le := LineEdit.new() + le.placeholder_text = f[2] + le.custom_minimum_size = UIScale.v2(320, 32) + if f[0] == "token": + le.secret = true + box.add_child(le) + _edit_fields[f[0]] = le + var tls := CheckBox.new() + tls.text = "Sichere Verbindung (https) – nur mit Reverse-Proxy" + box.add_child(tls) + _edit_fields["tls"] = tls + var show := CheckBox.new() + show.text = "Token anzeigen" + show.toggled.connect(func(on: bool) -> void: (_edit_fields["token"] as LineEdit).secret = not on) + box.add_child(show) + var err := _muted_label("") + box.add_child(err) + _edit_fields["_err"] = err + box.add_child(_btn("🔌 Verbindung testen", func() -> void: _test_dialog_entry())) + _edit_dialog.confirmed.connect(_on_edit_confirmed) + add_child(_edit_dialog) + + +# ------------------------------------------------------------------ Liste -- + +func _refresh_selector(select_id: String = "") -> void: + _sel.clear() + for e in store.servers: + _sel.add_item("%s (%s:%d)" % [e["name"], e["host"], e["port"]]) + _sel.set_item_metadata(_sel.item_count - 1, e["id"]) + if _sel.item_count == 0: + _sel.add_item("– noch kein Server gespeichert –") + _sel.disabled = true + current_id = "" + return + _sel.disabled = false + var idx := 0 + for i in _sel.item_count: + if str(_sel.get_item_metadata(i)) == (select_id if select_id != "" else current_id): + idx = i + _sel.select(idx) + _on_selected() + + +func _on_selected() -> void: + if _sel.item_count == 0 or _sel.disabled: + return + var id := str(_sel.get_item_metadata(_sel.selected)) + if id != current_id: + _set_connected(false, "Nicht verbunden") + current_id = id + + +func _on_add() -> void: + _open_edit({}) + + +func _on_edit() -> void: + if current_id != "": + _open_edit(store.get_entry(current_id)) + + +func _open_edit(e: Dictionary) -> void: + _edit_id = str(e.get("id", "")) + _edit_dialog.title = "Server bearbeiten" if _edit_id != "" else "Server hinzufügen" + (_edit_fields["name"] as LineEdit).text = str(e.get("name", "")) + (_edit_fields["host"] as LineEdit).text = str(e.get("host", "")) + (_edit_fields["port"] as LineEdit).text = str(e.get("port", ServerStore.DEFAULT_PORT)) + (_edit_fields["token"] as LineEdit).text = str(e.get("token", "")) + (_edit_fields["tls"] as CheckBox).button_pressed = bool(e.get("tls", false)) + (_edit_fields["_err"] as Label).text = "" + _edit_dialog.popup_centered(UIScale.v2i(380, 420)) + + +func _entry_from_dialog() -> Dictionary: + return { + "id": _edit_id, "name": (_edit_fields["name"] as LineEdit).text, + "host": (_edit_fields["host"] as LineEdit).text.strip_edges(), + "port": int((_edit_fields["port"] as LineEdit).text), + "token": (_edit_fields["token"] as LineEdit).text, + "tls": (_edit_fields["tls"] as CheckBox).button_pressed} + + +func _on_edit_confirmed() -> void: + var id := store.upsert(_entry_from_dialog()) + if id == "": + _notify(store.last_error) + return + _refresh_selector(id) + + +func _test_dialog_entry() -> void: + var e := _entry_from_dialog() + var err := AdminClient.check_address(str(e["host"]), int(e["port"])) + var lbl: Label = _edit_fields["_err"] + if err != "": + lbl.text = err + return + lbl.text = "Teste …" + var probe := AdminClient.new() + add_child(probe) + probe.use(e) + var res: Dictionary = await probe.call_api("GET", "/ping") + if bool(res["ok"]): + var auth: Dictionary = await probe.call_api("GET", "/status") + lbl.text = "✅ Server gefunden. " + ("Token passt." if bool(auth["ok"]) else AdminTexte.erklaere(auth)) + else: + lbl.text = "❌ " + AdminTexte.erklaere(res) + probe.queue_free() + + +func _on_remove() -> void: + if current_id == "": + return + var e := store.public_view(current_id) + _ask("„%s“ aus der Liste entfernen? (Der Server selbst bleibt unverändert.)" % str(e["name"]), func() -> void: + store.remove(current_id) + current_id = "" + _set_connected(false, "Nicht verbunden") + _refresh_selector()) + + +# ---------------------------------------------------------------- Verbinden -- + +func connect_selected() -> bool: + if current_id == "": + _notify("Bitte erst einen Server hinzufügen (➕ Neu).") + return false + client.use(store.get_entry(current_id)) + _conn_label.text = "Verbinde …" + var ping: Dictionary = await client.call_api("GET", "/ping") + if not bool(ping["ok"]): + _set_connected(false, "❌ " + AdminTexte.erklaere(ping)) + return false + var st: Dictionary = await client.call_api("GET", "/status") + if not bool(st["ok"]): + _set_connected(false, "❌ " + AdminTexte.erklaere(st)) + return false + _set_connected(true, "✅ Verbunden") + await refresh_all() + return true + + +func _set_connected(on: bool, text: String) -> void: + connected = on + _conn_label.text = text + _live_box.visible = on + + +## Ruft die API auf und meldet Fehler verständlich. null = Fehler (schon gemeldet). +func _api(method: String, path: String, body: Variant = null, query: Dictionary = {}) -> Variant: + var res: Dictionary = await client.call_api(method, path, body, query) + if bool(res["ok"]): + return res["body"] + var text := AdminTexte.erklaere(res) + if int(res.get("status", 0)) in [0, 401, 429]: + _set_connected(false, "❌ " + text.split("\n")[0]) + _notify(text) + return null + + +func _notify(text: String) -> void: + last_notice = text + _notice.text = text + + +func refresh_all() -> void: + await refresh_status() + await refresh_settings() + await refresh_players() + await refresh_maps() + + +# ------------------------------------------------------------------ Status -- + +func refresh_status() -> void: + var s: Variant = await _api("GET", "/status") + if s == null: + return + var p: Dictionary = s["players"] + var h := int(s["uptime_s"]) / 3600 + var m := (int(s["uptime_s"]) % 3600) / 60 + _status_label.text = "%s\nMap: %s · Modus: %s · Phase: %s\nSpieler: %d von %d (+ %d Bots) · Restzeit %d s\nLäuft seit %d h %d min · %s · Passwort: %s · Master: %s" % [ + s["server_name"], s["map"]["name"], str(s["mode"]).to_upper(), s["phase"], + p["humans"], p["max"], p["bots"], int(s["time_remaining_s"]), h, m, + "öffentlich" if s["public"] else "privat", "ja" if s["password_set"] else "nein", s["master"]] + + +# ------------------------------------------------------------ Einstellungen -- + +func refresh_settings() -> void: + var r: Variant = await _api("GET", "/settings") + if r == null: + return + _settings_spec = r["spec"] + _settings_loaded = r["settings"] + for c in _settings_box.get_children(): + c.queue_free() + _settings_editors.clear() + for key in _settings_spec.keys(): + var sp: Dictionary = _settings_spec[key] + var lbl := _field_label("%s (%s)" % [sp["label"], AdminTexte.wirkung(str(sp["effect"]))]) + _settings_box.add_child(lbl) + var ed: Control + match str(sp["type"]): + "bool": + ed = CheckBox.new() + "int", "float": + var sb := SpinBox.new() + sb.min_value = float(sp["min"]) + sb.max_value = float(sp["max"]) + sb.step = 1.0 if str(sp["type"]) == "int" else 0.5 + ed = sb + "enum": + var ob := OptionButton.new() + for v in sp["values"]: + ob.add_item(str(v)) + ed = ob + _: + var le := LineEdit.new() + le.max_length = int(sp.get("max_len", 64)) + if key == "password": + le.secret = true + le.placeholder_text = "(unverändert)" + ed = le + _settings_box.add_child(ed) + _settings_editors[key] = ed + _fill_settings_editors() + + +func _fill_settings_editors() -> void: + for key in _settings_editors.keys(): + var ed: Control = _settings_editors[key] + var sp: Dictionary = _settings_spec[key] + if key == "password": + (ed as LineEdit).text = "" + (ed as LineEdit).placeholder_text = "(gesetzt – leer lassen = unverändert)" if bool(_settings_loaded.get("password_set", false)) else "(kein Passwort)" + continue + var v: Variant = _settings_loaded.get(key) + match str(sp["type"]): + "bool": (ed as CheckBox).button_pressed = bool(v) + "int", "float": (ed as SpinBox).value = float(v) + "enum": (ed as OptionButton).select(maxi(0, (sp["values"] as Array).find(v))) + _: (ed as LineEdit).text = str(v) + _settings_result.text = "" + + +## Nur geänderte Werte (Passwort nur, wenn etwas eingetippt wurde). +func changed_settings() -> Dictionary: + var out := {} + for key in _settings_editors.keys(): + var ed: Control = _settings_editors[key] + var sp: Dictionary = _settings_spec[key] + var v: Variant + match str(sp["type"]): + "bool": v = (ed as CheckBox).button_pressed + "int": v = int((ed as SpinBox).value) + "float": v = (ed as SpinBox).value + "enum": v = (sp["values"] as Array)[(ed as OptionButton).selected] + _: v = (ed as LineEdit).text + if key == "password": + if str(v) != "": + out[key] = v + continue + if v != _settings_loaded.get(key): + out[key] = v + return out + + +func save_settings() -> void: + var ch := changed_settings() + if ch.is_empty(): + _settings_result.text = "Nichts geändert." + return + var r: Variant = await _api("PATCH", "/settings", ch) + if r == null: + return + var lines: PackedStringArray = [] + if not (r["applied_now"] as Array).is_empty(): + lines.append("✅ Sofort aktiv: " + ", ".join(_labels(r["applied_now"]))) + if not (r["applies_next_map"] as Array).is_empty(): + lines.append("⏭ Ab der nächsten Map: " + ", ".join(_labels(r["applies_next_map"]))) + if not (r["needs_restart"] as Array).is_empty(): + lines.append("🔁 Erst nach Server-Neustart: " + ", ".join(_labels(r["needs_restart"]))) + for w in r.get("warnings", []): + lines.append("⚠ " + str(w)) + _settings_result.text = "\n".join(lines) + last_notice = _settings_result.text + _settings_loaded = r["settings"] + _fill_settings_editors() + _settings_result.text = "\n".join(lines) + + +func _labels(keys: Array) -> Array: + return keys.map(func(k: Variant) -> String: return str((_settings_spec.get(k, {}) as Dictionary).get("label", k))) + + +# ----------------------------------------------------------------- Spieler -- + +func refresh_players() -> void: + var r: Variant = await _api("GET", "/players") + var b: Variant = await _api("GET", "/bans") + if r == null or b == null: + return + for c in _players_box.get_children(): + c.queue_free() + if (r["players"] as Array).is_empty(): + _players_box.add_child(_muted_label("Gerade ist niemand auf dem Server.")) + for p in r["players"]: + var row := HBoxContainer.new() + var lbl := Label.new() + lbl.text = "%s (Team %s · %d/%d · %d ms)" % [p["name"], "Blau" if int(p["team"]) == 0 else "Rot", p["kills"], p["deaths"], p["ping_ms"]] + lbl.size_flags_horizontal = Control.SIZE_EXPAND_FILL + lbl.clip_text = true + row.add_child(lbl) + var pid := int(p["peer_id"]) + var pname := str(p["name"]) + row.add_child(_btn("Kick", func() -> void: _ask("„%s“ vom Server werfen?" % pname, func() -> void: await kick(pid)))) + row.add_child(_btn("Sperren", func() -> void: _ask("„%s“ sperren (%s)?" % [pname, BAN_DAUER[_ban_minutes.selected][1]], func() -> void: await ban(pid)))) + _players_box.add_child(row) + for c in _bans_box.get_children(): + c.queue_free() + if (b["bans"] as Array).is_empty(): + _bans_box.add_child(_muted_label("Niemand gesperrt.")) + for ban_e in b["bans"]: + var row2 := HBoxContainer.new() + var l2 := Label.new() + var until := int(ban_e.get("until", 0)) + l2.text = "%s – %s" % [str(ban_e.get("name", "?")), "dauerhaft" if until == 0 else "bis " + Time.get_datetime_string_from_unix_time(until, true)] + l2.size_flags_horizontal = Control.SIZE_EXPAND_FILL + l2.clip_text = true + row2.add_child(l2) + var bid := str(ban_e["id"]) + row2.add_child(_btn("Aufheben", func() -> void: await unban(bid))) + _bans_box.add_child(row2) + + +func kick(peer_id: int) -> void: + if await _api("POST", "/players/%d/kick" % peer_id, {}) != null: + _notify("Spieler wurde vom Server geworfen.") + await refresh_players() + + +func ban(peer_id: int, minutes: int = -1) -> void: + if minutes < 0: + minutes = int(BAN_DAUER[_ban_minutes.selected][0]) + if await _api("POST", "/players/%d/ban" % peer_id, {"minutes": minutes}) != null: + _notify("Spieler gesperrt (%s)." % AdminTexte.sperrdauer_text(minutes)) + await refresh_players() + + +func unban(ban_id: String) -> void: + if await _api("DELETE", "/bans/" + ban_id) != null: + _notify("Sperre aufgehoben.") + await refresh_players() + + +# -------------------------------------------------------------- Match, Maps -- + +func _do_restart() -> void: + if await _api("POST", "/match/restart", {}) != null: + _notify("Match wird neu gestartet.") + await refresh_status() + + +## Ganzen Server neu starten und warten, bis er wieder antwortet; dann neu verbinden. +func restart_server() -> bool: + var id := current_id + if await _api("POST", "/restart", {}) == null: + return false + _set_connected(false, "Server startet neu…") + _notify("Server startet neu…") + var res: Dictionary = await _wait_for_new_server(id) + if current_id != id: + return false # inzwischen anderen Server gewählt + if not bool(res["ok"]): + _set_connected(false, "❌ " + str(res["text"])) + _notify(str(res["text"])) + return false + var ok: bool = await connect_selected() + if ok: + _notify("✅ Server wurde neu gestartet.") + return ok + + +## Der alte Prozess antwortet noch kurz: Erst eine Laufzeit, die kleiner ist als die +## Wartezeit bisher, beweist den neuen Prozess. +func _wait_for_new_server(id: String) -> Dictionary: + var start := Time.get_ticks_msec() + while current_id == id: + var waited := (Time.get_ticks_msec() - start) / 1000.0 + if waited >= restart_wait_s: + return {"ok": false, "text": AdminTexte.neustart_zeitueberschreitung(int(restart_wait_s))} + var st: Dictionary = await client.call_api("GET", "/status") + if bool(st["ok"]): + if float(st["body"].get("uptime_s", INF)) <= (Time.get_ticks_msec() - start) / 1000.0: + return {"ok": true, "text": ""} + elif int(st.get("status", 0)) in [401, 429]: + return {"ok": false, "text": AdminTexte.erklaere(st)} + await get_tree().create_timer(restart_poll_s).timeout + return {"ok": false, "text": ""} + + +func refresh_maps() -> void: + var r: Variant = await _api("GET", "/maps") + if r == null: + return + for c in _maps_box.get_children(): + c.queue_free() + _rotation_checks.clear() + for m in r["maps"]: + var row := HBoxContainer.new() + var cb := CheckBox.new() + cb.button_pressed = bool(m["in_rotation"]) + cb.tooltip_text = "In der Rotation" + row.add_child(cb) + _rotation_checks[str(m["id"])] = cb + var lbl := Label.new() + lbl.text = "%s%s%s" % [m.get("name", m["file"]), " ▶ läuft" if m["active"] else "", " (eingebaut)" if m["source"] == "builtin" else ""] + lbl.size_flags_horizontal = Control.SIZE_EXPAND_FILL + lbl.clip_text = true + row.add_child(lbl) + var mid := str(m["id"]) + var mname := str(m.get("name", m["file"])) + row.add_child(_btn("Laden", func() -> void: _ask("„%s“ jetzt auf dem Server laden? Die laufende Runde endet." % mname, func() -> void: await load_map(mid)))) + if m["source"] == "upload": + var slug := mid.get_file().get_basename() + row.add_child(_btn("🗑", func() -> void: _ask("„%s“ vom Server LÖSCHEN? Das kann nicht rückgängig gemacht werden." % mname, func() -> void: await delete_map(slug)))) + _maps_box.add_child(row) + + +func load_map(map_id: String) -> void: + if await _api("POST", "/match/map", {"map": map_id}) != null: + _notify("Map wird geladen.") + await refresh_status() + + +func delete_map(slug: String) -> void: + if await _api("DELETE", "/maps/" + slug) != null: + _notify("Map gelöscht.") + await refresh_maps() + + +func save_rotation() -> void: + var ids: Array = [] + for id in _rotation_checks.keys(): + if (_rotation_checks[id] as CheckBox).button_pressed: + ids.append(id) + if ids.is_empty(): + _notify("Die Rotation braucht mindestens eine Map.") + return + if await _api("PUT", "/rotation", {"maps": ids}) != null: + _notify("Rotation gespeichert (%d Maps)." % ids.size()) + await refresh_maps() + + +# -------------------------------------------------------------------- Push -- + +func push_current_map(overwrite: bool = false) -> Dictionary: + _push_result.text = "Prüfe und lade hoch …" + var res: Dictionary = await MapPush.push(client, main.doc, { + "name": _push_name.text, "overwrite": overwrite, "add_to_rotation": _push_rot.button_pressed}) + _push_result.text = ("✅ " if bool(res["ok"]) else "❌ ") + str(res["text"]) + last_notice = _push_result.text + if bool(res["exists"]): + _ask("Auf dem Server gibt es schon eine Map mit diesem Namen. Ersetzen?", func() -> void: await push_current_map(true)) + elif bool(res["ok"]): + await refresh_maps() + return res + + +# -------------------------------------------------------------------- Logs -- + +func load_logs() -> void: + var q := {"lines": 300} + if _log_filter.text.strip_edges() != "": + q["filter"] = _log_filter.text.strip_edges() + var r: Variant = await _api("GET", "/logs", null, q) + if r == null: + return + _log_text.text = "\n".join(r["lines"]) + _log_text.scroll_vertical = _log_text.get_line_count() + + +func _ask(text: String, action: Callable) -> void: + _confirm.dialog_text = text + _confirm_action = action + _confirm.popup_centered(UIScale.v2i(380, 140)) diff --git a/ui/panels/server_panel.gd.uid b/ui/panels/server_panel.gd.uid new file mode 100644 index 0000000..5330efa --- /dev/null +++ b/ui/panels/server_panel.gd.uid @@ -0,0 +1 @@ +uid://62khp60nljbt diff --git a/ui/panels/settings_panel.gd b/ui/panels/settings_panel.gd new file mode 100644 index 0000000..6018c42 --- /dev/null +++ b/ui/panels/settings_panel.gd @@ -0,0 +1,160 @@ +extends "res://core/ui/panels/editor_panel.gd" +## Einstellungen (Fenster „⚙ Einstellungen“ in der Kopfleiste — Karte +## t_aaff5dcc, T3 Komfort; 25.10. Test-Befund: Gitter, Höhenlinien, Symmetrie- +## Modus, UI-Größe, Raster-Snap, Gizmo-Schrittweite und „Karte prüfen“ ziehen +## aus Kopfleiste/Objekt-Werkzeugen hierher). +## +## Registry-Weg (Operator-Vorgabe 20.10.): main.gd bleibt unangetastet, das +## Modul meldet sich nur über core/ui/panels/registry.gd an. Der ZUSTAND lebt +## in core/editor/playtest/playtest_settings.gd (PlaytestSettings, user://-cfg) — +## dieses Panel zeigt/anpasst nur. Läuft gerade ein Testlauf, wird die neue +## Maus-Empfindlichkeit SOFORT über main.playtest.apply_sensitivity wirksam. + +var sens_box: SpinBox +## Perspektive im Testlauf (Karte t_17a35c59): Erste/Dritte Person, derselbe +## Eintrag wie Taste V (PlaytestSettings, persistiert). +var perspektive_box: OptionButton + +# Ansicht / Platzieren (vorher Kopfleiste und Tab „Objekt-Werkzeuge“). main +# hält dieselben Namen als Referenzen (grid_btn, contours_btn, size_menu, …). +var grid_btn: CheckButton +var contours_btn: CheckButton +var size_menu: OptionButton +var sym_menu: OptionButton +var raster_snap_check: CheckButton +var gizmo_step_box: SpinBox +var check_btn: Button + + +static func spec() -> Dictionary: + return {"titel": "Einstellungen", "gruppe": "dialog", "order": 10} + + +func panel_title() -> String: + return "Einstellungen" + + +func build() -> void: + add_child(_header_label("Ansicht")) + grid_btn = CheckButton.new() + grid_btn.text = "⊞ Maßstabsgitter (100-m-Raster)" + grid_btn.custom_minimum_size = UIScale.v2(0, 36) + grid_btn.tooltip_text = "Maßstabsgitter (100-m-Raster) im Viewport ein-/ausblenden. Über sichtbarem Terrain ist es standardmäßig aus." + grid_btn.toggled.connect(func(pressed: bool) -> void: main.call("_on_grid_toggled", pressed)) + add_child(grid_btn) + + contours_btn = CheckButton.new() + contours_btn.text = "≈ Höhenlinien fixieren" + contours_btn.custom_minimum_size = UIScale.v2(0, 36) + contours_btn.tooltip_text = "Höhenlinien (1 m, alle 5 m kräftiger) FIXIERT an/aus. Ohne Fixierung erscheinen sie nur im Terrain-Werkzeug (F1). Taste L schaltet ebenfalls. Bei flachem Terrain (< 2 m) sind sie automatisch aus." + contours_btn.toggled.connect(func(pressed: bool) -> void: main.call("_on_contours_toggled", pressed)) + add_child(contours_btn) + + add_child(_field_label("UI-Größe")) + size_menu = OptionButton.new() + for i in UIScale.step_count(): + size_menu.add_item(UIScale.step_label(i), i) + size_menu.custom_minimum_size = UIScale.v2(0, 36) + size_menu.tooltip_text = "Größe der Oberfläche: Klein (wie bisher), Mittel (1,25-fach), Groß (1,5-fach). Wirkt sofort und bleibt gespeichert." + size_menu.item_selected.connect(func(index: int) -> void: main.call("_on_ui_size_selected", index)) + add_child(size_menu) + + add_child(_separator()) + add_child(_header_label("Bauen & Platzieren")) + raster_snap_check = CheckButton.new() + raster_snap_check.text = "Raster-Snap (1 m)" + raster_snap_check.custom_minimum_size = UIScale.v2(0, 36) + raster_snap_check.tooltip_text = "Neue und verschobene Objekte rasten auf ein 1-Meter-Raster ein (Strg gedrückt halten geht immer)" + raster_snap_check.toggled.connect(func(pressed: bool) -> void: main.call("_on_grid_snap_changed", pressed)) + add_child(raster_snap_check) + + add_child(_field_label("Gizmo-Schrittweite (m)")) + gizmo_step_box = SpinBox.new() + gizmo_step_box.min_value = 0.01 + gizmo_step_box.max_value = 10.0 + gizmo_step_box.step = 0.01 + gizmo_step_box.value = main.gizmo_step_m + gizmo_step_box.custom_minimum_size = UIScale.v2(0, 36) + gizmo_step_box.tooltip_text = "Wie weit bewegt sich das Objekt am Achsen-Gizmo pro Schritt (in Metern). Mausrad WÄHREND des Ziehens wechselt zwischen fein (0.1) / normal (0.5) / grob (2.0)." + gizmo_step_box.value_changed.connect(func(v: float) -> void: + main.gizmo_step_m = v + if main.gizmo != null and is_instance_valid(main.gizmo): + main.gizmo.set_step_m(v)) + add_child(gizmo_step_box) + + add_child(_separator()) + add_child(_header_label("Symmetrie & Prüfen")) + add_child(_field_label("Symmetrie-Modus")) + sym_menu = OptionButton.new() + for i in SymmetryCore.MODE_LABELS.size(): + sym_menu.add_item("Symmetrie: %s" % SymmetryCore.MODE_LABELS[i], i) + sym_menu.custom_minimum_size = UIScale.v2(0, 36) + sym_menu.tooltip_text = "Gespiegeltes Bauen: Änderungen werden automatisch auf die andere Kartenseite übertragen. Aus / Punkt (180° um die Kartenmitte) / Achse X / Achse Z. Standard: Punkt." + sym_menu.item_selected.connect(func(index: int) -> void: main.call("_on_sym_mode_selected", index)) + add_child(sym_menu) + + check_btn = Button.new() + check_btn.text = "✅ Karte prüfen" + check_btn.custom_minimum_size = UIScale.v2(0, 40) + check_btn.tooltip_text = "Prüft, ob die Map bereit für den Export ist — sagt VORHER, was fehlt" + check_btn.pressed.connect(func() -> void: main.call("_on_check_map")) + add_child(check_btn) + + add_child(_separator()) + add_child(_header_label("Testlauf-Einstellungen")) + + add_child(_field_label("Maus-Empfindlichkeit (0,1 – 5,0)")) + sens_box = SpinBox.new() + sens_box.min_value = PlaytestSettings.MIN_SENS + sens_box.max_value = PlaytestSettings.MAX_SENS + sens_box.step = 0.1 + sens_box.value = PlaytestSettings.load_sens() + sens_box.custom_minimum_size = UIScale.v2(0, 36) + sens_box.tooltip_text = "Multiplikator auf die Blick-Geschwindigkeit im Testlauf. 1,0 = Standard; kleine Werte = feinfühlig, große Werte = schnell." + sens_box.value_changed.connect(_on_sens_changed) + add_child(sens_box) + + add_child(_field_label("Perspektive im Testlauf")) + perspektive_box = OptionButton.new() + perspektive_box.add_item("Erste Person (Standard)") + perspektive_box.add_item("Dritte Person (Bot-Avatar)") + perspektive_box.selected = 1 if PlaytestSettings.load_third() else 0 + perspektive_box.custom_minimum_size = UIScale.v2(0, 36) + perspektive_box.tooltip_text = "Dritte Person zeigt denselben Avatar wie die Bots im Spiel (Taste V schaltet im Testlauf ebenfalls). Dritte Person braucht die Avatar-Modelle aus dem Client-Klon." + perspektive_box.item_selected.connect(_on_perspektive_changed) + add_child(perspektive_box) + + add_child(_separator()) + + +func _on_sens_changed(value: float) -> void: + PlaytestSettings.save_sens(value) + var pt: Variant = main.get("playtest") + if pt != null and pt.has_method("apply_sensitivity"): + pt.call("apply_sensitivity", value) + + +func _on_perspektive_changed(index: int) -> void: + var dritte := index == 1 + PlaytestSettings.save_third(dritte) + # Live anwenden, falls der Testlauf gerade läuft. Ohne Avatar-Modelle + # bleibt First Person aktiv (set_perspektive lehnt Third ab) — der + # Klartext-Grund steht beim Start/V-Druck im HUD. + var pt: Variant = main.get("playtest") + if pt == null: + return + var body: Variant = pt.get("body") + if body != null: + body.call("set_perspektive", dritte) + + +## Schalter aus dem Editor-Zustand nachziehen (beim Öffnen des Fensters). +func refresh() -> void: + if main == null: + return + grid_btn.set_pressed_no_signal(bool(main.get("_grid_on"))) + contours_btn.set_pressed_no_signal(bool(main.get("_contours_on"))) + raster_snap_check.set_pressed_no_signal(bool(main.get("grid_snap"))) + gizmo_step_box.set_value_no_signal(float(main.gizmo_step_m)) + size_menu.select(UIScale.step_index()) + sym_menu.select(int(main.get("sym_mode"))) diff --git a/ui/panels/settings_panel.gd.uid b/ui/panels/settings_panel.gd.uid new file mode 100644 index 0000000..342df31 --- /dev/null +++ b/ui/panels/settings_panel.gd.uid @@ -0,0 +1 @@ +uid://bp0ii5exucqcy diff --git a/ui/panels/status_bar.gd b/ui/panels/status_bar.gd new file mode 100644 index 0000000..cb97547 --- /dev/null +++ b/ui/panels/status_bar.gd @@ -0,0 +1,81 @@ +extends HBoxContainer +## Statusleiste (aus main.gd ausgezogen, Karte t_eaccbfed U1 — Logik +## unverändert): Hilfs-Meldungen + permanente Werkzeug-Anzeige + +## Symmetrie-Anzeige + Objekt-/Terrain-Zähler + FPS-Timer. + +var main # core/ui/main.gd +var status_label: Label +var tool_label: Label # permanenter Werkzeugmodus + Flug-Hint +var sym_label: Label +var stats_objects: Label +var stats_terrain: Label + + +static func spec() -> Dictionary: + return {"titel": "Statuszeile", "gruppe": "status", "order": 0} + + +func setup(p_main) -> void: + main = p_main + # Eine Leiste ist EINE Zeile (VBox-Erbe stapelte alle Labels senkrecht → + # riesiger Balken, Befund 25.10.). + size_flags_vertical = Control.SIZE_SHRINK_END + size_flags_horizontal = Control.SIZE_EXPAND_FILL + + +func theme_color(cname: String) -> Color: + if main != null and main.theme != null and main.theme.has_color(cname, "Editor"): + return main.theme.get_color(cname, "Editor") + return get_theme_color(cname, "Editor") + + +func build() -> void: + add_theme_constant_override("separation", UIScale.px(16)) + status_label = Label.new() + status_label.size_flags_horizontal = Control.SIZE_EXPAND_FILL + status_label.clip_text = true # langer Text darf das Layout NICHT sprengen + add_child(status_label) + + # Karte 3/3 (t_11b5c25b): PERMANENTE Werkzeug-Anzeige — Sly sieht immer, + # in welchem Werkzeug er ist, plus Hint für den Flugmodus (Umschalt+F). + tool_label = Label.new() + # U7: Werkzeug-Farbe über Theme (Editor/colors/accent). + tool_label.add_theme_color_override("font_color", + theme_color("accent")) + # Karte t_297221b5: Statuszeilen-Labels egalisiert (min-size-Druck bei 1.5×) + tool_label.clip_text = true + tool_label.text_overrun_behavior = TextServer.OVERRUN_TRIM_ELLIPSIS + add_child(tool_label) + + # Symmetrie-Anzeige (Karte t_f5935023, M1): Sly sieht in der Statuszeile + # immer, ob/wie gespiegelt wird (Standard: Punkt). + sym_label = Label.new() + # U7: Symmetrie-Farbe über Theme (Editor/colors/accent). + sym_label.add_theme_color_override("font_color", + theme_color("accent")) + sym_label.clip_text = true + sym_label.text_overrun_behavior = TextServer.OVERRUN_TRIM_ELLIPSIS + add_child(sym_label) + + stats_objects = Label.new() + # U7: Nebentext-Farbe über Theme (Editor/colors/field). + stats_objects.add_theme_color_override("font_color", + theme_color("field")) + stats_objects.clip_text = true + stats_objects.text_overrun_behavior = TextServer.OVERRUN_TRIM_ELLIPSIS + add_child(stats_objects) + + # Terrain-Anteil + Editor-FPS (Perf-Zähler, Karte t_9aba04f1) + stats_terrain = Label.new() + # U7: Nebentext-Farbe über Theme (Editor/colors/field). + stats_terrain.add_theme_color_override("font_color", + theme_color("field")) + stats_terrain.clip_text = true + stats_terrain.text_overrun_behavior = TextServer.OVERRUN_TRIM_ELLIPSIS + add_child(stats_terrain) + + var fps_timer := Timer.new() + fps_timer.wait_time = 0.5 + fps_timer.autostart = true + fps_timer.timeout.connect(main.call.bind("_refresh_stats")) + add_child(fps_timer) diff --git a/ui/panels/status_bar.gd.uid b/ui/panels/status_bar.gd.uid new file mode 100644 index 0000000..afaedfb --- /dev/null +++ b/ui/panels/status_bar.gd.uid @@ -0,0 +1 @@ +uid://dddgvtqqr3lau diff --git a/ui/panels/symmetry_panel.gd b/ui/panels/symmetry_panel.gd new file mode 100644 index 0000000..7d81ca4 --- /dev/null +++ b/ui/panels/symmetry_panel.gd @@ -0,0 +1,237 @@ +extends "res://core/ui/panels/editor_panel.gd" +## Symmetrie-Panel (M5, Karte t_60014669 — Spec /opt/data/scopedvr/ +## KARTEN_MIRROR_vc27.md): Ein-Klick „Karte symmetrisch machen“ + Symmetrie- +## Check mit Klartext-Bericht. Erlaubnis-Regel des Operators (20.10.): +## main.gd NICHT anfassen — dieses Modul meldet sich über die Panel-Registry +## an (registry.gd, Eintrag) und greift wie alle Module über `main` auf +## Dokument/History zu. Die Spiegel-Arbeit lebt KOMPLETT in +## core/editor/symmetry_ops.gd (statisch, headless testbar). +## +## Ablauf „Karte symmetrisch machen“: +## 1. Symmetrie-Modus AUS → Hinweis, nichts passiert (Abnahme „Modus AUS +## ändert nichts“). +## 2. Analyse: nichts zu tun → Klartext „schon symmetrisch“, OHNE Undo. +## 3. Widersprüche? → Dialog nennt die ZAHL und lässt die Quell-Hälfte +## wählen (Sly entscheidet, bevor irgendwas überschrieben wird). +## 4. Anwenden = EIN Undo-Schritt (ActionHistory snapshotet das Dokument). + +const SymmetryOps := preload("res://core/editor/symmetry_ops.gd") + +var mode_label: Label +var half_label: Label +var half_option: OptionButton +var apply_btn: Button +var check_btn: Button +var report_label: Label +var conflict_dialog: ConfirmationDialog + +var _pending_high := false # Quell-Wahl des laufenden Widerspruchs-Dialogs + + +static func spec() -> Dictionary: + return {"titel": "Symmetrie", "gruppe": "map", "order": 30} + + +func panel_title() -> String: + return "Symmetrie" + + +func build() -> void: + add_child(_header_label("Symmetrie")) + add_child(_muted_label("Macht die ganze Karte symmetrisch: ergänzt die andere Seite, löscht nichts.")) + + mode_label = _field_label(_mode_text()) + add_child(mode_label) + + half_label = _field_label("Quell-Hälfte:") + add_child(half_label) + half_option = OptionButton.new() + half_option.custom_minimum_size = UIScale.v2(0, 36) + # U7: Klartext-Tooltip — welche Seite als Vorlage dient. + half_option.tooltip_text = "Welche Hälfte die Vorlage ist (die andere wird angepasst)" + half_option.item_selected.connect(_on_half_selected) + add_child(half_option) + _refresh_half_option() + + apply_btn = Button.new() + apply_btn.text = "🗺️ Karte symmetrisch machen" + apply_btn.custom_minimum_size = UIScale.v2(0, 48) + apply_btn.tooltip_text = "Ergänzt die andere Kartenseite (EIN Strg+Z macht alles rückgängig)" + apply_btn.pressed.connect(_on_apply_pressed) + add_child(apply_btn) + + check_btn = Button.new() + check_btn.text = "🔍 Symmetrie prüfen" + check_btn.custom_minimum_size = UIScale.v2(0, 40) + check_btn.tooltip_text = "Ehrlicher Bericht: Wo weicht die Karte von der Spiegelung ab?" + check_btn.pressed.connect(_on_check_pressed) + add_child(check_btn) + + report_label = _muted_label("") + report_label.custom_minimum_size = UIScale.v2(0, 96) + add_child(report_label) + + + conflict_dialog = ConfirmationDialog.new() + conflict_dialog.title = "Widersprüche — welche Seite gewinnt?" + conflict_dialog.dialog_close_on_escape = true + conflict_dialog.get_ok_button().text = "Anwenden" + conflict_dialog.confirmed.connect(_on_conflict_confirmed) + conflict_dialog.add_button("Andere Hälfte als Quelle", true, "other_half") + conflict_dialog.custom_action.connect(_on_conflict_other) + add_child(conflict_dialog) + + +# ------------------------------------------------------------- Zustands-Helfer + +func _current_mode() -> int: + ## Defensiv wie spawn_tool._sym_mode(): Mock-Mains ohne Feld → OFF. + var v: Variant = main.get("sym_mode") if main != null else null + return SymmetryCore.Mode.OFF if v == null else int(v) + + +func _mode_text() -> String: + var mode := _current_mode() + return "Modus: %s" % SymmetryCore.mode_label(mode) + + +func _source_high() -> bool: + ## false = erste Hälfte (links/vorn), true = zweite (rechts/hinten). + return half_option.selected == 1 + + +func _refresh_half_option() -> void: + var labels: Array = SymmetryOps.side_labels(_current_mode()) + half_option.clear() + half_option.add_item("Quelle: %s" % str(labels[0])) + half_option.add_item("Quelle: %s" % str(labels[1])) + half_option.selected = 0 + + +## Vom Einstellungen-Fenster gerufen, wenn der Modus wechselt. +func refresh_mode() -> void: + if mode_label == null or half_option == null: + return + _refresh_half_option() + _refresh_mode_line() + + +func _on_half_selected(_index: int) -> void: + _refresh_mode_line() + + +func _refresh_mode_line() -> void: + mode_label.text = _mode_text() + + +# ------------------------------------------------------------ Karte spiegeln -- + +func _on_apply_pressed() -> void: + var mode := _current_mode() + if mode == SymmetryCore.Mode.OFF: + _say("Der Symmetrie-Modus ist Aus — erst in den Einstellungen (⚙) Punkt oder eine Achse wählen.") + return + if main.doc.is_empty(): + _say("Keine Karte offen — erst eine Map anlegen oder laden.", true) + return + _refresh_mode_line() + _refresh_half_option() + var an := SymmetryOps.analyze(main.doc, mode) + if int(an["total_changes"]) == 0: + _say("Nichts zu tun — die Karte ist schon symmetrisch ✓") + return + if int(an["conflicts"]) == 0: + _apply(_source_high()) + return + _pending_high = _source_high() + conflict_dialog.dialog_text = _conflict_text(an) + conflict_dialog.get_ok_button().text = "Anwenden — %s gewinnt" % _half_name(_pending_high) + conflict_dialog.popup_centered(Vector2i(520, 260)) + + +## Klartext für den Widerspruchs-Dialog: ZAHL erst nennen, DANN anwenden +## (Spec: „Nichts wird gelöscht, ohne dass die Zahl vorher genannt wurde“). +func _conflict_text(an: Dictionary) -> String: + var parts: Array = [] + var obj_n := int(an["objects"]["diff"]) + var spawn_n := int(an["spawns"]["diff"]) + var boden_n := (an["terrain_cells"] as Array).size() + (an.get("material_cells", []) as Array).size() + if obj_n > 0: + parts.append("%d Objekt-Paare unterscheiden sich" % obj_n) + if spawn_n > 0: + parts.append("%d Spawn-Punkt-Paare unterscheiden sich" % spawn_n) + if boden_n > 0: + parts.append("%d Bodenstellen sind unterschiedlich" % boden_n) + var adds := int(an["adds"]) + var text := ", ".join(PackedStringArray(parts)) + ".\n\n" + text += "Beim Anwenden gewinnt die gewählte Quell-Hälfte (die andere Seite wird angepasst).\n" + if adds > 0: + text += "Zusätzlich werden %d fehlende Zwillinge ergänzt.\n" % adds + text += "Es wird NICHTS gelöscht. Ein Strg+Z macht alles rückgängig." + return text + + +func _half_name(high: bool) -> String: + var labels: Array = SymmetryOps.side_labels(_current_mode()) + return str(labels[1]) if high else str(labels[0]) + + +func _on_conflict_confirmed() -> void: + # OK = die im Auswahlfeld gewählte Quelle behalten (Dialog-Text nennt sie). + _apply(_pending_high) + + +func _on_conflict_other(_action: String) -> void: + conflict_dialog.hide() + _pending_high = not _pending_high + _apply(_pending_high) + + +## Snapshot über ALLE Blöcke; fehlt design_notes (alte Karte), wird es als +## null geseedet — sonst könnte das Undo den neu angelegten Block nicht +## entfernen (U3-Lektion: fehlernde Blöcke explizit als null snapshoten). +func _snapshot_all() -> Dictionary: + var snap: Dictionary = main.history.snapshot(main.doc.keys()) + if not snap.has("design_notes") and not main.doc.has("design_notes"): + snap["design_notes"] = null + return snap + + +func _apply(quelle_hoch: bool) -> void: + var mode := _current_mode() + var before: Dictionary = _snapshot_all() + var res := SymmetryOps.apply(main.doc, mode, quelle_hoch) + main.history.commit("Karte symmetrisch machen (%s → %s)" % [ + _half_name(quelle_hoch), _half_name(not quelle_hoch)], + before, main.history.snapshot(main.doc.keys())) + main.call("_after_structure_change") + var report := str(res["report"]) + report_label.text = report + # U7: Bericht-Farbe über Theme (Editor/colors/status_ok). + report_label.add_theme_color_override("font_color", theme_color("status_ok")) + main.call("_set_status", report.split(".")[0] + ".") + + +# ---------------------------------------------------------- Symmetrie-Check -- + +func _on_check_pressed() -> void: + var mode := _current_mode() + if mode == SymmetryCore.Mode.OFF: + _say("Der Symmetrie-Modus ist Aus — erst in den Einstellungen (⚙) Punkt oder eine Achse wählen, dann prüfen.") + return + _refresh_mode_line() + var rep := SymmetryOps.check(main.doc, mode) + var text := str(rep["text"]) + report_label.text = text + # U7: Bericht-Farben über Theme (Editor/colors/status_ok / warning). + report_label.add_theme_color_override("font_color", + theme_color("status_ok") if bool(rep["ok"]) else theme_color("warning")) + main.call("_set_status", text) + + +func _say(text: String, is_error := false) -> void: + report_label.text = text + # U7: Bericht-Farben über Theme (Editor/colors/warning / status_ok). + report_label.add_theme_color_override("font_color", + theme_color("warning") if is_error else theme_color("status_ok")) + main.call("_set_status", text, is_error) diff --git a/ui/panels/symmetry_panel.gd.uid b/ui/panels/symmetry_panel.gd.uid new file mode 100644 index 0000000..1c311e5 --- /dev/null +++ b/ui/panels/symmetry_panel.gd.uid @@ -0,0 +1 @@ +uid://ceu6y127v6lxc diff --git a/ui/panels/terrain_panel.gd b/ui/panels/terrain_panel.gd new file mode 100644 index 0000000..7841dd1 --- /dev/null +++ b/ui/panels/terrain_panel.gd @@ -0,0 +1,282 @@ +extends "res://core/ui/panels/editor_panel.gd" +## Terrain-Werkzeug-Panel (aus main.gd ausgezogen, Karte t_eaccbfed U1 — +## Logik unverändert, Karte t_9aba04f1 + t_603ec1a8): großer Modus-Button + +## Pinsel-Modi, Material-Palette, Größe/Stärke-Regler. Werkzeug-Ein/Aus bleibt +## im Koordinator (main.gd _enter/_leave terrain), das Panel hält nur die +## Widgets und die Regler-Verdrahtung. + +var terrain_edit_btn: Button +var terrain_panel: VBoxContainer +var terrain_mode_raise: Button +var terrain_mode_lower: Button +var terrain_mode_smooth: Button +var terrain_mode_paint: Button +var terrain_mode_flatten: Button +var terrain_mode_ramp: Button +var terrain_falloff_label: Label +var terrain_falloff_slider: HSlider +var terrain_palette: VBoxContainer +var terrain_mat_buttons: Array = [] # Gras/Sand/Fels (ButtonGroup) +var terrain_size_btn_small: Button +var terrain_size_btn_medium: Button +var terrain_size_btn_large: Button +var terrain_radius_slider: HSlider +var terrain_radius_label: Label +var terrain_strength_slider: HSlider +var terrain_strength_label: Label +var terrain_paint_hint: Label # Malen: Hinweis auf die Raster-Feinheit (24.10.) +var terrain_weich_label: Label # Malen: Kante hart ↔ weich (25.10.) +var terrain_weich_slider: HSlider + + +static func spec() -> Dictionary: + return {"titel": "Terrain", "gruppe": "rechts", "order": 40} + + +func build() -> void: + terrain_edit_btn = Button.new() + terrain_edit_btn.text = "⛰ Terrain formen" + terrain_edit_btn.custom_minimum_size = UIScale.v2(0, 48) + terrain_edit_btn.toggle_mode = true + terrain_edit_btn.tooltip_text = "Boden formen: heben, senken, glätten, einebnen, Rampe (F1)" + terrain_edit_btn.pressed.connect(_on_terrain_btn_pressed) + add_child(terrain_edit_btn) + + terrain_panel = VBoxContainer.new() + terrain_panel.add_theme_constant_override("separation", UIScale.px(8)) # U7-Raster + add_child(terrain_panel) + + terrain_panel.add_child(_field_label("Pinsel:")) + var mode_row := GridContainer.new() + mode_row.columns = 3 + mode_row.add_theme_constant_override("h_separation", UIScale.px(8)) # U7-Raster + mode_row.add_theme_constant_override("v_separation", UIScale.px(8)) + terrain_panel.add_child(mode_row) + var mode_group := ButtonGroup.new() + terrain_mode_raise = _terrain_mode_button("Heben ⬆", mode_group, + "Pinsel-Modus Heben: Boden unter dem Pinsel anheben (Taste 1)") + terrain_mode_lower = _terrain_mode_button("Senken ⬇", mode_group, + "Pinsel-Modus Senken: Boden unter dem Pinsel absenken (Taste 2)") + terrain_mode_smooth = _terrain_mode_button("Glätten ≈", mode_group, + "Pinsel-Modus Glätten: Höhenunterschiede verrutschen (Taste 3)") + terrain_mode_paint = _terrain_mode_button("Malen 🖌", mode_group, + "Pinsel-Modus Malen: Material auf den Boden malen (Taste 4)") + terrain_mode_flatten = _terrain_mode_button("Einebnen ▬", mode_group, + "Pinsel-Modus Einebnen: zieht den Boden auf die Höhe, die beim Strichstart unter dem Cursor war") + terrain_mode_ramp = _terrain_mode_button("Rampe ◢", mode_group, + "Pinsel-Modus Rampe: Klick = Start, ziehen und loslassen = Ende — Höhe läuft gleichmäßig dazwischen (Breite = Pinselgröße)") + terrain_mode_raise.button_pressed = true + terrain_mode_flatten.toggled.connect(_on_terrain_mode_changed) + terrain_mode_ramp.toggled.connect(_on_terrain_mode_changed) + terrain_mode_raise.toggled.connect(_on_terrain_mode_changed) + terrain_mode_lower.toggled.connect(_on_terrain_mode_changed) + terrain_mode_smooth.toggled.connect(_on_terrain_mode_changed) + terrain_mode_paint.toggled.connect(_on_terrain_mode_changed) + mode_row.add_child(terrain_mode_raise) + mode_row.add_child(terrain_mode_lower) + mode_row.add_child(terrain_mode_smooth) + mode_row.add_child(terrain_mode_flatten) + mode_row.add_child(terrain_mode_ramp) + # Malen hat seit 25.10. einen eigenen Tab (malen_panel.gd); der Modus-Knopf + # bleibt unsichtbar in der ButtonGroup (Taste 4, Malen-Tab-Knopf). + terrain_mode_paint.visible = false + terrain_panel.add_child(terrain_mode_paint) + + # Pinselgrößen-Presets (Karte t_603ec1a8): drei große Buttons + freier Slider. + terrain_panel.add_child(_field_label("Pinselgröße:")) + var size_row := HBoxContainer.new() + size_row.add_theme_constant_override("separation", UIScale.px(8)) # U7-Raster + terrain_panel.add_child(size_row) + var size_group := ButtonGroup.new() + terrain_size_btn_small = _terrain_size_button("Klein\n(4 m)", size_group, 4.0) + terrain_size_btn_medium = _terrain_size_button("Mittel\n(12 m)", size_group, 12.0) + terrain_size_btn_large = _terrain_size_button("Groß\n(32 m)", size_group, 32.0) + # Kein Signal: Der Handler greift auf terrain_radius_slider zu, der erst + # unten erzeugt wird — beim Panel-Bau wäre das ein Crash (GUI-Start-Bug + # 15.10.). Der Slider startet unten passend mit 12 m (= Mittel). + terrain_size_btn_medium.set_pressed_no_signal(true) + size_row.add_child(terrain_size_btn_small) + size_row.add_child(terrain_size_btn_medium) + size_row.add_child(terrain_size_btn_large) + + terrain_radius_label = _field_label("Pinsel-Größe: 12 m") + terrain_panel.add_child(terrain_radius_label) + terrain_radius_slider = HSlider.new() + terrain_radius_slider.min_value = 1.0 + terrain_radius_slider.max_value = 64.0 + terrain_radius_slider.step = 1.0 + terrain_radius_slider.value = 12.0 + terrain_radius_slider.custom_minimum_size = UIScale.v2(0, 32) + terrain_radius_slider.value_changed.connect(_on_terrain_radius_changed) + terrain_panel.add_child(terrain_radius_slider) + + terrain_strength_label = _field_label("Stärke: 8 m pro Sekunde") + terrain_panel.add_child(terrain_strength_label) + terrain_strength_slider = HSlider.new() + terrain_strength_slider.min_value = 1.0 + terrain_strength_slider.max_value = 20.0 + terrain_strength_slider.step = 0.5 + terrain_strength_slider.value = 8.0 + terrain_strength_slider.custom_minimum_size = UIScale.v2(0, 32) + terrain_strength_slider.value_changed.connect(_on_terrain_strength_changed) + terrain_panel.add_child(terrain_strength_slider) + + # Pinsel-Kante (Falloff, Karte 25.10.): ein Regler hart ↔ weich für alle + # Höhen-Pinsel (Malen hat seinen eigenen Kanten-Regler weiter unten). + terrain_falloff_label = _field_label("Kante: 50 % weich") + terrain_panel.add_child(terrain_falloff_label) + terrain_falloff_slider = HSlider.new() + terrain_falloff_slider.min_value = 0.0 + terrain_falloff_slider.max_value = 100.0 + terrain_falloff_slider.step = 5.0 + terrain_falloff_slider.value = 50.0 + terrain_falloff_slider.custom_minimum_size = UIScale.v2(0, 32) + terrain_falloff_slider.tooltip_text = "Links = harte Kante (breiter Kern), rechts = weich auslaufend" + terrain_falloff_slider.value_changed.connect(_on_terrain_falloff_changed) + terrain_panel.add_child(terrain_falloff_slider) + + + +func _on_terrain_btn_pressed() -> void: + if terrain_edit_btn.button_pressed: + if terrain_mode_paint.button_pressed: + terrain_mode_raise.button_pressed = true # Malen hat seinen eigenen Tab + main.call("_set_tool_mode", "terrain") + refresh_panels() + else: + main.call("_set_tool_mode", "objects") + + +func _terrain_mode_button(text: String, group: ButtonGroup, hinweis: String) -> Button: + var btn := Button.new() + btn.text = text + btn.toggle_mode = true + btn.button_group = group + btn.custom_minimum_size = UIScale.v2(0, 40) + btn.tooltip_text = hinweis # U7: Werkzeugname + Taste im Tooltip + return btn + + +func _selected_terrain_mode() -> int: + if terrain_mode_lower.button_pressed: + return TerrainField.Mode.LOWER + if terrain_mode_smooth.button_pressed: + return TerrainField.Mode.SMOOTH + if terrain_mode_paint.button_pressed: + return TerrainField.Mode.PAINT + if terrain_mode_flatten != null and terrain_mode_flatten.button_pressed: + return TerrainField.Mode.FLATTEN + if terrain_mode_ramp != null and terrain_mode_ramp.button_pressed: + return TerrainField.Mode.RAMP + return TerrainField.Mode.RAISE + + +## Mode-Buttons (ButtonGroup) → Pinsel-Modus; Palette nur im Malen-Modus. +func _on_terrain_mode_changed(_pressed: bool) -> void: + var paint := _selected_terrain_mode() == TerrainField.Mode.PAINT + if terrain_palette != null: + terrain_palette.visible = paint + if terrain_paint_hint != null: + terrain_paint_hint.text = paint_hint_text(main.doc.get("terrain", {}) if main.doc is Dictionary else {}) + refresh_panels() + if main.terrain_tool != null: + main.terrain_tool.call("set_brush_mode", _selected_terrain_mode()) + + +## Welche Bedienflächen sind sichtbar (Terrain-Tab bzw. Malen-Tab), welcher +## Start-Knopf steht gedrückt — Terrain und Malen teilen das Pinsel-Werkzeug. +func refresh_panels() -> void: + if terrain_panel == null: + return + var aktiv: bool = str(main.get("tool_mode")) == "terrain" + var paint := _selected_terrain_mode() == TerrainField.Mode.PAINT + terrain_edit_btn.set_pressed_no_signal(aktiv and not paint) + var malen = main.get("malen_mod") + if malen != null: + malen.malen_edit_btn.set_pressed_no_signal(aktiv and paint) + if aktiv: + _show_own_tab(malen if paint else self) + + +func _show_own_tab(tab: Control) -> void: + var tabs = main.get("ui_right_panel") + if tabs is TabContainer and tab != null and tab.get_parent() == tabs: + (tabs as TabContainer).current_tab = tab.get_index() + + +## Hinweistext Malen-Modus (pure, testbar): feinste Mal-Einheit = Abstand +## zweier Rasterpunkte der Karte (size / (resolution − 1)). +static func paint_hint_text(terrain: Dictionary) -> String: + var res := SvmapIO.material_resolution(terrain) # feines Material-Raster + var size := maxf(float(terrain.get("size_x_m", 0.0)), float(terrain.get("size_z_m", 0.0))) + if res < 2 or size <= 0.0: + return "Malen setzt das Material zellenweise — Stärke gibt es hier nicht." + var m := size / float(res - 1) + var m_text := str(int(roundf(m))) if absf(m - roundf(m)) < 0.05 \ + else String.num(m, 1).replace(".", ",") + return "Malen setzt das Material zellenweise: feinste Einheit auf dieser Karte ≈ %s m. Stärke gibt es hier nicht." % m_text + + +## Pinselgrößen-Presets (Karte t_603ec1a8): setzen den Radius-Slider +## (der Label-Text + Ring-Optik hängen am value_changed-Signal). +func _terrain_size_button(text: String, group: ButtonGroup, radius_m: float) -> Button: + var btn := Button.new() + btn.text = text + btn.toggle_mode = true + btn.button_group = group + btn.custom_minimum_size = UIScale.v2(0, 48) + btn.tooltip_text = "Pinselradius %d m" % int(radius_m) + btn.toggled.connect(_on_terrain_size_preset.bind(radius_m)) + return btn + + +func _on_terrain_size_preset(pressed: bool, radius_m: float) -> void: + # Null-Check als Schutznetz: beim Panel-Bau existiert der Slider noch + # nicht (Programmatic-Pressed darf den Handler nie früh treffen). + if pressed and terrain_radius_slider != null: + terrain_radius_slider.value = radius_m + + +func _on_terrain_radius_changed(value: float) -> void: + terrain_radius_label.text = "Pinsel-Größe: %d m" % int(value) + var malen = main.get("malen_mod") + if malen != null: + malen.set_radius_silent(value) + if main.terrain_tool != null: + main.terrain_tool.call("set_radius", value) + + +func _on_terrain_falloff_changed(value: float) -> void: + terrain_falloff_label.text = "Kante: %d %% weich" % int(value) if value > 0.0 else "Kante: hart" + if main.terrain_tool != null: + main.terrain_tool.call("set_falloff", value / 100.0) + + +func _on_terrain_strength_changed(value: float) -> void: + terrain_strength_label.text = "Stärke: %.1f m pro Sekunde" % value + if main.terrain_tool != null: + main.terrain_tool.call("set_strength", value) + + +## Terrain-Pinsel-Größe per [ / ] (Karte t_55257792): durch die 3 Presets +## Klein/Mittel/Groß zyklisch — der Preset-Button wird mit gesetzt (set_pressed +## feuert toggled → Slider + Label + Pinssel-Ring wandern mit). +## (Aus main.gd ausgezogen, Logik unverändert; Koordinator ruft weiter.) +func terrain_brush_size_step(up: bool) -> void: + if terrain_radius_slider == null: + return + var next := MoveMath.brush_next_preset(float(terrain_radius_slider.value), up) + var btn: Button = null + match next: + 4.0: + btn = terrain_size_btn_small + 12.0: + btn = terrain_size_btn_medium + 32.0: + btn = terrain_size_btn_large + if btn != null: + btn.set_pressed(true) # feuert _on_terrain_size_preset → Slider/Label + else: + terrain_radius_slider.value = next + main.terrain_tool.call("set_radius", next) + main.call("_set_status", "Pinsel-Größe: %d m (mit [ / ] durch Klein/Mittel/Groß zyklisch)." % int(next)) diff --git a/ui/panels/terrain_panel.gd.uid b/ui/panels/terrain_panel.gd.uid new file mode 100644 index 0000000..fe08e19 --- /dev/null +++ b/ui/panels/terrain_panel.gd.uid @@ -0,0 +1 @@ +uid://qvp3thn60awa diff --git a/ui/panels/test_start_panel.gd b/ui/panels/test_start_panel.gd new file mode 100644 index 0000000..53aa61a --- /dev/null +++ b/ui/panels/test_start_panel.gd @@ -0,0 +1,63 @@ +extends "res://core/ui/panels/editor_panel.gd" +## Test-Start-Bereich (rechte Spalte — Karte t_96e3c4ee / T1b, Wiederanbindung +## durch den Operator am 20.10.). +## +## Aufteilung: der ZUSTAND lebt in main.gd (`test_start_point`) samt den Haken +## `_test_start_apply` / `_test_start_delete` / `_test_start_reload`, weil die +## Prüfsuite tests/test_playtest_spawn.gd (56 checks) genau diese drei Namen auf +## main erwartet — das ist der T1b-Vertrag. Beim U1-Umbau waren sie verschwunden, +## die Suite brach mit „Nonexistent function '_test_start_reload'" ab. +## Dieses Modul zeigt den Zustand nur an (Info-Text + Löschen-Knopf) und meldet +## sich datengetrieben über registry.gd an — main.gd verdrahtet nichts fest. + +var info: Label +var delete_btn: Button +var info_hint: Label + + +static func spec() -> Dictionary: + return {"titel": "Test-Start", "gruppe": "map", "order": 20} + + +func panel_title() -> String: + return "Test-Start (F5)" + + +func build() -> void: + add_child(_header_label("Startpunkt für „▶ Karte testen“")) + info = Label.new() + info.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART + add_child(info) + + delete_btn = Button.new() + delete_btn.text = "🗑 Test-Start löschen" + delete_btn.custom_minimum_size = UIScale.v2(0, 40) + delete_btn.tooltip_text = "Test-Startpunkt entfernen — F5 startet dann wieder am ersten Team-Spawnpunkt." + delete_btn.pressed.connect(func() -> void: main.call("_test_start_delete")) + add_child(delete_btn) + + add_child(_separator()) + info_hint = Label.new() + info_hint.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART + info_hint.text = "Leiste „🎯 Test-Start“ oder Taste T, dann in die Karte klicken." + add_child(info_hint) + + # main holt sich das Modul hier ab (main._refresh_test_start_panel) — die + # Prüfsuite liest es als main.test_start_panel. Sichtbar erst, wenn das + # Werkzeug aktiv ist (wie vor dem U1-Umbau). + main.set("test_start_panel", self) + visible = false + refresh_point(main.get("test_start_point")) + + +## Wird von main._refresh_test_start_panel() gerufen. point = Vector3 oder null. +func refresh_point(point: Variant) -> void: + if info == null or delete_btn == null: + return + if point == null: + info.text = "Kein Test-Start gesetzt.\nF5 startet dann am ersten Team-Blau-Spawnpunkt (ohne Spawnpunkte: Kartenmitte)." + delete_btn.disabled = true + else: + var p: Vector3 = point + info.text = "Test-Start: x=%.0f z=%.0f\n(Höhe kommt automatisch vom Terrain)" % [p.x, p.z] + delete_btn.disabled = false diff --git a/ui/panels/test_start_panel.gd.uid b/ui/panels/test_start_panel.gd.uid new file mode 100644 index 0000000..05aaed2 --- /dev/null +++ b/ui/panels/test_start_panel.gd.uid @@ -0,0 +1 @@ +uid://brik7mu7wv0el diff --git a/ui/panels/toolbar.gd b/ui/panels/toolbar.gd new file mode 100644 index 0000000..45050c9 --- /dev/null +++ b/ui/panels/toolbar.gd @@ -0,0 +1,156 @@ +extends HBoxContainer +## Toolbar (aus main.gd ausgezogen, Karte t_eaccbfed U1 — Logik unverändert): +## Menü Datei + Undo/Redo + Gitter/Höhenlinien + Symmetrie + Toolbar-Aktionen +## aus der Registry (Karte prüfen, ▶ Karte testen). Neue Aktionen melden sich +## künftig in registry.gd an (U2–U7, T1-F5 bleibt unverändert erreichbar). +## +## NACHBESSERUNG 20.10. (Operator, Sly-Befund „Damit kann man nicht mehr +## arbeiten"): Diese Leiste erbte von EditorPanel (= VBoxContainer) und wurde +## dadurch SELBST senkrecht — jeder Knopf bekam eine eigene, fensterbreite +## Zeile, die Leiste wuchs auf ~11×40 px und drückte das 3D-Fenster auf einen +## Briefmarken-Streifen. Eine Leiste braucht eine WAAGERECHTE Zeile: extends +## HBoxContainer. Die Helfer der Basis (main-Zeiger, Label-Bauer) braucht nur +## die senkrechte Spalte; hier genügt der main-Zeiger. + +var main # core/ui/main.gd (script-erweitert → untypisiert) + + +func setup(p_main) -> void: + main = p_main + # Eine Leiste darf NIE in die Höhe wachsen (sie würde dem 3D-Fenster die + # Fläche wegnehmen): genau eine Knopfzeile, oben ausgerichtet. + size_flags_vertical = Control.SIZE_SHRINK_BEGIN + size_flags_horizontal = Control.SIZE_EXPAND_FILL + + +func panel_title() -> String: + return "Werkzeuge" + +var undo_btn: Button +var redo_btn: Button +var settings_btn: Button # „⚙ Einstellungen“ öffnet das Einstellungen-Fenster +var title_label: Label +var file_label: Label + + +static func spec() -> Dictionary: + return {"titel": "Toolbar", "gruppe": "toolbar", "order": 0} + + +func build() -> void: + add_theme_constant_override("separation", UIScale.px(8)) # U7-Raster (4/8) + + var file_menu := MenuButton.new() + file_menu.text = "Datei" + file_menu.flat = false + file_menu.custom_minimum_size = UIScale.v2(90, 40) + # U7: Klartext-Tooltip am Datei-Menü (alle Map-Aktionen an einem Ort). + file_menu.tooltip_text = "Map-Aktionen: neu, öffnen, speichern, testen, Updates" + var popup := file_menu.get_popup() + popup.add_item("Neue Map…", 0) + popup.add_item("Öffnen…", 1) + popup.add_item("Kartengröße ändern…", 6) + popup.add_separator() + popup.add_item("Speichern (Strg+S)", 2) + popup.add_item("Speichern unter…", 3) + popup.add_separator() + popup.add_item("▶ Karte testen", 5) + popup.add_separator() + popup.add_item("🖐 Hand-Haltung der Waffen…", 8) + popup.add_item("🔄 Updates prüfen", 7) + popup.add_item("Beenden", 4) + # FIX 20.10. (Sly-Befund „Kartengröße ändern tut nichts“): id_pressed sendet + # die Menü-ID. main.call.bind("_on_menu_action") hängt die ID aber ALS + # ARGUMENT an call() → effektiv call(6, "_on_menu_action") → + # „Cannot convert argument 1 from int to StringName“ (map-builder.log + # 20.10.) — das GESAMTE Datei-Menü verpufft, kein Eintrag tut etwas. + # Lambda macht die Reihenfolge (Name zuerst, ID als Argument) explizit, + # Stil wie grid_btn/contours_btn oben. + popup.id_pressed.connect(func(id: int) -> void: main.call("_on_menu_action", id)) + add_child(file_menu) + + undo_btn = Button.new() + undo_btn.text = "↩ Rückgängig" + undo_btn.custom_minimum_size = UIScale.v2(140, 40) + undo_btn.tooltip_text = "Letzte Aktion zurücknehmen (Strg+Z)" + undo_btn.pressed.connect(main.call.bind("_do_undo")) + add_child(undo_btn) + + redo_btn = Button.new() + redo_btn.text = "↪ Wiederholen" + redo_btn.custom_minimum_size = UIScale.v2(150, 40) + redo_btn.tooltip_text = "Zurückgenommene Aktion wiederherstellen (Strg+Y)" + redo_btn.pressed.connect(main.call.bind("_do_redo")) + add_child(redo_btn) + + # Toolbar-Aktionen DATENGETRIEBEN aus der Registry (Operator-Vorgabe + # 20.10.): Karte prüfen, ▶ Karte testen — künftige Karten melden sich + # hier an, ohne main.gd anzufassen. Die Buttons bekommen den Registry-Namen + # als Node-Namen (main kann sie per get_node/find_child ansprechen, z. B. + # der Shake-Effekt beim fehlgeschlagenen Map-Check). + for entry in PanelRegistry.toolbar_actions(): + var btn := Button.new() + btn.text = str(entry["titel"]) + btn.name = str(entry["id"]) + if str(entry["id"]) == "karte_pruefen": + btn.custom_minimum_size = UIScale.v2(170, 40) + btn.tooltip_text = "Prüft, ob die Map bereit für den Export ist — sagen wir VORHER, was fehlt" + else: + btn.custom_minimum_size = UIScale.v2(190, 40) + btn.tooltip_text = "Startet die Map SOFORT als Spiel zum Durchlaufen — eigenes Fenster, der Editor bleibt offen. ESC im Spiel = zurück zum Editor." + btn.pressed.connect(main.call.bind(str(entry["action"]))) + # Test-Start ist ein Umschalter: main liest/setzt seinen Zustand + # (Prüfsuite test_playtest_spawn.gd erwartet main.test_start_btn). + if str(entry["id"]) == "teststart": + btn.toggle_mode = true + main.set("test_start_btn", btn) + add_child(btn) + + # Einstellungen (25.10.): Gitter, Höhenlinien, Symmetrie-Modus, UI-Größe, + # Raster-Snap … stehen jetzt in einem eigenen Fenster. + settings_btn = Button.new() + settings_btn.text = "⚙ Einstellungen" + settings_btn.name = "einstellungen_knopf" + settings_btn.custom_minimum_size = UIScale.v2(170, 40) + settings_btn.tooltip_text = "Gitter, Höhenlinien, Symmetrie, UI-Größe, Raster-Snap und Testlauf-Einstellungen" + settings_btn.pressed.connect(func() -> void: main.call("_open_settings")) + add_child(settings_btn) + + var help_btn := Button.new() + help_btn.text = "❓ Hilfe" + help_btn.name = "hilfe" + help_btn.custom_minimum_size = UIScale.v2(110, 40) + help_btn.tooltip_text = "Werkzeuge, Steuerung und Tastenkürzel (H)" + help_btn.pressed.connect(func() -> void: main.call("_toggle_help_overlay")) + add_child(help_btn) + + title_label = Label.new() + title_label.text = " %s" % main.APP_TITLE + title_label.add_theme_font_size_override("font_size", UIScale.heading_font_size()) + # Karte t_297221b5: bei großer Stufe darf der Titel EGALISIEREN statt die + # Top-Bar aus dem Fenster zu drücken (Mindestbreite der Schrift skaliert mit). + # Mindestbreite, damit er nicht KOMPLETT verschwindet (Ellipsis macht "Scop…"). + # Expand: bei Platz bekommt er seine VOLLSTÄNDIGE natürliche Breite (wie + # Vorher bei „Klein“), erst bei knappem Fenster egalisiert er mit "…". + title_label.custom_minimum_size = UIScale.v2(180, 0) + title_label.size_flags_horizontal = Control.SIZE_EXPAND_FILL + title_label.text_overrun_behavior = TextServer.OVERRUN_TRIM_ELLIPSIS + title_label.clip_text = true + add_child(title_label) + + var spacer := Control.new() + spacer.size_flags_horizontal = Control.SIZE_EXPAND_FILL + add_child(spacer) + + file_label = Label.new() + file_label.text = "" + # U7: Farbe über Theme (Editor/colors/title) statt modulate-Wert im Code. + file_label.add_theme_color_override("font_color", + main.theme.get_color("title", "Editor")) + # Karte t_297221b5: Map-Pfad darf bei großer Stufe egalisiert werden + # (Voller Name im Tooltip, sonst drückt die Zeile die Top-Bar aus dem Fenster). + # Expand: bekommt zusammen mit dem Spacer seinen Anteil, egalisiert mit "…". + file_label.text_overrun_behavior = TextServer.OVERRUN_TRIM_ELLIPSIS + file_label.clip_text = true + file_label.size_flags_horizontal = Control.SIZE_EXPAND_FILL + add_child(file_label) diff --git a/ui/panels/toolbar.gd.uid b/ui/panels/toolbar.gd.uid new file mode 100644 index 0000000..9f1da55 --- /dev/null +++ b/ui/panels/toolbar.gd.uid @@ -0,0 +1 @@ +uid://po0n02xkbp2e diff --git a/ui/resize_map_dialog.gd b/ui/resize_map_dialog.gd new file mode 100644 index 0000000..101707f --- /dev/null +++ b/ui/resize_map_dialog.gd @@ -0,0 +1,275 @@ +extends ConfirmationDialog +## „Kartengröße ändern“-Dialog (R3, Karte t_c863b93b — PLAN.md „Map-Größe +## ändern“): aktuelle Größe anzeigen, neue X/Z in Metern eingeben (Preset- +## Buttons + Freifeld), Live-Vorschau aus SvmapDocument.resize_preview (R2). + +const UIScale := preload("res://core/ui/ui_scale.gd") # Karte t_297221b5 +## +## Stil wie new_map_dialog.gd: alles per Code, Deutsch, Klartext-Warnungen. +## Der Dialog mutiert NICHTS — das Anwenden macht main.gd (_on_resize_confirmed) +## als EINE Undo-Einheit über resize_apply + ActionHistory-Snapshot. + +var size_x_edit: SpinBox +var size_z_edit: SpinBox +var drop_check: CheckBox +var info_label: Label # aktuelle Größe + Auflösung +var preview_label: Label # Live-Vorschau (Verlust-Liste / Warnband) +var _scroll: ScrollContainer +var _vbox: VBoxContainer + +var _old_sx := 0.0 +var _old_sz := 0.0 +var _old_res := 0 +var _doc: Dictionary = {} + +const _PRESET_SIZES := [256, 512, 1024, 2048] + + +func _init() -> void: + title = "Kartengröße ändern" + ok_button_text = "Größe ändern" + cancel_button_text = "Abbrechen" + min_size = UIScale.v2i(520, 0) + unresizable = true # Der Dialog wächst selbst per Inhalt; kein Hand-Resize + + # FIX 20.10.b: Inhalt in einen ScrollContainer — wächst die Live-Vorschau + # NACH dem Öffnen (z. B. Preset 256 → Warnband), kann die Fensterhöhe + # gedeckelt werden, OHNE dass Inhalt oder OK/Abbrechen verloren gehen. + # Start-Mindesthöhe ~ kompletter Normalinhalt (kein Kollaps beim Popup); + # _fit_after_layout setzt sie dynamisch auf Inhalt vs. sichtbarer Platz. + var scroll := ScrollContainer.new() + scroll.horizontal_scroll_mode = ScrollContainer.SCROLL_MODE_DISABLED + scroll.custom_minimum_size = UIScale.v2(500, 430) + add_child(scroll) + scroll.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT) + _scroll = scroll + + var vbox := VBoxContainer.new() + vbox.add_theme_constant_override("separation", UIScale.px(12)) + vbox.custom_minimum_size = UIScale.v2(500, 0) + vbox.size_flags_horizontal = Control.SIZE_EXPAND_FILL + scroll.add_child(vbox) + _vbox = vbox + + info_label = _make_label("") + vbox.add_child(info_label) + + var preset_h := HBoxContainer.new() + preset_h.add_theme_constant_override("separation", UIScale.px(8)) + for size in _PRESET_SIZES: + var btn := Button.new() + btn.text = "%d m" % size + btn.custom_minimum_size = UIScale.v2(0, 40) + # U7: Klartext-Tooltips (Karte t_2336c58e). + btn.tooltip_text = "Preset: Karte quadratisch %d × %d m" % [size, size] + btn.pressed.connect(_on_preset.bind(float(size))) + preset_h.add_child(btn) + vbox.add_child(preset_h) + + vbox.add_child(_make_label("Neue Breite (X) in Metern:")) + size_x_edit = SpinBox.new() + _fill_spin(size_x_edit) + vbox.add_child(size_x_edit) + + vbox.add_child(_make_label("Neue Tiefe (Z) in Metern:")) + size_z_edit = SpinBox.new() + _fill_spin(size_z_edit) + vbox.add_child(size_z_edit) + + var hint := _make_label("Erlaubt: 256–4096 m. Die Karte bleibt mittig — das bestehende Terrain\nbehaftet seine Weltposition, die neue Randzone wird flach (Steppe).") + hint.modulate = Color(1, 1, 1, 0.7) + vbox.add_child(hint) + + preview_label = _make_label("") + preview_label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART + # FIX 20.10.b: gleiche autowrap-Explosion wie oben — (0, 60) überschreibt die + # Mindestbreite von _make_label, deshalb hier BREITE + Höhe explizit setzen. + preview_label.custom_minimum_size = UIScale.v2(500, 60) + vbox.add_child(preview_label) + + drop_check = CheckBox.new() + drop_check.text = "Draußen liegende Objekte/Bauteile/Spawn-Punkte beim Verkleinern entfernen" + drop_check.button_pressed = true + # U7: Klartext-Tooltip (Karte t_2336c58e). + drop_check.tooltip_text = "An = Dinge außerhalb der neuen Grenze fliegen raus (Strg+Z holt sie zurück).\nAus = sie bleiben, aber die Map ist dann NICHT speicherbar." + drop_check.toggled.connect(func(_p: bool) -> void: _update_preview()) + vbox.add_child(drop_check) + + size_x_edit.value_changed.connect(func(_v: float) -> void: _update_preview()) + size_z_edit.value_changed.connect(func(_v: float) -> void: _update_preview()) + + +func _make_label(text: String) -> Label: + var label := Label.new() + label.text = text + label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART + # FIX 20.10. (Sly-Befund „Fenster viel zu lang, nichts bestätigbar“): ein + # autowrap-Label OHNE Mindestbreite meldet VOR dem ersten Layout eine + # explosionsartige Mindesthöhe (es wrappet bei ~1 px Breite → jedes Wort + # eine Zeile). popup_centered() nimmt genau diesen Wert als Fensterhöhe + # (Probe: 10 322 px statt ~320). Mindestbreite ~ Dialogbreite verankert + # den Umbruch an der echten Breite → Fenster normal hoch. + label.custom_minimum_size = Vector2(UIScale.px(500), 0) + return label + + +func _fill_spin(spin: SpinBox) -> void: + spin.min_value = SvmapDocument.MIN_SIZE_M + spin.max_value = SvmapDocument.MAX_SIZE_M + spin.step = 1.0 + spin.suffix = " m" + spin.value = 1024.0 + spin.custom_minimum_size = UIScale.v2(0, 40) + + +## Vom Editor vor dem Öffnen füllen: aktueller Stand + Live-Vorschau. +func setup(doc: Dictionary) -> void: + _doc = doc + var terrain: Dictionary = doc.get("terrain", {}) + _old_sx = float(terrain.get("size_x_m", 0.0)) + _old_sz = float(terrain.get("size_z_m", 0.0)) + _old_res = int(terrain.get("resolution", 0)) + info_label.text = "Aktuelle Größe: %d × %d m — Auflösung: %d × %d Höhenpunkte" % [ + int(_old_sx), int(_old_sz), _old_res, _old_res] + size_x_edit.value = _old_sx + size_z_edit.value = _old_sz + _update_preview() + + +func _on_preset(size: float) -> void: + size_x_edit.value = size + size_z_edit.value = size + + +func get_new_size_x() -> float: + return clampf(size_x_edit.value, SvmapDocument.MIN_SIZE_M, SvmapDocument.MAX_SIZE_M) + + +func get_new_size_z() -> float: + return clampf(size_z_edit.value, SvmapDocument.MIN_SIZE_M, SvmapDocument.MAX_SIZE_M) + + +func get_drop_outside() -> bool: + return drop_check.button_pressed + + +## Live-Vorschau: Verlust-Liste (R2 resize_preview), Spawn-Speicher-Warnung +## (V11 verlangt ≥ 4 Punkte/Team), Warnband bei Vergrößern über ~1024 m +## (Dichte-Leiter deckelt bei 513 Punkten → grobes Raster, Quest-Perf). +func _update_preview() -> void: + if _doc.is_empty(): + preview_label.text = "" + preview_label.modulate = Color(1, 1, 1, 0.7) + return + var new_sx := get_new_size_x() + var new_sz := get_new_size_z() + var preview: Dictionary = SvmapDocument.resize_preview(_doc, new_sx, new_sz) + var lines: Array[String] = [] + + var shrink := new_sx < _old_sx - 0.5 or new_sz < _old_sz - 0.5 + var grow := new_sx > _old_sx + 0.5 or new_sz > _old_sz + 0.5 + var out_total := (preview["objects_out"] as Array).size() \ + + (preview["parts_out"] as Array).size() \ + + (preview["spawns_out"] as Array).size() + + if shrink and out_total > 0: + var detail := "Beim Verkleinern liegen draußen: %d Objekt(e), %d Bauteil(e), %d Spawn-Punkt(e)." % [ + (preview["objects_out"] as Array).size(), + (preview["parts_out"] as Array).size(), + (preview["spawns_out"] as Array).size()] + if drop_check.button_pressed: + detail += "\nDiese werden beim Anwenden ENTFERNT (Strg+Z holt sie zurück)." + else: + detail += "\nSie bleiben in der Map, ragen aber über den Rand hinaus — die Map ist dann NICHT speicherbar (nichts darf außerhalb der Match-Grenzen liegen). Zieh sie später wieder rein oder entferne sie." + preview_label.modulate = Color(1.0, 0.75, 0.3) # Warnorange + lines.append(detail) + elif shrink: + preview_label.modulate = Color(1, 1, 1, 0.7) + lines.append("Beim Verkleinern geht nichts verloren — alles liegt innerhalb der neuen Grenzen.") + elif grow: + preview_label.modulate = Color(1, 1, 1, 0.7) + lines.append("Beim Vergrößern bleibt alles erhalten — die neue Randzone wird flache Steppe.") + + # Spawn-Speicher-Warnung (R2-Befund): V11 verlangt ≥ 4 Punkte je Team beim + # SPEICHERN — nach dem Entfernen drohen Teams unter den Deckwert. + if drop_check.button_pressed and out_total > 0: + var zones = _doc.get("spawn_zones", {}) + if zones is Dictionary: + var dropped: Dictionary = {} + for entry in (preview["spawns_out"] as Array): + if entry is Dictionary: + dropped[int(entry.get("team", -1))] = int(dropped.get(int(entry.get("team", -1)), 0)) + 1 + for team_key in (zones as Dictionary).keys(): + var zone = zones[team_key] + if not (zone is Dictionary): + continue + var kept := (zone.get("points", []) as Array).size() - int(dropped.get(int(team_key), 0)) + if kept < 4: + lines.append("Achtung: Team „%s“ hätte danach nur %d Spawn-Punkte — Maps brauchen mindestens 4 pro Team, um SPEICHERN zu können. Abhilfe: Entfernen ausstellen oder später Punkte ergänzen." % [ + str(zone.get("label", "Team %s" % str(team_key))), kept]) + preview_label.modulate = Color(1.0, 0.75, 0.3) + + # Warnband Vergrößern: über ~1024 m Kante grobt die Dichte (Deckel 513 + # Punkte) — Detail-Dichte + Quest-Perf (Objektzahl/Draw-Calls) erwähnen. + if grow: + var m_per_point := SvmapDocument.resize_m_per_point(_projected_resolution(), maxf(new_sx, new_sz)) + if m_per_point > SvmapDocument.RESIZE_DENSITY_TARGET_M: + lines.append("Achtung: Ab dieser Größe wird das Terrain grober aufgelöst (%.1f m pro Höhenpunkt statt 2 m). Die Hügel-Details werden weicher — für Quest-Perf gilt: mehr Fläche = mehr Objekte/Draw-Calls beachten." % m_per_point) + preview_label.modulate = Color(1.0, 0.75, 0.3) + + preview_label.text = "\n".join(lines) + _fit_after_layout.call_deferred() + + +## Fenster im sichtbaren Bereich halten: Höhe deckeln (überzähliger Inhalt +## scrollt im ScrollContainer) und neu zentrieren — sonst rutschen +## OK/Abbrechen unter den Bildschirmrand, wenn die Live-Vorschau das Fenster +## NACH dem Öffnen wachsen lässt (Probe: Fenster blieb oben hängen, Buttons +## bei y≈940 in einem 900-px-Sichtbereich). +func _fit_dialog() -> void: + var area := _parent_area() + if area.x <= 0.0 or area.y <= 0.0: + return + var max_h := int(area.y) - 8 + if size.y > max_h: + size = Vector2i(size.x, max_h) + var half := (area - Vector2(size)) * 0.5 + position = Vector2(maxi(0, int(half.x)), maxi(0, int(half.y))) + + +## Erst das Layout (und damit das Fenster-Wachstum) abwarten, dann den +## Scrollbereich auf „Inhalt vs. sichtbarer Platz“ justieren und verankern. +func _fit_after_layout() -> void: + await get_tree().process_frame + await get_tree().process_frame + var area := _parent_area() + if area.x <= 0.0 or area.y <= 0.0: + return + # Scrollbereich: so hoch wie der Inhalt, aber nie höher als der sichtbare + # Platz (Titelleiste + OK/Abbrechen + Ränder bleiben reserviert). Ist der + # Inhalt größer, scrollt er INNEN — die Buttons bleiben immer erreichbar. + var needed := _vbox.get_combined_minimum_size().y + UIScale.px(16) + var max_body := area.y - UIScale.px(90) + _scroll.custom_minimum_size = Vector2(UIScale.px(500), minf(needed, max_body)) + _fit_dialog() + + +func _parent_area() -> Vector2: + var p := get_parent() + if p is Control: + return (p as Control).size + if p is Window: + return (p as Window).size + return Vector2.ZERO + + +## Projected new resolution nach dem Resize (gleiche Leiter wie resize_terrain, +## hier nur für die Warnband-Anzeige — kein Terrain-Resample im Dialog). +func _projected_resolution() -> int: + var res := _old_res + for step in SvmapDocument.RESIZE_RESOLUTION_LADDER: + if step < res: + continue + if maxf(get_new_size_x(), get_new_size_z()) / float(step - 1) <= SvmapDocument.RESIZE_DENSITY_TARGET_M: + return step + return SvmapIO.MAX_TERRAIN_RESOLUTION \ No newline at end of file diff --git a/ui/resize_map_dialog.gd.uid b/ui/resize_map_dialog.gd.uid new file mode 100644 index 0000000..67c203e --- /dev/null +++ b/ui/resize_map_dialog.gd.uid @@ -0,0 +1 @@ +uid://6bjars8usr43 diff --git a/ui/ui_scale.gd b/ui/ui_scale.gd new file mode 100644 index 0000000..75f5fdc --- /dev/null +++ b/ui/ui_scale.gd @@ -0,0 +1,136 @@ +class_name UIScale +extends RefCounted + +## Zentrale UI-Skalierung (Karte t_297221b5): EIN Faktor für den ganzen Editor. +## +## Stufen: Klein (1.0) / Mittel (1.25) / Groß (1.5). Der Faktor multipliziert +## alle Layout-Werte beim UI-Bau (Schrift, Zeilen-/Knopfhöhen, Panelbreiten, +## Thumbnail-Größe, Abstände) — bewusst als Faktor-Multiplikation und NICHT als +## stretch/canvas_items, damit (a) die 3D-Map-Ansicht pixelgenau unberührt bleibt, +## (b) nichts doppelt skaliert und (c) die Stufe vom Nutzer gewählt wird statt +## von der Fenstergröße abzuhängen. +## +## Die gewählte Stufe liegt in user://scopedvr_editor.cfg, Abschnitt [ui] +## (Key "groesse"). ConfigFile lädt+speichert die GANZE Datei — der Abschnitt +## [library] (Klapp-Zustand, Karte t_59fc0f21) bleibt dabei erhalten. +## +## Für Tests/Probes kann per Umgebungsvariable SCOPEDVR_UI_CFG eine andere +## Config-Datei erzwungen werden (hermetische Läufe ohne Nutzer-Config). + +## Typografie-Ebenen (Karte t_2336c58e/U7 — verbindlich): genau ZWEI Schrift- +## Größen (Body + Klein) plus eine Überschriften-Stufe. KEINE weiteren Größen +## im Code — alles über die drei Helfer unten, skaliert mit der UI-Stufe. +const HEADING_FONT_SIZE := 20 # Überschriften (Panel-/Gruppen-Header, Titel) +const SMALL_FONT_SIZE := 13 # Nebentext (Zähler, Badges, Tile-IDs) + +const CFG_PATH := "user://scopedvr_editor.cfg" +const CFG_SECTION := "ui" +const CFG_KEY := "groesse" # "klein" | "mittel" | "gross" +const WIN_SECTION := "fenster" # Fenster-Zustand (maximiert/Größe/Position) + +## [key, Anzeige-Name, Faktor] +const STEPS: Array = [ + ["klein", "Klein", 1.0], + ["mittel", "Mittel", 1.25], + ["gross", "Groß", 1.5], +] +const BASE_FONT_SIZE := 16 # bisherige feste Schriftgröße (main.gd, Vorher) + +static var _factor: float = -1.0 # Cache; < 0 = noch nicht aus der Config gelesen + + +static func cfg_path() -> String: + var env := OS.get_environment("SCOPEDVR_UI_CFG") + if not env.is_empty(): + return env + return CFG_PATH + + +static func step_count() -> int: + return STEPS.size() + + +static func step_label(i: int) -> String: + return str(STEPS[clampi(i, 0, STEPS.size() - 1)][1]) + + +static func step_key(i: int) -> String: + return str(STEPS[clampi(i, 0, STEPS.size() - 1)][0]) + + +static func step_index_from_key(key: String) -> int: + for i in STEPS.size(): + if str(STEPS[i][0]) == key: + return i + return 0 # unbekannt/leer → Klein (Vorher-Verhalten) + + +## Aktuelle Stufe aus der Config (ohne Cache). +static func step_index() -> int: + var cfg := ConfigFile.new() + if cfg.load(cfg_path()) != OK: + return 0 # keine Config = Klein (altes Verhalten) + return step_index_from_key(str(cfg.get_value(CFG_SECTION, CFG_KEY, ""))) + + +## Faktor der aktuellen Stufe (cached — UI-Bau ruft das sehr oft). +static func factor() -> float: + if _factor < 0.0: + _factor = float(STEPS[step_index()][2]) + return _factor + + +## Stufe setzen UND sofort in die Config schreiben (Abschnitte wie [library] +## bleiben erhalten — ConfigFile liest/schreibt die ganze Datei). +static func set_step_index(i: int) -> void: + i = clampi(i, 0, STEPS.size() - 1) + var cfg := ConfigFile.new() + cfg.load(cfg_path()) # fehlt die Datei: leer anfangen, Abschnitte bleiben + cfg.set_value(CFG_SECTION, CFG_KEY, str(STEPS[i][0])) + var err := cfg.save(cfg_path()) + if err != OK: + push_warning("UIScale: Config nicht schreibbar (%s), Stufe nur für diese Sitzung." % err) + _factor = float(STEPS[i][2]) + + +## Cache verwerfen und neu lesen — simuliert den Neustart (für Tests/Probes). +static func reload() -> void: + _factor = -1.0 + factor() + + +# ------------------------------------------------------- Rechenhelfer (Bau) -- + +## Ganzzahliges Pixel-Maß (Höhen, Breiten, Abstände, Schriftgrößen). +static func px(v: float) -> int: + return int(round(v * factor())) + + +## Fließkommamaß (z. B. split_offset). +static func f(v: float) -> float: + return v * factor() + + +## custom_minimum_size = UIScale.v2(b, h) statt Vector2(b, h). +static func v2(x: float, y: float) -> Vector2: + return Vector2(px(x), px(y)) + + +## Dialog-/Fenstergrößen. +static func v2i(x: float, y: float) -> Vector2i: + return Vector2i(px(x), px(y)) + + +## Standardschriftgröße (Body-Text, bisher fest 16). +static func font_size() -> int: + return px(BASE_FONT_SIZE) + + +## Überschriften-Größe (Panel-/Gruppen-Header, Titel) — U7-Raster. +static func heading_font_size() -> int: + return px(HEADING_FONT_SIZE) + + +## Nebentext-Größe (Zähler, Badges, Tile-IDs) — U7-Raster. +static func small_font_size() -> int: + return px(SMALL_FONT_SIZE) diff --git a/ui/ui_scale.gd.uid b/ui/ui_scale.gd.uid new file mode 100644 index 0000000..beeeff8 --- /dev/null +++ b/ui/ui_scale.gd.uid @@ -0,0 +1 @@ +uid://d4d60533njpla diff --git a/ui/viewport_toolbar.gd b/ui/viewport_toolbar.gd new file mode 100644 index 0000000..1f85a2f --- /dev/null +++ b/ui/viewport_toolbar.gd @@ -0,0 +1,78 @@ +extends PanelContainer +## Werkzeugleiste oben links in der 3D-Ansicht (25.10.): erscheint, sobald ein +## Objekt ausgewählt ist. Umschalter Verschieben / Drehen & Kippen (steuert den +## Gizmo) plus schnelle Aktionen (Auf den Boden, Duplizieren, Löschen). +## Objekte werden bewusst NIE skaliert — es gibt kein Skalieren-Werkzeug. + +var main +var move_btn: Button +var rotate_btn: Button +var ground_btn: Button +var dup_btn: Button +var delete_btn: Button + + +func setup(p_main) -> void: + main = p_main + set_anchors_preset(Control.PRESET_TOP_LEFT) + offset_left = UIScale.px(12) + offset_top = UIScale.px(12) + mouse_filter = Control.MOUSE_FILTER_STOP + visible = false + var box := HBoxContainer.new() + box.add_theme_constant_override("separation", UIScale.px(6)) + add_child(box) + var group := ButtonGroup.new() + move_btn = _btn("↔ Verschieben", "Pfeile am Objekt ziehen: X rot, Y grün, Z blau", true, group) + move_btn.pressed.connect(func() -> void: _set_mode("move")) + box.add_child(move_btn) + rotate_btn = _btn("⟳ Drehen / Kippen", "Ringe am Objekt ziehen: um alle drei Achsen, in 15°-Schritten", true, group) + rotate_btn.pressed.connect(func() -> void: _set_mode("rotate")) + box.add_child(rotate_btn) + move_btn.set_pressed_no_signal(true) + box.add_child(VSeparator.new()) + ground_btn = _btn("⤓ Auf den Boden", "Auswahl aufs Terrain absetzen (Strg+Bild↑)", false, null) + ground_btn.pressed.connect(func() -> void: main.interaction.snap_selection_to_floor()) + box.add_child(ground_btn) + dup_btn = _btn("⧉ Kopie", "Duplizieren (Strg+D)", false, null) + dup_btn.pressed.connect(func() -> void: main.interaction.duplicate_selected()) + box.add_child(dup_btn) + delete_btn = _btn("🗑 Löschen", "Löschen (Entf) — Strg+Z holt es zurück", false, null) + delete_btn.pressed.connect(func() -> void: main.interaction.delete_selected()) + box.add_child(delete_btn) + + +func _btn(text: String, tip: String, toggle: bool, group: ButtonGroup) -> Button: + var b := Button.new() + b.text = text + b.tooltip_text = tip + b.toggle_mode = toggle + if group != null: + b.button_group = group + b.custom_minimum_size = UIScale.v2(0, 36) + b.focus_mode = Control.FOCUS_NONE # Leertaste/Pfeile bleiben beim Viewport + return b + + +func _set_mode(m: String) -> void: + if main.gizmo != null: + main.gizmo.set_mode(m) + + +## Sichtbarkeit pro Frame aus der Auswahl ableiten (wie der Gizmo selbst). +func _process(_delta: float) -> void: + if main == null or main.get("interaction") == null: + return + var inter = main.interaction + var mode: String = str(main.get("tool_mode")) + var want: bool = mode == "objects" \ + and not inter.selected_indices.is_empty() \ + and not bool(inter.get("placing")) \ + and main.get("playtest") == null + if want != visible: + visible = want + if visible and main.gizmo != null: + var rotate_on: bool = main.gizmo.mode == "rotate" + if rotate_btn.button_pressed != rotate_on: + rotate_btn.set_pressed_no_signal(rotate_on) + move_btn.set_pressed_no_signal(not rotate_on) diff --git a/ui/viewport_toolbar.gd.uid b/ui/viewport_toolbar.gd.uid new file mode 100644 index 0000000..d93f503 --- /dev/null +++ b/ui/viewport_toolbar.gd.uid @@ -0,0 +1 @@ +uid://jjp1jooped0q diff --git a/vendor/modular_builder/LICENSE b/vendor/modular_builder/LICENSE new file mode 100644 index 0000000..1e93566 --- /dev/null +++ b/vendor/modular_builder/LICENSE @@ -0,0 +1,125 @@ +CC0 1.0 Universal + +Copyright (c) 2026 Michel Savadim + +This CC0 dedication applies only to the original Modular Builder source code, +icons, and documentation in this directory authored by Michel Savadim. It does +not apply to Godot Engine, user-created project content, trademarks, patents, +or third-party materials distributed separately. + +CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE +LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN +ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS +INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES +REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS +PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM +THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED +HEREUNDER. + +Statement of Purpose + +The laws of most jurisdictions throughout the world automatically confer +exclusive Copyright and Related Rights (defined below) upon the creator +and subsequent owner(s) (each and all, an "owner") of an original work of +authorship and/or a database (each, a "Work"). + +Certain owners wish to permanently relinquish those rights to a Work for +the purpose of contributing to a commons of creative, cultural and +scientific works ("Commons") that the public can reliably and without fear +of later claims of infringement build upon, modify, incorporate in other +works, reuse and redistribute as freely as possible in any form whatsoever +and for any purposes, including without limitation commercial purposes. +These owners may contribute to the Commons to promote the ideal of a free +culture and the further production of creative, cultural and scientific +works, or to gain reputation or greater distribution for their Work in +part through the use and efforts of others. + +For these and/or other purposes and motivations, and without any +expectation of additional consideration or compensation, the person +associating CC0 with a Work (the "Affirmer"), to the extent that he or she +is an owner of Copyright and Related Rights in the Work, voluntarily +elects to apply CC0 to the Work and publicly distribute the Work under its +terms, with knowledge of his or her Copyright and Related Rights in the +Work and the meaning and intended legal effect of CC0 on those rights. + +1. Copyright and Related Rights. A Work made available under CC0 may be +protected by copyright and related or neighboring rights ("Copyright and +Related Rights"). Copyright and Related Rights include, but are not +limited to, the following: + i. the right to reproduce, adapt, distribute, perform, display, + communicate, and translate a Work; + ii. moral rights retained by the original author(s) and/or performer(s); +iii. publicity and privacy rights pertaining to a person's image or + likeness depicted in a Work; + iv. rights protecting against unfair competition in regards to a Work, + subject to the limitations in paragraph 4(a), below; + v. rights protecting the extraction, dissemination, use and reuse of data + in a Work; + vi. database rights (such as those arising under Directive 96/9/EC of the + European Parliament and of the Council of 11 March 1996 on the legal + protection of databases, and under any national implementation + thereof, including any amended or successor version of such + directive); and +vii. other similar, equivalent or corresponding rights throughout the + world based on applicable law or treaty, and any national + implementations thereof. + +2. Waiver. To the greatest extent permitted by, but not in contravention +of, applicable law, Affirmer hereby overtly, fully, permanently, +irrevocably and unconditionally waives, abandons, and surrenders all of +Affirmer's Copyright and Related Rights and associated claims and causes +of action, whether now known or unknown (including existing as well as +future claims and causes of action), in the Work (i) in all territories +worldwide, (ii) for the maximum duration provided by applicable law or +treaty (including future time extensions), (iii) in any current or future +medium and for any number of copies, and (iv) for any purpose whatsoever, +including without limitation commercial, advertising or promotional +purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each +member of the public at large and to the detriment of Affirmer's heirs and +successors, fully intending that such Waiver shall not be subject to +revocation, rescission, cancellation, termination, or any other legal or +equitable action to disrupt the quiet enjoyment of the Work by the public +as contemplated by Affirmer's express Statement of Purpose. + +3. Public License Fallback. Should any part of the Waiver for any reason +be judged legally invalid or ineffective under applicable law, then the +Waiver shall be preserved to the maximum extent permitted taking into +account Affirmer's express Statement of Purpose. In addition, to the +extent the Waiver is so judged Affirmer hereby grants to each affected +person a royalty-free, non transferable, non sublicensable, non exclusive, +irrevocable and unconditional license to exercise Affirmer's Copyright and +Related Rights in the Work (i) in all territories worldwide, (ii) for the +maximum duration provided by applicable law or treaty (including future +time extensions), (iii) in any current or future medium and for any number +of copies, and (iv) for any purpose whatsoever, including without +limitation commercial, advertising or promotional purposes (the +"License"). The License shall be deemed effective as of the date CC0 was +applied by Affirmer to the Work. Should any part of the License for any +reason be judged legally invalid or ineffective under applicable law, such +partial invalidity or ineffectiveness shall not invalidate the remainder +of the License, and in such case Affirmer hereby affirms that he or she +will not (i) exercise any of his or her remaining Copyright and Related +Rights in the Work or (ii) assert any associated claims and causes of +action with respect to the Work, in either case contrary to Affirmer's +express Statement of Purpose. + +4. Limitations and Disclaimers. + a. No trademark or patent rights held by Affirmer are waived, abandoned, + surrendered, licensed or otherwise affected by this document. + b. Affirmer offers the Work as-is and makes no representations or + warranties of any kind concerning the Work, express, implied, + statutory or otherwise, including without limitation warranties of + title, merchantability, fitness for a particular purpose, non + infringement, or the absence of latent or other defects, accuracy, or + the present or absence of errors, whether or not discoverable, all to + the greatest extent permissible under applicable law. + c. Affirmer disclaims responsibility for clearing rights of other persons + that may apply to the Work or any use thereof, including without + limitation any person's Copyright and Related Rights in the Work. + Further, Affirmer disclaims responsibility for obtaining any necessary + consents, permissions or other rights required for any use of the Work. + d. Affirmer understands and acknowledges that Creative Commons is not a + party to this document and has no duty or obligation with respect to + this CC0 or use of the Work. + +https://creativecommons.org/publicdomain/zero/1.0/legalcode diff --git a/vendor/modular_builder/modular_building_detail.gd b/vendor/modular_builder/modular_building_detail.gd new file mode 100644 index 0000000..afe295d --- /dev/null +++ b/vendor/modular_builder/modular_building_detail.gd @@ -0,0 +1,284 @@ +@tool +class_name ModularBuilderDetail +extends Node3D + +enum DetailType { WINDOW, DOOR, HATCH, PILLAR, FENCE, PARAPET } +enum DetailMode { OPENING, SEPARATE_OBJECT } +enum WindowStyle { SINGLE_PANE, CROSS_PANE } +enum DoorStyle { FLAT, PANELED } + +@export var detail_type: DetailType = DetailType.WINDOW: + set(value): + detail_type = value + notify_property_list_changed() + _rebuild() +@export var detail_mode: DetailMode = DetailMode.OPENING: + set(value): + detail_mode = value + notify_property_list_changed() + _rebuild() +@export var center_align: bool = false: + set(value): + center_align = value + _apply_pillar_alignment() + notify_property_list_changed() +@export_storage var pillar_direction: Vector3 = Vector3.UP +@export_storage var pillar_alignment_basis: Basis = Basis.IDENTITY +@export var window_style: WindowStyle = WindowStyle.SINGLE_PANE: + set(value): + window_style = value + _rebuild() +@export var door_style: DoorStyle = DoorStyle.FLAT: + set(value): + door_style = value + _rebuild() +@export_range(0.01, 5.0, 0.001, "suffix:m") var width: float = 1.0: + set(value): + width = value + _rebuild() +@export_range(0.2, 5.0, 0.001, "suffix:m") var height: float = 1.0: + set(value): + height = value + _rebuild() +@export_range(0.02, 0.5, 0.001, "suffix:m") var frame_depth: float = 0.08: + set(value): + frame_depth = value + _rebuild() +@export_range(0.1, 8.0, 0.001, "suffix:m") var fence_height: float = 0.7: + set(value): + fence_height = value + _rebuild() +@export_range(0, 100, 1, "suffix: posts") var fence_divisions: int = 1: + set(value): + fence_divisions = value + _rebuild() +@export_storage var path_points: PackedVector3Array = PackedVector3Array() +@export_range(0.01, 0.5, 0.001, "suffix:m") var frame_width: float = 0.08: + set(value): + frame_width = value + _rebuild() +@export var follow_host_thickness: bool = true: + set(value): + follow_host_thickness = value + _rebuild() +@export var surface_material: Material: + set(value): + surface_material = value + _rebuild() +@export var frame_material: Material: + set(value): + frame_material = value + _rebuild() +@export var panel_material: Material: + set(value): + panel_material = value + _rebuild() + +func _validate_property(property: Dictionary) -> void: + var separate_object := detail_mode == DetailMode.SEPARATE_OBJECT + var is_window := detail_type == DetailType.WINDOW + var is_door := detail_type == DetailType.DOOR + var has_frame_and_panel := separate_object and detail_type != DetailType.PILLAR and detail_type != DetailType.FENCE and detail_type != DetailType.PARAPET + var show_property := true + match StringName(property.name): + &"detail_mode": + show_property = detail_type != DetailType.PILLAR and detail_type != DetailType.FENCE and detail_type != DetailType.PARAPET + &"center_align": + show_property = detail_type == DetailType.PILLAR + &"fence_height", &"fence_divisions": + show_property = detail_type == DetailType.FENCE or detail_type == DetailType.PARAPET + &"path_points": + show_property = false + &"width": + show_property = detail_type != DetailType.FENCE and detail_type != DetailType.PARAPET + if detail_type == DetailType.PILLAR: + property.hint = PROPERTY_HINT_RANGE + property.hint_string = "0.01,5.0,0.001,suffix:m" + &"height": + show_property = detail_type != DetailType.FENCE and detail_type != DetailType.PARAPET + &"window_style": + show_property = is_window and separate_object + &"door_style": + show_property = is_door and separate_object + &"frame_width", &"frame_material", &"panel_material": + show_property = has_frame_and_panel + &"follow_host_thickness": + show_property = has_frame_and_panel + &"frame_depth": + show_property = has_frame_and_panel and not follow_host_thickness + &"surface_material": + show_property = separate_object + if not show_property: + property.usage = PROPERTY_USAGE_NO_EDITOR + +func _ready() -> void: + set_notify_transform(true) + _rebuild() + +func _notification(what: int) -> void: + if what == NOTIFICATION_TRANSFORM_CHANGED and is_inside_tree(): + var host := get_parent() + if host != null and host.has_method("_rebuild"): + host.call("_rebuild") + +func _on_host_thickness_changed() -> void: + _rebuild(false) + +func _apply_pillar_alignment() -> void: + if detail_type != DetailType.PILLAR: + return + var direction := pillar_direction.normalized() + if direction.is_zero_approx(): + direction = Vector3.UP + if center_align: + var object_axes := pillar_alignment_basis.orthonormalized() + var best_axis := direction + var best_dot := -1.0 + for axis in [object_axes.x, object_axes.y, object_axes.z]: + var normalized_axis: Vector3 = axis.normalized() + var alignment := absf(direction.dot(normalized_axis)) + if alignment > best_dot: + best_dot = alignment + best_axis = normalized_axis if direction.dot(normalized_axis) >= 0.0 else -normalized_axis + direction = best_axis + var reference_axis := Vector3.FORWARD if absf(direction.dot(Vector3.UP)) > 0.99 else Vector3.UP + var x_axis := reference_axis.cross(direction).normalized() + var z_axis := x_axis.cross(direction).normalized() + transform.basis = Basis(x_axis, direction, z_axis).orthonormalized() + if center_align and pillar_direction.length() > 0.0: + height = pillar_direction.length() + +func _rebuild(notify_host: bool = true) -> void: + if not is_inside_tree(): + return + for child in get_children(): + if child.name == "DetailGeometry": + remove_child(child) + child.queue_free() + var host := get_parent() + if notify_host and host != null and host.has_method("_rebuild"): + host.call("_rebuild") + if detail_mode == DetailMode.OPENING and detail_type != DetailType.FENCE and detail_type != DetailType.PARAPET: + return + var holder := Node3D.new() + holder.name = "DetailGeometry" + add_child(holder) + var scene_root: Node = null + if Engine.is_editor_hint() and not has_meta("modular_builder_preview"): + scene_root = get_tree().edited_scene_root + if scene_root: + holder.owner = scene_root + var effective_depth := _effective_frame_depth() + var frame := minf(maxf(frame_width, 0.01), minf(width, height) * 0.45) + if detail_type == DetailType.FENCE or detail_type == DetailType.PARAPET: + _build_fence_geometry(holder) + return + if detail_type == DetailType.PILLAR: + _add_box(holder, "PillarBody", Vector3(width, height, width), Vector3.ZERO, surface_material) + return + if detail_type == DetailType.HATCH: + _add_box(holder, "LeftFrame", Vector3(frame, effective_depth, height), Vector3(-width * 0.5 + frame * 0.5, 0.0, 0.0), _frame_material()) + _add_box(holder, "RightFrame", Vector3(frame, effective_depth, height), Vector3(width * 0.5 - frame * 0.5, 0.0, 0.0), _frame_material()) + _add_box(holder, "NearFrame", Vector3(width, effective_depth, frame), Vector3(0.0, 0.0, -height * 0.5 + frame * 0.5), _frame_material()) + _add_box(holder, "FarFrame", Vector3(width, effective_depth, frame), Vector3(0.0, 0.0, height * 0.5 - frame * 0.5), _frame_material()) + _add_box(holder, "HatchPanel", Vector3(width - frame * 2.0, effective_depth * 0.35, height - frame * 2.0), Vector3(0.0, effective_depth * 0.4, 0.0), _panel_material()) + return + _add_box(holder, "LeftFrame", Vector3(frame, height, effective_depth), Vector3(-width * 0.5 + frame * 0.5, 0.0, 0.0), _frame_material()) + _add_box(holder, "RightFrame", Vector3(frame, height, effective_depth), Vector3(width * 0.5 - frame * 0.5, 0.0, 0.0), _frame_material()) + _add_box(holder, "TopFrame", Vector3(width, frame, effective_depth), Vector3(0.0, height * 0.5 - frame * 0.5, 0.0), _frame_material()) + if detail_type != DetailType.DOOR: + _add_box(holder, "BottomFrame", Vector3(width, frame, effective_depth), Vector3(0.0, -height * 0.5 + frame * 0.5, 0.0), _frame_material()) + if detail_type == DetailType.WINDOW: + _add_box(holder, "WindowPanel", Vector3(maxf(width - frame * 2.0, 0.001), maxf(height - frame * 2.0, 0.001), effective_depth * 0.35), Vector3.ZERO, _panel_material()) + if window_style == WindowStyle.CROSS_PANE: + _add_box(holder, "VerticalMullion", Vector3(frame * 0.55, height - frame * 2.0, effective_depth * 0.4), Vector3.ZERO, _frame_material()) + _add_box(holder, "HorizontalMullion", Vector3(width - frame * 2.0, frame * 0.55, effective_depth * 0.4), Vector3.ZERO, _frame_material()) + elif detail_type == DetailType.DOOR: + _add_box(holder, "DoorPanel", Vector3(width - frame * 2.0, height - frame, effective_depth * 0.45), Vector3(0.0, -frame * 0.5, 0.0), _panel_material()) + if door_style == DoorStyle.PANELED: + var inset_depth := maxf(effective_depth * 0.04, 0.005) + var panel_width := (width - frame * 2.0) * 0.82 + var panel_height := maxf((height - frame) * 0.28, 0.05) + for panel_index in range(2): + var panel_y := -frame * 0.5 + (panel_index - 0.5) * (panel_height + frame * 0.25) + _add_box(holder, "DoorInset_%d" % panel_index, Vector3(panel_width, panel_height, inset_depth), Vector3(0.0, panel_y, effective_depth * 0.24), _frame_material()) + +func _effective_frame_depth() -> float: + if follow_host_thickness: + var host := get_parent() + if host != null: + var host_thickness = host.get("thickness") + if host_thickness is float or host_thickness is int: + var depth := float(host_thickness) + if detail_type == DetailType.WINDOW or detail_type == DetailType.DOOR: + depth *= 1.25 + return maxf(depth, 0.02) + return frame_depth + +func _build_fence_geometry(holder: Node3D) -> void: + if path_points.size() < 2 or fence_height <= 0.0: + return + var start := path_points[0] + var finish := path_points[1] + var path := finish - start + var path_length := path.length() + if path_length < 0.05: + return + var path_axis := path / path_length + var up_axis := Vector3.UP - path_axis * path_axis.dot(Vector3.UP) + if up_axis.length_squared() < 0.001: + up_axis = Vector3.FORWARD - path_axis * path_axis.dot(Vector3.FORWARD) + up_axis = up_axis.normalized() + var side_axis := path_axis.cross(up_axis).normalized() + var post_width := 0.16 if detail_type == DetailType.PARAPET else 0.08 + var post_count := fence_divisions + 2 + var posts: Array[Vector3] = [] + for i in range(post_count): + var base := start.lerp(finish, float(i) / float(post_count - 1)) + posts.append(base) + _add_oriented_box(holder, "Post_%d" % i, base + up_axis * fence_height * 0.5, path_axis, up_axis, side_axis, Vector3(post_width, fence_height, post_width)) + for i in range(posts.size() - 1): + var a := posts[i] + var b := posts[i + 1] + var segment := b - a + var segment_length := segment.length() + if detail_type == DetailType.PARAPET: + _add_oriented_box(holder, "Rail_%d" % i, (a + b) * 0.5 + up_axis * fence_height * 0.78, segment.normalized(), up_axis, side_axis, Vector3(segment_length, post_width * 0.8, post_width * 0.8)) + else: + for height_ratio in [0.28, 0.78]: + _add_oriented_box(holder, "Rail_%d_%d" % [i, int(height_ratio * 100.0)], (a + b) * 0.5 + up_axis * fence_height * height_ratio, segment.normalized(), up_axis, side_axis, Vector3(segment_length, post_width, post_width)) + +func _add_oriented_box(holder: Node3D, node_name: String, center: Vector3, axis_x: Vector3, axis_y: Vector3, axis_z: Vector3, dimensions: Vector3) -> void: + var mesh_instance := MeshInstance3D.new() + mesh_instance.name = node_name + var box := BoxMesh.new() + box.size = dimensions + mesh_instance.mesh = box + var basis := Basis(axis_x.normalized(), axis_y.normalized(), axis_z.normalized()).orthonormalized() + mesh_instance.transform = Transform3D(basis, center) + mesh_instance.material_override = surface_material + holder.add_child(mesh_instance) + if Engine.is_editor_hint() and not has_meta("modular_builder_preview"): + var scene_root := get_tree().edited_scene_root + if scene_root: + mesh_instance.owner = scene_root + +func _frame_material() -> Material: + return frame_material if frame_material != null else surface_material + +func _panel_material() -> Material: + return panel_material if panel_material != null else surface_material + +func _add_box(holder: Node3D, node_name: String, box_size: Vector3, box_position: Vector3, material: Material = null) -> void: + var mesh_instance := MeshInstance3D.new() + mesh_instance.name = node_name + var box := BoxMesh.new() + box.size = box_size + mesh_instance.mesh = box + mesh_instance.position = box_position + mesh_instance.material_override = material if material != null else surface_material + holder.add_child(mesh_instance) + if Engine.is_editor_hint() and not has_meta("modular_builder_preview"): + var scene_root := get_tree().edited_scene_root + if scene_root: + mesh_instance.owner = scene_root diff --git a/vendor/modular_builder/modular_building_detail.gd.uid b/vendor/modular_builder/modular_building_detail.gd.uid new file mode 100644 index 0000000..4f8775f --- /dev/null +++ b/vendor/modular_builder/modular_building_detail.gd.uid @@ -0,0 +1 @@ +uid://3niej5acydsb diff --git a/vendor/modular_builder/modular_piece_geometry.gd b/vendor/modular_builder/modular_piece_geometry.gd new file mode 100644 index 0000000..24becb0 --- /dev/null +++ b/vendor/modular_builder/modular_piece_geometry.gd @@ -0,0 +1,748 @@ +@tool +class_name ModularBuilderPieceGeometry +extends Node3D + +const DETAIL_SCRIPT_PATH := "res://core/vendor/modular_builder/modular_building_detail.gd" +const DETAIL_TYPE_HATCH := 2 +const DETAIL_TYPE_PILLAR := 3 + +enum PieceType { FOUNDATION_SQUARE, FOUNDATION_TRIANGLE, FLOOR, WALL, BUILDING, GABLE_WALL, ROOF_GABLE, ROOF_SHED, GABLE_WALL_RIGHT, ROOF_PYRAMID, STAIRS, FENCE } + +@export var piece_type: PieceType = PieceType.FOUNDATION_SQUARE: + set(value): + piece_type = value + notify_property_list_changed() + _rebuild() +@export_range(0.5, 8.0, 0.001, "suffix:m") var unit_size: float = 2.0: + set(value): + unit_size = value + _rebuild() +@export_range(0.01, 1.0, 0.001, "suffix:m") var thickness: float = 0.2: + set(value): + thickness = value + _rebuild() + for child in get_children(): + if child.has_method("_on_host_thickness_changed"): + child.call("_on_host_thickness_changed") +@export_range(0.1, 8.0, 0.001, "suffix:m") var rise: float = 1.0: + set(value): + rise = value + _rebuild() +@export_range(0.01, 32.0, 0.001, "suffix:m") var roof_width: float = 2.0: + set(value): + roof_width = value + _rebuild() +@export_range(1, 100, 1, "suffix: steps") var stair_count: int = 10: + set(value): + stair_count = value + _rebuild() +@export_range(0.01, 8.0, 0.001, "suffix:m") var stair_width: float = 1.0: + set(value): + stair_width = value + _rebuild() +@export_range(0, 100, 1, "suffix: posts") var fence_divisions: int = 1: + set(value): + fence_divisions = value + _rebuild() +@export_range(0.1, 8.0, 0.001, "suffix:m") var fence_height: float = 1.0: + set(value): + fence_height = value + _rebuild() +@export var symmetric_dimensions: bool = true: + set(value): + if symmetric_dimensions == value: + return + if not value: + _capture_mesh_dimensions() + symmetric_dimensions = value + notify_property_list_changed() + if value: + scale = Vector3.ONE + else: + _apply_dimension_scale() +@export_range(0.01, 100.0, 0.001, "suffix:m") var dimension_width: float = 2.0: + set(value): + dimension_width = value + _apply_dimension_scale() +@export_range(0.01, 100.0, 0.001, "suffix:m") var dimension_height: float = 2.0: + set(value): + dimension_height = value + _apply_dimension_scale() +@export_range(0.01, 100.0, 0.001, "suffix:m") var dimension_depth: float = 2.0: + set(value): + dimension_depth = value + _apply_dimension_scale() +@export_storage var _dimension_reference: Vector3 = Vector3.ZERO +@export var center_align: bool = false: + set(value): + center_align = value + _rebuild() +@export var surface_material: Material: + set(value): + surface_material = value + _rebuild() +@export var custom_points: PackedVector3Array = PackedVector3Array(): + set(value): + custom_points = value + _rebuild() +@export var centered_origin: bool = false: + set(value): + centered_origin = value + _rebuild() + +func _rebuild() -> void: + pass + +func _capture_mesh_dimensions() -> void: + var geometry := get_node_or_null("Geometry") as MeshInstance3D + if geometry == null or geometry.mesh == null: + return + var dimensions := geometry.mesh.get_aabb().size + if dimensions.x > 0.001: + dimension_width = dimensions.x + if dimensions.y > 0.001: + dimension_height = dimensions.y + if dimensions.z > 0.001: + dimension_depth = dimensions.z + _dimension_reference = dimensions + +func _apply_dimension_scale() -> void: + if symmetric_dimensions or _dimension_reference.x <= 0.001 or _dimension_reference.y <= 0.001 or _dimension_reference.z <= 0.001: + return + var target := Vector3(dimension_width, dimension_height, dimension_depth) + if piece_type == PieceType.FOUNDATION_SQUARE or piece_type == PieceType.FOUNDATION_TRIANGLE or piece_type == PieceType.FLOOR: + target.y = _dimension_reference.y + if piece_type == PieceType.WALL: + target.z = _dimension_reference.z + scale = Vector3(target.x / _dimension_reference.x, target.y / _dimension_reference.y, target.z / _dimension_reference.z) + +func _make_mesh() -> ArrayMesh: + if piece_type == PieceType.GABLE_WALL and custom_points.size() >= 2: + return _make_gable_wall_mesh() + if piece_type == PieceType.GABLE_WALL_RIGHT and custom_points.size() >= 2: + return _make_right_gable_wall_mesh() + if (piece_type == PieceType.ROOF_GABLE or piece_type == PieceType.ROOF_SHED or piece_type == PieceType.ROOF_PYRAMID) and custom_points.size() >= 2: + return _make_roof_mesh() + if piece_type == PieceType.STAIRS and custom_points.size() >= 2: + return _make_stair_mesh() + if piece_type == PieceType.FENCE and custom_points.size() >= 2: + return _make_fence_mesh() + if custom_points.size() >= 2 and piece_type == PieceType.WALL: + return _make_custom_wall_mesh() + if custom_points.size() >= 3 and piece_type == PieceType.FLOOR: + return _make_custom_floor_mesh() + if custom_points.size() >= 3 and (piece_type == PieceType.FOUNDATION_SQUARE or piece_type == PieceType.FOUNDATION_TRIANGLE): + return _make_custom_foundation_mesh() + var vertices := PackedVector3Array() + var normals := PackedVector3Array() + var s := unit_size + var polygon: Array[Vector2] + match piece_type: + PieceType.FOUNDATION_TRIANGLE: + polygon = [Vector2(-s * 0.5, -s * 0.5), Vector2(s * 0.5, -s * 0.5), Vector2(-s * 0.5, s * 0.5)] + _: + polygon = [Vector2(-s * 0.5, -s * 0.5), Vector2(s * 0.5, -s * 0.5), Vector2(s * 0.5, s * 0.5), Vector2(-s * 0.5, s * 0.5)] + var y0 := -thickness * 0.5 if centered_origin else 0.0 + var y1 := thickness * 0.5 if centered_origin else thickness + if piece_type == PieceType.WALL: + polygon = [Vector2(-s * 0.5, -thickness * 0.5), Vector2(s * 0.5, -thickness * 0.5), Vector2(s * 0.5, thickness * 0.5), Vector2(-s * 0.5, thickness * 0.5)] + y0 = -s * 0.5 if centered_origin else 0.0 + y1 = s * 0.5 if centered_origin else s + if piece_type == PieceType.FOUNDATION_SQUARE or piece_type == PieceType.FOUNDATION_TRIANGLE: + var hatch_mesh := _make_hatch_surface_mesh(polygon, y1, y0) + if hatch_mesh != null: + return hatch_mesh + for i in range(1, polygon.size() - 1): + _add_tri(vertices, normals, Vector3(polygon[0].x, y1, polygon[0].y), Vector3(polygon[i + 1].x, y1, polygon[i + 1].y), Vector3(polygon[i].x, y1, polygon[i].y)) + _add_tri(vertices, normals, Vector3(polygon[0].x, y0, polygon[0].y), Vector3(polygon[i].x, y0, polygon[i].y), Vector3(polygon[i + 1].x, y0, polygon[i + 1].y)) + for i in range(polygon.size()): + var j := (i + 1) % polygon.size() + var a := polygon[i] + var b := polygon[j] + _add_tri(vertices, normals, Vector3(a.x, y0, a.y), Vector3(b.x, y0, b.y), Vector3(b.x, y1, b.y)) + _add_tri(vertices, normals, Vector3(a.x, y0, a.y), Vector3(b.x, y1, b.y), Vector3(a.x, y1, a.y)) + var arrays: Array = [] + arrays.resize(Mesh.ARRAY_MAX) + arrays[Mesh.ARRAY_VERTEX] = vertices + arrays[Mesh.ARRAY_NORMAL] = normals + var result := ArrayMesh.new() + result.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, arrays) + return result + +func _make_gable_wall_mesh() -> ArrayMesh: + var vertices := PackedVector3Array() + var normals := PackedVector3Array() + var base_points := _get_centered_gable_base() if center_align else PackedVector3Array([custom_points[0], custom_points[1]]) + var a: Vector3 = base_points[0] + var b: Vector3 = base_points[1] + var direction := (b - a).normalized() + var side := Vector3(-direction.z, 0.0, direction.x).normalized() * thickness * 0.5 + var peak := (a + b) * 0.5 + Vector3.UP * rise + var front_a := a + side + var front_b := b + side + var front_peak := peak + side + var back_a := a - side + var back_b := b - side + var back_peak := peak - side + _add_tri(vertices, normals, front_a, front_b, front_peak) + _add_tri(vertices, normals, back_b, back_a, back_peak) + _add_quad(vertices, normals, front_a, back_a, back_b, front_b) + _add_quad(vertices, normals, front_b, back_b, back_peak, front_peak) + _add_quad(vertices, normals, front_peak, back_peak, back_a, front_a) + return _array_mesh(vertices, normals) + +func _make_right_gable_wall_mesh() -> ArrayMesh: + var vertices := PackedVector3Array() + var normals := PackedVector3Array() + var base_points := _get_centered_gable_base() if center_align else PackedVector3Array([custom_points[0], custom_points[1]]) + var a: Vector3 = base_points[0] + var b: Vector3 = base_points[1] + var direction := (b - a).normalized() + var side := Vector3(-direction.z, 0.0, direction.x).normalized() * thickness * 0.5 + var peak := b + Vector3.UP * rise + var front_a := a + side + var front_b := b + side + var front_peak := peak + side + var back_a := a - side + var back_b := b - side + var back_peak := peak - side + _add_tri(vertices, normals, front_a, front_b, front_peak) + _add_tri(vertices, normals, back_peak, back_b, back_a) + _add_quad(vertices, normals, front_a, back_a, back_b, front_b) + _add_quad(vertices, normals, front_b, back_b, back_peak, front_peak) + _add_quad(vertices, normals, front_peak, back_peak, back_a, front_a) + return _array_mesh(vertices, normals) + +func _make_roof_mesh() -> ArrayMesh: + if piece_type == PieceType.ROOF_SHED and custom_points.size() == 2: + return _make_shed_roof_mesh() + if custom_points.size() >= 4: + return _make_oriented_roof_mesh() + var vertices := PackedVector3Array() + var normals := PackedVector3Array() + var first: Vector3 = custom_points[0] + var second: Vector3 = custom_points[1] + var min_x := minf(first.x, second.x) + var max_x := maxf(first.x, second.x) + var min_z := minf(first.z, second.z) + var max_z := maxf(first.z, second.z) + var span_x := max_x - min_x + var span_z := max_z - min_z + if span_x < 0.02 or span_z < 0.02: + return _array_mesh(vertices, normals) + var panels: Array = [] + if piece_type == PieceType.ROOF_GABLE: + if span_x <= span_z: + var ridge_x := (min_x + max_x) * 0.5 + panels.append([Vector3(min_x, 0.0, min_z), Vector3(min_x, 0.0, max_z), Vector3(ridge_x, rise, max_z), Vector3(ridge_x, rise, min_z)]) + panels.append([Vector3(ridge_x, rise, min_z), Vector3(ridge_x, rise, max_z), Vector3(max_x, 0.0, max_z), Vector3(max_x, 0.0, min_z)]) + else: + var ridge_z := (min_z + max_z) * 0.5 + panels.append([Vector3(min_x, 0.0, min_z), Vector3(max_x, 0.0, min_z), Vector3(max_x, rise, ridge_z), Vector3(min_x, rise, ridge_z)]) + panels.append([Vector3(min_x, rise, ridge_z), Vector3(max_x, rise, ridge_z), Vector3(max_x, 0.0, max_z), Vector3(min_x, 0.0, max_z)]) + else: + if span_x <= span_z: + var low_x := first.x + var high_x := second.x + panels.append([Vector3(low_x, 0.0, min_z), Vector3(low_x, 0.0, max_z), Vector3(high_x, rise, max_z), Vector3(high_x, rise, min_z)]) + else: + var low_z := first.z + var high_z := second.z + panels.append([Vector3(min_x, 0.0, low_z), Vector3(max_x, 0.0, low_z), Vector3(max_x, rise, high_z), Vector3(min_x, rise, high_z)]) + for panel in panels: + _append_solid_panel(vertices, normals, panel) + return _array_mesh(vertices, normals) + +func _make_shed_roof_mesh() -> ArrayMesh: + var vertices := PackedVector3Array() + var normals := PackedVector3Array() + var low: Vector3 = custom_points[0] + var high: Vector3 = custom_points[1] + var slope := high - low + var horizontal := Vector3(slope.x, 0.0, slope.z) + if horizontal.length_squared() < 0.0001 or roof_width <= 0.0: + return _array_mesh(vertices, normals) + var across := Vector3(horizontal.z, 0.0, -horizontal.x).normalized() * roof_width * 0.5 + var panel := [low - across, low + across, high + across, high - across] + _append_solid_panel(vertices, normals, panel) + return _array_mesh(vertices, normals) + +func _make_oriented_roof_mesh() -> ArrayMesh: + var vertices := PackedVector3Array() + var normals := PackedVector3Array() + var p0: Vector3 = custom_points[0] + var p1: Vector3 = custom_points[1] + var p2: Vector3 = custom_points[2] + var p3: Vector3 = custom_points[3] + var edge_01 := Vector2(p1.x - p0.x, p1.z - p0.z).length() + var edge_12 := Vector2(p2.x - p1.x, p2.z - p1.z).length() + var panels: Array = [] + if piece_type == PieceType.ROOF_GABLE: + if edge_01 <= edge_12: + var ridge_01 := (p0 + p1) * 0.5 + Vector3.UP * rise + var ridge_23 := (p2 + p3) * 0.5 + Vector3.UP * rise + panels.append([p0, p3, ridge_23, ridge_01]) + panels.append([ridge_01, ridge_23, p2, p1]) + else: + var ridge_12 := (p1 + p2) * 0.5 + Vector3.UP * rise + var ridge_30 := (p3 + p0) * 0.5 + Vector3.UP * rise + panels.append([p0, p1, ridge_12, ridge_30]) + panels.append([ridge_30, ridge_12, p2, p3]) + elif piece_type == PieceType.ROOF_PYRAMID: + var peak := (p0 + p1 + p2 + p3) * 0.25 + Vector3.UP * rise + panels.append([p0, p1, peak]) + panels.append([p1, p2, peak]) + panels.append([p2, p3, peak]) + panels.append([p3, p0, peak]) + else: + # The four points define the low and high edges. Keep their centers + # fixed when adjusting both edge widths in the Inspector. + var base_width := Vector2(p1.x - p0.x, p1.z - p0.z).length() + if base_width > 0.001 and roof_width > 0.0: + var direction := Vector3(p1.x - p0.x, 0.0, p1.z - p0.z).normalized() + var low_center := (p0 + p1) * 0.5 + var high_center := (p2 + p3) * 0.5 + var half_width := roof_width * 0.5 + panels.append([ + low_center - direction * half_width, + low_center + direction * half_width, + high_center + direction * half_width, + high_center - direction * half_width, + ]) + else: + panels.append([p0, p1, p2, p3]) + for panel in panels: + _append_solid_panel(vertices, normals, panel) + return _array_mesh(vertices, normals) + +func _make_stair_mesh() -> ArrayMesh: + var vertices := PackedVector3Array() + var normals := PackedVector3Array() + var start: Vector3 = custom_points[0] + var finish: Vector3 = custom_points[1] + var horizontal := Vector3(finish.x - start.x, 0.0, finish.z - start.z) + var run := horizontal.length() + var rise_amount := finish.y - start.y + if run < 0.05 or rise_amount <= 0.05 or stair_count < 1 or stair_width <= 0.0: + return _array_mesh(vertices, normals) + var forward := horizontal / run + var width_axis := Vector3(-forward.z, 0.0, forward.x) * stair_width * 0.5 + var profile := PackedVector2Array([Vector2(0.0, 0.0), Vector2(run, 0.0), Vector2(run, rise_amount)]) + for step_index in range(stair_count - 1, -1, -1): + var tread_start := run * float(step_index) / stair_count + var tread_end := run * float(step_index + 1) / stair_count + var tread_height := rise_amount * float(step_index + 1) / stair_count + profile.append(Vector2(tread_start, tread_height)) + if step_index > 0: + profile.append(Vector2(tread_start, rise_amount * float(step_index) / stair_count)) + var triangulation := Geometry2D.triangulate_polygon(profile) + for side_sign in [-1.0, 1.0]: + for triangle_index in range(0, triangulation.size(), 3): + var a := profile[triangulation[triangle_index]] + var b := profile[triangulation[triangle_index + 1]] + var c := profile[triangulation[triangle_index + 2]] + var point_a: Vector3 = start + forward * a.x + Vector3.UP * a.y + width_axis * side_sign + var point_b: Vector3 = start + forward * b.x + Vector3.UP * b.y + width_axis * side_sign + var point_c: Vector3 = start + forward * c.x + Vector3.UP * c.y + width_axis * side_sign + if side_sign > 0.0: + _add_tri(vertices, normals, point_a, point_b, point_c) + else: + _add_tri(vertices, normals, point_c, point_b, point_a) + for profile_index in range(profile.size()): + var next_index := (profile_index + 1) % profile.size() + var a := profile[profile_index] + var b := profile[next_index] + var point_a_left := start + forward * a.x + Vector3.UP * a.y - width_axis + var point_b_left := start + forward * b.x + Vector3.UP * b.y - width_axis + var point_b_right := start + forward * b.x + Vector3.UP * b.y + width_axis + var point_a_right := start + forward * a.x + Vector3.UP * a.y + width_axis + _add_quad(vertices, normals, point_a_left, point_b_left, point_b_right, point_a_right) + return _array_mesh(vertices, normals) + +func _make_fence_mesh() -> ArrayMesh: + var vertices := PackedVector3Array() + var normals := PackedVector3Array() + var start: Vector3 = custom_points[0] + var finish: Vector3 = custom_points[1] + var path := finish - start + var path_length := path.length() + if path_length < 0.05 or fence_height <= 0.0: + return _array_mesh(vertices, normals) + var path_axis := path / path_length + var post_count := fence_divisions + 2 + var post_positions: Array[Vector3] = [] + for post_index in range(post_count): + var base_position := start.lerp(finish, float(post_index) / float(post_count - 1)) + post_positions.append(base_position) + var side_axis := path_axis.cross(Vector3.UP).normalized() + if side_axis.length_squared() < 0.001: + side_axis = Vector3.FORWARD + _append_oriented_box(vertices, normals, base_position + Vector3.UP * fence_height * 0.5, path_axis, Vector3.UP, side_axis, Vector3(thickness, fence_height, thickness)) + for section_index in range(post_positions.size() - 1): + var section_start := post_positions[section_index] + var section_end := post_positions[section_index + 1] + var section_axis := (section_end - section_start).normalized() + var rail_up := Vector3.UP - section_axis * section_axis.dot(Vector3.UP) + if rail_up.length_squared() < 0.001: + rail_up = Vector3.FORWARD - section_axis * section_axis.dot(Vector3.FORWARD) + rail_up = rail_up.normalized() + var rail_side := section_axis.cross(rail_up).normalized() + var section_length := section_start.distance_to(section_end) + for height_ratio in [0.28, 0.78]: + var rail_center: Vector3 = (section_start + section_end) * 0.5 + Vector3.UP * fence_height * height_ratio + _append_oriented_box(vertices, normals, rail_center, section_axis, rail_up, rail_side, Vector3(section_length, thickness, thickness)) + return _array_mesh(vertices, normals) + +func _append_oriented_box(vertices: PackedVector3Array, normals: PackedVector3Array, center: Vector3, axis_x: Vector3, axis_y: Vector3, axis_z: Vector3, dimensions: Vector3) -> void: + var x := axis_x.normalized() * dimensions.x * 0.5 + var y := axis_y.normalized() * dimensions.y * 0.5 + var z := axis_z.normalized() * dimensions.z * 0.5 + var nnn := center - x - y - z + var pnn := center + x - y - z + var ppn := center + x + y - z + var npn := center - x + y - z + var nnp := center - x - y + z + var pnp := center + x - y + z + var ppp := center + x + y + z + var npp := center - x + y + z + _add_quad(vertices, normals, nnp, pnp, ppp, npp) + _add_quad(vertices, normals, pnn, nnn, npn, ppn) + _add_quad(vertices, normals, npp, ppp, ppn, npn) + _add_quad(vertices, normals, nnn, pnn, pnp, nnp) + _add_quad(vertices, normals, nnn, nnp, npp, npn) + _add_quad(vertices, normals, pnp, pnn, ppn, ppp) + +func _get_centered_gable_base() -> PackedVector3Array: + var selected_a := to_global(custom_points[0]) + var selected_b := to_global(custom_points[1]) + var search_root: Node = get_parent() + while search_root != null and not search_root is ModularBuilderPieceGeometry: + search_root = search_root.get_parent() + if search_root == null: + return PackedVector3Array([custom_points[0], custom_points[1]]) + var walls: Array[ModularBuilderPieceGeometry] = [] + _collect_centering_walls(search_root, walls) + var centered_a := selected_a + var centered_b := selected_b + var nearest_a := INF + var nearest_b := INF + for wall in walls: + if wall.custom_points.size() < 2: + continue + var wall_a := wall.to_global(wall.custom_points[0] + Vector3.UP * wall.unit_size) + var wall_b := wall.to_global(wall.custom_points[1] + Vector3.UP * wall.unit_size) + var tolerance: float = wall.thickness + 0.04 + for endpoint in [wall_a, wall_b]: + var distance_a := selected_a.distance_to(endpoint) + if distance_a < nearest_a and distance_a <= tolerance: + nearest_a = distance_a + centered_a = endpoint + var distance_b := selected_b.distance_to(endpoint) + if distance_b < nearest_b and distance_b <= tolerance: + nearest_b = distance_b + centered_b = endpoint + if nearest_a < INF and nearest_b < INF and centered_a.distance_to(centered_b) >= 0.02: + return PackedVector3Array([to_local(centered_a), to_local(centered_b)]) + return PackedVector3Array([custom_points[0], custom_points[1]]) + +func _collect_centering_walls(node: Node, walls: Array[ModularBuilderPieceGeometry]) -> void: + if node is ModularBuilderPieceGeometry and node.piece_type == PieceType.WALL: + walls.append(node) + for child in node.get_children(): + _collect_centering_walls(child, walls) + +func _append_solid_panel(vertices: PackedVector3Array, normals: PackedVector3Array, panel: Array) -> void: + if panel.size() < 3: + return + var p0: Vector3 = panel[0] + var p1: Vector3 = panel[1] + var p2: Vector3 = panel[2] + var normal: Vector3 = (p1 - p0).cross(p2 - p0).normalized() + if normal.is_zero_approx(): + return + var half_depth: Vector3 = normal * thickness * 0.5 + var front: Array[Vector3] = [] + var back: Array[Vector3] = [] + for point in panel: + front.append(point + half_depth) + back.append(point - half_depth) + for i in range(1, panel.size() - 1): + _add_tri(vertices, normals, front[0], front[i], front[i + 1]) + _add_tri(vertices, normals, back[i + 1], back[i], back[0]) + for i in range(panel.size()): + var next := (i + 1) % panel.size() + _add_quad(vertices, normals, front[i], back[i], back[next], front[next]) + +func _make_custom_wall_mesh() -> ArrayMesh: + var vertices := PackedVector3Array() + var normals := PackedVector3Array() + var wall_points: PackedVector3Array = _get_centered_wall_points() if center_align else custom_points + var a: Vector3 = wall_points[0] + var b: Vector3 = wall_points[1] + var direction := (b - a).normalized() + var length := a.distance_to(b) + var side := Vector3(-direction.z, 0.0, direction.x).normalized() * thickness * 0.5 + var height := Vector3.UP * unit_size + var openings: Array[PackedVector2Array] = [] + for child in get_children(): + if _is_detail_node(child) and int(child.get("detail_type")) != DETAIL_TYPE_HATCH and int(child.get("detail_type")) != DETAIL_TYPE_PILLAR: + var detail := child as Node3D + var center := Vector2((detail.position - a).dot(direction), detail.position.y - a.y) + var axis_x := Vector2(detail.transform.basis.x.dot(direction), detail.transform.basis.x.y).normalized() + var axis_y := Vector2(detail.transform.basis.y.dot(direction), detail.transform.basis.y.y).normalized() + var opening := PackedVector2Array([ + center - axis_x * float(detail.get("width")) * 0.5 - axis_y * float(detail.get("height")) * 0.5, + center + axis_x * float(detail.get("width")) * 0.5 - axis_y * float(detail.get("height")) * 0.5, + center + axis_x * float(detail.get("width")) * 0.5 + axis_y * float(detail.get("height")) * 0.5, + center - axis_x * float(detail.get("width")) * 0.5 + axis_y * float(detail.get("height")) * 0.5 + ]) + var wall_rect := PackedVector2Array([Vector2(0.0, 0.0), Vector2(length, 0.0), Vector2(length, unit_size), Vector2(0.0, unit_size)]) + for clipped_opening in Geometry2D.intersect_polygons(opening, wall_rect): + if clipped_opening.size() >= 3: + openings.append(clipped_opening) + var xs: Array[float] = [0.0, length] + var ys: Array[float] = [0.0, unit_size] + for opening in openings: + for point in opening: + xs.append(clampf(point.x, 0.0, length)) + ys.append(clampf(point.y, 0.0, unit_size)) + xs.sort() + ys.sort() + for xi in range(xs.size() - 1): + for yi in range(ys.size() - 1): + var u0: float = xs[xi] + var u1: float = xs[xi + 1] + var v0: float = ys[yi] + var v1: float = ys[yi + 1] + var mid := Vector2((u0 + u1) * 0.5, (v0 + v1) * 0.5) + var cell := PackedVector2Array([Vector2(u0, v0), Vector2(u1, v0), Vector2(u1, v1), Vector2(u0, v1)]) + var remaining: Array[PackedVector2Array] = [cell] + for opening in openings: + var next_remaining: Array[PackedVector2Array] = [] + for polygon in remaining: + for clipped in Geometry2D.clip_polygons(polygon, opening): + if clipped.size() >= 3: + next_remaining.append(clipped) + remaining = next_remaining + for polygon in remaining: + var indices := Geometry2D.triangulate_polygon(polygon) + for ti in range(0, indices.size(), 3): + var p0: Vector2 = polygon[indices[ti]] + var p1: Vector2 = polygon[indices[ti + 1]] + var p2: Vector2 = polygon[indices[ti + 2]] + var f0 := a + direction * p0.x + Vector3.UP * p0.y + var f1 := a + direction * p1.x + Vector3.UP * p1.y + var f2 := a + direction * p2.x + Vector3.UP * p2.y + _add_tri(vertices, normals, f0 + side, f1 + side, f2 + side) + _add_tri(vertices, normals, f2 - side, f1 - side, f0 - side) + # Close the wall body at its ends, top, and base. + _add_quad(vertices, normals, a - side, a + side, a + side + height, a - side + height) + _add_quad(vertices, normals, b + side, b - side, b - side + height, b + side + height) + _add_quad(vertices, normals, a + side + height, b + side + height, b - side + height, a - side + height) + _add_quad(vertices, normals, a - side, b - side, b + side, a + side) + for opening in openings: + for edge_index in range(opening.size()): + var p0 := opening[edge_index] + var p1 := opening[(edge_index + 1) % opening.size()] + var a0 := a + direction * p0.x + Vector3.UP * p0.y + var a1 := a + direction * p1.x + Vector3.UP * p1.y + _add_quad(vertices, normals, a0 + side, a0 - side, a1 - side, a1 + side) + return _array_mesh(vertices, normals) + +func _get_centered_wall_points() -> PackedVector3Array: + if custom_points.size() < 2: + return custom_points + var selected_a := to_global(custom_points[0]) + var selected_b := to_global(custom_points[1]) + var search_root: Node = get_parent() + while search_root != null and not search_root is ModularBuilderPieceGeometry: + search_root = search_root.get_parent() + if search_root == null: + return custom_points + var walls: Array[ModularBuilderPieceGeometry] = [] + _collect_centering_walls(search_root, walls) + var centered_a := selected_a + var centered_b := selected_b + var nearest_a := INF + var nearest_b := INF + for wall in walls: + if wall == self or wall.custom_points.size() < 2: + continue + var direction := (wall.custom_points[1] - wall.custom_points[0]).normalized() + var side := Vector3(-direction.z, 0.0, direction.x).normalized() * wall.thickness * 0.5 + for endpoint in wall.custom_points: + var center := wall.to_global(endpoint + Vector3.UP * wall.unit_size) + for surface_corner in [center + side, center - side]: + var distance_a := selected_a.distance_to(surface_corner) + if distance_a < nearest_a and distance_a <= wall.thickness + 0.04: + nearest_a = distance_a + centered_a = center + var distance_b := selected_b.distance_to(surface_corner) + if distance_b < nearest_b and distance_b <= wall.thickness + 0.04: + nearest_b = distance_b + centered_b = center + if nearest_a < INF and nearest_b < INF and centered_a.distance_to(centered_b) >= 0.02: + return PackedVector3Array([to_local(centered_a), to_local(centered_b)]) + return custom_points + +func _make_custom_floor_mesh() -> ArrayMesh: + var polygon: Array[Vector2] = [] + for point in custom_points: + polygon.append(Vector2(point.x, point.z)) + var hatch_mesh := _make_hatch_surface_mesh(polygon, custom_points[0].y, custom_points[0].y - thickness) + if hatch_mesh != null: + return hatch_mesh + var vertices := PackedVector3Array() + var normals := PackedVector3Array() + var points := custom_points + var bottom: Array[Vector3] = [] + for point in points: + bottom.append(point - Vector3.UP * thickness) + for i in range(1, points.size() - 1): + _add_tri(vertices, normals, points[0], points[i + 1], points[i]) + _add_tri(vertices, normals, bottom[0], bottom[i], bottom[i + 1]) + for i in range(points.size()): + var j := (i + 1) % points.size() + _add_quad(vertices, normals, bottom[i], bottom[j], points[j], points[i]) + return _array_mesh(vertices, normals) + +func _make_hatch_surface_mesh(polygon: Array[Vector2], top_y: float, bottom_y: float) -> ArrayMesh: + var openings: Array[PackedVector2Array] = [] + for child in get_children(): + if _is_detail_node(child) and int(child.get("detail_type")) == DETAIL_TYPE_HATCH: + var detail := child as Node3D + var center := Vector2(detail.position.x, detail.position.z) + var axis_x := Vector2(detail.transform.basis.x.x, detail.transform.basis.x.z).normalized() + var axis_y := Vector2(detail.transform.basis.z.x, detail.transform.basis.z.z).normalized() + var opening := PackedVector2Array([ + center - axis_x * float(detail.get("width")) * 0.5 - axis_y * float(detail.get("height")) * 0.5, + center + axis_x * float(detail.get("width")) * 0.5 - axis_y * float(detail.get("height")) * 0.5, + center + axis_x * float(detail.get("width")) * 0.5 + axis_y * float(detail.get("height")) * 0.5, + center - axis_x * float(detail.get("width")) * 0.5 + axis_y * float(detail.get("height")) * 0.5 + ]) + openings.append(opening) + if openings.is_empty() or polygon.size() < 3: + return null + var min_x := polygon[0].x + var max_x := polygon[0].x + var min_z := polygon[0].y + var max_z := polygon[0].y + var xs: Array[float] = [] + var zs: Array[float] = [] + for point in polygon: + min_x = minf(min_x, point.x) + max_x = maxf(max_x, point.x) + min_z = minf(min_z, point.y) + max_z = maxf(max_z, point.y) + xs.append(point.x) + zs.append(point.y) + for opening in openings: + for point in opening: + xs.append(clampf(point.x, min_x, max_x)) + zs.append(clampf(point.y, min_z, max_z)) + xs.sort() + zs.sort() + var vertices := PackedVector3Array() + var normals := PackedVector3Array() + var source_polygon := PackedVector2Array() + for point in polygon: + source_polygon.append(point) + for xi in range(xs.size() - 1): + for zi in range(zs.size() - 1): + var x0: float = xs[xi] + var x1: float = xs[xi + 1] + var z0: float = zs[zi] + var z1: float = zs[zi + 1] + if x1 - x0 < 0.0001 or z1 - z0 < 0.0001: + continue + var cell := PackedVector2Array([Vector2(x0, z0), Vector2(x1, z0), Vector2(x1, z1), Vector2(x0, z1)]) + var remaining: Array[PackedVector2Array] = [] + for clipped_surface in Geometry2D.intersect_polygons(source_polygon, cell): + remaining.append(clipped_surface) + for opening in openings: + var next_remaining: Array[PackedVector2Array] = [] + for surface_polygon in remaining: + for clipped_surface in Geometry2D.clip_polygons(surface_polygon, opening): + if clipped_surface.size() >= 3: + next_remaining.append(clipped_surface) + remaining = next_remaining + for clipped_surface in remaining: + var triangulated := Geometry2D.triangulate_polygon(clipped_surface) + for ti in range(0, triangulated.size(), 3): + var a: Vector2 = clipped_surface[triangulated[ti]] + var b: Vector2 = clipped_surface[triangulated[ti + 1]] + var c: Vector2 = clipped_surface[triangulated[ti + 2]] + _add_tri(vertices, normals, Vector3(a.x, top_y, a.y), Vector3(c.x, top_y, c.y), Vector3(b.x, top_y, b.y)) + _add_tri(vertices, normals, Vector3(a.x, bottom_y, a.y), Vector3(b.x, bottom_y, b.y), Vector3(c.x, bottom_y, c.y)) + for i in range(polygon.size()): + var j := (i + 1) % polygon.size() + var a := polygon[i] + var b := polygon[j] + _add_quad(vertices, normals, Vector3(a.x, bottom_y, a.y), Vector3(b.x, bottom_y, b.y), Vector3(b.x, top_y, b.y), Vector3(a.x, top_y, a.y)) + for opening in openings: + var visible_edges := Geometry2D.intersect_polygons(opening, source_polygon) + for visible_opening in visible_edges: + for edge_index in range(visible_opening.size()): + var p0 := visible_opening[edge_index] + var p1 := visible_opening[(edge_index + 1) % visible_opening.size()] + _add_quad(vertices, normals, Vector3(p0.x, bottom_y, p0.y), Vector3(p0.x, top_y, p0.y), Vector3(p1.x, top_y, p1.y), Vector3(p1.x, bottom_y, p1.y)) + return _array_mesh(vertices, normals) + +func _is_detail_node(node: Node) -> bool: + if not node is Node3D or node.get_script() == null: + return false + return node.get_script().resource_path == DETAIL_SCRIPT_PATH + +func _make_custom_foundation_mesh() -> ArrayMesh: + var polygon: Array[Vector2] = [] + for point in custom_points: + polygon.append(Vector2(point.x, point.z)) + var bottom_y := -thickness * 0.5 if centered_origin else 0.0 + var top_y := thickness * 0.5 if centered_origin else thickness + var hatch_mesh := _make_hatch_surface_mesh(polygon, top_y, bottom_y) + if hatch_mesh != null: + return hatch_mesh + var vertices := PackedVector3Array() + var normals := PackedVector3Array() + for i in range(1, custom_points.size() - 1): + var a := custom_points[0] + var b := custom_points[i] + var c := custom_points[i + 1] + _add_tri(vertices, normals, Vector3(a.x, top_y, a.z), Vector3(c.x, top_y, c.z), Vector3(b.x, top_y, b.z)) + _add_tri(vertices, normals, Vector3(a.x, bottom_y, a.z), Vector3(b.x, bottom_y, b.z), Vector3(c.x, bottom_y, c.z)) + for i in range(custom_points.size()): + var j := (i + 1) % custom_points.size() + var a := custom_points[i] + var b := custom_points[j] + _add_quad(vertices, normals, Vector3(a.x, bottom_y, a.z), Vector3(b.x, bottom_y, b.z), Vector3(b.x, top_y, b.z), Vector3(a.x, top_y, a.z)) + return _array_mesh(vertices, normals) + +func _add_quad(v: PackedVector3Array, n: PackedVector3Array, a: Vector3, b: Vector3, c: Vector3, d: Vector3) -> void: + _add_tri(v, n, a, b, c) + _add_tri(v, n, a, c, d) + +func _array_mesh(v: PackedVector3Array, n: PackedVector3Array) -> ArrayMesh: + var arrays: Array = [] + arrays.resize(Mesh.ARRAY_MAX) + arrays[Mesh.ARRAY_VERTEX] = v + arrays[Mesh.ARRAY_NORMAL] = n + var result := ArrayMesh.new() + result.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, arrays) + return result + +func _add_tri(v: PackedVector3Array, n: PackedVector3Array, a: Vector3, b: Vector3, c: Vector3) -> void: + var normal := (b - a).cross(c - a).normalized() + v.append(a) + v.append(b) + v.append(c) + n.append(normal) + n.append(normal) + n.append(normal) + # Also generate reversed faces to show both sides. + # This keeps floors and foundations visible from below with any material. + v.append(c) + v.append(b) + v.append(a) + n.append(-normal) + n.append(-normal) + n.append(-normal) diff --git a/vendor/modular_builder/modular_piece_geometry.gd.uid b/vendor/modular_builder/modular_piece_geometry.gd.uid new file mode 100644 index 0000000..a2905f8 --- /dev/null +++ b/vendor/modular_builder/modular_piece_geometry.gd.uid @@ -0,0 +1 @@ +uid://jkyypf7girrd diff --git a/viewport/gizmo.gd b/viewport/gizmo.gd new file mode 100644 index 0000000..4fa020a --- /dev/null +++ b/viewport/gizmo.gd @@ -0,0 +1,628 @@ +extends Node3D +## Achsen-Gizmo (Karte t_e0120dc2): drei farbige Pfeile (X rot, Y grün, +## Z blau) am EINZELN markierten Objekt. Zieht man einen Pfeil, bewegt sich +## das Objekt GENAU entlang dieser Achse — die Zahlen im Objekt-Inspektor +## laufen LIVE mit. Mausrad WÄHREND des Ziehens wechselt die Schrittweite +## (fein/normal/grob); derselbe Wert steht als „Schrittweite“-Feld im +## rechten Panel (main.gd). +## +## Regeln der Karte: +## - NUR Einzelauswahl (Mehrfachauswahl bekommt kein Gizmo — Folgekarte). +## - JEDER Zug = EIN Undo-Schritt (Commit beim Loslassen). Esc bricht EXAKT +## auf die Startposition zurück (byte-identisch, wie grab_cancel). +## - Zieh-Werte rasten auf Vielfache der Schrittweite (Voreinstellungen +## 0,1 / 0,5 / 2 m; das Feld im Panel nimmt jeden Wert 0,01–10 m). +## - Klemmen wie der Inspektor: X/Z an der Map-Grenze, Y nie unter dem +## Terrain (X/Z-Zug folgt dem Boden wie der normale Objekt-Zug) und +## oben an der Höhen-Grenze. +## +## Eingabe-Verdrahtung: dieses Gizmo hängt als KIND an interaction.gd — +## Knoten bekommen _unhandled_input TIEFER IM BAUM ZUERST, so fängt es +## Pfeil-Klicks ab, BEVOR die Auswahl-/Zieh-Logik des Parents sie sieht. +## interaction.gd bleibt dadurch UNVERÄNDERT (Karten-Grenze) und der +## bestehende Klick-/Zieh-Pfad wird 1:1 wiederverwendet. + +const SvmapDocument := preload("res://core/svmap/map_document.gd") + +const AXIS_LEN := 2.2 # Pfeil-Länge in Metern (Weltmaß) +const SHAFT_R := 0.045 +const CONE_H := 0.45 +const CONE_R := 0.13 +const HIT_PX := 18.0 # Treffer-Toleranz am Bildschirm (Pixel) +const MIN_PX_PER_M := 10.0 # Zieh-Sensitivität deckeln (Achse fast im Blick) +const STEP_MIN := 0.01 +const STEP_MAX := 10.0 + +const STEP_PRESETS := [0.1, 0.5, 2.0] +const STEP_PRESET_NAMES := ["fein", "normal", "grob"] + +const AXES := { + "x": Vector3(1.0, 0.0, 0.0), + "y": Vector3(0.0, 1.0, 0.0), + "z": Vector3(0.0, 0.0, 1.0), +} +const AXIS_COLORS := { + "x": Color(1.0, 0.25, 0.25), + "y": Color(0.3, 0.95, 0.35), + "z": Color(0.35, 0.55, 1.0), +} + +var main # core/ui/main.gd (script-erweitert) +var camera: Camera3D +var view_builder # core/viewport/map_view_builder.gd + +var step_m := 0.5 # Schrittweite (m) — Panel-Feld + Mausrad-Presets + +# --- Zieh-Zustand --- +var _dragging := false +var _drag_idx := -1 +var _drag_axis := "" +var _drag_axis_vec := Vector3.ZERO +var _press_screen := Vector2.ZERO +var _screen_axis := Vector2.RIGHT # Achse am Bildschirm (normalisiert, px) +var _px_per_m := 1.0 +var _start_pos := Vector3.ZERO # doc-Position beim Zieh-Start +var _start_saved: Array = [] # exakte Start-Position für Esc-Rückabwicklung +var _drag_lift := 0.0 # Boden-Abstand (X/Z-Zug folgt dem Terrain) +var _drag_moved := false +var _last_delta := 0.0 # zuletzt angewendeter Delta (m) — 0 = kein Commit +var _drag_before: Dictionary = {} # History-Snapshot VOR dem Zug + +var _arrows := {} # "x"/"y"/"z" → Node3D (Pfeil-Root) + +# --- Dreh-/Kipp-Modus (25.10.): Ringe um alle drei Achsen ------------------- +const RING_R := 1.5 # Ring-Radius in Metern +const RING_SEGMENTS := 48 +const ROT_STEP_DEG := 15.0 +var mode := "move" # "move" = Pfeile, "rotate" = Ringe +var rot_step_deg := ROT_STEP_DEG +var _rings := {} # "x"/"y"/"z" → MeshInstance3D +var _rot_dragging := false +var _rot_axis := "" +var _rot_center := Vector2.ZERO +var _rot_start_angle := 0.0 +var _rot_applied := 0.0 # bisher angewendete (gerastete) Grad +var _rot_suffix := "" # merge-Kennung: EIN Undo-Schritt pro Zug +var _rot_serial := 0 + + +func setup(p_main, p_camera: Camera3D, p_builder) -> void: + main = p_main + camera = p_camera + view_builder = p_builder + _build_arrows() + _build_rings() + _apply_mode_visibility() + visible = false + + +## Pfeile bauen: Schaft (Zylinder) + Spitze (Kegel), ungeschattet und OHNE +## Tiefentest — die Pfeile bleiben auch vor/über Objekten gut sichtbar. +func _build_arrows() -> void: + for a in AXES: + var root := Node3D.new() + # Alle Pfeile zeigen lokal +Y; der Root dreht sie auf die Welt-Achse. + if a == "x": + root.rotation.z = -PI / 2.0 # +Y → +X + elif a == "z": + root.rotation.x = PI / 2.0 # +Y → +Z + var mat := StandardMaterial3D.new() + mat.albedo_color = AXIS_COLORS[a] + mat.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED + mat.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA + mat.no_depth_test = true + mat.render_priority = 20 + var shaft := MeshInstance3D.new() + var cyl := CylinderMesh.new() + cyl.top_radius = SHAFT_R + cyl.bottom_radius = SHAFT_R + cyl.height = AXIS_LEN + shaft.mesh = cyl + shaft.material_override = mat + shaft.cast_shadow = GeometryInstance3D.SHADOW_CASTING_SETTING_OFF + shaft.position.y = AXIS_LEN * 0.5 + root.add_child(shaft) + var tip := MeshInstance3D.new() + var cone := CylinderMesh.new() + cone.top_radius = 0.0 + cone.bottom_radius = CONE_R + cone.height = CONE_H + tip.mesh = cone + tip.material_override = mat + tip.cast_shadow = GeometryInstance3D.SHADOW_CASTING_SETTING_OFF + tip.position.y = AXIS_LEN + CONE_H * 0.5 + root.add_child(tip) + add_child(root) + _arrows[a] = root + + +## Drehringe bauen: je Achse ein dünner Torus, ungeschattet, ohne Tiefentest. +func _build_rings() -> void: + for a in AXES: + var mat := StandardMaterial3D.new() + mat.albedo_color = AXIS_COLORS[a] + mat.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED + mat.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA + mat.no_depth_test = true + mat.render_priority = 20 + var ring := MeshInstance3D.new() + var torus := TorusMesh.new() + torus.inner_radius = RING_R - 0.06 + torus.outer_radius = RING_R + 0.06 + torus.rings = 48 + torus.ring_segments = 8 + ring.mesh = torus + ring.material_override = mat + ring.cast_shadow = GeometryInstance3D.SHADOW_CASTING_SETTING_OFF + # Torus liegt lokal in der XZ-Ebene (Achse = Y). + if a == "x": + ring.rotation.z = PI / 2.0 + elif a == "z": + ring.rotation.x = PI / 2.0 + ring.visible = false + add_child(ring) + _rings[a] = ring + + +## Modus wechseln ("move" = Verschieben, "rotate" = Drehen/Kippen). +func set_mode(m: String) -> void: + if m != "move" and m != "rotate": + return + if _dragging: + _finish_drag(false) + if _rot_dragging: + _finish_rotate(false) + mode = m + var inter = main.get("interaction") if main != null else null + if inter != null: + inter.no_drag_move = (m == "rotate") + _apply_mode_visibility() + + +func _apply_mode_visibility() -> void: + for a in _arrows: + (_arrows[a] as Node3D).visible = mode == "move" + for a in _rings: + (_rings[a] as Node3D).visible = mode == "rotate" + + +func _axis_vec(a: String) -> Vector3: + return AXES.get(a, Vector3.ZERO) as Vector3 + + +## Sichtbarkeit + Position JEDES Frames aus der Auswahl ableiten (kein +## Verdrahten jedes Auswahl-Wegs nötig — Auswahl kommt aus interaction.gd, +## Baum, Undo/Redo, Inspektor … alles landet automatisch hier). +func _process(_delta: float) -> void: + if main == null or view_builder == null: + return + var inter = main.get("interaction") + if inter == null: + return + var sel: Array = inter.selected_indices + if sel.size() != 1: + visible = false + return + if bool(inter.get("placing")): + visible = false # Ghost-Platzieren: keine Pfeile im Weg + return + var idx: int = int(inter.selected_index) + var markers: Array = view_builder.object_markers + if idx < 0 or idx >= markers.size(): + visible = false + return + var marker = markers[idx] + if marker == null or not is_instance_valid(marker): + visible = false + return + visible = true + global_position = marker.global_position + + +func _unhandled_input(event: InputEvent) -> void: + var p := MousePointer.from_input(event) + if p != null and handle_pointer(p): + get_viewport().set_input_as_handled() + + +func handle_pointer(p: PointerEvent) -> bool: + if main == null or camera == null: + return false + var doc: Dictionary = main.get("doc") + if doc == null or doc.is_empty(): + return false + var tool_mode: String = str(main.get("tool_mode")) + if tool_mode == "terrain" or tool_mode == "spawns": + return false # Terrain-Pinsel / Spawn-Zonen haben das Zepter + match p.kind: + PointerEvent.Kind.PRESS: + if _dragging: + return false + var inter = main.get("interaction") + if inter == null or bool(inter.get("placing")): + return false + if mode == "rotate": + var ring_axis := pick_ring(p.position) + if ring_axis != "": + _begin_rotate(ring_axis, p.position) + return true + return false + var axis := pick(p.position) + if axis != "": + _begin_drag(axis, p.position) + return true + PointerEvent.Kind.RELEASE: + if _rot_dragging: + _finish_rotate(true) + return true + if _dragging: + _finish_drag(true) + return true + PointerEvent.Kind.SCROLL: + if _rot_dragging: + return true # Mausrad zoomt nicht mitten im Dreh-Zug + if _dragging: + cycle_step(p.scroll) + return true + PointerEvent.Kind.MOVE: + if _rot_dragging: + _rotate_motion(p.position) + return true + if _dragging: + _drag_motion(p.position) + return true + PointerEvent.Kind.CANCEL: + if _rot_dragging: + _finish_rotate(false) + return true + if _dragging: + _finish_drag(false) + return true + return false + + +# ------------------------------------------------------------- Treffer ----- + +## Achse unter dem Cursor (Bildschirm-Segment-Distanz) — "" = kein Pfeil. +func pick(screen_pos: Vector2) -> String: + if not visible: + return "" + var o := _safe_unproject(global_position) + if o == Vector2.INF: + return "" + var best := "" + var best_d := HIT_PX + for a in AXES: + var t := _safe_unproject(global_position + _axis_vec(a) * AXIS_LEN) + if t == Vector2.INF: + continue + var d := _dist_point_segment(screen_pos, o, t) + if d < best_d: + best_d = d + best = a + return best + + +## Ring unter dem Cursor (Abstand zum projizierten Kreis) — "" = keiner. +func pick_ring(screen_pos: Vector2) -> String: + if not visible or mode != "rotate": + return "" + var best := "" + var best_d := HIT_PX * 1.6 + for a in AXES: + var pts := _ring_screen_points(a) + for i in pts.size() - 1: + if pts[i] == Vector2.INF or pts[i + 1] == Vector2.INF: + continue + var d := _dist_point_segment(screen_pos, pts[i], pts[i + 1]) + if d < best_d: + best_d = d + best = a + return best + + +func _ring_screen_points(a: String) -> Array: + var axis := _axis_vec(a) + var u := axis.cross(Vector3.UP if absf(axis.dot(Vector3.UP)) < 0.9 else Vector3.RIGHT).normalized() + var v := axis.cross(u).normalized() + var out: Array = [] + for i in RING_SEGMENTS + 1: + var t := TAU * float(i) / float(RING_SEGMENTS) + out.append(_safe_unproject(global_position + (u * cos(t) + v * sin(t)) * RING_R)) + return out + + +func _safe_unproject(p: Vector3) -> Vector2: + if camera == null: + return Vector2.INF + if camera.is_position_behind(p): + return Vector2.INF + return camera.unproject_position(p) + + +func _dist_point_segment(p: Vector2, a: Vector2, b: Vector2) -> float: + var ab := b - a + var len_sq := ab.length_squared() + if len_sq < 0.0001: + return p.distance_to(a) + var t := clampf((p - a).dot(ab) / len_sq, 0.0, 1.0) + return p.distance_to(a + ab * t) + + +# -------------------------------------------------------------- Ziehen ----- + +func _begin_drag(axis: String, mb_pos: Vector2) -> void: + if not _begin_drag_state(axis): + return + # Bildschirm-Mathe: Achse in Pixeln → Zieh-Sensitivität (Meter pro Pixel). + var markers: Array = view_builder.object_markers + var marker = markers[_drag_idx] + var origin: Vector3 = marker.global_position + var o := _safe_unproject(origin) + var t := _safe_unproject(origin + _drag_axis_vec * AXIS_LEN) + if o == Vector2.INF or t == Vector2.INF: + _dragging = false + return + var seg := t - o + var seg_len := seg.length() + if seg_len < 1.0: + _dragging = false + return + _screen_axis = seg.normalized() + _px_per_m = maxf(seg_len / AXIS_LEN, MIN_PX_PER_M) + _press_screen = mb_pos + main.call("_set_status", "Gizmo-Zug: entlang %s ziehen — Mausrad wechselt die Schrittweite (%.2f m), Esc bricht ab." % [ + _drag_axis.to_upper(), step_m]) + + +## Zieh-Zustand NUR aus dem Doc/Marke r aufsetzen (ohne Bildschirm-Mathe — +## auch für den Demo-/Test-Hook demo_drag_axis). +func _begin_drag_state(axis: String) -> bool: + var inter = main.get("interaction") + if inter == null or inter.selected_indices.size() != 1: + return false + var idx: int = int(inter.selected_index) + var markers: Array = view_builder.object_markers + if idx < 0 or idx >= markers.size(): + return false + var marker = markers[idx] + if marker == null or not is_instance_valid(marker): + return false + var objects: Array = main.doc.get("objects", []) + if idx >= objects.size(): + return false + var pos: Array = (objects[idx] as Dictionary).get("pos", [0.0, 0.0, 0.0]) + _drag_idx = idx + _drag_axis = axis + _drag_axis_vec = _axis_vec(axis) + _press_screen = Vector2.ZERO + _start_pos = Vector3(float(pos[0]), float(pos[1]), float(pos[2])) + _start_saved = (pos as Array).duplicate() + _drag_lift = marker.position.y - SvmapDocument.terrain_height_at( + main.doc, _start_pos.x, _start_pos.z) + _drag_before = main.history.snapshot(["objects"]) + _drag_moved = false + _last_delta = 0.0 + _dragging = true + return true + + +func _drag_motion(mb_pos: Vector2) -> void: + var d := mb_pos - _press_screen + var raw := d.dot(_screen_axis) / _px_per_m + _apply_axis_delta(snappedf(raw, step_m)) + + +## Delta entlang der Achse anwenden: doc + Marke + Gizmo, Inspektor LIVE. +func _apply_axis_delta(delta: float) -> void: + if not _dragging or absf(delta - _last_delta) < 0.0005: + return + var objects: Array = main.doc.get("objects", []) + if _drag_idx >= objects.size(): + _finish_drag(false) + return + var np := _start_pos + _drag_axis_vec * delta + var half := _terrain_half() + np.x = clampf(np.x, -half.x, half.x) + np.z = clampf(np.z, -half.y, half.y) + if _drag_axis == "y": + np.y = clampf(np.y, SvmapDocument.terrain_height_at(main.doc, np.x, np.z), _max_y()) + else: + # X/Z-Zug folgt dem Boden (gleiches Verhalten wie der normale Zug): + # der Boden-Abstand bleibt erhalten, nichts begräbt sich. + np.y = SvmapDocument.terrain_height_at(main.doc, np.x, np.z) + _drag_lift + var obj: Dictionary = objects[_drag_idx] + obj["pos"] = [np.x, np.y, np.z] + var markers: Array = view_builder.object_markers + if _drag_idx < markers.size(): + var marker = markers[_drag_idx] + if marker != null and is_instance_valid(marker): + marker.position = np + global_position = np + _last_delta = delta + _drag_moved = true + main.call("_sync_selection_panel") # Inspektor-Zahlen LIVE mitziehen + + +## Zug beenden: commit = true → EIN Undo-Schritt (wirklich bewegt), +## commit = false → exakte Rückabwicklung, KEIN History-Eintrag. +func _finish_drag(commit: bool) -> void: + if not _dragging: + return + _dragging = false + var objects: Array = main.doc.get("objects", []) + var idx := _drag_idx + if commit and absf(_last_delta) > 0.0005 and idx >= 0 and idx < objects.size(): + var desc: String + match _drag_axis: + "x": + desc = "Objekt entlang X verschoben (Gizmo)" + "y": + desc = "Objekt angehoben/abgesenkt (Gizmo, Y-Achse)" + _: + desc = "Objekt entlang Z verschoben (Gizmo)" + main.history.commit(desc, _drag_before, main.history.snapshot(["objects"])) + main.set("dirty", true) + main.call("_refresh_file_label") + main.call("_refresh_history_buttons") + main.call("_refresh_stats") + main.call("_sync_selection_panel") + main.call("_set_status", "%s — %.2f m. Strg+Z nimmt den Zug zurück; Mausrad WÄHREND des Ziehens wechselt fein/grob." % [ + desc, absf(_last_delta)]) + elif not commit and idx >= 0 and idx < objects.size(): + (objects[idx] as Dictionary)["pos"] = _start_saved.duplicate() + var markers: Array = view_builder.object_markers + if idx < markers.size(): + var marker = markers[idx] + if marker != null and is_instance_valid(marker): + marker.position = _start_pos + global_position = _start_pos + main.call("_sync_selection_panel") + main.call("_set_status", "Gizmo-Zug abgebrochen — Position wie vorher.") + _drag_before = {} + _drag_idx = -1 + _drag_axis = "" + _drag_moved = false + _last_delta = 0.0 + + +## Für die Esc-Kette in main.gd: Zug abbrechen, falls einer läuft. true = +## es lief einer und wurde abgebrochen (idempotent, weil _dragging prüft). +func cancel_drag_if_active() -> bool: + if _rot_dragging: + _finish_rotate(false) + return true + if not _dragging: + return false + _finish_drag(false) + return true + + +# --------------------------------------------------- Drehen / Kippen ------- + +func _ring_angle(mouse: Vector2) -> float: + var d := mouse - _rot_center + return atan2(d.y, d.x) + + +func _begin_rotate(axis: String, mouse: Vector2) -> void: + var inter = main.get("interaction") + if inter == null or inter.selected_indices.is_empty(): + return + var c := _safe_unproject(global_position) + if c == Vector2.INF: + return + _rot_axis = axis + _rot_center = c + _rot_start_angle = _ring_angle(mouse) + _rot_applied = 0.0 + _rot_serial += 1 + _rot_suffix = "#g%d" % _rot_serial + _rot_dragging = true + var name := "Drehen (Y)" if axis == "y" else ("Kippen um X" if axis == "x" else "Kippen um Z") + main.call("_set_status", "%s — Ring ziehen, rastet in %.0f°-Schritten; Esc bricht ab, Strg+Z nimmt den Zug zurück." % [name, rot_step_deg]) + + +func _rotate_motion(mouse: Vector2) -> void: + # Bildschirmwinkel → Drehwinkel um die Achse (Vorzeichen je nach Blickrichtung). + var delta_screen := wrapf(_ring_angle(mouse) - _rot_start_angle, -PI, PI) + var facing := _axis_vec(_rot_axis).dot(camera.global_transform.basis.z) + var deg := -rad_to_deg(delta_screen) * (1.0 if facing >= 0.0 else -1.0) + var snapped_deg := snappedf(deg, rot_step_deg) + _rotate_to(snapped_deg) + + +## Auf einen Gesamtwinkel (gerastet) nachführen — in Schritten, EIN Undo-Eintrag. +func _rotate_to(total_deg: float) -> void: + var diff := total_deg - _rot_applied + if absf(diff) < 0.001: + return + var inter = main.get("interaction") + if inter == null: + return + if _rot_axis == "y": + inter.rotate_selected(diff, _rot_suffix) + else: + inter.tilt_selected(_rot_axis == "x", diff, _rot_suffix) + _rot_applied = total_deg + + +func _finish_rotate(commit: bool) -> void: + if not _rot_dragging: + return + _rot_dragging = false + if not commit and absf(_rot_applied) > 0.001: + main.call("_do_undo") # der ganze Zug ist EIN Eintrag → komplett zurück + main.call("_set_status", "Dreh-Zug abgebrochen — Objekt wie vorher.") + _rot_axis = "" + _rot_applied = 0.0 + + +## Probes/Tests: derselbe Pfad wie ein echter Ring-Zug (ohne Maus-Mathe). +func demo_rotate_axis(axis: String, deg: float) -> bool: + var inter = main.get("interaction") if main != null else null + if inter == null or inter.selected_indices.is_empty() or absf(deg) < 0.001: + return false + _rot_axis = axis + _rot_serial += 1 + _rot_suffix = "#g%d" % _rot_serial + _rot_applied = 0.0 + _rotate_to(snappedf(deg, rot_step_deg)) + _rot_axis = "" + _rot_applied = 0.0 + return true + + +# ------------------------------------------------------ Schrittweite ------- + +## Mausrad WÄHREND des Ziehens: durch die Voreinstellungen blättern +## (fein 0,1 → normal 0,5 → grob 2,0 m, wrappt). Das Panel-Feld folgt. +func cycle_step(dir: int) -> void: + var idx := STEP_PRESETS.find(step_m) + if idx < 0: + idx = STEP_PRESETS.size() - 1 # eigener Feld-Wert: vom größten Preset starten + idx = wrapi(idx + dir, 0, STEP_PRESETS.size()) + set_step_m(STEP_PRESETS[idx]) + main.call("_set_status", "Gizmo-Schrittweite: %.2f m (%s) — Mausrad wechselt weiter, das Feld rechts setzt sie exakt." % [ + step_m, STEP_PRESET_NAMES[idx]]) + + +## Feld-Wert übernehmen (Panel-Feld ODER Mausrad-Preset). Haupt-Var hält den +## Wert über UI-Rebuilds (UIScale) hinweg. +func set_step_m(v: float) -> void: + step_m = clampf(v, STEP_MIN, STEP_MAX) + if main != null: + main.set("gizmo_step_m", step_m) + + +# ------------------------------------------------------- Demo-/Test-Hook --- + +## Probes/Tests: denselben Anwendungs- + Commit-Pfad wie ein echter Zug, +## ohne Bildschirm-Mathe. true = es wurde wirklich bewegt + committed. +func demo_drag_axis(axis: String, meters: float) -> bool: + if main == null: + return false + var applied := snappedf(meters, step_m) + if absf(applied) < 0.0005: + return false + if not _begin_drag_state(axis): + return false + _apply_axis_delta(applied) + _finish_drag(true) + return true + + +# ------------------------------------------------------------ Helfer ------- + +func _terrain_half() -> Vector2: + var terrain: Dictionary = main.doc.get("terrain", {}) + return Vector2(float(terrain.get("size_x_m", 1024.0)), + float(terrain.get("size_z_m", 1024.0))) * 0.5 + + +func _max_y() -> float: + var bounds: Dictionary = main.doc.get("bounds", {}) + var mx = bounds.get("max", null) + if mx is Array and (mx as Array).size() == 3: + return float((mx as Array)[1]) + return 80.0 diff --git a/viewport/gizmo.gd.uid b/viewport/gizmo.gd.uid new file mode 100644 index 0000000..c114071 --- /dev/null +++ b/viewport/gizmo.gd.uid @@ -0,0 +1 @@ +uid://bchu6tv6aetfh diff --git a/viewport/glb_mesh_store.gd b/viewport/glb_mesh_store.gd new file mode 100644 index 0000000..e4f3eda --- /dev/null +++ b/viewport/glb_mesh_store.gd @@ -0,0 +1,450 @@ +extends RefCounted +class_name GlbMeshStore +## Echte GLB-Renderings für Bibliotheks-Objekte im Editor-Viewport +## (Karte t_9b50b231). Der Viewport-Bauer zeigt bisher nur den +## Kollisions-Platzhalter (MeshShapes.make_placeholder) — diese statische +## Loader-Schicht holt stattdessen das ECHTE Modell aus dem Mesh-Lager +## (Sibling-Repos, gleiche Quellen wie tools/gen_thumbs.gd) und fällt ohne +## GLB auf den Platzhalter zurück. +## +## Messkonvention wie addons/modular_builder/scopedvr_export.gd +## `normalisiere`: das geladene Mesh wird in Fußpunkt-Koordinaten gebacken — +## Unterkante auf y = 0, XZ um den Mittelpunkt zentriert. Pack-GLBs haben +## ihren Mesh-Ursprung oft in der Mitte, deshalb wird die AABB-Unterkante +## GERECHNET und nie blind platziert. Damit gilt wie beim Compound-Platzhalter: +## MeshShapes.half_height(mesh) == 0 und marker.position == Fußpunkt. +## +## Plattform-Regel (PLAN.md): nur relative Kandidaten-Pfade, konfigurierbar +## über ProjectSettings — läuft identisch auf Linux und Windows. +## +## Performance: EIN Parse pro OID, Ergebnis gecacht — der Rebuild bei jedem +## Platzieren/Undo liest nur noch aus dem Cache. + +## ProjectSettings-Schlüssel für die GLB-Quellen (relativ zum Editor-Projekt). +const QUELLEN_SETTING := "scopedvr/editor/glb_quellen" +## Voreinstellung = dieselben Quellen wie tools/gen_thumbs.gd (Sibling-Repos). +const DEFAULT_QUELLEN := ["../scopedvr-match-server/assets/objekte", "../scopedvr-client/assets/objekte"] +## Mitgelieferter Modell-Ordner (Karte t_12cf94fe): direkt neben der App +## (im Editor = Projektordner, in der exportierten App = neben der EXE). +## Der sync über tools/sync_models.sh legt hier die GLBs + Pack-Texturen +## ab — dann läuft der Map Builder auf einem fremden PC OHNE Sibling-Repos. +## Der Ordner trägt eine .gdignore (kein Import/PCK-Aufnahme; FileAccess +## mit absolutem Pfad funktioniert trotzdem). +const MODELS_DIR := "models" +## Klarer Hinweistext (Karte t_12cf94fe, Auftrag 3), wenn Modelle fehlen: +## wird als Klartext-Meldung gezeigt — kein stiller Platzhalter. +## Notfall-Modus: Terrain/Bauteile brauchen keine GLBs und funktionieren immer. +const FEHLT_TEXT := "Für die Anzeige fehlen die Modelle. So bekommst du sie:\n" \ + + " 1. tools/sync_models.sh aus dem Map-Editor-Ordner laufen lassen\n" \ + + " (kopiert die Modelle in den Ordner %s),\n" \ + + " 2. oder in den Einstellungen einen Ordner mit den Objekt-GLBs setzen.\n" \ + + "Terrain und Bauteile funktionieren trotzdem vollständig (Notfall-Modus)." +## Registry (A6): liefert das Feld "glb" für die Kategorie-verschachtelte Ablage. +const MANIFEST_PATH := "res://library/objects.json" +static var _manifest: Dictionary = {} +static var _manifest_geladen := false + +# WYSIWYG-Fix (t_c8748efc, korrigiert in t_279df760): GLTFDocument löst externe +# Textur-URIs (Sibling-Repos, außerhalb res://) NICHT auf — im Editor-Viewport +# blieben die GLB-Objekte untexturiert/Editor-Farbe, während sie im Spiel +# getextured sind. Flächen OHNE albedo_texture bekommen hier die Textur, die das +# ITHappy-Pack für ihren MATERIALNAMEN vorsieht — Zuordnung identisch zu +# tools/PACK_TEXTURE_MAPPING.md (Client-Repo, verbindlich): +# military_base (+_00x) = Palette (Demonstration_Textures1.png, 1024²) +# picture_1/2/3 = echtes Multicam (Demonstration_picture_N.png, 2048²) +# Wichtig: Nichts wird überschrieben — GLTF-aufgelöste Texturen bleiben unangetastet. +# (Der frühere Inhalt-Vergleich + Kategorie-Camo stammte aus aa94bde und hat auch +# korrekte Pack-Texturen wieder durch Camo ersetzt — das war der Fehler.) +const PACK_TEX_PALETTE := "Demonstration_Textures1.png" +const PACK_TEX_PICTURE_1 := "Demonstration_picture_1.png" +const PACK_TEX_PICTURE_2 := "Demonstration_picture_2.png" +const PACK_TEX_PICTURE_3 := "Demonstration_picture_3.png" + +# ImageTexture pro Textur-Pfad gecacht — sonst erzeugt jede der 291 GLBs +# ihre eigene 2048²-Textur (~16 MB VRAM je Stück statt 2 × 16 MB gesamt). +# false = Ladeversuch fehlgeschlagen (kein endloser Retry + Warn-Flut). +static var _camo_tex_cache: Dictionary = {} +## Dekodierte Multicam-Bilder (RAM, 2 × 2048² ≈ 32 MB) für den Inhalts- +## Vergleich gegen GLTF-eigene Textur-Instanzen. +static var _camo_bild_cache: Dictionary = {} +## Urteil pro GLTF-Textur-Instanz (instance_id → geteilte Textur | false), +## damit der 16-MB-Datenvergleich nur einmal je Instanz läuft. +static var _camo_ersetzung_cache: Dictionary = {} + +# Cache pro OID: Mesh (normalisiert) oder `false` = GLB gefunden, aber nicht +# ladbar (Parse-Fehler — kein endloser Retry pro Rebuild). Fehlende Datei +# bleibt UNGECACHED (nur ein billiger Datei-Check pro Rebuild; legt man die +# GLB später ab, erscheint sie ohne Editor-Neustart). +static var _cache: Dictionary = {} + + +## Kandidaten-Pfade der Quellen in Ladereihenfolge (Karte t_12cf94fe, +## Auftrag 1 — EINE Stelle, erster Treffer gewinnt): +## 1. in den Einstellungen gesetzter Pfad (QUELLEN_SETTING), +## 2. bisheriges Verhalten = Sibling-Repos (DEFAULT_QUELLEN), +## 3. mitgelieferter Ordner models/ direkt neben der App (MODELS_DIR). +## Doppelnennungen werden gefiltert (Reihenfolge bleibt erhalten); ein +## ungültiger Settings-Wert (kein Array) fällt komplett auf die Vorgabe. +static func quellen() -> Array: + var out: Array = [] + var setting: Variant = ProjectSettings.get_setting(QUELLEN_SETTING, DEFAULT_QUELLEN) + if setting is Array or setting is PackedStringArray: + for q in setting: + _quelle_add(out, q) + for q in DEFAULT_QUELLEN: + _quelle_add(out, q) + _quelle_add(out, MODELS_DIR) + return out + + +## Gültigen Quellpfad dedupliziert anhängen (typisiert, keine impliziten casts). +static func _quelle_add(out: Array, q: Variant) -> void: + if not (q is String): + return + var s := (q as String).strip_edges() + if s.is_empty() or out.has(s): + return + out.append(s) + + +## Absoluter Pfad des mitgelieferten Modell-Ordners (für die Klartext- +## Meldung und tools/sync_models.sh-Verweis). Im Editor = Projektordner, +## in der exportierten App = Ordner der EXE. +static func models_pfad() -> String: + return ProjectSettings.globalize_path("res://").path_join(MODELS_DIR) + + +## Erster EXISTIERENDER Dateipfad für die OID (ohne Laden/Parse — billiger +## Datei-Check über alle Kandidaten in Quellen-Reihenfolge). Leerer String = +## kein Quellpfad hat die Datei. Für Klartext-Meldungen/Probe-Logs: zeigt, +## AUS WELCHEM Ordner die Modelle kommen. +static func probe_source_fuer(oid: String) -> String: + if oid.is_empty(): + return "" + for pfad in _kandidaten(oid): + if FileAccess.file_exists(pfad): + return pfad + return "" + + +## Ausgefüllter Klartext-Hinweis (FEHLT_TEXT + echter models/-Pfad) — +## diese EINE Funktion liefert die Meldung, die die App zeigt, wenn +## Modelle fehlen (Karte t_12cf94fe, Auftrag 3). +static func fehl_text() -> String: + return FEHLT_TEXT % models_pfad() + + +## Kandidaten-Pfade (absolut) in Ladereihenfolge: Registry-`glb` (A6, Kategorie- +## Ablage assets/objekte/military_desert//.glb) VOR der flachen +## Alt-Ablage /.glb. Die Quelle ist ein Mesh-Lager (/assets/ +## objekte) — für den verschachtelten Pfad wird sie auf die Repo-Wurzel gekürzt. +static func _kandidaten(oid: String) -> Array: + var basis := ProjectSettings.globalize_path("res://") + var out: Array = [] + var rel := str(_eintrag(oid).get("glb", "")) + if rel.begins_with("res://"): + var sub := rel.substr(6) + # Operator-Korrektur 20.10. (Eigenständigkeits-Beweis): der mitgelieferte + # models/-Ordner NEBEN der App enthält die Pack-Struktur DIREKT + # (models/military_desert/props/box_010.glb) — nicht unter + # models/assets/objekte/. Ohne den zweiten Kandidaten unten werden ALLE + # verschachtelten Pack-Objekte in der eigenständigen App nicht gefunden + # (belegt: barrel_001/box_010 -> leer, fehlende_glbs=2 trotz 334 GLBs). + var sub_kurz := sub.trim_prefix("assets/objekte/") + for quelle in quellen(): + var q := str(quelle) + var marke := "/assets/objekte" + var wurzel := q.substr(0, q.length() - marke.length()) if q.ends_with(marke) else q + out.append(basis.path_join(wurzel).path_join(sub)) + if sub_kurz != sub: + out.append(basis.path_join(wurzel).path_join(sub_kurz)) + for quelle in quellen(): + out.append(basis.path_join(str(quelle)).path_join(oid + ".glb")) + return out + + +## Registry-Eintrag der OID (einmal gelesen, dann gecacht). +static func _eintrag(oid: String) -> Dictionary: + if not _manifest_geladen: + _manifest_geladen = true + var parsed: Variant = JSON.parse_string(FileAccess.get_file_as_string(MANIFEST_PATH)) + if parsed is Dictionary: + _manifest = (parsed as Dictionary).get("objects", {}) + return _manifest.get(oid, {}) + + +## Echtes Mesh für eine Objekt-ID (normalisiert, Fußpunkt-Koordinaten) oder +## null = keine brauchbare GLB → Aufrufer zeigt den Platzhalter. +static func mesh_fuer(oid: String) -> Mesh: + if oid.is_empty(): + return null + # Bauteile (bau_*) entstehen aus dem Katalog — identisch zu den GLBs, die + # der Client lädt (tools/gen_bauteile.gd), aber ohne Modell-Ordner nötig. + if BauKatalog.ist_bau(oid): + return BauKatalog.mesh(oid) + if _cache.has(oid): + return _cache[oid] if _cache[oid] is Mesh else null + for pfad in _kandidaten(oid): + if FileAccess.file_exists(pfad): + var m := _glb_mesh(pfad) + if m != null: + camo_tex_setzen(m, pfad) + _cache[oid] = m + return m + # Datei da, aber kaputt → NEGATIV cachen (Parse-Fehler wiederholt + # sich sonst bei jedem Rebuild und kostet Zeit). + _cache[oid] = false + return null + return null + + +## Liegt für die OID überhaupt eine GLB-Datei im Lager? (Billiger Check ohne +## Parse — für Statuszeilen-Hinweise beim Platzieren.) +static func fehlt(oid: String) -> bool: + if oid.is_empty(): + return true + if BauKatalog.ist_bau(oid): + return false + if _cache.has(oid): + return not (_cache[oid] is Mesh) + for pfad in _kandidaten(oid): + if FileAccess.file_exists(pfad): + return false + return true + + +## true = KEINE Quelle (Einstellungen/Siblings/models/) enthält irgend eine +## GLB-Datei → die App hat nirgends echte Modelle. Für das Klartext-Banner +## beim Start (Karte t_12cf94fe, Auftrag 3). Nicht-cachend, einmal pro Start. +static func lager_ist_leer() -> bool: + for quelle in quellen(): + if _quelle_hat_glb(ProjectSettings.globalize_path("res://").path_join(str(quelle))): + return false + return true + + +## Enthält der Ordner (rekursiv) mindestens eine .glb-Datei? +static func _quelle_hat_glb(basis: String) -> bool: + var d := DirAccess.open(basis) + if d == null: + return false + d.list_dir_begin() + var name := d.get_next() + while name != "": + var pfad := basis.path_join(name) + if d.current_is_dir(): + if _quelle_hat_glb(pfad): + return true + elif name.ends_with(".glb"): + return true + name = d.get_next() + return false + + +## Cache leeren (Tests / nach manuellem Eingriff ins Mesh-Lager). +static func cache_leeren() -> void: + _cache.clear() + _camo_tex_cache.clear() + _camo_bild_cache.clear() + _camo_ersetzung_cache.clear() + _manifest.clear() + _manifest_geladen = false + + +# ------------------------------------------------------------ Laden -------- + +## GLB OHNE Import-System laden (GLTFDocument, wie gen_thumbs) und ALLE +## MeshInstance3D der Szene in EIN ArrayMesh zusammenbacken (Jedes Teil-Node +## mit seiner Node-Transform; Materialien je Oberfläche bleiben erhalten — +## echte Texturen statt Editor-Farbe). null = Load-Fehlschlag. +static func _glb_mesh(pfad: String) -> Mesh: + var gltf := GLTFDocument.new() + var state := GLTFState.new() + if gltf.append_from_file(pfad, state) != OK: + push_warning("GlbMeshStore: GLB nicht ladbar: %s" % pfad) + return null + var szene: Node = gltf.generate_scene(state) + if szene == null: + return null + var m := _zusammenbacken(szene) + # Das Mesh ist eine Resource (RefCounted) — das Freigeben der Szene + # berührt die Referenz im Rückgabewert nicht. + szene.free() + return m + + +## Alle Mesh-Instanzen der Szene → ein ArrayMesh (Transforms angewandt, +## Materialien übernommen), dann normalisiert (Fußpunkt-Konvention). +static func _zusammenbacken(szene: Node) -> Mesh: + var roh := ArrayMesh.new() + _sammeln(szene, Transform3D.IDENTITY, roh) + if roh.get_surface_count() == 0: + return null + return _normalisiert(roh) + + +static func _sammeln(n: Node, xf: Transform3D, out: ArrayMesh) -> void: + if n is Node3D: + xf = xf * (n as Node3D).transform + if n is MeshInstance3D and (n as MeshInstance3D).mesh != null: + var m: Mesh = (n as MeshInstance3D).mesh + for s in m.get_surface_count(): + var arrays: Array = m.surface_get_arrays(s) + if arrays.is_empty() or not (arrays[Mesh.ARRAY_VERTEX] is PackedVector3Array): + continue + var verts: PackedVector3Array = arrays[Mesh.ARRAY_VERTEX] + for i in verts.size(): + verts[i] = xf * verts[i] + arrays[Mesh.ARRAY_VERTEX] = verts + if arrays[Mesh.ARRAY_NORMAL] is PackedVector3Array: + var norms: PackedVector3Array = arrays[Mesh.ARRAY_NORMAL] + for i in norms.size(): + norms[i] = (xf.basis * norms[i]).normalized() + arrays[Mesh.ARRAY_NORMAL] = norms + # Statisch fürs Editor-Viewport: Skin-Daten fliegen raus (sonst + # verlangt add_surface_from_arrays ein Skeleton). + arrays[Mesh.ARRAY_BONES] = null + arrays[Mesh.ARRAY_WEIGHTS] = null + out.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, arrays) + var mat: Material = m.surface_get_material(s) + if mat != null: + out.surface_set_material(out.get_surface_count() - 1, mat) + for c in n.get_children(): + _sammeln(c, xf, out) + + +## Fußpunkt-Konvention (wie scopedvr_export.normalisiere): Unterkante y = 0, +## XZ um den AABB-Mittelpunkt zentriert. Materialien bleiben an den Flächen. +static func _normalisiert(mesh: ArrayMesh) -> ArrayMesh: + var aabb := mesh.get_aabb() + var offset := Vector3(-aabb.get_center().x, -aabb.position.y, -aabb.get_center().z) + var out := ArrayMesh.new() + out.resource_name = mesh.resource_name + for s in mesh.get_surface_count(): + var arrays: Array = mesh.surface_get_arrays(s) + if arrays.is_empty() or not (arrays[Mesh.ARRAY_VERTEX] is PackedVector3Array): + continue + var verts: PackedVector3Array = arrays[Mesh.ARRAY_VERTEX] + for i in verts.size(): + verts[i] = verts[i] + offset + arrays[Mesh.ARRAY_VERTEX] = verts + out.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, arrays) + var mat: Material = mesh.surface_get_material(s) + if mat != null: + out.surface_set_material(out.get_surface_count() - 1, mat) + return out + + +# ------------------------------------------------------- Camo-Textur -------- + +## Camo-Fix (t_50a07d4b): Multicam-Textur von der Platte laden und auf alle +## Flächen ohne albedo_texture setzen (GLTFDocument löst externe URIs der +## Sibling-Repos nicht auf). Zuordnung exakt wie tools/CAMO_TEXTURE_MAPPING.md +## bzw. gen_thumbs._camo_tex_setzen — diese Funktion ist ab jetzt DIE EINE +## Quelle der Zuordnung (gen_thumbs delegiert hierher). Objekte außerhalb +## military_desert//.glb bleiben unangetastet. Fehlt die +## Textur-Datei, wird klar gewarnt (push_warning) statt still weiß zu rendern. +## +## EINE-Quelle-Dedup (t_50a07d4b): GLTFDocument lädt externe Texturen +## inzwischen selbst — aber als EIGENE ImageTexture-Instanz JEDES Parses +## (291 GLBs = 291 × 16 MB VRAM statt 2 × 16 MB, bewiesen per Probe: +## iid pro Parse unterschiedlich, Inhalt identisch zur Datei). Deshalb wird +## hier ZUSÄTZLICH geprüft: stimmt der Inhalt einer GLTF-Textur mit einer +## Multicam-Datei überein, ersetzen wir sie durch DIE eine geteilte Instanz +## aus dem Cache — gleiche Optik (WYSIWYG bleibt), eine Quelle statt Kopien. +## Eingebettete/Fremd-Texturen (Alt-Bestand, Waffen-GLBs) bleiben unangetastet. +static func camo_tex_setzen(mesh: Mesh, glb_pfad: String) -> void: + # Siehe Kopf-Kommentar: nur Flächen OHNE aufgelöste Textur werden versorgt. + var tex_dir := glb_pfad.get_base_dir().path_join("../../../textures/military_desert") + for s in mesh.get_surface_count(): + var mat := mesh.surface_get_material(s) + if not (mat is BaseMaterial3D): + continue + var bm := mat as BaseMaterial3D + if bm.albedo_texture != null: + continue + var datei := pack_datei_fuer(bm.resource_name) + var tex := _camo_tex(tex_dir.path_join(datei)) + if tex != null: + bm.albedo_texture = tex + else: + push_warning("GlbMeshStore: Pack-Textur fehlt fuer Material '%s': %s" % [bm.resource_name, datei]) + + +## Materialname (GLTF) -> Pack-Texturdatei. Quelle: tools/PACK_TEXTURE_MAPPING.md (Client). +static func pack_datei_fuer(material_name: String) -> String: + match material_name: + "picture_1": + return PACK_TEX_PICTURE_1 + "picture_2": + return PACK_TEX_PICTURE_2 + "picture_3": + return PACK_TEX_PICTURE_3 + "military_base": + return PACK_TEX_PALETTE + if material_name.begins_with("military_base"): + return PACK_TEX_PALETTE + return PACK_TEX_PALETTE + +static func _camo_image(pfad: String, warnen: bool) -> Image: + if _camo_bild_cache.has(pfad): + var v: Variant = _camo_bild_cache[pfad] + return v if v is Image else null + if not FileAccess.file_exists(pfad): + if warnen: + push_warning("GlbMeshStore: Camo-Textur fehlt: %s" % pfad) + _camo_bild_cache[pfad] = false + return null + var img := Image.load_from_file(pfad) + if img == null: + if warnen: + push_warning("GlbMeshStore: Camo-Textur nicht ladbar: %s" % pfad) + _camo_bild_cache[pfad] = false + return null + _camo_bild_cache[pfad] = img + return img + + +## DIE EINE geteilte ImageTexture für eine Multicam-Datei (VRAM-Cache). +## Alle getextureden GLB-Flächen teilen sich genau diese Instanz. +static func _camo_tex(tex_pfad: String) -> ImageTexture: + if _camo_tex_cache.has(tex_pfad): + var v: Variant = _camo_tex_cache[tex_pfad] + return v if v is ImageTexture else null + var img := _camo_image(tex_pfad, true) + if img == null: + _camo_tex_cache[tex_pfad] = false + return null + var tex := ImageTexture.create_from_image(img) + _camo_tex_cache[tex_pfad] = tex + return tex + + +## Ersetzt eine GLTF-eigene ImageTexture durch die geteilte Multicam-Instanz, +## WENN der Inhalt (Größe, Format, Pixeldaten) mit einer der Kandidaten- +## Dateien übereinstimmt. null = kein Match → Textur bleibt unangetastet +## (eingebettete/Fremd-Texturen). Urteil je Instanz gecacht. +static func _camo_ersetzung_fuer(tex: Texture2D, kandidaten: Array) -> ImageTexture: + if not (tex is ImageTexture): + return null + var iid := tex.get_instance_id() + if _camo_ersetzung_cache.has(iid): + var v: Variant = _camo_ersetzung_cache[iid] + return v if v is ImageTexture else null + var img: Image = (tex as ImageTexture).get_image() + if img == null: + _camo_ersetzung_cache[iid] = false + return null + var out: ImageTexture = null + for pfad in kandidaten: + var vergleich := _camo_image(str(pfad), false) + if vergleich == null: + continue + if img.get_width() == vergleich.get_width() \ + and img.get_height() == vergleich.get_height() \ + and img.get_format() == vergleich.get_format() \ + and img.data == vergleich.data: + out = _camo_tex(str(pfad)) + break + _camo_ersetzung_cache[iid] = out if out != null else false + return out diff --git a/viewport/glb_mesh_store.gd.uid b/viewport/glb_mesh_store.gd.uid new file mode 100644 index 0000000..7fbaa0f --- /dev/null +++ b/viewport/glb_mesh_store.gd.uid @@ -0,0 +1 @@ +uid://bdbx4rc3fx5ix diff --git a/viewport/map_view_builder.gd b/viewport/map_view_builder.gd new file mode 100644 index 0000000..aec3570 --- /dev/null +++ b/viewport/map_view_builder.gd @@ -0,0 +1,883 @@ +extends Node3D +## Baut die visuelle Repräsentation der Map im Editor-Viewport: +## Terrain-Höhenfeld-Mesh + Maßstabsgitter + Himmel/Licht +## + Echte GLB-Meshes für Bibliotheks-Objekte (GlbMeshStore; ohne GLB = +## Platzhalter-Mesh aus dem Kollisions-Eintrag) + Spawn-Marker mit Beschriftung. +## ## +## Objekt-Marker werden in object_markers gemerkt (Meta: obj_index, +## pick_radius) — Auswahl/Werkzeuge (interaction.gd) greifen darauf zu, +## statt die Szene selbst zu durchsuchen. + +const GRID_COLOR := Color(0.35, 0.45, 0.55, 0.6) +const AXIS_COLOR := Color(0.9, 0.7, 0.2, 0.9) +const OBJECT_COLOR := Color(0.55, 0.75, 0.95) +const TEAM_COLORS := [Color(0.3, 0.6, 1.0), Color(1.0, 0.35, 0.3)] # Blau / Rot +# Auswahl-Markierung (U6, t_639135dd): Farbe + Breite kommen aus dem Theme +# (eine Quelle) — Auswahl-Kontur, schwächere Hover-Kontur, dünn-gestrichelte +# Partner-Kontur. Kein Vollflächen-Orange mehr: das Grundmaterial (mit Textur) +# bleibt sichtbar, die Markierung lebt als Außenhüllen-Kontur darum herum. +const THEME_PATH := "res://core/theme/editor_theme.tres" +const OUTLINE_SHADER := "res://core/shaders/selection_outline.gdshader" +# Fallback, falls das Theme (noch) nicht geladen werden kann. +const OUTLINE_FALLBACK := Color(1.0, 0.6, 0.15, 0.95) + +# Wetter → Licht/Himmel — 1:1-SPIEGEL aus client/scripts/world/weather_presets.gd +# (Karte t_f72913d4: Editor-Vorschau zeigt exakt was der Client zeigt — dieselbe +# Projekt-Konvention wie KolliderBau als 1:1-Spiegel von svmap_world, t_1da96275). +# Bei Preset-Änderungen im Client HIER MITPFLEGEN. Schlüssel = Client-Keys. +const WEATHER_LIGHT := { + "mittag": { + "sky_top": Color(0.30, 0.54, 0.86), "sky_horizon": Color(0.72, 0.83, 0.92), + "ground_bottom": Color(0.20, 0.23, 0.27), "ground_horizon": Color(0.66, 0.75, 0.83), + "sky_energy": 1.0, + "sun_deg": Vector2(-52.0, 30.0), "sun_energy": 1.2, "sun_color": Color(1.0, 0.98, 0.92), + "ambient_source": "sky", "ambient_color": Color(0.60, 0.70, 0.85), "ambient_energy": 1.0, + "fog_enabled": false, "fog_color": Color(0.80, 0.85, 0.90), + "fog_density": 0.0, "fog_sky_affect": 0.0, + "sky_panorama": false, + "panorama_fog_color": Color(0.93, 0.80, 0.66), "panorama_energy": 1.0, + }, + "abend": { + "sky_top": Color(0.25, 0.30, 0.55), "sky_horizon": Color(0.95, 0.55, 0.28), + "ground_bottom": Color(0.16, 0.13, 0.14), "ground_horizon": Color(0.80, 0.45, 0.25), + "sky_energy": 1.0, + "sun_deg": Vector2(-8.0, 250.0), "sun_energy": 0.9, "sun_color": Color(1.0, 0.62, 0.35), + "ambient_source": "color", "ambient_color": Color(0.55, 0.40, 0.32), "ambient_energy": 0.8, + "fog_enabled": true, "fog_color": Color(0.85, 0.55, 0.35), + "fog_density": 0.004, "fog_sky_affect": 0.2, + "sky_panorama": false, + "panorama_fog_color": Color(0.95, 0.72, 0.48), "panorama_energy": 0.8, + }, + "regen": { + "sky_top": Color(0.38, 0.41, 0.45), "sky_horizon": Color(0.55, 0.58, 0.62), + "ground_bottom": Color(0.22, 0.23, 0.25), "ground_horizon": Color(0.50, 0.53, 0.57), + "sky_energy": 0.9, + "sun_deg": Vector2(-40.0, 120.0), "sun_energy": 0.25, "sun_color": Color(0.75, 0.78, 0.82), + "ambient_source": "color", "ambient_color": Color(0.55, 0.58, 0.62), "ambient_energy": 1.0, + "fog_enabled": true, "fog_color": Color(0.55, 0.58, 0.62), + "fog_density": 0.015, "fog_sky_affect": 0.6, + "sky_panorama": false, + "panorama_fog_color": Color(0.76, 0.72, 0.68), "panorama_energy": 0.55, + }, + "nacht": { + "sky_top": Color(0.015, 0.03, 0.08), "sky_horizon": Color(0.05, 0.08, 0.15), + "ground_bottom": Color(0.01, 0.015, 0.025), "ground_horizon": Color(0.04, 0.06, 0.11), + "sky_energy": 1.0, + "sun_deg": Vector2(-65.0, 200.0), "sun_energy": 0.35, "sun_color": Color(0.62, 0.72, 1.0), + "ambient_source": "color", "ambient_color": Color(0.10, 0.14, 0.25), "ambient_energy": 0.5, + "fog_enabled": true, "fog_color": Color(0.04, 0.06, 0.11), + "fog_density": 0.006, "fog_sky_affect": 0.4, + "sky_panorama": false, + "panorama_fog_color": Color(0.10, 0.12, 0.18), "panorama_energy": 0.10, + }, +} + +## Pack-Panorama-Skybox (Karte t_f72913d4): die Textur liegt im Client-Repo +## (Nachbar-Klon — KEINE Duplikat-Pflicht im Editor, siehe Spec) und wird über +## einen absoluten Pfad geladen; fehlt sie → Fallback ProceduralSky. +const PANORAMA_SKY_CLIENT_REL := "assets/textures/military_desert/Skybox_3.png" + +## Absoluter Pfad der Pack-Skybox im Nachbar-Klon ("" = kein Klon gefunden). +static func panorama_sky_pfad() -> String: + var root := TestRun.find_client(ProjectSettings.globalize_path("res://"), + TestRun.load_cfg()) + if root.is_empty(): + return "" + return root.path_join(PANORAMA_SKY_CLIENT_REL) + +var selected_index := -1 # aktuelles Auswahl-Objekt (Kontur-Markierung) +var selected_indices: Array = [] # komplette Auswahl (Karte t_f6f29d86 — Mehrfachauswahl) +var hover_index := -1 # Hover-Objekt (schwächste Kontur; U6-Abstufung) +var object_markers: Array = [] # Node3D je Objekt (gleiche Reihenfolge wie doc.objects) +var fehlende_glbs: Array = [] # OIDs ohne echte GLB (Platzhalter-Fallback — Statuszeilen-Hinweis) +var zone_root: Node3D = null # Conquest-Zonen bzw. Hills (Spielmodus), Kinder je Zone +var spawn_markers: Array = [] # Node3D je Spawn-Point (Meta: spawn_team/spawn_id/spawn_radius) +var terrain_view # TerrainMesh-Ansicht (script-erweitert, Variant) +var grid_node: MeshInstance3D # Maßstabsgitter (Toggle „⊞ Gitter“, Karte t_7ac70014) + +var _doc_ref: Dictionary = {} # letztes rebuild-Doc (Auswahl-Markierung) + +var _base_mat: StandardMaterial3D +var _sym_partners: Array = [] # Indizes der Zwillinge der aktuellen Auswahl +# Kontur-Materialien (U6): Auswahl / Hover / Spiegel-Zwilling — Farben und +# Breiten kommen aus dem Theme, der Shader ist die Außenhüllen-Technik. +var _outline_mat_sel: ShaderMaterial +var _outline_mat_hover: ShaderMaterial +var _outline_mat_partner: ShaderMaterial + + +func _ready() -> void: + rebuild({}, {}) + + +## Komplette Szene aus dem Map-Dict neu aufbauen. manifest = Bibliotheks-Registry. +func rebuild(data: Dictionary, manifest: Dictionary) -> void: + for child in get_children(): + child.queue_free() + object_markers = [] + spawn_markers = [] + zone_root = null + grid_node = null + _doc_ref = data + _base_mat = StandardMaterial3D.new() + _base_mat.albedo_color = OBJECT_COLOR + _base_mat.roughness = 0.8 + # U6 (t_639135dd): keine Vollfarben-Materialien mehr — die Markierung + # (Auswahl/Hover/Partner) lebt als Außenhüllen-Kontur um das Modell, + # Farben + Breiten aus dem Theme. + _markierung_theme_laden() + _sym_partners = [] + + if data.is_empty(): + return + + var terrain: Dictionary = data.get("terrain", {}) + var size_x := float(terrain.get("size_x_m", 1024.0)) + var size_z := float(terrain.get("size_z_m", 1024.0)) + var ground_y := float(terrain.get("min_height_m", 0.0)) + var weather := str(data.get("weather", "mittag")) + # Skybox-Option (Karte t_f72913d4): optionales svmap-Feld `weather_sky` + # ("sky_panorama"/"prozedural"/leer) — dieselbe Semantik wie im Client. + var weather_sky := str(data.get("weather_sky", "")) + + _build_environment(weather, weather_sky) + _build_terrain(data) + _build_wasser(data) # Karte t_28fdef03: nach dem Terrain (Senken füllen sich) + _build_grid(size_x, size_z, ground_y) + # Gitter default AUS über sichtbarem Terrain (Karte t_7ac70014): das + # Terrain ist die Bodendarstellung — das Gitter lag als Linien-Overlay + # DARÜBER und wirkte wie ein „unfertiges“ Editor-Raster. Ohne Terrain- + # Block bleibt es als Boden-Referenz sichtbar. + if grid_node != null: + grid_node.visible = terrain.is_empty() + _build_objects(data.get("objects", []), manifest) + _rebuild_spawn_markers(data) + rebuild_zone_markers(data) + + +## Terrain als echtes Höhenfeld-Mesh statt flacher Ebene (Karte t_9aba04f1): +## der Terrain-Pinsel schreibt die Vertices live neu (terrain_view.update_terrain). +func _build_terrain(data: Dictionary) -> void: + terrain_view = Node3D.new() + terrain_view.set_script(load("res://core/viewport/terrain_mesh.gd")) + add_child(terrain_view) + terrain_view.call("rebuild_from_doc", data) + + +## Wasserfläche (Karte t_28fdef03): EINE transparente Fläche auf `water_level` +## über der GANZEN Map (SvmapWasser.baue — Senken unter der Höhe füllen sich +## automatisch). OHNE Feld → kein Wasser (Legacy-Maps unverändert). Dasselbe +## Material-Verfahren wie der Client (SvmapWasser.make_material — Identitäts- +## Vertrag der Vorschau: Editor zeigt exakt, was der Quest-Client zeigt). +## Leicht ÜBER dem Terrain eingehängt (y-Offset +0.01 über Reihenfolge), aber +## die Fläche selbst liegt exakt auf der Wasserhöhe (Z-Fight-Vermeidung macht +## der Shader über die Tiefen-Textur, nicht über einen Off-Aufschlag). +func _build_wasser(data: Dictionary) -> void: + var level := SvmapWasser.level(data) + if not is_finite(level): + return # Legacy/fehlendes Feld — kein Wasser, nichts bauen. + var terrain: Dictionary = data.get("terrain", {}) + var wetter := str(data.get("weather", "mittag")) + var wasser := SvmapWasser.baue(terrain, level, wetter) + if wasser != null: + add_child(wasser) + + +## Live-Update während eines Pinsel-Strichs (aus terrain_tool.gd): nur die +## Vertices werden neu geschrieben — Grid/Objekte/Marker bleiben unangetastet. +## mats (optional) = Material-Schicht (Karte t_603ec1a8, Malen-Modus) — +## leer = terrain_mesh verwendet die zuletzt gesehene Schicht weiter (Cache, +## Karte t_55ed041a); nur bei NIE gesehener Schicht (Legacy-v1) gilt Gras. +## splat_rect_cells (optional, Karte t_7a0a6b79) = Zellrechteck des Mal- +## Schritts (inkl. Spiegelzellen) — terrain_mesh leitet nur die Splat-Region +## neu ab (Sub-Rect-Update, kein Voll-Rebuild pro Mal-Frame). +func update_terrain(heights: PackedFloat32Array, mats: PackedByteArray = PackedByteArray(), + splat_rect_cells: Rect2i = Rect2i()) -> void: + if terrain_view != null and is_instance_valid(terrain_view): + terrain_view.call("update_heights", heights, 0, 0.0, 0.0, mats, splat_rect_cells) + + +## Misch-Schicht für das nächste Live-Update (Malen mit weichem Rand, Karte 25.10.). +func set_terrain_mix(mix_b: PackedByteArray, mix_w: PackedByteArray) -> void: + if terrain_view != null and is_instance_valid(terrain_view): + terrain_view.call("set_mix", mix_b, mix_w) + + +## Nur das Terrain neu aufbauen (nach Strich-Commit/Undo) — Objekt-Marker und +## Auswahl bleiben bestehen, kein Flackern der ganzen Szene. +func rebuild_terrain_from_doc(data: Dictionary) -> void: + if terrain_view != null and is_instance_valid(terrain_view): + terrain_view.call("rebuild_from_doc", data) + + +## Himmel/Licht — 1:1-Spiegel von client autoload/weather.gd._apply_environment +## (Karte t_f72913d4): Map-Override > Preset-Key > ProceduralSky; ACES-Tonemap; +## Fog koppelt im Panorama-Fall an den Skybox-Horizont (aerial perspective). +## Kein Glow/Bloom/Volumetric — dokumentierte Absage (Mobile/Perf). +func _build_environment(weather: String, sky_override: String = "") -> void: + var preset: Dictionary = WEATHER_LIGHT.get(weather, WEATHER_LIGHT["mittag"]) + var env := Environment.new() + var sky := Sky.new() + # Katalog-ID (weather_sky) > Preset-Key `sky_panorama` > ProceduralSky. + var pano_id := "" + if sky_override == "prozedural": + pass + elif sky_override != "": + pano_id = sky_override + elif bool(preset.get("sky_panorama", false)): + pano_id = SkyboxKatalog.ID_PACK_WUESTE + var panorama := false + if pano_id != "": + var tex := SkyboxKatalog.panorama_textur(pano_id) + if tex != null: + var pano_mat := PanoramaSkyMaterial.new() + pano_mat.panorama = tex + pano_mat.energy_multiplier = float(preset.get("panorama_energy", 1.0)) + sky.sky_material = pano_mat + panorama = true + else: + push_warning("MAPBUILDER: weather_sky=%s, aber Skybox-Textur fehlt/unbekannt — Fallback ProceduralSky" % pano_id) + if sky.sky_material == null: + var sky_mat := ProceduralSkyMaterial.new() + sky_mat.sky_top_color = preset["sky_top"] + sky_mat.sky_horizon_color = preset["sky_horizon"] + sky_mat.ground_bottom_color = preset["ground_bottom"] + sky_mat.ground_horizon_color = preset["ground_horizon"] + sky_mat.sky_energy_multiplier = float(preset["sky_energy"]) + sky.sky_material = sky_mat + env.background_mode = Environment.BG_SKY + env.sky = sky + # Ambient: "sky" = aus dem Himmel ableiten, "color" = feste Farbe (Client-Logik). + if str(preset.get("ambient_source", "color")) == "sky": + env.ambient_light_source = Environment.AMBIENT_SOURCE_SKY + else: + env.ambient_light_source = Environment.AMBIENT_SOURCE_COLOR + env.ambient_light_color = preset["ambient_color"] + env.ambient_light_energy = float(preset["ambient_energy"]) + # Tonemap ACES — derselbe filmische Look wie der Client; Grading bewusst + # NUR über Tonemap + Preset-Farben (kein Fullscreen-Adjustment-Pass). + env.tonemap_mode = Environment.TONE_MAPPER_ACES + env.fog_enabled = bool(preset["fog_enabled"]) + env.fog_light_color = SkyboxKatalog.fog_farbe(sky_override, + preset.get("panorama_fog_color", preset["fog_color"]), + float(preset.get("panorama_energy", 1.0))) if panorama else preset["fog_color"] + env.fog_density = float(preset["fog_density"]) + env.fog_sky_affect = float(preset["fog_sky_affect"]) + var we := WorldEnvironment.new() + we.environment = env + add_child(we) + + var sun := DirectionalLight3D.new() + var deg: Vector2 = preset["sun_deg"] + sun.rotation_degrees = Vector3(deg.x, deg.y, 0.0) + sun.light_energy = float(preset["sun_energy"]) + sun.light_color = preset["sun_color"] + sun.shadow_enabled = true + add_child(sun) + + +## Maßstabsgitter: Linien alle 100 m, gelbe Mittelachsen (X rot? — Z-Achse +## blau wäre Godot-Konvention; hier neutral gelb für gute Sichtbarkeit). +func _build_grid(size_x: float, size_z: float, ground_y: float) -> void: + var mesh := ImmediateMesh.new() + mesh.surface_begin(Mesh.PRIMITIVE_LINES) + var step := _grid_step(size_x) + var half_x := size_x / 2.0 + var half_z := size_z / 2.0 + var y := ground_y + 0.05 + var x := -half_x + while x <= half_x + 0.01: + var major: bool = absf(fmod(x, step * 5.0)) < 0.01 or absf(x) < 0.01 + _add_line(mesh, Vector3(x, y, -half_z), Vector3(x, y, half_z), + AXIS_COLOR if absf(x) < 0.01 else (GRID_COLOR if not major else GRID_COLOR)) + x += step + var z := -half_z + while z <= half_z + 0.01: + _add_line(mesh, Vector3(-half_x, y, z), Vector3(half_x, y, z), + AXIS_COLOR if absf(z) < 0.01 else GRID_COLOR) + z += step + mesh.surface_end() + var mi := MeshInstance3D.new() + mi.mesh = mesh + var mat := StandardMaterial3D.new() + mat.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED + mat.vertex_color_use_as_albedo = true + mi.material_override = mat + grid_node = mi + add_child(mi) + + +## Gitter ohne Rebuild zu-/abschalten (Toggle in der Top-Bar, Karte t_7ac70014). +func set_grid_visible(visible_now: bool) -> void: + if grid_node != null and is_instance_valid(grid_node): + grid_node.visible = visible_now + + +func grid_is_visible() -> bool: + return grid_node != null and is_instance_valid(grid_node) and grid_node.visible + + +func _grid_step(size_m: float) -> float: + # Ziel: ~10–20 Linien pro Achse, runde Werte. + var raw := size_m / 16.0 + var candidates := [10.0, 25.0, 50.0, 100.0, 250.0, 500.0] + for c in candidates: + if raw <= float(c): + return float(c) + return 1000.0 + + +func _add_line(mesh: ImmediateMesh, from: Vector3, to: Vector3, color: Color) -> void: + mesh.surface_set_color(color) + mesh.surface_add_vertex(from) + mesh.surface_set_color(color) + mesh.surface_add_vertex(to) + + +## Platzhalter je Objekt: Form aus dem Bibliotheks-Manifest (wie der Server- +## Kollider), Position = Objekt-Fußpunkt. ECHTES GLB-Mesh vorziehen +## (Karte t_9b50b231, GlbMeshStore): vorhanden = echtes Modell mit Texturen, +## fehlend = Platzhalter + Eintrag in fehlende_glbs (Statuszeilen-Hinweis). +## Marker-Root bekommt Metas für Auswahl/Anfassen: obj_index, pick_radius +## (Kugel-Approximation), half_height, glb (true = echtes Modell — keine +## Grundfarbe drüberlegen, sonst sind die Texturen weg). +func _build_objects(objects: Array, manifest: Dictionary) -> void: + var lib: Dictionary = manifest.get("objects", {}) + fehlende_glbs = [] + for i in objects.size(): + var obj = objects[i] + if not (obj is Dictionary): + object_markers.append(null) + continue + var oid := str(obj.get("id", "")) + if not lib.has(oid): + object_markers.append(null) + continue # Validierung fängt das — defensiv überspringen. + var entry: Dictionary = lib[oid] + var col: Dictionary = entry.get("collision", {}) + var scale := float(obj.get("scale", 1.0)) + var mesh := GlbMeshStore.mesh_fuer(oid) + var echt := mesh != null + if not echt: + if GlbMeshStore.fehlt(oid): + fehlende_glbs.append(oid) + mesh = MeshShapes.make_placeholder(str(col.get("shape", "box")), col, scale) + var pos: Array = obj.get("pos", [0.0, 0.0, 0.0]) + var marker := Node3D.new() + marker.position = Vector3(float(pos[0]), float(pos[1]), float(pos[2])) + # Karte t_e166e656: 3-Achsen-Rotation — `rot` (Euler xyz) oder Fallback + # rot_y_deg, identische Regel wie im Client/Server (SvmapIO.objekt_rotation). + marker.rotation_degrees = SvmapIO.objekt_rotation(obj) + marker.set_meta("obj_index", i) + var mi := MeshInstance3D.new() + mi.mesh = mesh + if echt: + # Normalisiertes GLB liegt schon in Fußpunkt-Koordinaten + # (Unterkante y = 0) → KEIN half_height-Lift; Objekt-Maßstab + # über Node-Scale. AABB-Metas mal scale (Node-Scale geht nicht + # in mesh.get_aabb() ein). + mi.scale = Vector3.ONE * scale + else: + mi.position.y = MeshShapes.half_height(mesh) + # U6 (t_639135dd): das Grundmaterial wird NIE MEHR durch die Auswahl + # ersetzt — echte GLB-Objekte tragen ihre Texturen weiter (override null), + # Platzhalter die Editor-Grundfarbe. Markiert wird per Kontur (unten). + mi.material_override = null if echt else _base_mat + marker.add_child(mi) + var half: Vector3 = (mesh.get_aabb().size * (scale if echt else 1.0) * 0.5) as Vector3 + marker.set_meta("pick_radius", half.length() + maxf(0.6, half.y * 0.25)) + marker.set_meta("half_height", + MeshShapes.center_height(mesh) * (scale if echt else 1.0)) + marker.set_meta("glb", echt) + object_markers.append(marker) + add_child(marker) + # Farbe je Objekt (Karte t_b0edb807): optionales Feld "tint" — nur + # Objekte MIT Feld bekommen die Überschreibung (Rückwärtskompatibel). + # Die Farbe bleibt jetzt auch bei Markierung sichtbar (U6: Auswahl = Kontur, + # Grundmaterial bleibt) — kein „Orange gewinnt“ mehr. + if SvmapTint.hat(obj): + SvmapTint.anwenden(marker, SvmapTint.von(obj)) + # Markierung (Auswahl/Hover/Partner) als Kontur-Hülle anlegen. + _outline_anwenden(marker, i) + + +## Auswahl nachträglich umfärben (ohne ganzen Rebuild) — z. B. nach Drag. +## Einzel-Variante bleibt für Rückwärtskompatibilität bestehen. +func set_selected(idx: int) -> void: + selected_index = idx + set_selected_multi([idx] if idx >= 0 else []) + + +## Mehrfachauswahl (Karte t_f6f29d86): ALLE markierten Objekte bekommen die +## Auswahl-Kontur (U6, t_639135dd) — Gruppen/Mehrfachauswahl sind auf einen +## Blick erkennbar, OHNE die Textur zu übermalen. Das Grundmaterial bleibt +## überall sichtbar: echte GLB-Objekte tragen ihre Texturen weiter (Karte +## t_9b50b231), Platzhalter die Editor-Grundfarbe — material_override wird +## von der Markierung nicht mehr angefasst. +func set_selected_multi(indices: Array) -> void: + selected_indices = indices.duplicate() + selected_index = indices.back() if not indices.is_empty() else -1 + # sym-Zwillinge (M3, t_34908425): aus dem doc ableiten — Partner der + # Auswahl, die nicht selbst ausgewählt sind, bekommen die dünnere, + # gestrichelte Partner-Kontur (U6-Abstufung statt dunkler Vollfarbe). + _sym_partners = _sym_partners_of(indices) + var objects: Array = _doc_ref.get("objects", []) + for marker in object_markers: + if marker == null or not is_instance_valid(marker): + continue + var idx := int(marker.get_meta("obj_index", -1)) + _outline_anwenden(marker, idx) + # Tint-Abgleich (Karte t_b0edb807): ALLE Objekte zeigen ihre doc-Farbe + # (oder — nach „Zurücksetzen“ — wieder die Pack-Farbe). Der Tint bleibt + # jetzt auch bei Markierung sichtbar (Auswahl = Kontur um das Modell). + if idx >= 0 and idx < objects.size() and objects[idx] is Dictionary: + var obj: Dictionary = objects[idx] + if SvmapTint.hat(obj): + SvmapTint.anwenden(marker, SvmapTint.von(obj)) + else: + SvmapTint.zuruecknehmen(marker) + + +func _is_partner(idx: int) -> bool: + return _sym_partners.has(idx) + + +## sym-Partner der Auswahl aus dem doc bestimmen (M3, t_34908425): Objekte mit +## sym-Kennung, deren Partner NICHT selbst in der Auswahl ist. Keine sym-Felder +## im doc (alte Karten, Modus Aus) → leer, Verhalten wie bisher. +func _sym_partners_of(indices: Array) -> Array: + var objects: Array = _doc_ref.get("objects", []) + var out: Array = [] + for i in indices: + if not (i is int) or i < 0 or i >= objects.size() or not (objects[i] is Dictionary): + continue + var key := SymmetryCore.sym_of(objects[i] as Dictionary) + if key.is_empty(): + continue + var t := SymmetryCore.find_partner_index(objects, key, i) + if t >= 0 and not indices.has(t) and not out.has(t): + out.append(t) + return out + + +## Tint frisch aus dem doc auf die MARKIERTEN Objekte anwenden (Inspector- +## Änderung ohne Rebuild). U6: die Farbe bleibt auch bei Markierung sichtbar +## (Auswahl = Kontur um das Modell) — kein „Orange gewinnt“-Skip mehr. +func tint_refresh(indices: Array) -> void: + var objects: Array = _doc_ref.get("objects", []) + for i in indices: + if i < 0 or i >= object_markers.size(): + continue + var marker = object_markers[i] + if marker == null or not is_instance_valid(marker): + continue + if i >= objects.size() or not (objects[i] is Dictionary): + continue + var obj: Dictionary = objects[i] + if SvmapTint.hat(obj): + SvmapTint.anwenden(marker, SvmapTint.von(obj)) + else: + SvmapTint.zuruecknehmen(marker) + + +func _is_selected(idx: int) -> bool: + return selected_indices.has(idx) + + +## Spawn-Zonen (Karte t_c4162c5d): JEDE Zone ist ein flacher, teamfarbiger +## Kreis auf dem Boden (Radius = design_notes.spawn_radius_m, Editor-eigen) +## + Label3D mit der Punkt-ID. Marker-Root bekommt Metas für das Spawn-Tool +## (spawn_team, spawn_id, spawn_radius → Anfassen/Regel). +func _rebuild_spawn_markers(data: Dictionary) -> void: + for marker in spawn_markers: + if marker != null and is_instance_valid(marker): + marker.queue_free() + spawn_markers = [] + var zones = SpawnOps.zones_of(data) # bearbeiteter Spawn-Satz (Basis oder Modus) + if not (zones is Dictionary): + return + for team_key in zones.keys(): + if not (zones[team_key] is Dictionary): + continue + var team := 0 if str(team_key) == "all" else int(team_key) + var zone: Dictionary = zones[team_key] + var points = zone.get("points", []) + if not (points is Array): + continue + for p in points: + if not (p is Dictionary): + continue + var pid: String = str(p.get("id", "?")) + var pos: Array = p.get("pos", [0.0, 0.0, 0.0]) + var marker := _spawn_marker( + Vector3(float(pos[0]), float(pos[1]), float(pos[2])), + team, pid, SpawnOps.zone_radius(data, pid)) + var yaw_col: Color = TEAM_COLORS[team] if team < TEAM_COLORS.size() else Color.WHITE + marker.set_meta("yaw_color", yaw_col) + marker.add_child(_yaw_arrow(SpawnOps.zone_radius(data, pid), + SpawnOps.effective_yaw(data, p), SpawnOps.has_yaw(p), yaw_col)) + spawn_markers.append(marker) + add_child(marker) + + +## Zonen des Spielmodus: Conquest = gelb, King of the Hill = orange (mit Nummer der +## Wanderreihenfolge). Boden-Kreis + durchscheinender Zylinder + Name. +func rebuild_zone_markers(data: Dictionary) -> void: + if zone_root != null and is_instance_valid(zone_root): + zone_root.queue_free() + zone_root = null + var mode := ModusKatalog.mode_of(data) + if not ModusKatalog.has_zones(mode): + return + zone_root = Node3D.new() + zone_root.name = "Zonen" + add_child(zone_root) + var col := Color(1.0, 0.8, 0.2) if mode == ModusKatalog.MODE_CONQUEST else Color(1.0, 0.45, 0.15) + var zlist := ModusKatalog.zones(data, mode) + for zi in zlist.size(): + var cp = zlist[zi] + if not (cp is Dictionary): + continue + var pos: Array = cp.get("pos", [0, 0, 0]) + var r := float(cp.get("radius_m", ModusKatalog.DEFAULT_RADIUS)) + var node := Node3D.new() + node.name = "CP_%s" % str(cp.get("id", "")) + node.position = Vector3(float(pos[0]), float(pos[1]), float(pos[2])) + var mat := StandardMaterial3D.new() + mat.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED + mat.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA + mat.cull_mode = BaseMaterial3D.CULL_DISABLED + mat.albedo_color = Color(col.r, col.g, col.b, 0.18) + var cyl := MeshInstance3D.new() + var cm := CylinderMesh.new() + cm.top_radius = r + cm.bottom_radius = r + cm.height = 8.0 + cm.cap_top = false + cm.cap_bottom = false + cyl.mesh = cm + cyl.material_override = mat + cyl.position.y = 4.0 + node.add_child(cyl) + var ring := MeshInstance3D.new() + var tm := TorusMesh.new() + tm.inner_radius = r - 0.2 + tm.outer_radius = r + 0.2 + tm.rings = 48 + tm.ring_segments = 6 + ring.mesh = tm + var rmat := StandardMaterial3D.new() + rmat.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED + rmat.albedo_color = col + ring.material_override = rmat + ring.position.y = 0.15 + node.add_child(ring) + var label := Label3D.new() + label.text = ("⚑ %s" if mode == ModusKatalog.MODE_CONQUEST else "♛ %d · %%s" % (zi + 1)) % str(cp.get("label", cp.get("id", ""))) + label.position.y = 10.0 + label.billboard = BaseMaterial3D.BILLBOARD_ENABLED + label.modulate = col + label.outline_size = 12 + label.font_size = 160 + label.pixel_size = 0.01 + node.add_child(label) + if mode == ModusKatalog.MODE_CONQUEST: # Hills sind keine Spawns + node.set_meta("zone_id", str(cp.get("id", ""))) + node.set_meta("yaw_radius", r) + node.add_child(_yaw_arrow(r, SpawnOps.effective_yaw(data, cp), SpawnOps.has_yaw(cp), col)) + zone_root.add_child(node) + + +## Ein Spawn-Marker bauen (flacher Kreis + Label). radius = angezeigter Zonen-Radius. +func _spawn_marker(pos: Vector3, team: int, pid: String, radius: float) -> Node3D: + var marker := Node3D.new() + marker.position = pos + marker.set_meta("spawn_team", team) + marker.set_meta("spawn_id", pid) + marker.set_meta("spawn_radius", radius) + marker.set_meta("spawn_pick_radius", maxf(radius + 2.0, 4.0)) + marker.set_meta("spawn_selected", false) + marker.add_child(_spawn_disc(radius, team)) + var label := Label3D.new() + label.text = pid + label.position.y = 2.5 + label.billboard = BaseMaterial3D.BILLBOARD_ENABLED + label.modulate = TEAM_COLORS[team] if team < TEAM_COLORS.size() else Color.WHITE + label.outline_size = 12 + label.font_size = 160 + label.pixel_size = 0.01 + marker.add_child(label) + return marker + + +## Pfeil der Blickrichtung: flach am Boden, zeigt lokal nach -Z, rotation.y = Blickrichtung. +## Gesetzte Richtung kräftig, Standard (zur Kartenmitte) blass grau. Ohne Tiefentest, damit +## Hügel und Objekte ihn nicht verdecken. +func _yaw_arrow(radius: float, yaw_deg: float, is_set: bool, col: Color) -> MeshInstance3D: + var length := yaw_arrow_length(radius) + var half_w := maxf(0.25, length * 0.04) + var head_w := half_w * 3.0 + var head_l := minf(length * 0.4, head_w * 2.5) + var neck := -(length - head_l) + var verts := PackedVector3Array([ + Vector3(-half_w, 0, 0), Vector3(half_w, 0, 0), Vector3(half_w, 0, neck), + Vector3(-half_w, 0, 0), Vector3(half_w, 0, neck), Vector3(-half_w, 0, neck), + Vector3(-head_w, 0, neck), Vector3(head_w, 0, neck), Vector3(0, 0, -length), + ]) + var arrays := [] + arrays.resize(Mesh.ARRAY_MAX) + arrays[Mesh.ARRAY_VERTEX] = verts + var mesh := ArrayMesh.new() + mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, arrays) + var mat := StandardMaterial3D.new() + mat.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED + mat.cull_mode = BaseMaterial3D.CULL_DISABLED + mat.no_depth_test = true + mat.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA + mat.albedo_color = col.lightened(0.35) if is_set else Color(0.75, 0.75, 0.75, 0.55) + var arrow := MeshInstance3D.new() + arrow.name = "YawArrow" + arrow.mesh = mesh + arrow.material_override = mat + arrow.position.y = 0.4 + arrow.rotation.y = deg_to_rad(yaw_deg) + arrow.set_meta("yaw_deg", yaw_deg) + arrow.set_meta("yaw_set", is_set) + arrow.set_meta("yaw_length", length) + return arrow + + +static func yaw_arrow_length(radius: float) -> float: + return maxf(radius, 3.0) + 2.0 + + +func yaw_arrow_of(node: Node3D) -> MeshInstance3D: + return node.get_node_or_null("YawArrow") as MeshInstance3D + + +## Alle Pfeile zum Anfassen: [{kind:"spawn"|"zone", team, id, node, tip:Vector3}]. +func yaw_handles() -> Array: + var out: Array = [] + var add := func(node: Node3D, entry: Dictionary) -> void: + var arrow := yaw_arrow_of(node) + if arrow == null: + return + var yaw := deg_to_rad(float(arrow.get_meta("yaw_deg", 0.0))) + var length := float(arrow.get_meta("yaw_length", 0.0)) + entry["node"] = node + entry["tip"] = node.global_position + Vector3(-sin(yaw), 0.0, -cos(yaw)) * length + out.append(entry) + for marker in spawn_markers: + if marker != null and is_instance_valid(marker): + add.call(marker, {"kind": "spawn", "team": int(marker.get_meta("spawn_team", -1)), "id": str(marker.get_meta("spawn_id", ""))}) + if zone_root != null and is_instance_valid(zone_root): + for node in zone_root.get_children(): + if node.has_meta("zone_id"): + add.call(node, {"kind": "zone", "team": -1, "id": str(node.get_meta("zone_id"))}) + return out + + +## Kreisfläche EINES Markers (neu) bauen — Werkzeuge rufen nach Radius-Änderung +## style_spawn_marker auf. U6 (t_639135dd): die Fläche bleibt IMMER gleich +## dezent (Teamfarbe, halbtransparent) — die Auswahl zeigt sich als schmaler +## Kontur-Ring am Zonenrand (Theme-Farbe), nicht als aufgehellte Vollfläche. +func _spawn_disc(radius: float, team: int, _selected := false) -> MeshInstance3D: + var mi := MeshInstance3D.new() + var cyl := CylinderMesh.new() + cyl.top_radius = radius + cyl.bottom_radius = radius + cyl.height = 0.25 + mi.mesh = cyl + mi.position.y = 0.12 + var col: Color = TEAM_COLORS[team] if team >= 0 and team < TEAM_COLORS.size() else Color.WHITE + var mat := StandardMaterial3D.new() + mat.albedo_color = Color(col.r, col.g, col.b, 0.55) + mat.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA + mat.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED + mi.material_override = mat + return mi + + +## Dezenter Auswahl-Ring EINES Spawn-Markers (U6): dünner Torus am Zonenrand, +## Farbe aus dem Theme. Muss NUR bei Auswahl existieren (restlos weg bei +## Abwahl) — style_spawn_marker legt ihn an/entfernt ihn. +func _spawn_ring(radius: float) -> MeshInstance3D: + var mi := MeshInstance3D.new() + var torus := TorusMesh.new() + var t := maxf(0.15, radius * 0.06) + torus.inner_radius = maxf(0.01, radius - t) + torus.outer_radius = radius + t + mi.mesh = torus + mi.position.y = 0.26 + var mat := StandardMaterial3D.new() + mat.albedo_color = _markierung_farbe("selection_outline") + mat.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA + mat.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED + mi.material_override = mat + return mi + + +## Radius/Anfass-Optik eines Spawn-Markers aktualisieren OHNE Gesamtrebuild +## (Radius-Regel gedreht, Zone ausgewählt/abgewählt). +func style_spawn_marker(marker: Node3D, radius: float, selected: bool) -> void: + if marker == null or not is_instance_valid(marker): + return + var team := int(marker.get_meta("spawn_team", -1)) + var pid := str(marker.get_meta("spawn_id", "")) + marker.set_meta("spawn_radius", radius) + marker.set_meta("spawn_pick_radius", maxf(radius + 2.0, 4.0)) + marker.set_meta("spawn_selected", selected) + if marker.get_child_count() > 0 and marker.get_child(0) is MeshInstance3D: + (marker.get_child(0) as MeshInstance3D).queue_free() + var disc := _spawn_disc(radius, team, selected) + marker.add_child(disc) + marker.move_child(disc, 0) + # Auswahl-Kontur: alter Ring weg, bei Auswahl neuer (restloser Wechsel). + var alter_ring: Node = null + if marker.has_meta("spawn_ring"): + alter_ring = marker.get_meta("spawn_ring") + if alter_ring != null and is_instance_valid(alter_ring): + alter_ring.queue_free() + marker.remove_meta("spawn_ring") + if selected: + var ring := _spawn_ring(radius) + marker.add_child(ring) + marker.set_meta("spawn_ring", ring) + var arrow := yaw_arrow_of(marker) + if arrow != null: # Länge folgt dem Radius + var yaw_deg := float(arrow.get_meta("yaw_deg", 0.0)) + var yaw_set := bool(arrow.get_meta("yaw_set", false)) + arrow.name = "YawArrowAlt" + arrow.queue_free() + marker.add_child(_yaw_arrow(radius, yaw_deg, yaw_set, marker.get_meta("yaw_color", Color.WHITE))) + + +## Auswahl-Highlight über ALLE Spawn-Marker (Werkzeug ruft bei Änderung). +func set_spawn_selected(team: int, pid: String) -> void: + for marker in spawn_markers: + if marker == null or not is_instance_valid(marker): + continue + var is_sel := int(marker.get_meta("spawn_team", -1)) == team \ + and str(marker.get_meta("spawn_id", "")) == pid + if bool(marker.get_meta("spawn_selected", false)) == is_sel: + continue + style_spawn_marker(marker, float(marker.get_meta("spawn_radius", 6.0)), is_sel) + # Label sofort umfärben (auch ohne Disc-Neubau sichtbar) — Farbe aus + # dem Theme statt hartkodiertem Gelb (U6). + var col: Color = TEAM_COLORS[clampi(team, 0, 1)] if team >= 0 else Color.WHITE + if marker.get_child_count() > 1 and marker.get_child(1) is Label3D: + var label := marker.get_child(1) as Label3D + label.modulate = _markierung_farbe("selection_outline") if is_sel else col + + +# ------------------------------------------------------ U6-Markierung ------- +# (Karte t_639135dd — dezente Auswahl: Kontur statt Vollorange. Eine Quelle +# für Farben/Breiten ist das Theme; der Shader ist die Außenhüllen-Technik.) + +## Theme-Farben + -Breiten in die drei Kontur-Materialien überführen +## (Auswahl / Hover / Partner). Fehlende Einträge → Fallback-Farbe. +func _markierung_theme_laden() -> void: + _outline_mat_sel = _outline_material( + _markierung_farbe("selection_outline"), + _markierung_breite("selection_outline_width_mm"), 0.0) + _outline_mat_hover = _outline_material( + _markierung_farbe("selection_outline_hover"), + _markierung_breite("selection_outline_width_hover_mm"), 0.0) + _outline_mat_partner = _outline_material( + _markierung_farbe("selection_outline_partner"), + _markierung_breite("selection_outline_width_partner_mm"), 3.5) + + +## Eine Markierungs-Farbe aus dem Theme lesen (fehlt sie → Fallback). +func _markierung_farbe(name: String) -> Color: + var theme_res: Variant = load(THEME_PATH) + if theme_res is Theme: + var th := theme_res as Theme + if th.has_color(name, "Editor"): + return th.get_color(name, "Editor") + return OUTLINE_FALLBACK + + +## Eine Markierungs-Breite aus dem Theme lesen (Theme speichert Millimeter +## als Ganzzahl — Theme kennt keine Gleitkommakonstanten). +func _markierung_breite(name: String) -> float: + var theme_res: Variant = load(THEME_PATH) + if theme_res is Theme: + var th := theme_res as Theme + if th.has_constant(name, "Editor"): + return float(th.get_constant(name, "Editor")) / 1000.0 + return 0.06 + + +## Kontur-Material für einen Zustand bauen (streifen > 0 = gestrichelt). +func _outline_material(farbe: Color, breite: float, streifen: float) -> ShaderMaterial: + var mat := ShaderMaterial.new() + var shader: Variant = load(OUTLINE_SHADER) + if shader is Shader: + mat.shader = shader + mat.set_shader_parameter("linien_farbe", farbe) + mat.set_shader_parameter("breite_m", breite) + mat.set_shader_parameter("streifen_hz", streifen) + return mat + + +## Zustand eines Objekts (U6-Abstufung): Auswahl > Partner > Hover > nichts. +func _markierung_zustand(idx: int) -> String: + if _is_selected(idx): + return "sel" + if _is_partner(idx): + return "partner" + if idx >= 0 and idx == hover_index: + return "hover" + return "" + + +## Kontur-Hülle eines Objekt-Markers anlegen/umschalten/restlos entfernen. +## Die Hülle hängt als Kind UNTER dem Mesh (erbt Position + Scale — GLB- +## Skalierung bleibt korrekt) und trägt das Mesh ein zweites Mal mit dem +## Außenhüllen-Material (visuell = zweite Render-Passage um das Modell, +## das Grundmaterial mit seiner Textur bleibt unangetastet). +func _outline_anwenden(marker: Node3D, idx: int) -> void: + if marker == null or not is_instance_valid(marker): + return + var zustand := _markierung_zustand(idx) + var alt: Node = null + if marker.has_meta("outline"): + alt = marker.get_meta("outline") + if zustand.is_empty(): + if alt != null and is_instance_valid(alt): + alt.queue_free() + if marker.has_meta("outline"): + marker.remove_meta("outline") + return + var mat: ShaderMaterial = _outline_mat_sel + if zustand == "hover": + mat = _outline_mat_hover + elif zustand == "partner": + mat = _outline_mat_partner + if alt != null and is_instance_valid(alt): + (alt as MeshInstance3D).material_override = mat + return + var mi := marker.get_child(0) as MeshInstance3D + if mi == null or mi.mesh == null: + return + var huelle := MeshInstance3D.new() + huelle.name = "SelectionOutline" + huelle.mesh = mi.mesh + huelle.material_override = mat + mi.add_child(huelle) + marker.set_meta("outline", huelle) + + +## Hover-Markierung (U6-Abstufung, schwächste Kontur). idx = obj_index oder +## -1 für „kein Hover“. Der Aufrufer ist das Objekt-Werkzeug — der Anschluss +## an die Mausbewegung liegt in interaction.gd (Grenze dieser Karte) und +## kommt als Folge-Karte; die Abstufung selbst ist hier voll wirksam. +func set_hover(idx: int) -> void: + if hover_index == idx: + return + hover_index = idx + for marker in object_markers: + if marker == null or not is_instance_valid(marker): + continue + _outline_anwenden(marker, int(marker.get_meta("obj_index", -1))) \ No newline at end of file diff --git a/viewport/map_view_builder.gd.uid b/viewport/map_view_builder.gd.uid new file mode 100644 index 0000000..1761658 --- /dev/null +++ b/viewport/map_view_builder.gd.uid @@ -0,0 +1 @@ +uid://cot16hrvgdx4a diff --git a/viewport/mesh_shapes.gd b/viewport/mesh_shapes.gd new file mode 100644 index 0000000..e51ba1a --- /dev/null +++ b/viewport/mesh_shapes.gd @@ -0,0 +1,88 @@ +extends RefCounted +class_name MeshShapes +## Platzhalter-Meshes für Bibliotheks-Objekte (Form aus dem Kollider-Eintrag, +## wie der Server-Sichtbarkeit) — geteilt von Viewport-Bauer und Ghost-Preview, +## damit Objekte im Editor überall identisch aussehen. + +const SHAPE_BOX := "box" +const SHAPE_SPHERE := "sphere" +const SHAPE_CYLINDER := "cylinder" +const SHAPE_COMPOUND := "compound" +const SHAPE_NONE := "none" + + +static func make_placeholder(shape: String, col: Dictionary, scale: float) -> Mesh: + match shape: + SHAPE_NONE: + # Rein dekorativ (Natur-Update, t_7cf80244): kein Kollider — aber + # im Editor trotzdem sichtbar/wählbar: flache Fußpunkt-Scheibe. + var d := CylinderMesh.new() + d.top_radius = 0.4 * scale + d.bottom_radius = d.top_radius + d.height = maxf(0.02, 0.02 * scale) + return d + SHAPE_SPHERE: + var s := SphereMesh.new() + var r := maxf(0.01, float(col.get("radius", 1.0)) * scale) + s.radius = r + s.height = r * 2.0 + return s + SHAPE_CYLINDER: + var c := CylinderMesh.new() + c.top_radius = maxf(0.01, float(col.get("radius", 1.0)) * scale) + c.bottom_radius = c.top_radius + c.height = maxf(0.01, float(col.get("height", 1.0)) * scale) + return c + SHAPE_COMPOUND: + # Struktur-Objekte (t_d8be9ed7): EIN Mesh aus allen Verbund-Teilen, + # gebacken in Fußpunkt-Koordinaten (Teil-pos = Versatz vom Fußpunkt, + # rot_deg = Euler-Grad) — Rampe/Durchgänge also sichtbar wie die + # echte Kollision. half_height() liefert dafür 0 (schon gebacken). + var st := SurfaceTool.new() + st.begin(Mesh.PRIMITIVE_TRIANGLES) + st.set_smooth_group(-1) + for teil_v in col.get("parts", []): + var teil: Dictionary = teil_v if teil_v is Dictionary else {} + var teil_mesh := make_placeholder(str(teil.get("shape", "box")), teil, scale) + if teil_mesh == null: + continue + var off: Array = teil.get("pos", [0.0, 0.0, 0.0]) + var rot: Array = teil.get("rot_deg", [0.0, 0.0, 0.0]) + var xf := Transform3D( + Basis.from_euler(Vector3(deg_to_rad(float(rot[0])), deg_to_rad(float(rot[1])), deg_to_rad(float(rot[2])))), + Vector3(float(off[0]), float(off[1]), float(off[2])) * scale) + # PrimitiveMesh → Roht_arrays (MeshDataTool bräuchte ArrayMesh). + var arrays: Array = teil_mesh.surface_get_arrays(0) + var verts: PackedVector3Array = arrays[Mesh.ARRAY_VERTEX] + var norms: PackedVector3Array = arrays[Mesh.ARRAY_NORMAL] + var idx: PackedInt32Array = arrays[Mesh.ARRAY_INDEX] + for ii in idx: + st.set_normal(xf.basis * norms[ii]) + st.add_vertex(xf * verts[ii]) + return st.commit() + _: + var b := BoxMesh.new() + var size: Array = col.get("size", [1.0, 1.0, 1.0]) + b.size = Vector3(maxf(0.01, float(size[0])), maxf(0.01, float(size[1])), + maxf(0.01, float(size[2]))) * scale + return b + + +## Halbe Höhe des Meshes über dem Fußpunkt (Mesh-Ursprung = Objekt-Fuß). +## Compound-ArrayMeshes sind bereits in Fußpunkt-Koordinaten gebacken → 0. +static func half_height(mesh: Mesh) -> float: + if mesh is BoxMesh: + return (mesh as BoxMesh).size.y * 0.5 + if mesh is CylinderMesh: + return (mesh as CylinderMesh).height * 0.5 + if mesh is SphereMesh: + return (mesh as SphereMesh).radius + return 0.0 + + +## Höhe des Mesh-MITTELPUNKTS über dem Fußpunkt — für das Drehzentrum der +## Objekt-Auswahl. Bei Grundformen = half_height (Mesh ist zentriert); beim +## Compound-ArrayMesh = AABB-Mitte (schon in Fußpunkt-Koordinaten gebacken). +static func center_height(mesh: Mesh) -> float: + var aabb := mesh.get_aabb() + return half_height(mesh) + aabb.position.y + aabb.size.y * 0.5 \ No newline at end of file diff --git a/viewport/mesh_shapes.gd.uid b/viewport/mesh_shapes.gd.uid new file mode 100644 index 0000000..d7c65ea --- /dev/null +++ b/viewport/mesh_shapes.gd.uid @@ -0,0 +1 @@ +uid://cs588kkixa7rg diff --git a/viewport/orbit_camera.gd b/viewport/orbit_camera.gd new file mode 100644 index 0000000..1e6cea0 --- /dev/null +++ b/viewport/orbit_camera.gd @@ -0,0 +1,454 @@ +extends Camera3D +## Orbit-Kamera + Freelook-Flug für den Editor-Viewport. +## Steuerung: +## Mittlere Maustaste ziehen = Drehen (Orbit) +## Mittlere Maustaste + Shift = Verschieben (Pan, parallel zum Boden) +## Mausrad = Zoom — AUSSER ein Objekt/eine Platzier-Vorschau +## ist aktiv: dann dreht das Mausrad das Objekt +## (interaction.gd meldet das per wheel_filter). +## Rechte Maustaste GEDACHT halten = Freelook-Flug (Karte t_c46d31c2): Umsehen + +## W vor / S zurück / A links / D rechts, +## Leertaste hoch / Shift runter (Shooter- +## Konvention, Sly-Wunsch 17.10.), +## Strg = schneller, Alt = langsamer. +## Mausrad ändert im Flug die +## GRUNDgeschwindigkeit dauerhaft. +## Umschalt+F (main.gd) = Freelook dauerhaft an/aus (Flug bleibt auch +## ohne gedrückte rechte Maustaste aktiv). +## F (main.gd) = Auswahl ins Bild zentrieren → focus_on(). +## Orbit bleibt der Default-Zustand: Beim Verlassen des Flugs werden Orbit- +## Ziel/Winkel/Abstand aus der Flugposition/Blickrichtung zurückgerechnet. +## Die Mathe lebt in core/editor/fly_math.gd (pure, headless testbar). +## Ziel-Punkt, Winkel und Abstand bleiben intern; Position wird jede Frame +## aus ihnen berechnet (Orbit) bzw. im Flug direkt bewegt. +## Karte K1 (t_950fddaa): Beim Dreh-Start liegt der Drehpunkt UNTER DEM +## MAUSZEIGER (Unity/Blender-Verhalten) — Objekt/Bauteil-Treffer zuerst, sonst +## Terrain, sonst alter Ziel-Punkt. Kameraposition und Blickrichtung bleiben +## exakt unverändert (kein Sprung), nur Ziel/Winkel/Abstand werden neu +## gerechnet. fit_to_bounds() ersetzt frame_map(): ganze Map ins Bild. + +const FlyMath := preload("res://core/editor/fly_math.gd") +const TerrainField := preload("res://core/svmap/terrain_field.gd") +const SvmapIO := preload("res://core/svmap/svmap_io.gd") + +const ORBIT_DEG_PER_PX := 0.3 # Karte K1: Drehgeschwindigkeit gekapselt — kein Nachlaufen +const DISTANCE_MIN := 5.0 +const FIT_FLOOR_MIN := 30.0 # fit_to_bounds: nie näher als 30 m an die Map ran +## Karte K1d (t_6c1027c1): Startabstand nach Laden/Neu — Slys Wahl („Nah dran: +## startet ~80 m über der Kartenmitte, Objekte sind sofort groß und greifbar"). +const START_DISTANCE_M := 80.0 +const START_YAW_DEG := 45.0 +const START_PITCH_DEG := 35.0 + +var target := Vector3.ZERO +var yaw_deg := 45.0 +var pitch_deg := 35.0 +var distance := 300.0 + +## Von main.gd gesetzt: Callable → true, wenn das Mausrad gerade ein Objekt +## drehen soll (Platzier-Modus oder Auswahl) statt zu zoomen. +var wheel_filter := Callable() +## Von main.gd gesetzt: Callable für Klartext-Status-Meldungen. +var status_cb := Callable() + +## Grundgeschwindigkeit des Flugs (Mausrad ändert sie dauerhaft, Karte 1/3). +var base_speed_mps := FlyMath.BASE_SPEED_MPS + +var _dragging := false +var _panning := false +var _fly_held := false # Rechte Maustaste gehalten → Flug temporär aktiv +var _fly_locked := false # Umschalt+F: Flug dauerhaft (auch ohne RMT) +var _flying := false # Ergebnis-Flag: gerade im Flugmodus? +var _fly_yaw := 0.0 +var _fly_pitch := 0.0 +var _fit_bounds_mn := Vector3.ZERO # zuletzt gesetzte Map-Bounds (fit_to_bounds) +var _fit_bounds_mx := Vector3.ZERO +var _fit_bounds_valid := false + + +func _ready() -> void: + _apply() + + +func _process(delta: float) -> void: + if not _flying or not InputMap.has_action("editor_fly_forward"): + return + var f := Input.get_action_strength("editor_fly_forward") - Input.get_action_strength("editor_fly_back") + var s := Input.get_action_strength("editor_fly_right") - Input.get_action_strength("editor_fly_left") + var v := Input.get_action_strength("editor_fly_up") - Input.get_action_strength("editor_fly_down") + if f == 0.0 and s == 0.0 and v == 0.0: + return + var speed := FlyMath.speed_for(base_speed_mps, + Input.is_action_pressed("editor_fly_fast"), + Input.is_action_pressed("editor_fly_slow")) + var forward := FlyMath.forward_from_euler(_fly_yaw, _fly_pitch) + var right := FlyMath.forward_from_euler(_fly_yaw, 0.0).cross(Vector3.UP).normalized() + position += FlyMath.move_delta(forward, right, f, s, v, speed, delta) + _apply_fly_orientation() + + +func _unhandled_input(event: InputEvent) -> void: + if event is InputEventKey: + # Karte K1: Pos1/Home = ganze Karte ins Bild (fit_to_bounds). + _handle_home_key(event as InputEventKey) + if event is InputEventMouseButton: + var mb := event as InputEventMouseButton + if mb.button_index == MOUSE_BUTTON_RIGHT: + # Karte t_2470de89: RMB = Flug mit ABSOLUTEM Vorrang — kein Filter, + # keine Heuristik. Werkzeuge behandeln RMB nicht mehr, also startet + # der Flug in JEDEM Werkzeugzustand (auch Terrain/Platzieren/Bauen). + if mb.pressed: + _enter_fly() + _fly_held = true + elif _fly_held: + _fly_held = false + if not _fly_locked: + _exit_fly() + elif mb.button_index == MOUSE_BUTTON_MIDDLE: + if _flying: + return # Im Flug: MMT-Ziehen bleibt unangetastet (kein Orbit-Sprung) + if mb.pressed: + # Karte K1: Drehpunkt unter den Mauszeiger legen — VOR dem + # ersten Ziehen, damit kein Sprung passiert. + _pivot_to_cursor(mb.position) + _dragging = mb.pressed and not mb.shift_pressed + _panning = mb.pressed and mb.shift_pressed + elif mb.button_index == MOUSE_BUTTON_WHEEL_UP and mb.pressed: + if _flying: + base_speed_mps = FlyMath.wheel_speed(base_speed_mps, true) + _status("Flug-Tempo: %.0f m/s (Grundgeschwindigkeit, bleibt dauerhaft)." % base_speed_mps) + return + if _wheel_blocked(): + return + distance = maxf(DISTANCE_MIN, distance * 0.9) + _apply() + elif mb.button_index == MOUSE_BUTTON_WHEEL_DOWN and mb.pressed: + if _flying: + base_speed_mps = FlyMath.wheel_speed(base_speed_mps, false) + _status("Flug-Tempo: %.0f m/s (Grundgeschwindigkeit, bleibt dauerhaft)." % base_speed_mps) + return + if _wheel_blocked(): + return + distance = minf(distance * 1.1, distance_max()) + _apply() + elif event is InputEventMouseMotion: + var mm := event as InputEventMouseMotion + if _flying: + if _fly_held: + # Umsehen: volle 360° Yaw, Pitch −85…+85 (auch von unten hoch). + _fly_yaw = wrapf(_fly_yaw - mm.relative.x * 0.25, -180.0, 180.0) + _fly_pitch = clampf(_fly_pitch + mm.relative.y * 0.25, + -FlyMath.PITCH_MAX_DEG, FlyMath.PITCH_MAX_DEG) + _apply_fly_orientation() + return + if _dragging: + yaw_deg = wrapf(yaw_deg - mm.relative.x * ORBIT_DEG_PER_PX, -180.0, 180.0) + pitch_deg = clampf(pitch_deg + mm.relative.y * ORBIT_DEG_PER_PX, 5.0, 85.0) + _apply() + elif _panning: + var right := transform.basis.x + var fwd := -transform.basis.z + fwd.y = 0.0 + fwd = fwd.normalized() + var scale := distance * 0.0015 + target -= right * mm.relative.x * scale + target += fwd * mm.relative.y * scale + _apply() + + +func _wheel_blocked() -> bool: + return wheel_filter.is_valid() and bool(wheel_filter.call()) + + +func distance_max() -> float: + return 6000.0 + + +## Freelook dauerhaft an/aus (Umschalt+F, main.gd ruft an). +func toggle_fly_lock() -> void: + if _flying: + _fly_locked = false + if not _fly_held: + _exit_fly() + _status("Freelook-Flug aus — zurück zum Orbit (Mittlere Maustaste ziehen = drehen).") + else: + _fly_locked = true + _enter_fly() + _status("Freelook-Flug DAUERHAFT an: W/S/A/D fliegen, Leertaste hoch / Shift runter, Strg schneller, Alt langsamer — Umschalt+F zurück zum Orbit.") + + +## Im Flugmodus? (interaction.gd blockt z. B. Mausrad-Objektdrehung dann ab.) +func fly_active() -> bool: + return _flying + + +## Aktueller Gierwinkel der BLICKRICHTUNG (Karte t_55257792): im Flug der +## Flug-Yaw, im Orbit der Orbit-Yaw. Für die Pfeiltasten-Richtung (MoveMath +## rastet sie auf die nächste Weltachse). +func view_yaw_deg() -> float: + return _fly_yaw if _flying else yaw_deg + + +## Auswahl ins Bild zentrieren (F): Orbit → Ziel-Punkt auf den Auswahl-Mittelpunkt; +## Flug → Blickrichtung drehen, Position bleibt. +func focus_on(center: Vector3) -> void: + if _flying: + var to := center - position + if to.length_squared() < 0.01: + return + var ep := FlyMath.euler_from_forward(to.normalized()) + _fly_yaw = ep.x + _fly_pitch = clampf(ep.y, -FlyMath.PITCH_MAX_DEG, FlyMath.PITCH_MAX_DEG) + _apply_fly_orientation() + else: + target = center + _apply() + + +func _enter_fly() -> void: + if _flying: + return + _fly_yaw = yaw_deg + _fly_pitch = pitch_deg + _flying = true + # Konflikt-Check (Sly-Wunsch 17.10.): Leertaste ist jetzt „hoch fliegen" — + # ein fokussierter Button würde Space/Enter als Klick interpretieren + # (Bibliothek-Button = Platzierung starten). Im Flug gehört die Leertaste + # der Kamera, also GUI-Fokus freigeben. + var vp := get_viewport() + if vp != null and vp.gui_get_focus_owner() != null: + vp.gui_release_focus() + _status("Freelook-Flug an: W/S/A/D fliegen, Leertaste hoch / Shift runter, Strg = schnell, Alt = langsam, Mausrad = Grund-Tempo. Rechte Maustaste loslassen = zurück zum Orbit.") + + +func _exit_fly() -> void: + if not _flying: + return + _flying = false + # Orbit-Zustand aus Flugposition/Blickrichtung zurückrechnen — kein Sprung. + var fwd := -transform.basis.z + if fwd.length_squared() < 0.0000001: + fwd = FlyMath.forward_from_euler(yaw_deg, pitch_deg) + var ep := FlyMath.euler_from_forward(fwd) + yaw_deg = ep.x + pitch_deg = clampf(ep.y, 5.0, 85.0) + distance = clampf(distance, 30.0, distance_max()) + target = position + fwd.normalized() * distance + _apply() + + +func _apply_fly_orientation() -> void: + var fwd := FlyMath.forward_from_euler(_fly_yaw, _fly_pitch) + look_at_from_position(position, position + fwd, Vector3.UP) + + +## Karte K1 (t_950fddaa): Drehpunkt unter den Mauszeiger — aus der unver- +## änderten Kameraposition werden Ziel/Winkel/Abstand neu gerechnet. +func set_pivot(hit: Vector3) -> void: + var pos := position + var fwd := -transform.basis.z + if fwd.length_squared() < 0.0000001: + fwd = FlyMath.forward_from_euler(yaw_deg, pitch_deg) + var ep := FlyMath.euler_from_forward(fwd.normalized()) + target = hit + distance = pos.distance_to(hit) + yaw_deg = ep.x + pitch_deg = ep.y + # Bewusst KEIN _apply(): Position und Basis bleiben exakt wie vorher — + # kein Sprung. Der nächste Dreh-/Zoom-Schritt rechnet aus dem neuen + # Zustand dieselbe Position zurück (Offset-Konvention konsistent). + + +## MMT-Druck: Punkt unter dem Cursor bestimmen — Objekt/Bauteil zuerst, sonst +## Terrain/Boden, sonst aktuellen Ziel-Punkt behalten (kein Sprung). +func _pivot_to_cursor(viewport_pos: Vector2) -> void: + var inter := _find_sibling("_pick_object") + if inter != null: + var idx := int(inter.call("_pick_object", viewport_pos)) + if idx >= 0: + var pt: Variant = _object_pivot_point(idx) + if pt != null: + set_pivot(pt) + return + var g: Variant = inter.call("_ground_point", viewport_pos) + if g != null: + set_pivot(g) + return + # Kein Treffer: Ziel-Punkt unverändert lassen — Ansicht darf nicht springen. + + +## Mittelpunkt des Objekt-Markers (Fußpunkt + halbe Höhe — gleiche Konvention +## wie interaction.gd beim F-Tasten-Zentrieren). +func _object_pivot_point(idx: int) -> Variant: + var builder := _find_builder() + if builder == null: + return null + var markers: Array = builder.get("object_markers") + if markers == null or idx < 0 or idx >= (markers as Array).size(): + return null + var marker = (markers as Array)[idx] + if marker == null or not is_instance_valid(marker): + return null + var half_h := float(marker.get_meta("half_height", 0.0)) + return (marker as Node3D).global_position + Vector3.UP * half_h + + +func _find_sibling(has_method_name: String) -> Node: + var p := get_parent() + if p == null: + return null + for child in p.get_children(): + var c := child as Node + if c != self and c.has_method(has_method_name): + return c + return null + + +func _find_builder() -> Node: + var p := get_parent() + if p == null: + return null + for child in p.get_children(): + var c := child as Node + if c != self and c.get("object_markers") != null: + return c + return null + + +## Fit: target = Mitte der bounds; Abstand so, dass die GANZE Map im Frustum +## liegt; Pos1 ruft das mit den zuletzt gesetzten Bounds erneut auf. Ersetzt +## das tote frame_map(). +func fit_to_bounds(mn: Vector3, mx: Vector3) -> void: + _fit_bounds_mn = Vector3(minf(mn.x, mx.x), minf(mn.y, mx.y), minf(mn.z, mx.z)) + _fit_bounds_mx = Vector3(maxf(mn.x, mx.x), maxf(mn.y, mx.y), maxf(mn.z, mx.z)) + _fit_bounds_valid = true + _fly_held = false + _fly_locked = false + _flying = false + var span := _fit_bounds_mx - _fit_bounds_mn + target = _fit_bounds_mn + span * 0.5 + # Karte K1: Abstand über Umkugel-Formel — ALLE 8 Ecken sicher im Bild. + # (Reiner Faktor der Kantenlänge reicht bei flachen Maps nicht: die nahe + # Oberecke liegt dann fast seitlich zur Blickachse.) + distance = clampf(_fit_distance(span.length() * 0.5), + FIT_FLOOR_MIN, distance_max()) + yaw_deg = 45.0 + pitch_deg = 35.0 + _apply() + + +## Karte K1d (t_6c1027c1, Neuauflage von K1c): Startansicht NAH am Karteninhalt. +## Laden/Neu setzt die Kamera auf die KARTENMITTE (XZ-Mitte der Map-Bounds, +## Höhe = Gelände dort) mit festem Abstand START_DISTANCE_M (80 m), yaw 45°, +## pitch 35° — Objekte sind +## sofort groß und greifbar (Slys Wahl), statt die 1-km-Fläche von weitem zu +## zeigen. Die Regel ist bewusst UNABHÄNGIG von Größe/Lage des Inhalts: immer +## 80 m. Pos1 (Home) bleibt die GANZE Karte — dafür werden hier die MAP-Bounds +## gemerkt (NICHT die Content-Bounds), sodass fit_to_bounds danach die Karte +## einpasst; Startansicht und Pos1 sind also zwei verschiedene Ansichten. +func fit_to_document(doc: Dictionary, map_mn: Vector3, map_mx: Vector3) -> void: + var mn := Vector3(minf(map_mn.x, map_mx.x), minf(map_mn.y, map_mx.y), + minf(map_mn.z, map_mx.z)) + var mx := Vector3(maxf(map_mn.x, map_mx.x), maxf(map_mn.y, map_mx.y), + maxf(map_mn.z, map_mx.z)) + _fly_held = false + _fly_locked = false + _flying = false + # Pos1 = ganze Karte: MAP-Bounds merken (NICHT die Content-Bounds). + _fit_bounds_mn = mn + _fit_bounds_mx = mx + _fit_bounds_valid = true + # Kartenmitte in XZ — in y aber die GELÄNDE-Oberfläche, nicht die Mitte der + # Bounds: die Bounds reichen bei neuen Maps von −10 bis 80 m, ihre Mitte + # (35 m) liegt 35 m über dem Boden. Damit hätte die Ansicht 35 m über den + # Boden gezielt und die Objekte stünden am unteren Bildrand. + var mitte := mn + (mx - mn) * 0.5 + target = Vector3(mitte.x, SvmapDocument.terrain_height_at(doc, mitte.x, mitte.z), mitte.z) + distance = clampf(START_DISTANCE_M, DISTANCE_MIN, distance_max()) + yaw_deg = START_YAW_DEG + pitch_deg = START_PITCH_DEG + _apply() + var count := int(content_bounds(doc)["count"]) + if count == 0: + _status("Ansicht: Kartenmitte, Abstand %d m (kein Inhalt — Pos1 = ganze Karte)." % + int(START_DISTANCE_M)) + else: + _status("Ansicht: Kartenmitte, Abstand %d m (Pos1 = ganze Karte)." % + int(START_DISTANCE_M)) + + +## Bounding-Box des Dokument-INHALTS: Objekte (inkl. Bauteile) und +## Spawnpunkte — Terrain und Map-Bounds zählen NICHT (Karte K1b). +## Rückgabe: {mn: Vector3, mx: Vector3, count: int}; count 0 = leeres Dokument. +static func content_bounds(doc: Dictionary) -> Dictionary: + var mn := Vector3(INF, INF, INF) + var mx := Vector3(-INF, -INF, -INF) + var count := 0 + for p: Vector3 in _content_points(doc.get("objects", []) as Array): + mn = mn.min(p) + mx = mx.max(p) + count += 1 + var zones: Dictionary = doc.get("spawn_zones", {}) as Dictionary + for team_key in zones: + var zone: Dictionary = zones[team_key] if zones[team_key] is Dictionary else {} + for p: Vector3 in _content_points(zone.get("points", []) as Array): + mn = mn.min(p) + mx = mx.max(p) + count += 1 + if count == 0: + return {"mn": Vector3.ZERO, "mx": Vector3.ZERO, "count": 0} + return {"mn": mn, "mx": mx, "count": count} + + +## pos-Felder [x, y, z] aus einer Dokument-Liste lesen; defekte Einträge +## überspringen (stillschweigend, nie ein harter Fehler beim Laden). +static func _content_points(items: Array) -> Array: + var pts: Array = [] + for item in items: + if not (item is Dictionary): + continue + var pos: Variant = (item as Dictionary).get("pos") + if pos is Array and (pos as Array).size() >= 3: + pts.append(Vector3(float(pos[0]), float(pos[1]), float(pos[2]))) + return pts + + +## Abstand, damit die Umkugel (Radius um den Ziel-Punkt) komplett sichtbar +## bleibt: d = R / sin(halber FOV der SCHMALEREN Bildachse) + 2 % Reserve. +func _fit_distance(radius: float) -> float: + var vfov_half := deg_to_rad(fov * 0.5) # fov ist vertikal (KEEP_HEIGHT) + var aspect := 16.0 / 9.0 + var vp := get_viewport() + if vp != null: + var vs := vp.get_visible_rect().size + if vs.y > 0.0: + aspect = vs.x / vs.y + var hfov_half := atan(aspect * tan(vfov_half)) + var half := minf(vfov_half, hfov_half) + if half <= 0.0 or half >= PI * 0.5: + half = deg_to_rad(37.5) + return maxf(radius, 1.0) / sin(half) * 1.02 + + +func _handle_home_key(key: InputEventKey) -> void: + if key.pressed and not key.echo and key.keycode == KEY_HOME: + if _fit_bounds_valid: + fit_to_bounds(_fit_bounds_mn, _fit_bounds_mx) + _status("Pos1: ganze Karte ins Bild.") + + +func _apply() -> void: + var pitch := deg_to_rad(pitch_deg) + var yaw := deg_to_rad(yaw_deg) + var offset := Vector3( + sin(yaw) * cos(pitch), + sin(pitch), + cos(yaw) * cos(pitch) + ) * distance + position = target + offset + look_at(target, Vector3.UP) + + +func _status(text: String) -> void: + if status_cb.is_valid(): + status_cb.call(text) \ No newline at end of file diff --git a/viewport/orbit_camera.gd.uid b/viewport/orbit_camera.gd.uid new file mode 100644 index 0000000..d848fc0 --- /dev/null +++ b/viewport/orbit_camera.gd.uid @@ -0,0 +1 @@ +uid://bhv55tde24sxg diff --git a/viewport/terrain_contour.gdshader b/viewport/terrain_contour.gdshader new file mode 100644 index 0000000..225a6f7 --- /dev/null +++ b/viewport/terrain_contour.gdshader @@ -0,0 +1,237 @@ +shader_type spatial; +// Terrain-Konturlinien (EDITOR-ONLY, Karte t_3ebe4086): Höhenlinien alle 1 m +// plus kräftigere 5-m-Indexlinie, per-pixel aus UV2.x (= Vertex-Höhe in m). +// Der Quest-3-Perf-Vertrag (kein Custom-Shader) gilt fürs SPIEL — der Editor +// darf teurer sein (DECISIONS.md-Konvention). +// +// Karte t_ab408127 (Terrain-Texturierung): der Editor rendert DIESELBEN +// Texturen wie der Match-Client — Albedo/Normal-Arrays über die Vertex-Alpha +// (Material-ID), Worldspace-Tiling. Konturlinien liegen OBENDRAUF (dunkle +// Multiplikation auf der texturierten Fläche). Ohne Arrays (uniforms nicht +// gesetzt, Fallback-Klon) bleibt es beim reinen Vertex-Farb-Look. +// +// Farbquelle = COLOR: RGB = gebackenes Relief-Shading (Höhen-Kurve × +// Pseudo-Licht), A = Material-ID (m/N gepackt). Unshaded: das gebackene +// Shading ist exakt sichtbar (deterministisch für die Render-Probe). +render_mode unshaded, cull_back; + +// Linienstärken (0 = aus). Terrain-Mesh setzt linien_an auf 0, wenn die +// Map flacher als 2 m ist (sonst wäre ALLES auf der 0-m-Linie dunkel). +uniform float linien_an : hint_range(0.0, 1.0) = 1.0; +uniform float linien_staerke : hint_range(0.0, 1.0) = 0.5; +uniform float index_staerke : hint_range(0.0, 1.0) = 0.75; + +// Textur-Arrays (t_ab408127) — identische Semantik wie terrain_splat.gdshader +// im Client. Nicht gesetzt → ausschalten (vertex_only-Modus). +uniform sampler2DArray albedo_array : source_color, filter_linear_mipmap, repeat_enable; +uniform float layer_count = 20.0; +uniform float tile_size = 3.0; +uniform float texturen_an = 0.0; // 1.0 = Texturen aktiv (vom Mesh-Code gesetzt) + +// Splat-Gewichtstextur (Karte t_7a0a6b79 — weiche Übergänge): je Texel die +// Top-2-Zell-IDs + bilineare Gewichte, von TerrainArrays.build_splat_bytes +// abgeleitet (Spiegel-Datei, identische Formel im Client). R=id0, G=w0, +// B=id1, A=w1 (w0+w1=1). FILTER_NEAREST: IDs dürfen NICHT bilinear vermisch +// werden — die Weichheit steckt IN den Gewichten, nicht in der Filterung. +// Ohne source_color-Hint: raw-Bytes, id = round(kanal × 255). +// Karte 25.10. (Sly: „immer noch harte Kanten“): statt der Splat-Textur (ein +// Texel je Materialpunkt → beim feinen 1-m-Raster harte Pixelstufen) liest der +// Shader die MATERIAL-ID-KARTE direkt (R8, ein Texel je Materialpunkt, +// material_res²) und mischt PRO PIXEL bilinear zwischen den 4 umliegenden +// Punkten — weiche Übergänge über genau einen Rasterabstand, egal wie fein. +// 4 Albedo- + 4 Normal-Fetches + 4 texelFetch, keine Branches. +uniform sampler2D material_map : filter_nearest, repeat_disable; +// Misch-Schicht (Karte 25.10., weiche Pinselränder): je Punkt ein zweites +// Material (b) und dessen Anteil (w, 0–255). Ohne Mischung: alles 0. +uniform sampler2D material_b_map : filter_nearest, repeat_disable; +uniform sampler2D material_w_map : filter_nearest, repeat_disable; +uniform float material_res = 2.0; // Kantenlänge der Material-Karte (Punkte) +uniform float map_size_x = 1.0; // Terrain-Kantenlänge in Weltmetern +uniform float map_size_z = 1.0; + +varying vec3 world_pos; +varying vec2 map_uv; + +void vertex() { + world_pos = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xyz; + // UV 0..1 über die Map (Index 0 = −X/−Z-Ecke, konventionstreu zum Mesh-Bau). + map_uv = vec2((world_pos.x + 0.5 * map_size_x) / max(map_size_x, 0.001), + (world_pos.z + 0.5 * map_size_z) / max(map_size_z, 0.001)); +} + +// Organische Kanten (Karte 25.10.): die Materialpunkte liegen auf einem +// 1-m-Raster — ohne Störung zeichnet die bilineare Mischung dessen Treppen +// nach. Ein leichter Domain-Warp (Value-Noise in Rasterzellen, ±0,45 Zelle) +// verwackelt die Abtaststelle, die Kante wird unregelmäßig wie echter Boden. +// Ganzzahl-Hash statt sin()-Hash (Karte 25.10.): sin() großer Argumente ist +// auf der GPU ungenau — die Noise bekam gerade, rasterförmige Sprünge, die +// als harte Kanten durch die Verläufe liefen (Sly-Befund, nah gezoomt). +float hash2(vec2 p) { + uvec2 q = uvec2(ivec2(p) + ivec2(4096)); + uint h = q.x * 1597334677u ^ q.y * 3812015801u; + h = (h ^ (h >> 16u)) * 2246822519u; + h = h ^ (h >> 13u); + return float(h & 65535u) / 65535.0; +} + +float vnoise(vec2 p) { + vec2 i = floor(p); + vec2 f = fract(p); + f = f * f * (3.0 - 2.0 * f); + return mix(mix(hash2(i), hash2(i + vec2(1.0, 0.0)), f.x), + mix(hash2(i + vec2(0.0, 1.0)), hash2(i + vec2(1.0, 1.0)), f.x), f.y); +} + +vec2 warp(vec2 g) { + vec2 o = vec2(vnoise(g * 0.9), vnoise(g * 0.9 + vec2(17.3, 5.1))) - 0.5; + return g + o * 0.9; // eine Oktave: Quest-Budget (8 Hash statt 16) +} + +// Anti-Wiederholung v2 (Karte 25.10., Sly: Büschel sitzen im Raster, diagonale +// Streifen): Hex-Tiling (Mikkelsen/Heitz-Neyret): die Ebene wird in ein +// Dreiecksgitter geteilt, jede Ecke bekommt zufälligen Versatz + Drehung, die +// 3 Abtastungen werden mit weichen Gewichten überblendet — kein Raster, keine +// Achsen mehr, keine harten Nähte. Quest-Kosten: 3 Albedo-Fetches je Material +// (nur 1 Material in ~allen Pixeln, die Mischzone nimmt 2). Danach Makro- +// Variation: Helligkeit (~35 m) + Farbstich (~120 m), je 1 Value-Noise. +uniform float detail_kontrast = 1.3; // >1 = Büschel/Steine kräftiger (Hex-Mischung glättet sonst) + +vec3 alb_hex(float id, vec2 wp, vec2 gx, vec2 gy) { + float T = max(tile_size, 0.05); + vec2 st = wp / T * 1.7320508; // sqrt(3): Dreieckskante ≈ 0,58 Kachel (größer = weniger Mischzone) + vec2 sk = vec2(st.x - 0.57735027 * st.y, 1.15470054 * st.y); + vec2 base = floor(sk); + vec2 fr = fract(sk); + float tz = 1.0 - fr.x - fr.y; + float up = step(0.0, tz); // 1: unteres Dreieck, 0: oberes + vec3 w = mix(vec3(-tz, 1.0 - fr.y, 1.0 - fr.x), vec3(tz, fr.y, fr.x), up); + vec2 v1 = mix(base + vec2(1.0), base, up); + vec2 v2 = mix(base + vec2(1.0, 0.0), base + vec2(0.0, 1.0), up); + vec2 v3 = mix(base + vec2(0.0, 1.0), base + vec2(1.0, 0.0), up); + w = w * w * w; // Mitte stärker, Nähte weicher + w /= (w.x + w.y + w.z); + float wn = sqrt(dot(w, w)); // für Kontrast-Erhalt (Varianz der Mischung) + vec2 uv = wp / T; + vec3 acc = vec3(0.0); + for (int k = 0; k < 3; k++) { + vec2 v = k == 0 ? v1 : (k == 1 ? v2 : v3); + float wk = k == 0 ? w.x : (k == 1 ? w.y : w.z); + float a = hash2(v + vec2(31.0, 7.0)) * 6.2831853; + vec2 off = vec2(hash2(v), hash2(v + vec2(53.0, 11.0))); + float c = cos(a); + float s = sin(a); + vec2 r = vec2(c * uv.x - s * uv.y, s * uv.x + c * uv.y) + off; + acc += wk * textureGrad(albedo_array, vec3(r, id), gx, gy).rgb; + } + // Kontrast-Erhalt: Mischen dreier Abtastungen glättet auf den Mittelwert → + // Abweichung vom Mittelwert (grober Mip) durch ||w|| teilen. + vec3 mean_c = textureLod(albedo_array, vec3(0.5, 0.5, id), 8.0).rgb; + acc = mean_c + (acc - mean_c) * (detail_kontrast / max(wn, 0.577)); + float bright = mix(0.86, 1.12, vnoise(wp * 0.028 + vec2(17.0, 3.0))); + float tint = vnoise(wp * 0.0085 + vec2(5.0, 41.0)) - 0.5; + vec3 col = acc * bright; + return col * vec3(1.0 + 0.10 * tint, 1.0 + 0.03 * tint, 1.0 - 0.10 * tint); +} + +float mat_id(ivec2 p) { + return clamp(floor(texelFetch(material_map, p, 0).r * 255.0 + 0.5), 0.0, layer_count - 1.0); +} + +float mat_b(ivec2 p) { + return clamp(floor(texelFetch(material_b_map, p, 0).r * 255.0 + 0.5), 0.0, layer_count - 1.0); +} + +// Top-2-Mischung (Karte 25.10.): 4 Nachbarpunkte × (a, b) = 8 Kandidaten mit +// Gewicht (bilinear × Punkt-Anteil). Gleiche IDs werden aufsummiert, die +// zwei stärksten Materialien gewinnen. Rückgabe: (id1, id2, Anteil id1). +// Danach nur 2 Albedo- + 2 Normal-Fetches. +vec3 top2(vec2 g) { + vec2 gi = min(floor(g), vec2(max(material_res - 2.0, 0.0))); + vec2 f = clamp(g - gi, 0.0, 1.0); + ivec2 p = ivec2(gi); + ivec2 q[4] = ivec2[4](p, p + ivec2(1, 0), p + ivec2(0, 1), p + ivec2(1, 1)); + float cw[4] = float[4]((1.0 - f.x) * (1.0 - f.y), f.x * (1.0 - f.y), (1.0 - f.x) * f.y, f.x * f.y); + float ids[8]; + float ws[8]; + for (int k = 0; k < 4; k++) { + float wb = texelFetch(material_w_map, q[k], 0).r; + ids[2 * k] = mat_id(q[k]); + ws[2 * k] = cw[k] * (1.0 - wb); + ids[2 * k + 1] = mat_b(q[k]); + ws[2 * k + 1] = cw[k] * wb; + } + float id1 = ids[0]; + float s1 = -1.0; + for (int i = 0; i < 8; i++) { + float s = 0.0; + for (int j = 0; j < 8; j++) { + s += ids[j] == ids[i] ? ws[j] : 0.0; + } + if (s > s1) { + s1 = s; + id1 = ids[i]; + } + } + float id2 = id1; + float s2 = 0.0; + for (int i = 0; i < 8; i++) { + if (ids[i] == id1) { + continue; + } + float s = 0.0; + for (int j = 0; j < 8; j++) { + s += ids[j] == ids[i] ? ws[j] : 0.0; + } + if (s > s2) { + s2 = s; + id2 = ids[i]; + } + } + return vec3(id1, id2, s1 / max(s1 + s2, 0.00001)); +} + +void fragment() { + vec3 col = COLOR.rgb; + // --- Textur (t_ab408127): Material-ID aus Vertex-Alpha, Worldspace-UV --- + // Editor-Vorschau ALBEDO-ONLY (der Editor-Viewport ist unshaded; eine + // Normal-Map würde ohne Licht ohnehin nichts zeigen — die Relief-Optik + // kommt aus dem gebackenen Hillshade in COLOR.rgb). + if (texturen_an > 0.5) { + // Top-2-Splat-Blend (t_7a0a6b79): die Weichheit steckt in den Gewich- + // ten der Splat-Textur — an Zellgrenzen rampen die IDs weich (bilinear + // über die 4 umliegenden Zellen), im Flachbereich w0=1 (reines id0). + // Karte 25.10.: Top-2 aus 4 Nachbarpunkten inkl. Misch-Schicht + // (Spiegel zum Client-Shader terrain_splat.gdshader). + float m1 = max(material_res - 1.0, 1.0); + vec2 g = clamp(warp(clamp(map_uv, 0.0, 1.0) * m1), vec2(0.0), vec2(m1)); + vec3 t2 = top2(g); + // Ableitungen VOR dem Branch (Mip-Wahl bleibt gültig, textureGrad). + vec2 guv = world_pos.xz / max(tile_size, 0.05); + vec2 gx = dFdx(guv); + vec2 gy = dFdy(guv); + // Reiner Boden (Anteil ≥ 0,999, Normalfall): nur 3 statt 6 Fetches. + vec3 alb = t2.z > 0.999 ? alb_hex(t2.x, world_pos.xz, gx, gy) + : mix(alb_hex(t2.y, world_pos.xz, gx, gy), alb_hex(t2.x, world_pos.xz, gx, gy), t2.z); + col = alb * col; // Tönung/Shading multipliziert (wie Client) + } + // --- Konturlinien (unverändert, Karte t_3ebe4086) --- + float h = UV2.x; + // Flachflächen-Schutz: liegt eine GANZE Platte exakt auf einer Meter-Marke + // (z. B. Tal = 0.0 m, Plateau = 5.0 m), wäre jedes Pixel „auf der Linie“ + // → die Fläche würde komplett dunkel übermalt. Deshalb: Linienstärke an + // der lokalen Steigung dämpfen — exakt flach (dh = 0) → keine Linie, + // sanfte bis steile Hänge → volle Linie. + float dh = max(abs(dFdx(h)), abs(dFdy(h))); + float relief = smoothstep(0.0, 0.0005, dh); + // Abstand (in m) zur nächsten ganzen Meter-Marke: + float d1 = abs(fract(h + 0.5) - 0.5); + float w1 = fwidth(h) * 1.2; // Linie ~1–2 px breit, auflösungsstabil + float linie = 1.0 - smoothstep(w1 * 0.5, w1 * 1.5, d1); + // 5-m-Indexlinie (Abstand in m zur nächsten 5er-Marke): + float d5 = abs(fract(h / 5.0 + 0.5) - 0.5) * 5.0; + float w5 = fwidth(h) * 2.2; + float linie5 = 1.0 - smoothstep(w5 * 0.5, w5 * 1.5, d5); + col = mix(col, col * 0.55, linie * linien_an * linien_staerke * relief); + col = mix(col, col * 0.32, linie5 * linien_an * index_staerke * relief); + ALBEDO = col; +} diff --git a/viewport/terrain_contour.gdshader.uid b/viewport/terrain_contour.gdshader.uid new file mode 100644 index 0000000..c6426a4 --- /dev/null +++ b/viewport/terrain_contour.gdshader.uid @@ -0,0 +1 @@ +uid://clp2k02n02ruk diff --git a/viewport/terrain_mesh.gd b/viewport/terrain_mesh.gd new file mode 100644 index 0000000..9f63186 --- /dev/null +++ b/viewport/terrain_mesh.gd @@ -0,0 +1,446 @@ +extends Node3D +## Terrain-Ansicht: baut das Höhenfeld (svmap terrain-Block) als Mesh im +## Editor-Viewport (M2, Karte t_9aba04f1). +## +## Zwei Wege: +## rebuild_from_doc(data) — nach Laden/Neu/Undo: Base64 dekodieren + Mesh neu. +## update_heights(...) — während eines Pinsel-Strichs: nur Vertices neu +## schreiben (SOFT-war das Mesh live — kein Rebuild, +## kein Flackern, res 129 ≈ 16,6k Punkte = flott). +## +## Farben (Karte t_603ec1a8): Vertex-Farben aus der Material-Schicht +## (terrain.materials_r8_b64, v2) — Gras/Sand/Fels, plus Höhen-Faktor. +## +## Relief-Lesbarkeit (Karte t_3ebe4086, Sly-Befund „Erhöhungen/Vertiefungen +## kaum erkennbar"): TWO-PUNCH im Vertex-Farben-Pfad: +## 1. Höhen-Faktor deutlich kontrastreicher: steilere S-Kurve statt linear +## und breitere Faktor-Spanne (Senken dunkler, Hügel heller). +## 2. Pseudo-Licht: Terrain-Normale × feste Sonnenrichtung (Hillshade) — +## Sonnenabgewandte Hänge werden dunkler, zugewandte heller. Das ist der +## günstigste echte Relief-Eindruck für die mobile Vertex-Farb-Pipeline +## und identisch zum Match-Client (svmap_terrain.gd, gleiche Konstanten). +## +## Editor-only Extra (gleiche Karte): Höhenlinien alle 1 m + 5-m-Indexlinie +## per Custom-Shader (terrain_contour.gdshader, UV2.x = Höhe). Quest-Vertrag +## „kein Custom-Shader" gilt fürs Spiel — der EDITOR darf teurer sein +## (DECISIONS.md-Konvention). Der Match-Client bleibt StandardMaterial3D. +## Editor-Viewport material ist UNSHADED: das gebackene Shading ist exakt +## sichtbar (kein Doppel-Shading mit dem Viewport-Sonnenlicht, deterministisch +## für die Render-Probe). + +const MATERIAL_COLORS: Array[Color] = [ + Color(1.0, 1.0, 1.0), # 0 = Gras — Karte t_ab408127: Textur liefert die + Color(1.0, 1.0, 1.0), # 1 = Sand — Farbe; Vertex-RGB ist nur noch Shading- + Color(1.0, 1.0, 1.0), # 2 = Fels — Multiplikator (Höhe × Hillshade), + # 20-Slot-Palette: Weiß = neutral, Albedo-Textur trägt die Färbung. + Color(1.0, 1.0, 1.0), # 3 + Color(1.0, 1.0, 1.0), # 4 + Color(1.0, 1.0, 1.0), # 5 + Color(1.0, 1.0, 1.0), # 6 + Color(1.0, 1.0, 1.0), # 7 + Color(1.0, 1.0, 1.0), # 8 + Color(1.0, 1.0, 1.0), # 9 + Color(1.0, 1.0, 1.0), # 10 + Color(1.0, 1.0, 1.0), # 11 + Color(1.0, 1.0, 1.0), # 12 + Color(1.0, 1.0, 1.0), # 13 + Color(1.0, 1.0, 1.0), # 14 + Color(1.0, 1.0, 1.0), # 15 + Color(1.0, 1.0, 1.0), # 16 + Color(1.0, 1.0, 1.0), # 17 + Color(1.0, 1.0, 1.0), # 18 + Color(1.0, 1.0, 1.0), # 19 +] +# Höhen-Faktor (Material-Farbe × Faktor) — KARTE t_3ebe4086: bewusst breiter +# und mit S-Kurve (t*t*(3-2t)) kalibriert als die alte Linear-Version +# (0.72 … 1.15): Senken deutlich dunkler, Hügel deutlich heller. +const SHADING_LOW := 0.58 # Tal-Faktor +const SHADING_HIGH := 1.28 # Hügel-Faktor +# Pseudo-Licht (Hillshade): feste Sonnenrichtung, editor-seitig so gewählt, +# dass beim Default-Blick (Kamera südlich der Map, Blick Richtung −Z) die +# Formen seitlich beleuchtet wirken (Licht von rechts-hinten +X/+Z). +const RELIEF_SUN := Vector3(0.45, 0.75, 0.5) +const LIGHT_LOW := 0.62 # Hang abgewandt von der Sonne +const LIGHT_HIGH := 1.22 # Hang zugewandt +const LIGHT_T0 := 0.15 # Smoothstep-Fenster der NDOT-Kurve +const LIGHT_T1 := 0.95 +const SHADE_MIN := 0.40 # Gesamtklemme (Höhen × Licht), Schutz vor Schwarz +const SHADE_MAX := 1.35 +# Höhenlinien (editor-only) nur ab 2 m Gesamtrelief — auf einer flachen Map +# läge sonst ALLES auf der 0-m-Linie und die Fläche würde dunkel übermalt. +const CONTOUR_MIN_SPAN := 2.0 + +const CONTOUR_SHADER := "res://core/viewport/terrain_contour.gdshader" + +var _mi: MeshInstance3D +var _res := 0 +var _size_x := 0.0 +var _size_z := 0.0 +var _mats_cache := PackedByteArray() # zuletzt gesehene Material-Schicht + # (res²) — Live-Pfad-Fallback, Karte + # t_55ed041a. +var _wasser_level := INF # Karte t_28fdef03: Wasserhöhe aus dem doc + # (INF = kein Wasser — Matsch-Ring aus). +var _triangles := 0 +var _contours_pref := true # UI-Toggle „Höhenlinien“ (Default AN) +var _shader: Shader + +# --- Splat-Gewichtstextur (Karte t_7a0a6b79 — weiche Übergänge) ------------- +# CPU-Image + GPU-Textur der Top-2-Splat-Gewichte (RGBA8: R=id0 G=w0 B=id1 +# A=w1, Formel TerrainArrays.build_splat_bytes — Spiegel-Datei). Beim Malen +# wird NUR die betroffene Region neu abgeleitet (Sub-Rect-Update, siehe +# _refresh_splat_region) — kein Voll-Rebuild pro Mal-Frame. +var _splat_image: Image +var _splat_tex: ImageTexture +var _splat_side := 0 # Texel-Kantenlänge (Zweierpotenz) +var _splat_res := 0 # Zellraster-Auflösung, für die die Splat gilt +# Misch-Schicht (Karte 25.10.): zweites Material + Anteil je Punkt — eigene +# R8-Texturen neben der Material-Karte (gleiche Größe, Shader liest alle drei). +var _mix_b_cache := PackedByteArray() +var _mix_w_cache := PackedByteArray() +var _mix_b_image: Image +var _mix_w_image: Image +var _mix_b_tex: ImageTexture +var _mix_w_tex: ImageTexture + + +func _ready() -> void: + _ensure_mesh_instance() + + +func _ensure_mesh_instance() -> void: + if _mi != null and is_instance_valid(_mi): + return + _mi = MeshInstance3D.new() + _mi.material_override = _make_material() + add_child(_mi) + + +## Material fürs Editor-Terrain: unshaded Kontur-Shader (Vertex-Farbe als +## Albedo + Höhenlinien). Karte t_ab408127: zusätzlich die Terrain-Texturen +## (TerrainArrays.res — spiegelgleich zum Client-Pfad, aber EDITOR-EIGENE +## Kopie der Resource-Klasse, Repos sind entkoppelt). Fällt auf unshaded +## StandardMaterial3D zurück, wenn der Shader nicht ladbar ist (Robustheit — +## Terrain bleibt immer sichtbar). +func _make_material() -> Material: + _shader = load(CONTOUR_SHADER) + if _shader != null: + var mat := ShaderMaterial.new() + mat.shader = _shader + _apply_texture_uniforms(mat) + return mat + push_warning("TerrainMesh: Kontur-Shader fehlt — Fallback StandardMaterial3D (unshaded).") + var std := StandardMaterial3D.new() + std.vertex_color_use_as_albedo = true + std.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED + std.roughness = 1.0 + return std + + +## Terrain-Texturen an den Kontur-Shader binden (t_ab408127). Quelle = +## res://assets/textures/terrain/terrain_arrays.res — vom Sync-Skript +## (tools/sync_terrain_tex.sh) aus dem Client-Klon gespiegelt, analog +## tools/sync_models.sh (models/-Ordner-Muster). Fehlt die Resource +## (frischer Editor-Klon ohne Sync), bleibt texturen_an=0 → reiner +## Vertex-Farb-Look (Fallback, kein Crash). +func _apply_texture_uniforms(mat: ShaderMaterial) -> void: + const ARRAYS_PATH := "res://assets/textures/terrain/terrain_arrays.res" + if not ResourceLoader.exists(ARRAYS_PATH): + return # Fallback-Klon: texturen_an bleibt 0 (Vertex-Farb-Look) + var arrays = load(ARRAYS_PATH) + if arrays == null or not ("albedo_images" in arrays): + return + var imgs: Array = arrays.albedo_images + if imgs.size() < 3: + return + var albedo := Texture2DArray.new() + albedo.create_from_images(imgs) + mat.set_shader_parameter("albedo_array", albedo) + mat.set_shader_parameter("layer_count", float(imgs.size())) + mat.set_shader_parameter("tile_size", 3.0) # Spiegel Client TILE_SIZE (Karte 25.10.) + mat.set_shader_parameter("texturen_an", 1.0) + + +## UI-Toggle „Höhenlinien“ (main.gd): ohne Rebuild an/ab. +func set_contours(on: bool) -> void: + _contours_pref = on + _apply_contour_state(_last_span >= CONTOUR_MIN_SPAN) + + +func contours_enabled() -> bool: + return _contours_pref + + +var _last_span := 0.0 + + +## Kompletter Neuaufbau aus dem svmap-terrain-Block (inkl. Material-Schicht). +func rebuild_from_doc(data: Dictionary) -> void: + var terrain: Dictionary = data.get("terrain", {}) + if terrain.is_empty(): + _triangles = 0 + if _mi != null: + _mi.mesh = null + return + # Splat-Textur verwerfen — sie wird im update_heights frisch aus der + # (nach Undo/Load evtl. geänderten) Zell-Schicht abgeleitet. + _splat_tex = null + var mix := SvmapIO.decode_mix(data.get("terrain", {})) + _mix_b_cache = mix[0] + _mix_w_cache = mix[1] + # Wasser (Karte t_28fdef03): Höhe merken — der Matsch-Ring (Ufer-Automatik) + # mischt sich in relief_color ein. INF = kein Wasser (Legacy unverändert). + _wasser_level = SvmapWasser.level(data) + var heights := SvmapIO.decode_heights(terrain) + var mats := SvmapIO.decode_materials(terrain) + update_heights(heights, int(terrain.get("resolution", 0)), + float(terrain.get("size_x_m", 1.0)), float(terrain.get("size_z_m", 1.0)), mats) + + +## Mesh aus einem (neuen) Höhenfeld bauen — auch live während des Strichs. +## res/size 0 = zuletzt verwendete Werte weiterverwenden (Live-Pfad). +## mats = Material-Schicht (res² Bytes, 0=Gras/1=Sand/2=Fels); leer → die +## zuletzt gesehene Schicht (Cache) wird weiterverwendet, damit Live-Updates +## ohne explizite Schicht (z. B. Heben/Senken-Stroke) die Material-Farben +## BEHALTEN statt live auf alles-Gras zurückzufallen (Karte t_55ed041a). +## Nur wenn NIE eine Schicht gesehen wurde (Legacy-v1-Map) gilt alles Gras. +func update_heights(heights: PackedFloat32Array, res: int = 0, size_x: float = 0.0, + size_z: float = 0.0, mats: PackedByteArray = PackedByteArray(), + splat_rect_cells: Rect2i = Rect2i()) -> void: + if res < 2: + res = _res + if size_x <= 0.0: + size_x = _size_x + if size_z <= 0.0: + size_z = _size_z + if _mi == null: + _ensure_mesh_instance() + if res < 2 or heights.size() < res * res or size_x <= 0.0 or size_z <= 0.0: + return + _res = res + _size_x = size_x + _size_z = size_z + # Material-Schicht hat ihr eigenes (feines) Raster (Karte 24.10.) — mres + # aus der Länge (quadratisch); alte Karten: mres == res. + if mats.is_empty() and not _mats_cache.is_empty(): + mats = _mats_cache + elif not mats.is_empty(): + _mats_cache = mats + var mres := mat_res_of(mats, res) + var last := float(res - 1) + var positions := PackedVector3Array() + var normals := PackedVector3Array() + var colors := PackedColorArray() + var heights_uv := PackedVector2Array() + var indices := PackedInt32Array() + positions.resize(res * res) + normals.resize(res * res) + colors.resize(res * res) + heights_uv.resize(res * res) + + var hmin := INF + var hmax := -INF + for v in heights: + if v < hmin: + hmin = v + if v > hmax: + hmax = v + var span := maxf(hmax - hmin, 0.0001) + _last_span = span + var cell_x := size_x / last + var cell_z := size_z / last + _apply_contour_state(span >= CONTOUR_MIN_SPAN) + + var z := 0 + while z < res: + var x := 0 + while x < res: + var idx := z * res + x + # Index→Welt-Konvention (Karte t_234490cf): Index 0 = −X/−Z-Ecke, + # x-Index läuft MIT +WeltX, z-Index MIT +WeltZ — IDENTISCH zu + # SvmapDocument.terrain_height_at, TerrainField.height_at und dem + # Match-Client (svmap_terrain.gd: −size*0.5 + index*cell). + # Vor b7b160d…+Fix stand hier eine SPIGELUNG (+0.5 − index·cell in + # beiden Achsen) — der Renderer war damit der einzige Verbraucher + # dieser Konvention: der Pinsel-Strahl traf das Mesh an der + # punktgespiegelten Stelle (Sly-Befund „Pinsel wirkt woanders“). + positions[idx] = Vector3( + -size_x * 0.5 + float(x) * cell_x, + heights[idx], + -size_z * 0.5 + float(z) * cell_z) + # Normale aus zentralen Differenzen (Rand: einseitig geklemmt): + # n ∝ (−∂h/∂x, 1, −∂h/∂z), skaliert mit 2·cell_x·cell_z. + var hx_l := heights[z * res + maxi(x - 1, 0)] + var hx_r := heights[z * res + mini(x + 1, res - 1)] + var hz_d := heights[maxi(z - 1, 0) * res + x] + var hz_u := heights[mini(z + 1, res - 1) * res + x] + normals[idx] = Vector3( + (hx_l - hx_r) * cell_z, + 2.0 * cell_x * cell_z, + (hz_d - hz_u) * cell_x).normalized() + var mat_id := clampi(SvmapIO.material_at_height_point(mats, mres, res, x, z), + 0, MATERIAL_COLORS.size() - 1) + # Material-Farbe × Höhen-Kurve × Pseudo-Licht (Relief lesbar). + var farbe := relief_color(mat_id, heights[idx], hmin, hmax, normals[idx]) + # Ufer-Automatik (Karte t_28fdef03): Zellen knapp unter der Wasser- + # höhe bekommen den Matsch-Ring — IDENTISCHE Formel wie der Client + # (SvmapWasser.ufer_faktor/matsch_anwenden — dieselbe Spiegel-Datei). + # Alpha (gepackte Material-ID) bleibt unangetastet (Splat-Vertrag). + if _wasser_level < INF: + farbe = SvmapWasser.matsch_anwenden(farbe, + SvmapWasser.ufer_faktor(heights[idx], _wasser_level)) + colors[idx] = farbe + heights_uv[idx] = Vector2(heights[idx], 0.0) + x += 1 + z += 1 + + z = 0 + while z < res - 1: + var x := 0 + while x < res - 1: + var i := z * res + x + # Winding-Order: Godot betrachtet Clockwise (von der Vorderseite + # betrachtet) als Vorderseite. Von oben gelesen muss jedes Dreieck + # IM Uhrzeigersinn laufen, sonst cullt der Renderer die komplette + # Deckfläche als Backface (Karte t_7ac70014: „dunkle Platte“). + indices.append_array([i, i + 1, i + res, i + 1, i + res + 1, i + res]) + x += 1 + z += 1 + + var arrays := [] + arrays.resize(Mesh.ARRAY_MAX) + arrays[Mesh.ARRAY_VERTEX] = positions + arrays[Mesh.ARRAY_NORMAL] = normals + arrays[Mesh.ARRAY_COLOR] = colors + arrays[Mesh.ARRAY_TEX_UV2] = heights_uv # Höhe je Vertex → Kontur-Shader + arrays[Mesh.ARRAY_INDEX] = indices + var mesh := ArrayMesh.new() + mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, arrays) + _mi.mesh = mesh + _triangles = indices.size() / 3 + + # --- Splat-Gewichtstextur (t_7a0a6b79): map_size + Sub-Rect-Update -------- + # map_size_x/z in Weltmetern (Shader rechnet map_uv = Weltkoord. über Map). + # Mal-Stroke: splat_rect_cells = betroffenes Zellrechteck → NUR die Region + # neu ableiten. Voll-Rebuild (Load/Undo/Stroke-Ende): Textur frisch bauen. + var mat := _mi.material_override + if mat is ShaderMaterial: + var shm := mat as ShaderMaterial + shm.set_shader_parameter("map_size_x", size_x) + shm.set_shader_parameter("map_size_z", size_z) + # Material-ID-Karte (Karte 25.10.): Malen = gleiche Größe → nur Daten + # tauschen (1 Upload); sonst neu anlegen. splat_rect_cells bleibt als + # Parameter (Aufrufer-Vertrag), wird aber nicht mehr gebraucht. + if _splat_tex != null and _splat_res == mres and mats.size() == mres * mres \ + and _mix_b_tex != null and _mix_b_cache.size() == mres * mres: + _splat_image.set_data(mres, mres, false, Image.FORMAT_R8, mats) + _splat_tex.update(_splat_image) + _mix_b_image.set_data(mres, mres, false, Image.FORMAT_R8, _mix_b_cache) + _mix_b_tex.update(_mix_b_image) + _mix_w_image.set_data(mres, mres, false, Image.FORMAT_R8, _mix_w_cache) + _mix_w_tex.update(_mix_w_image) + else: + _build_splat(shm, mats, mres, size_x, size_z) + + +## Misch-Schicht fürs nächste update_heights (Live-Malen, Karte 25.10.). +func set_mix(mix_b: PackedByteArray, mix_w: PackedByteArray) -> void: + _mix_b_cache = mix_b + _mix_w_cache = mix_w + + +## Raster einer Material-Schicht aus ihrer Länge (quadratisch). Unpassend/leer +## → Höhenraster (alte Karten, Legacy ohne Schicht). +static func mat_res_of(mats: PackedByteArray, res: int) -> int: + if mats.is_empty(): + return res + var r := int(roundf(sqrt(float(mats.size())))) + return r if r >= 2 and r * r == mats.size() else res + + +## Höhenlinien-Uniform an die aktuelle Situation anpassen (Pref ∧ Relief ≥ 2 m). +func _apply_contour_state(span_ok: bool) -> void: + if _mi == null or not is_instance_valid(_mi): + return + var mat := _mi.material_override + if mat is ShaderMaterial: + mat.set_shader_parameter("linien_an", 1.0 if (_contours_pref and span_ok) else 0.0) + + +## Vertex-Farbe EINER Zelle: Material × Höhen-Kurve × Pseudo-Licht. +## Static (statt inline), damit Tests die Mathematik direkt prüfen können und +## Editor/Client die IDENTISCHE Formel teilen (Konstanten spiegeln — gleiche +## Kommentare/Konstanten wie scripts/world/svmap_terrain.gd im Client-Repo). +## Alpha = Material-ID (Karte t_ab408127): m/N gepackt — der Shader (Client +## UND Editor-Vorschau) sampelt die Texture2DArray-Layer über die Alpha. +## Der Shading-Faktor wirkt NUR auf RGB (Color × float skaliert auch Alpha — +## deshalb wird die ID erst im Return gezielt gesetzt). +static func relief_color(mat_id: int, h: float, hmin: float, hmax: float, + normal: Vector3) -> Color: + var m := clampi(mat_id, 0, MATERIAL_COLORS.size() - 1) + var span := maxf(hmax - hmin, 0.0001) + var t := clampf((h - hmin) / span, 0.0, 1.0) + # Steilere Kurve statt linear: S-Kurve hebt die Enden, senkt die Mitte — + # Hügel/Senken trennen sich stärker als bei t direkt. + var t_s := t * t * (3.0 - 2.0 * t) + var hf := lerpf(SHADING_LOW, SHADING_HIGH, t_s) + # Pseudo-Licht: Normale × feste Sonnenrichtung → Hillshade. + var nd := clampf(normal.normalized().dot(RELIEF_SUN.normalized()), 0.0, 1.0) + var x := clampf((nd - LIGHT_T0) / (LIGHT_T1 - LIGHT_T0), 0.0, 1.0) + var lf := lerpf(LIGHT_LOW, LIGHT_HIGH, x * x * (3.0 - 2.0 * x)) + # Ausbrennen-Fix (t_7a0a6b79): der Faktor wird auf 1.0 normalisiert. Vorher + # lief hf·lf bis 1.35 und RGBA8 klemmte auf 1.0 — ALLE Relief-Unterschiede + # oberhalb 1.0 kollabierten zu flachem Weiß (Slys „ausgebrannte Weißflächen“ + # auf Sand hell/Schnee). Relative Spanne bleibt identisch (0.40…1.35 → + # 0.296…1.0), Kontrast-Verhältnis unverändert, Shading bleibt sichtbar. + var f := clampf(hf * lf, SHADE_MIN, SHADE_MAX) / SHADE_MAX + var base := MATERIAL_COLORS[m] as Color + # Kanäle auf 0..1 klemmen: der Mesh-Speicher (ARRAY_COLOR, RGBA8) clamp't + # genauso — der Helfer muss die RENDER-Wahrheit liefern (Probe-Vergleich), + # nicht die unbehandelte Mathematik. + return Color(clampf(base.r * f, 0.0, 1.0), clampf(base.g * f, 0.0, 1.0), + clampf(base.b * f, 0.0, 1.0), float(m) / float(MATERIAL_COLORS.size())) + + +func triangle_count() -> int: + return _triangles + + +func resolution() -> int: + return _res + + +## Splat-Gewichtstextur komplett ableiten (t_7a0a6b79). Die Zell-Schicht +## (mats, res²) bleibt die Quelle der Wahrheit — die Textur ist reine +## Ableitung (Datenformat unverändert). Unbrauchbare Schicht → alte Textur +## bleibt (Robustheit, kein Crash). +## size_x/size_z (t_5c94d098): Karten-Kantenlänge in Metern → Texel-Dichte der +## Splat (1 m/Texel bei 1024 m; vorher 2 m/Texel = sichtbare Stufen). +func _build_splat(mat: ShaderMaterial, mats: PackedByteArray, res: int, + _size_x: float = 0.0, _size_z: float = 0.0) -> void: + if res < 2: + _splat_tex = null + return + # Karte 25.10.: Material-ID-Karte statt Splat-Gewichte (weiche Übergänge + # pro Pixel im Shader, Spiegel zum Client). + _splat_image = TerrainArrays.material_image(mats, res) + _splat_side = _splat_image.get_width() + _splat_res = res + _splat_tex = ImageTexture.create_from_image(_splat_image) + # Misch-Schicht: passt sie nicht zum Raster (Legacy/leer) → Nullen. + if _mix_b_cache.size() != res * res or _mix_w_cache.size() != res * res: + _mix_b_cache = PackedByteArray() + _mix_b_cache.resize(res * res) + _mix_w_cache = PackedByteArray() + _mix_w_cache.resize(res * res) + _mix_b_image = TerrainArrays.material_image(_mix_b_cache, res) + _mix_w_image = TerrainArrays.material_image(_mix_w_cache, res) + _mix_b_tex = ImageTexture.create_from_image(_mix_b_image) + _mix_w_tex = ImageTexture.create_from_image(_mix_w_image) + if mat != null: + mat.set_shader_parameter("material_map", _splat_tex) + mat.set_shader_parameter("material_b_map", _mix_b_tex) + mat.set_shader_parameter("material_w_map", _mix_w_tex) + mat.set_shader_parameter("material_res", float(_splat_side)) + + diff --git a/viewport/terrain_mesh.gd.uid b/viewport/terrain_mesh.gd.uid new file mode 100644 index 0000000..157ab7a --- /dev/null +++ b/viewport/terrain_mesh.gd.uid @@ -0,0 +1 @@ +uid://bwwwoxt0cxfj diff --git a/viewport/wasser.gdshader b/viewport/wasser.gdshader new file mode 100644 index 0000000..1504512 --- /dev/null +++ b/viewport/wasser.gdshader @@ -0,0 +1,92 @@ +shader_type spatial; +// Wasser-Oberfläche pro Map (Karte t_28fdef03) — SPIEGELGLEICHE Datei: +// scopedvr-client → res://shaders/wasser.gdshader +// scopedvr-map-editor → res://src/viewport/wasser.gdshader (byteidentischer +// Spiegel, sync via tools/sync_wasser.sh — wie terrain_splat/terrain_arrays). +// +// Quest-3-Perf-Vertrag (bewusste Absagen der Spec): KEINE echte Spiegelung, +// KEINE Brechung, KEIN SSR. Spiegel-Impression = Skybox-Farbreflex (uniform) +// + Fresnel-Glanz. Wellen NUR im Fragment-Shader (analytische 2-Layer-Sinus- +// Normalen — keine Wellen-Texturen, keine Geometrie-Bewegung). Ufer-Schaum + +// Flachwasser-Transparenz aus der Tiefe-Textur (ufer_tex, R8 = Tiefe/TIEFE_MAX, +// siehe SvmapWasser.ufer_bild). Ferne Fragmente vereinfachen sich selbst +// (Wasserdistanz-Regel): nur Grundfarbe, keine Wellen/Schaum-Mathematik. +// +// Eine Fläche, ein Draw-Call — Overdraw ist die einzige echte Kostenquelle. + +render_mode blend_mix, depth_draw_never, cull_back, unshaded, shadows_disabled; + +uniform vec4 farbe_flach : source_color = vec4(0.10, 0.30, 0.34, 1.0); +uniform vec4 farbe_tief : source_color = vec4(0.02, 0.10, 0.15, 1.0); +uniform vec3 reflex : source_color = vec3(0.72, 0.83, 0.92); // Skybox-Farbreflex (Wetter) +uniform float glanz : hint_range(0.0, 2.0) = 1.0; // Glint-Stärke (Wetter) +uniform sampler2D ufer_tex : filter_linear; // R = Tiefe 0..1 (0..TIEFE_MAX) +uniform float tiefe_max = 4.0; // SvmapWasser.TIEFE_MAX (Spiegel-Konstante) +uniform float schaum_band = 0.35; // SvmapWasser.SCHAUM_BAND (Meter) +uniform float wellen_scale = 0.55; // Wellenfrequenz (1/m) +uniform float wellen_staerke = 0.16; // Normal-Neigung (flach = Spiegel-Optik) + +varying vec3 welt_pos; // Welt-Position des Fragments (Fresnel + Distanz-Regel) + +void vertex() { + welt_pos = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xyz; +} + +// Analytische Wellen-Normale aus 2 Scroll-Ebenen (kleine Skala, verschiedene +// Richtungen/Geschwindigkeiten — läuft nie synchron): h = Σ A·sin(dot(p,d)·f + t·s), +// n ∝ (−∂h/∂x, 1, −∂h/∂z) mit ∂h/∂p = Σ A·f·d·cos(…). +vec3 wellen_normal(vec2 p, float t) { + vec2 d1 = vec2(0.94, 0.34); + vec2 d2 = vec2(-0.42, 0.91); + float f1 = wellen_scale * 2.1; + float f2 = wellen_scale * 3.7; + float s1 = 1.25; + float s2 = 1.75; + float a1 = wellen_staerke; + float a2 = wellen_staerke * 0.6; + vec2 g1 = d1 * (f1 * a1 * cos(dot(p, d1) * f1 + t * s1)); + vec2 g2 = d2 * (f2 * a2 * cos(dot(p, d2) * f2 + t * s2)); + vec2 g = g1 + g2; + return normalize(vec3(-g.x, 1.0, -g.y)); +} + +void fragment() { + // Tiefe am Fragment (ufer_tex, UV deckt die Map 1:1 ab — SvmapWasser.ufer_bild). + float tiefe01 = texture(ufer_tex, UV).r; + float tiefe = tiefe01 * tiefe_max; + + // Wasserdistanz-Regel: ferne Fragmente = vereinfachter Modus (Grundfarbe, + // flache Normale, kein Schaum). Weiches Fenster 45→90 m, pro Fragment. + float fern = smoothstep(45.0, 90.0, length(welt_pos - CAMERA_POSITION_WORLD)); + float detail = 1.0 - fern; + + vec3 n = wellen_normal(welt_pos.xz, TIME); + n = normalize(mix(vec3(0.0, 1.0, 0.0), n, detail)); + + vec3 v = normalize(CAMERA_POSITION_WORLD - welt_pos); + float fresnel = pow(1.0 - clamp(dot(n, v), 0.0, 1.0), 5.0); + + // Grundfarbe: seicht heller/durchsichtiger, tief dunkler. + vec3 grund = mix(farbe_flach.rgb, farbe_tief.rgb, clamp(tiefe01 * 1.4, 0.0, 1.0)); + + // Spiegel-Impression: Skybox-Farbreflex via Fresnel + Sonnen-Glint. + vec3 reflex_f = reflex * mix(0.25, 1.0, fresnel); + vec3 l = normalize(vec3(-0.45, 0.75, 0.5)); // SvmapTerrain.RELIEF_SUN (Spiegel) + float glint = pow(max(dot(reflect(-v, n), l), 0.0), 48.0) * glanz; + + // Ufer-Schaum: schmales Band an der Wasserlinie, Kante leicht wellig + // (Wellen-Phase pulsiert das Band ±20 %). + float schaum_grenze = schaum_band * (0.9 + 0.2 * sin(welt_pos.x * 1.7 + welt_pos.z * 1.3 + TIME * 1.2)); + float schaum = (1.0 - smoothstep(0.0, max(schaum_grenze, 0.02), tiefe)) * detail; + + vec3 farbe = grund + reflex_f + vec3(glint) + vec3(schaum * 0.85); + // Transparenz: Ufer fast klar, tiefes Wasser dicht. Schaum deckt voll. + float alpha = mix(0.38, 0.88, clamp(tiefe01 * 1.6, 0.0, 1.0)); + alpha = max(alpha, schaum * 0.9); + + // spatial-Vertrag: Farbe über ALBEDO, Transparenz über ALPHA (COLOR gibt + // es nur im canvas_item-Shader — schreibend dort = „Constants cannot be + // modified“). + ALBEDO = farbe; + ALPHA = alpha; +} diff --git a/viewport/wasser.gdshader.uid b/viewport/wasser.gdshader.uid new file mode 100644 index 0000000..71814f5 --- /dev/null +++ b/viewport/wasser.gdshader.uid @@ -0,0 +1 @@ +uid://c7s4uhqs208da