From 866f0e47baf8deb37d27298fe29044b05549c143 Mon Sep 17 00:00:00 2001 From: Martin Pourrat Date: Wed, 20 May 2026 15:20:34 +0200 Subject: [PATCH 01/42] Fix oblong fig_leader PNG URLs missing _stadium suffix Overlays.ttslua referenced range_fig_leader_long.png and range_fig_leader_snail.png, but the assets shipped in mod/data/mac-fallback-assets/ are named with the _stadium suffix (consistent with generate_overlay_assets.py output and the inline copy in mac-patcher/patch_save_for_mac.py). TTS hit a GitHub 404 and surfaced "Load image failed unsupported format: UNKNOWN". Co-Authored-By: Claude Opus 4.7 (1M context) --- mod/src/includes/Overlays.ttslua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mod/src/includes/Overlays.ttslua b/mod/src/includes/Overlays.ttslua index 503a2375c..6af43dd7a 100644 --- a/mod/src/includes/Overlays.ttslua +++ b/mod/src/includes/Overlays.ttslua @@ -36,8 +36,8 @@ local RANGE_DECAL_URLS = { huge = ASSETS_BASE .. "range_fig_leader_huge.png", laat = ASSETS_BASE .. "range_fig_leader_laat.png", epic = ASSETS_BASE .. "range_fig_leader_epic.png", - long = ASSETS_BASE .. "range_fig_leader_long.png", - snail = ASSETS_BASE .. "range_fig_leader_snail.png", + long = ASSETS_BASE .. "range_fig_leader_long_stadium.png", + snail = ASSETS_BASE .. "range_fig_leader_snail_stadium.png", }, } local RANGE_MAX_RADIUS = { From a5a361cec018305b584793e220b9e58d6ee2c78c Mon Sep 17 00:00:00 2001 From: Martin Pourrat Date: Tue, 11 Aug 2026 03:47:10 +0200 Subject: [PATCH 02/42] Add apple_logo.png UI sprite for the Mac patch toggle button Co-Authored-By: Claude Fable 5 --- mod/data/mac-fallback-assets/apple_logo.png | Bin 0 -> 1442 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 mod/data/mac-fallback-assets/apple_logo.png diff --git a/mod/data/mac-fallback-assets/apple_logo.png b/mod/data/mac-fallback-assets/apple_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..b7bf86f9adffa32286743c2d797554d25bc7b95c GIT binary patch literal 1442 zcmZ`(`9IVN0R4VvFih^+M7fO^VL$F6M`j#fw{hi&Da^Q5v##tGhDsA{MF{I!CPf-Y zsA!t8j>?dBEY%efmA>O03ZQ5;_%;{azIg$ z@7if~o(%xPkr3{TcXG+sDgU}DuOqM5W}^CQinF9S6?iPJ?f7>cR|#kiE<@UuTF5wd;f;@7^APf;Lco=9HuG0w29G&{*=BC-?^z9; zn=e`~wQLvk{Sb8q|0E)!;4wP$#~_3=@3dOkQk%Pp7$r2lo24(9U8D2Eu_7mgUcTwk z^_{CuoJy~w07spE_v46#UWsWzKl2|^d?PxF=U{W+jdwX%m(ujc!oX^{a|9`PWVZ!` z$6mzju$>zcrb3RZa5cCC1t8hspn$ak1+6Cp<>}{!;Hk)+*Qi|L<5D}B#>zR;lg##1 zLO44l?X9d~`|?u>X>u&PV;^otU)&p~fOlGs3F6|DJx5YnRDpt)ow@RvMC)HfDNh1} zzPT^8m78d==%M0*0B$V7ek7$?6-JExc~u$y47ePHB%h(~NoKt0?;16gS-V<&H&_TD zKc`ip6w#5UkcA`9hto^!Sr&%s9lFNFTGMcbs30Y9JIBbGlaxE`$n)jg&$TMp$fSKy z|Cis9=FFEP$Z<6Z*OFc#mO;trvAy8gn6wQ>=V6xM;}>32tYC?fytYdg81m1W_dtMpEw=q z%iZX3f=IZoXeW($|DAkG1%bYXqO#1~bx*XmA>c9HqV<$@_o+-{5{XHD*WqUfhSHO+7A|7(q?CBEv^+f`ykcKKEJS_ zfm|u&=83`!+dN%)r(Zi0#7*{5@d1pi{H!M*A;ZKec+qjhH}*8vNiP(5`C#w41>XuT z4_8SP8#2r9e&}3`)x`InmB#ZnTwV3O0z@`zWIT~}c<4T;R{7E)&3@Owoikz6mMA$7 zt5|F1k&?8Ngy{$qKiPRbuu3xK?DV~bibkbGb{RNO8>($+gA-`Zdv1=LfcQG;dGZy& z?S-+!9hrmEmvOkaaiva0U=~#?8$0b~&A5Ah)eB)WtG79r;-vN!Mfjius^{XFuE!rX z)pM7qT8A7g?wiAnvUOs8n3F}}tAiwpr$4tUCh)O~$8Vi4F5+lK>u#l>eRz68d$j9& z<027emUx5GYJzLNN$4p#orx|QTE1Qz*osNobg_84rQBP;$EEJLyrnUP>f~fXpf>Ns zHuNmlPb`_zcFOm{P!Mbw-l~0h->>QVq$8$NMJ?4Ee-LI6JEhhDeF&?ZHy%tD`q=WY*i1e j;P_zXP;1eT(X%DTA1XF~5mDIv{d)n(&J9PmC1m^$(xI@x literal 0 HcmV?d00001 From 495c450ae2f42639272e7aaad74ee57eb0d2e5cd Mon Sep 17 00:00:00 2001 From: Martin Pourrat Date: Tue, 11 Aug 2026 04:34:47 +0200 Subject: [PATCH 03/42] Add silhouette_mac_fallback_v2.unity3d: Unlit/Transparent hologram Material references the player's built-in Unlit/Transparent via resources/unity_builtin_extra (like every working vanilla bundle) instead of embedding a custom shader that TTS U6 on Mac refuses to load. Co-Authored-By: Claude Fable 5 --- .../silhouette_mac_fallback_v2.unity3d | Bin 0 -> 106057 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 mod/data/mac-fallback-assets/silhouette_mac_fallback_v2.unity3d diff --git a/mod/data/mac-fallback-assets/silhouette_mac_fallback_v2.unity3d b/mod/data/mac-fallback-assets/silhouette_mac_fallback_v2.unity3d new file mode 100644 index 0000000000000000000000000000000000000000..ffbc3ea51966983e858924deaaac0b29eba6b7b2 GIT binary patch literal 106057 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 Pz5Lk%{^eWpC1U;y0=YU6 literal 0 HcmV?d00001 From 3f20dfeb4447971c7fabf3827b14bc2dd9c01161 Mon Sep 17 00:00:00 2001 From: Martin Pourrat Date: Tue, 11 Aug 2026 04:53:39 +0200 Subject: [PATCH 04/42] Add collider_null.obj: degenerate collider for non-physical spawns Co-Authored-By: Claude Fable 5 --- mod/data/mac-fallback-assets/collider_null.obj | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 mod/data/mac-fallback-assets/collider_null.obj diff --git a/mod/data/mac-fallback-assets/collider_null.obj b/mod/data/mac-fallback-assets/collider_null.obj new file mode 100644 index 000000000..86297cd2f --- /dev/null +++ b/mod/data/mac-fallback-assets/collider_null.obj @@ -0,0 +1,4 @@ +v 0 0 0 +v 0.001 0 0 +v 0 0.001 0 +f 1 2 3 From 6a41acdc5072d10a4e57ffe2cf26fa79438010af Mon Sep 17 00:00:00 2001 From: Martin Pourrat Date: Tue, 11 Aug 2026 05:13:42 +0200 Subject: [PATCH 05/42] Add stadium silhouette meshes for oblong bases (long/snail) Co-Authored-By: Claude Fable 5 --- mod/data/mac-fallback-assets/stadium_long.obj | 303 ++++++++++++++++++ .../mac-fallback-assets/stadium_snail.obj | 303 ++++++++++++++++++ 2 files changed, 606 insertions(+) create mode 100644 mod/data/mac-fallback-assets/stadium_long.obj create mode 100644 mod/data/mac-fallback-assets/stadium_snail.obj diff --git a/mod/data/mac-fallback-assets/stadium_long.obj b/mod/data/mac-fallback-assets/stadium_long.obj new file mode 100644 index 000000000..902907aae --- /dev/null +++ b/mod/data/mac-fallback-assets/stadium_long.obj @@ -0,0 +1,303 @@ +o stadium +v -1.96850 0.00000 1.47638 +v -1.95166 0.00000 1.73332 +v -1.90142 0.00000 1.98587 +v -1.81866 0.00000 2.22969 +v -1.70477 0.00000 2.46063 +v -1.56172 0.00000 2.67473 +v -1.39194 0.00000 2.86832 +v -1.19835 0.00000 3.03810 +v -0.98425 0.00000 3.18115 +v -0.75331 0.00000 3.29504 +v -0.50949 0.00000 3.37780 +v -0.25694 0.00000 3.42804 +v -0.00000 0.00000 3.44488 +v 0.25694 0.00000 3.42804 +v 0.50949 0.00000 3.37780 +v 0.75331 0.00000 3.29504 +v 0.98425 0.00000 3.18115 +v 1.19835 0.00000 3.03810 +v 1.39194 0.00000 2.86832 +v 1.56172 0.00000 2.67473 +v 1.70477 0.00000 2.46063 +v 1.81866 0.00000 2.22969 +v 1.90142 0.00000 1.98587 +v 1.95166 0.00000 1.73332 +v 1.96850 0.00000 1.47638 +v 1.96850 0.00000 -1.47638 +v 1.95166 0.00000 -1.73332 +v 1.90142 0.00000 -1.98587 +v 1.81866 0.00000 -2.22969 +v 1.70477 0.00000 -2.46063 +v 1.56172 0.00000 -2.67473 +v 1.39194 0.00000 -2.86832 +v 1.19835 0.00000 -3.03810 +v 0.98425 0.00000 -3.18115 +v 0.75331 0.00000 -3.29504 +v 0.50949 0.00000 -3.37780 +v 0.25694 0.00000 -3.42804 +v 0.00000 0.00000 -3.44488 +v -0.25694 0.00000 -3.42804 +v -0.50949 0.00000 -3.37780 +v -0.75331 0.00000 -3.29504 +v -0.98425 0.00000 -3.18115 +v -1.19835 0.00000 -3.03810 +v -1.39194 0.00000 -2.86832 +v -1.56172 0.00000 -2.67473 +v -1.70477 0.00000 -2.46063 +v -1.81866 0.00000 -2.22969 +v -1.90142 0.00000 -1.98587 +v -1.95166 0.00000 -1.73332 +v -1.96850 0.00000 -1.47638 +v -1.96850 1.00000 1.47638 +v -1.95166 1.00000 1.73332 +v -1.90142 1.00000 1.98587 +v -1.81866 1.00000 2.22969 +v -1.70477 1.00000 2.46063 +v -1.56172 1.00000 2.67473 +v -1.39194 1.00000 2.86832 +v -1.19835 1.00000 3.03810 +v -0.98425 1.00000 3.18115 +v -0.75331 1.00000 3.29504 +v -0.50949 1.00000 3.37780 +v -0.25694 1.00000 3.42804 +v -0.00000 1.00000 3.44488 +v 0.25694 1.00000 3.42804 +v 0.50949 1.00000 3.37780 +v 0.75331 1.00000 3.29504 +v 0.98425 1.00000 3.18115 +v 1.19835 1.00000 3.03810 +v 1.39194 1.00000 2.86832 +v 1.56172 1.00000 2.67473 +v 1.70477 1.00000 2.46063 +v 1.81866 1.00000 2.22969 +v 1.90142 1.00000 1.98587 +v 1.95166 1.00000 1.73332 +v 1.96850 1.00000 1.47638 +v 1.96850 1.00000 -1.47638 +v 1.95166 1.00000 -1.73332 +v 1.90142 1.00000 -1.98587 +v 1.81866 1.00000 -2.22969 +v 1.70477 1.00000 -2.46063 +v 1.56172 1.00000 -2.67473 +v 1.39194 1.00000 -2.86832 +v 1.19835 1.00000 -3.03810 +v 0.98425 1.00000 -3.18115 +v 0.75331 1.00000 -3.29504 +v 0.50949 1.00000 -3.37780 +v 0.25694 1.00000 -3.42804 +v 0.00000 1.00000 -3.44488 +v -0.25694 1.00000 -3.42804 +v -0.50949 1.00000 -3.37780 +v -0.75331 1.00000 -3.29504 +v -0.98425 1.00000 -3.18115 +v -1.19835 1.00000 -3.03810 +v -1.39194 1.00000 -2.86832 +v -1.56172 1.00000 -2.67473 +v -1.70477 1.00000 -2.46063 +v -1.81866 1.00000 -2.22969 +v -1.90142 1.00000 -1.98587 +v -1.95166 1.00000 -1.73332 +v -1.96850 1.00000 -1.47638 +v 0.00000 0.00000 0.00000 +v 0.00000 1.00000 0.00000 +f 1 2 52 +f 1 52 51 +f 101 2 1 +f 102 51 52 +f 2 3 53 +f 2 53 52 +f 101 3 2 +f 102 52 53 +f 3 4 54 +f 3 54 53 +f 101 4 3 +f 102 53 54 +f 4 5 55 +f 4 55 54 +f 101 5 4 +f 102 54 55 +f 5 6 56 +f 5 56 55 +f 101 6 5 +f 102 55 56 +f 6 7 57 +f 6 57 56 +f 101 7 6 +f 102 56 57 +f 7 8 58 +f 7 58 57 +f 101 8 7 +f 102 57 58 +f 8 9 59 +f 8 59 58 +f 101 9 8 +f 102 58 59 +f 9 10 60 +f 9 60 59 +f 101 10 9 +f 102 59 60 +f 10 11 61 +f 10 61 60 +f 101 11 10 +f 102 60 61 +f 11 12 62 +f 11 62 61 +f 101 12 11 +f 102 61 62 +f 12 13 63 +f 12 63 62 +f 101 13 12 +f 102 62 63 +f 13 14 64 +f 13 64 63 +f 101 14 13 +f 102 63 64 +f 14 15 65 +f 14 65 64 +f 101 15 14 +f 102 64 65 +f 15 16 66 +f 15 66 65 +f 101 16 15 +f 102 65 66 +f 16 17 67 +f 16 67 66 +f 101 17 16 +f 102 66 67 +f 17 18 68 +f 17 68 67 +f 101 18 17 +f 102 67 68 +f 18 19 69 +f 18 69 68 +f 101 19 18 +f 102 68 69 +f 19 20 70 +f 19 70 69 +f 101 20 19 +f 102 69 70 +f 20 21 71 +f 20 71 70 +f 101 21 20 +f 102 70 71 +f 21 22 72 +f 21 72 71 +f 101 22 21 +f 102 71 72 +f 22 23 73 +f 22 73 72 +f 101 23 22 +f 102 72 73 +f 23 24 74 +f 23 74 73 +f 101 24 23 +f 102 73 74 +f 24 25 75 +f 24 75 74 +f 101 25 24 +f 102 74 75 +f 25 26 76 +f 25 76 75 +f 101 26 25 +f 102 75 76 +f 26 27 77 +f 26 77 76 +f 101 27 26 +f 102 76 77 +f 27 28 78 +f 27 78 77 +f 101 28 27 +f 102 77 78 +f 28 29 79 +f 28 79 78 +f 101 29 28 +f 102 78 79 +f 29 30 80 +f 29 80 79 +f 101 30 29 +f 102 79 80 +f 30 31 81 +f 30 81 80 +f 101 31 30 +f 102 80 81 +f 31 32 82 +f 31 82 81 +f 101 32 31 +f 102 81 82 +f 32 33 83 +f 32 83 82 +f 101 33 32 +f 102 82 83 +f 33 34 84 +f 33 84 83 +f 101 34 33 +f 102 83 84 +f 34 35 85 +f 34 85 84 +f 101 35 34 +f 102 84 85 +f 35 36 86 +f 35 86 85 +f 101 36 35 +f 102 85 86 +f 36 37 87 +f 36 87 86 +f 101 37 36 +f 102 86 87 +f 37 38 88 +f 37 88 87 +f 101 38 37 +f 102 87 88 +f 38 39 89 +f 38 89 88 +f 101 39 38 +f 102 88 89 +f 39 40 90 +f 39 90 89 +f 101 40 39 +f 102 89 90 +f 40 41 91 +f 40 91 90 +f 101 41 40 +f 102 90 91 +f 41 42 92 +f 41 92 91 +f 101 42 41 +f 102 91 92 +f 42 43 93 +f 42 93 92 +f 101 43 42 +f 102 92 93 +f 43 44 94 +f 43 94 93 +f 101 44 43 +f 102 93 94 +f 44 45 95 +f 44 95 94 +f 101 45 44 +f 102 94 95 +f 45 46 96 +f 45 96 95 +f 101 46 45 +f 102 95 96 +f 46 47 97 +f 46 97 96 +f 101 47 46 +f 102 96 97 +f 47 48 98 +f 47 98 97 +f 101 48 47 +f 102 97 98 +f 48 49 99 +f 48 99 98 +f 101 49 48 +f 102 98 99 +f 49 50 100 +f 49 100 99 +f 101 50 49 +f 102 99 100 +f 50 1 51 +f 50 51 100 +f 101 1 50 +f 102 100 51 diff --git a/mod/data/mac-fallback-assets/stadium_snail.obj b/mod/data/mac-fallback-assets/stadium_snail.obj new file mode 100644 index 000000000..e39f79447 --- /dev/null +++ b/mod/data/mac-fallback-assets/stadium_snail.obj @@ -0,0 +1,303 @@ +o stadium +v -1.96850 0.00000 1.96851 +v -1.95166 0.00000 2.22545 +v -1.90142 0.00000 2.47800 +v -1.81866 0.00000 2.72182 +v -1.70477 0.00000 2.95276 +v -1.56172 0.00000 3.16686 +v -1.39194 0.00000 3.36045 +v -1.19835 0.00000 3.53023 +v -0.98425 0.00000 3.67328 +v -0.75331 0.00000 3.78717 +v -0.50949 0.00000 3.86993 +v -0.25694 0.00000 3.92017 +v -0.00000 0.00000 3.93701 +v 0.25694 0.00000 3.92017 +v 0.50949 0.00000 3.86993 +v 0.75331 0.00000 3.78717 +v 0.98425 0.00000 3.67328 +v 1.19835 0.00000 3.53023 +v 1.39194 0.00000 3.36045 +v 1.56172 0.00000 3.16686 +v 1.70477 0.00000 2.95276 +v 1.81866 0.00000 2.72182 +v 1.90142 0.00000 2.47800 +v 1.95166 0.00000 2.22545 +v 1.96850 0.00000 1.96851 +v 1.96850 0.00000 -1.96851 +v 1.95166 0.00000 -2.22545 +v 1.90142 0.00000 -2.47800 +v 1.81866 0.00000 -2.72182 +v 1.70477 0.00000 -2.95276 +v 1.56172 0.00000 -3.16686 +v 1.39194 0.00000 -3.36045 +v 1.19835 0.00000 -3.53023 +v 0.98425 0.00000 -3.67328 +v 0.75331 0.00000 -3.78717 +v 0.50949 0.00000 -3.86993 +v 0.25694 0.00000 -3.92017 +v 0.00000 0.00000 -3.93701 +v -0.25694 0.00000 -3.92017 +v -0.50949 0.00000 -3.86993 +v -0.75331 0.00000 -3.78717 +v -0.98425 0.00000 -3.67328 +v -1.19835 0.00000 -3.53023 +v -1.39194 0.00000 -3.36045 +v -1.56172 0.00000 -3.16686 +v -1.70477 0.00000 -2.95276 +v -1.81866 0.00000 -2.72182 +v -1.90142 0.00000 -2.47800 +v -1.95166 0.00000 -2.22545 +v -1.96850 0.00000 -1.96851 +v -1.96850 1.00000 1.96851 +v -1.95166 1.00000 2.22545 +v -1.90142 1.00000 2.47800 +v -1.81866 1.00000 2.72182 +v -1.70477 1.00000 2.95276 +v -1.56172 1.00000 3.16686 +v -1.39194 1.00000 3.36045 +v -1.19835 1.00000 3.53023 +v -0.98425 1.00000 3.67328 +v -0.75331 1.00000 3.78717 +v -0.50949 1.00000 3.86993 +v -0.25694 1.00000 3.92017 +v -0.00000 1.00000 3.93701 +v 0.25694 1.00000 3.92017 +v 0.50949 1.00000 3.86993 +v 0.75331 1.00000 3.78717 +v 0.98425 1.00000 3.67328 +v 1.19835 1.00000 3.53023 +v 1.39194 1.00000 3.36045 +v 1.56172 1.00000 3.16686 +v 1.70477 1.00000 2.95276 +v 1.81866 1.00000 2.72182 +v 1.90142 1.00000 2.47800 +v 1.95166 1.00000 2.22545 +v 1.96850 1.00000 1.96851 +v 1.96850 1.00000 -1.96851 +v 1.95166 1.00000 -2.22545 +v 1.90142 1.00000 -2.47800 +v 1.81866 1.00000 -2.72182 +v 1.70477 1.00000 -2.95276 +v 1.56172 1.00000 -3.16686 +v 1.39194 1.00000 -3.36045 +v 1.19835 1.00000 -3.53023 +v 0.98425 1.00000 -3.67328 +v 0.75331 1.00000 -3.78717 +v 0.50949 1.00000 -3.86993 +v 0.25694 1.00000 -3.92017 +v 0.00000 1.00000 -3.93701 +v -0.25694 1.00000 -3.92017 +v -0.50949 1.00000 -3.86993 +v -0.75331 1.00000 -3.78717 +v -0.98425 1.00000 -3.67328 +v -1.19835 1.00000 -3.53023 +v -1.39194 1.00000 -3.36045 +v -1.56172 1.00000 -3.16686 +v -1.70477 1.00000 -2.95276 +v -1.81866 1.00000 -2.72182 +v -1.90142 1.00000 -2.47800 +v -1.95166 1.00000 -2.22545 +v -1.96850 1.00000 -1.96851 +v 0.00000 0.00000 0.00000 +v 0.00000 1.00000 0.00000 +f 1 2 52 +f 1 52 51 +f 101 2 1 +f 102 51 52 +f 2 3 53 +f 2 53 52 +f 101 3 2 +f 102 52 53 +f 3 4 54 +f 3 54 53 +f 101 4 3 +f 102 53 54 +f 4 5 55 +f 4 55 54 +f 101 5 4 +f 102 54 55 +f 5 6 56 +f 5 56 55 +f 101 6 5 +f 102 55 56 +f 6 7 57 +f 6 57 56 +f 101 7 6 +f 102 56 57 +f 7 8 58 +f 7 58 57 +f 101 8 7 +f 102 57 58 +f 8 9 59 +f 8 59 58 +f 101 9 8 +f 102 58 59 +f 9 10 60 +f 9 60 59 +f 101 10 9 +f 102 59 60 +f 10 11 61 +f 10 61 60 +f 101 11 10 +f 102 60 61 +f 11 12 62 +f 11 62 61 +f 101 12 11 +f 102 61 62 +f 12 13 63 +f 12 63 62 +f 101 13 12 +f 102 62 63 +f 13 14 64 +f 13 64 63 +f 101 14 13 +f 102 63 64 +f 14 15 65 +f 14 65 64 +f 101 15 14 +f 102 64 65 +f 15 16 66 +f 15 66 65 +f 101 16 15 +f 102 65 66 +f 16 17 67 +f 16 67 66 +f 101 17 16 +f 102 66 67 +f 17 18 68 +f 17 68 67 +f 101 18 17 +f 102 67 68 +f 18 19 69 +f 18 69 68 +f 101 19 18 +f 102 68 69 +f 19 20 70 +f 19 70 69 +f 101 20 19 +f 102 69 70 +f 20 21 71 +f 20 71 70 +f 101 21 20 +f 102 70 71 +f 21 22 72 +f 21 72 71 +f 101 22 21 +f 102 71 72 +f 22 23 73 +f 22 73 72 +f 101 23 22 +f 102 72 73 +f 23 24 74 +f 23 74 73 +f 101 24 23 +f 102 73 74 +f 24 25 75 +f 24 75 74 +f 101 25 24 +f 102 74 75 +f 25 26 76 +f 25 76 75 +f 101 26 25 +f 102 75 76 +f 26 27 77 +f 26 77 76 +f 101 27 26 +f 102 76 77 +f 27 28 78 +f 27 78 77 +f 101 28 27 +f 102 77 78 +f 28 29 79 +f 28 79 78 +f 101 29 28 +f 102 78 79 +f 29 30 80 +f 29 80 79 +f 101 30 29 +f 102 79 80 +f 30 31 81 +f 30 81 80 +f 101 31 30 +f 102 80 81 +f 31 32 82 +f 31 82 81 +f 101 32 31 +f 102 81 82 +f 32 33 83 +f 32 83 82 +f 101 33 32 +f 102 82 83 +f 33 34 84 +f 33 84 83 +f 101 34 33 +f 102 83 84 +f 34 35 85 +f 34 85 84 +f 101 35 34 +f 102 84 85 +f 35 36 86 +f 35 86 85 +f 101 36 35 +f 102 85 86 +f 36 37 87 +f 36 87 86 +f 101 37 36 +f 102 86 87 +f 37 38 88 +f 37 88 87 +f 101 38 37 +f 102 87 88 +f 38 39 89 +f 38 89 88 +f 101 39 38 +f 102 88 89 +f 39 40 90 +f 39 90 89 +f 101 40 39 +f 102 89 90 +f 40 41 91 +f 40 91 90 +f 101 41 40 +f 102 90 91 +f 41 42 92 +f 41 92 91 +f 101 42 41 +f 102 91 92 +f 42 43 93 +f 42 93 92 +f 101 43 42 +f 102 92 93 +f 43 44 94 +f 43 94 93 +f 101 44 43 +f 102 93 94 +f 44 45 95 +f 44 95 94 +f 101 45 44 +f 102 94 95 +f 45 46 96 +f 45 96 95 +f 101 46 45 +f 102 95 96 +f 46 47 97 +f 46 97 96 +f 101 47 46 +f 102 96 97 +f 47 48 98 +f 47 98 97 +f 101 48 47 +f 102 97 98 +f 48 49 99 +f 48 99 98 +f 101 49 48 +f 102 98 99 +f 49 50 100 +f 49 100 99 +f 101 50 49 +f 102 99 100 +f 50 1 51 +f 50 51 100 +f 101 1 50 +f 102 100 51 From 3ce7dddedd6a7d812948f9c6619b5f19a55b83bf Mon Sep 17 00:00:00 2001 From: Martin Pourrat Date: Tue, 11 Aug 2026 05:21:20 +0200 Subject: [PATCH 06/42] Stadium meshes: smooth normals + cylindrical UVs Co-Authored-By: Claude Fable 5 --- mod/data/mac-fallback-assets/stadium_long.obj | 553 +++++++++++------- .../mac-fallback-assets/stadium_snail.obj | 553 +++++++++++------- 2 files changed, 706 insertions(+), 400 deletions(-) diff --git a/mod/data/mac-fallback-assets/stadium_long.obj b/mod/data/mac-fallback-assets/stadium_long.obj index 902907aae..b996946a5 100644 --- a/mod/data/mac-fallback-assets/stadium_long.obj +++ b/mod/data/mac-fallback-assets/stadium_long.obj @@ -101,203 +101,356 @@ v -1.95166 1.00000 -1.73332 v -1.96850 1.00000 -1.47638 v 0.00000 0.00000 0.00000 v 0.00000 1.00000 0.00000 -f 1 2 52 -f 1 52 51 -f 101 2 1 -f 102 51 52 -f 2 3 53 -f 2 53 52 -f 101 3 2 -f 102 52 53 -f 3 4 54 -f 3 54 53 -f 101 4 3 -f 102 53 54 -f 4 5 55 -f 4 55 54 -f 101 5 4 -f 102 54 55 -f 5 6 56 -f 5 56 55 -f 101 6 5 -f 102 55 56 -f 6 7 57 -f 6 57 56 -f 101 7 6 -f 102 56 57 -f 7 8 58 -f 7 58 57 -f 101 8 7 -f 102 57 58 -f 8 9 59 -f 8 59 58 -f 101 9 8 -f 102 58 59 -f 9 10 60 -f 9 60 59 -f 101 10 9 -f 102 59 60 -f 10 11 61 -f 10 61 60 -f 101 11 10 -f 102 60 61 -f 11 12 62 -f 11 62 61 -f 101 12 11 -f 102 61 62 -f 12 13 63 -f 12 63 62 -f 101 13 12 -f 102 62 63 -f 13 14 64 -f 13 64 63 -f 101 14 13 -f 102 63 64 -f 14 15 65 -f 14 65 64 -f 101 15 14 -f 102 64 65 -f 15 16 66 -f 15 66 65 -f 101 16 15 -f 102 65 66 -f 16 17 67 -f 16 67 66 -f 101 17 16 -f 102 66 67 -f 17 18 68 -f 17 68 67 -f 101 18 17 -f 102 67 68 -f 18 19 69 -f 18 69 68 -f 101 19 18 -f 102 68 69 -f 19 20 70 -f 19 70 69 -f 101 20 19 -f 102 69 70 -f 20 21 71 -f 20 71 70 -f 101 21 20 -f 102 70 71 -f 21 22 72 -f 21 72 71 -f 101 22 21 -f 102 71 72 -f 22 23 73 -f 22 73 72 -f 101 23 22 -f 102 72 73 -f 23 24 74 -f 23 74 73 -f 101 24 23 -f 102 73 74 -f 24 25 75 -f 24 75 74 -f 101 25 24 -f 102 74 75 -f 25 26 76 -f 25 76 75 -f 101 26 25 -f 102 75 76 -f 26 27 77 -f 26 77 76 -f 101 27 26 -f 102 76 77 -f 27 28 78 -f 27 78 77 -f 101 28 27 -f 102 77 78 -f 28 29 79 -f 28 79 78 -f 101 29 28 -f 102 78 79 -f 29 30 80 -f 29 80 79 -f 101 30 29 -f 102 79 80 -f 30 31 81 -f 30 81 80 -f 101 31 30 -f 102 80 81 -f 31 32 82 -f 31 82 81 -f 101 32 31 -f 102 81 82 -f 32 33 83 -f 32 83 82 -f 101 33 32 -f 102 82 83 -f 33 34 84 -f 33 84 83 -f 101 34 33 -f 102 83 84 -f 34 35 85 -f 34 85 84 -f 101 35 34 -f 102 84 85 -f 35 36 86 -f 35 86 85 -f 101 36 35 -f 102 85 86 -f 36 37 87 -f 36 87 86 -f 101 37 36 -f 102 86 87 -f 37 38 88 -f 37 88 87 -f 101 38 37 -f 102 87 88 -f 38 39 89 -f 38 89 88 -f 101 39 38 -f 102 88 89 -f 39 40 90 -f 39 90 89 -f 101 40 39 -f 102 89 90 -f 40 41 91 -f 40 91 90 -f 101 41 40 -f 102 90 91 -f 41 42 92 -f 41 92 91 -f 101 42 41 -f 102 91 92 -f 42 43 93 -f 42 93 92 -f 101 43 42 -f 102 92 93 -f 43 44 94 -f 43 94 93 -f 101 44 43 -f 102 93 94 -f 44 45 95 -f 44 95 94 -f 101 45 44 -f 102 94 95 -f 45 46 96 -f 45 96 95 -f 101 46 45 -f 102 95 96 -f 46 47 97 -f 46 97 96 -f 101 47 46 -f 102 96 97 -f 47 48 98 -f 47 98 97 -f 101 48 47 -f 102 97 98 -f 48 49 99 -f 48 99 98 -f 101 49 48 -f 102 98 99 -f 49 50 100 -f 49 100 99 -f 101 50 49 -f 102 99 100 -f 50 1 51 -f 50 51 100 -f 101 1 50 -f 102 100 51 +vt 0.00000 0.0 +vt 0.01410 0.0 +vt 0.02819 0.0 +vt 0.04229 0.0 +vt 0.05639 0.0 +vt 0.07049 0.0 +vt 0.08458 0.0 +vt 0.09868 0.0 +vt 0.11278 0.0 +vt 0.12688 0.0 +vt 0.14097 0.0 +vt 0.15507 0.0 +vt 0.16917 0.0 +vt 0.18327 0.0 +vt 0.19736 0.0 +vt 0.21146 0.0 +vt 0.22556 0.0 +vt 0.23966 0.0 +vt 0.25375 0.0 +vt 0.26785 0.0 +vt 0.28195 0.0 +vt 0.29605 0.0 +vt 0.31014 0.0 +vt 0.32424 0.0 +vt 0.33834 0.0 +vt 0.50000 0.0 +vt 0.51410 0.0 +vt 0.52819 0.0 +vt 0.54229 0.0 +vt 0.55639 0.0 +vt 0.57049 0.0 +vt 0.58458 0.0 +vt 0.59868 0.0 +vt 0.61278 0.0 +vt 0.62688 0.0 +vt 0.64097 0.0 +vt 0.65507 0.0 +vt 0.66917 0.0 +vt 0.68327 0.0 +vt 0.69736 0.0 +vt 0.71146 0.0 +vt 0.72556 0.0 +vt 0.73966 0.0 +vt 0.75375 0.0 +vt 0.76785 0.0 +vt 0.78195 0.0 +vt 0.79605 0.0 +vt 0.81014 0.0 +vt 0.82424 0.0 +vt 0.83834 0.0 +vt 0.00000 1.0 +vt 0.01410 1.0 +vt 0.02819 1.0 +vt 0.04229 1.0 +vt 0.05639 1.0 +vt 0.07049 1.0 +vt 0.08458 1.0 +vt 0.09868 1.0 +vt 0.11278 1.0 +vt 0.12688 1.0 +vt 0.14097 1.0 +vt 0.15507 1.0 +vt 0.16917 1.0 +vt 0.18327 1.0 +vt 0.19736 1.0 +vt 0.21146 1.0 +vt 0.22556 1.0 +vt 0.23966 1.0 +vt 0.25375 1.0 +vt 0.26785 1.0 +vt 0.28195 1.0 +vt 0.29605 1.0 +vt 0.31014 1.0 +vt 0.32424 1.0 +vt 0.33834 1.0 +vt 0.50000 1.0 +vt 0.51410 1.0 +vt 0.52819 1.0 +vt 0.54229 1.0 +vt 0.55639 1.0 +vt 0.57049 1.0 +vt 0.58458 1.0 +vt 0.59868 1.0 +vt 0.61278 1.0 +vt 0.62688 1.0 +vt 0.64097 1.0 +vt 0.65507 1.0 +vt 0.66917 1.0 +vt 0.68327 1.0 +vt 0.69736 1.0 +vt 0.71146 1.0 +vt 0.72556 1.0 +vt 0.73966 1.0 +vt 0.75375 1.0 +vt 0.76785 1.0 +vt 0.78195 1.0 +vt 0.79605 1.0 +vt 0.81014 1.0 +vt 0.82424 1.0 +vt 0.83834 1.0 +vt 0.5 0.5 +vn -1.00000 0.00000 0.00000 +vn -0.99144 0.00000 0.13053 +vn -0.96593 0.00000 0.25882 +vn -0.92388 0.00000 0.38268 +vn -0.86603 0.00000 0.50000 +vn -0.79335 0.00000 0.60876 +vn -0.70711 0.00000 0.70711 +vn -0.60876 0.00000 0.79335 +vn -0.50000 0.00000 0.86603 +vn -0.38268 0.00000 0.92388 +vn -0.25882 0.00000 0.96593 +vn -0.13053 0.00000 0.99144 +vn -0.00000 0.00000 1.00000 +vn 0.13053 0.00000 0.99144 +vn 0.25882 0.00000 0.96593 +vn 0.38268 0.00000 0.92388 +vn 0.50000 0.00000 0.86603 +vn 0.60876 0.00000 0.79335 +vn 0.70711 0.00000 0.70711 +vn 0.79335 0.00000 0.60876 +vn 0.86603 0.00000 0.50000 +vn 0.92388 0.00000 0.38268 +vn 0.96593 0.00000 0.25882 +vn 0.99144 0.00000 0.13053 +vn 1.00000 0.00000 0.00000 +vn 1.00000 0.00000 -0.00000 +vn 0.99144 0.00000 -0.13053 +vn 0.96593 0.00000 -0.25882 +vn 0.92388 0.00000 -0.38268 +vn 0.86603 0.00000 -0.50000 +vn 0.79335 0.00000 -0.60876 +vn 0.70711 0.00000 -0.70711 +vn 0.60876 0.00000 -0.79335 +vn 0.50000 0.00000 -0.86603 +vn 0.38268 0.00000 -0.92388 +vn 0.25882 0.00000 -0.96593 +vn 0.13053 0.00000 -0.99144 +vn 0.00000 0.00000 -1.00000 +vn -0.13053 0.00000 -0.99144 +vn -0.25882 0.00000 -0.96593 +vn -0.38268 0.00000 -0.92388 +vn -0.50000 0.00000 -0.86603 +vn -0.60876 0.00000 -0.79335 +vn -0.70711 0.00000 -0.70711 +vn -0.79335 0.00000 -0.60876 +vn -0.86603 0.00000 -0.50000 +vn -0.92388 0.00000 -0.38268 +vn -0.96593 0.00000 -0.25882 +vn -0.99144 0.00000 -0.13053 +vn -1.00000 0.00000 -0.00000 +vn 0 -1 0 +vn 0 1 0 +f 1/1/1 2/2/2 52/52/2 +f 1/1/1 52/52/2 51/51/1 +f 101/101/51 2/2/51 1/1/51 +f 102/101/52 51/51/52 52/52/52 +f 2/2/2 3/3/3 53/53/3 +f 2/2/2 53/53/3 52/52/2 +f 101/101/51 3/3/51 2/2/51 +f 102/101/52 52/52/52 53/53/52 +f 3/3/3 4/4/4 54/54/4 +f 3/3/3 54/54/4 53/53/3 +f 101/101/51 4/4/51 3/3/51 +f 102/101/52 53/53/52 54/54/52 +f 4/4/4 5/5/5 55/55/5 +f 4/4/4 55/55/5 54/54/4 +f 101/101/51 5/5/51 4/4/51 +f 102/101/52 54/54/52 55/55/52 +f 5/5/5 6/6/6 56/56/6 +f 5/5/5 56/56/6 55/55/5 +f 101/101/51 6/6/51 5/5/51 +f 102/101/52 55/55/52 56/56/52 +f 6/6/6 7/7/7 57/57/7 +f 6/6/6 57/57/7 56/56/6 +f 101/101/51 7/7/51 6/6/51 +f 102/101/52 56/56/52 57/57/52 +f 7/7/7 8/8/8 58/58/8 +f 7/7/7 58/58/8 57/57/7 +f 101/101/51 8/8/51 7/7/51 +f 102/101/52 57/57/52 58/58/52 +f 8/8/8 9/9/9 59/59/9 +f 8/8/8 59/59/9 58/58/8 +f 101/101/51 9/9/51 8/8/51 +f 102/101/52 58/58/52 59/59/52 +f 9/9/9 10/10/10 60/60/10 +f 9/9/9 60/60/10 59/59/9 +f 101/101/51 10/10/51 9/9/51 +f 102/101/52 59/59/52 60/60/52 +f 10/10/10 11/11/11 61/61/11 +f 10/10/10 61/61/11 60/60/10 +f 101/101/51 11/11/51 10/10/51 +f 102/101/52 60/60/52 61/61/52 +f 11/11/11 12/12/12 62/62/12 +f 11/11/11 62/62/12 61/61/11 +f 101/101/51 12/12/51 11/11/51 +f 102/101/52 61/61/52 62/62/52 +f 12/12/12 13/13/13 63/63/13 +f 12/12/12 63/63/13 62/62/12 +f 101/101/51 13/13/51 12/12/51 +f 102/101/52 62/62/52 63/63/52 +f 13/13/13 14/14/14 64/64/14 +f 13/13/13 64/64/14 63/63/13 +f 101/101/51 14/14/51 13/13/51 +f 102/101/52 63/63/52 64/64/52 +f 14/14/14 15/15/15 65/65/15 +f 14/14/14 65/65/15 64/64/14 +f 101/101/51 15/15/51 14/14/51 +f 102/101/52 64/64/52 65/65/52 +f 15/15/15 16/16/16 66/66/16 +f 15/15/15 66/66/16 65/65/15 +f 101/101/51 16/16/51 15/15/51 +f 102/101/52 65/65/52 66/66/52 +f 16/16/16 17/17/17 67/67/17 +f 16/16/16 67/67/17 66/66/16 +f 101/101/51 17/17/51 16/16/51 +f 102/101/52 66/66/52 67/67/52 +f 17/17/17 18/18/18 68/68/18 +f 17/17/17 68/68/18 67/67/17 +f 101/101/51 18/18/51 17/17/51 +f 102/101/52 67/67/52 68/68/52 +f 18/18/18 19/19/19 69/69/19 +f 18/18/18 69/69/19 68/68/18 +f 101/101/51 19/19/51 18/18/51 +f 102/101/52 68/68/52 69/69/52 +f 19/19/19 20/20/20 70/70/20 +f 19/19/19 70/70/20 69/69/19 +f 101/101/51 20/20/51 19/19/51 +f 102/101/52 69/69/52 70/70/52 +f 20/20/20 21/21/21 71/71/21 +f 20/20/20 71/71/21 70/70/20 +f 101/101/51 21/21/51 20/20/51 +f 102/101/52 70/70/52 71/71/52 +f 21/21/21 22/22/22 72/72/22 +f 21/21/21 72/72/22 71/71/21 +f 101/101/51 22/22/51 21/21/51 +f 102/101/52 71/71/52 72/72/52 +f 22/22/22 23/23/23 73/73/23 +f 22/22/22 73/73/23 72/72/22 +f 101/101/51 23/23/51 22/22/51 +f 102/101/52 72/72/52 73/73/52 +f 23/23/23 24/24/24 74/74/24 +f 23/23/23 74/74/24 73/73/23 +f 101/101/51 24/24/51 23/23/51 +f 102/101/52 73/73/52 74/74/52 +f 24/24/24 25/25/25 75/75/25 +f 24/24/24 75/75/25 74/74/24 +f 101/101/51 25/25/51 24/24/51 +f 102/101/52 74/74/52 75/75/52 +f 25/25/25 26/26/26 76/76/26 +f 25/25/25 76/76/26 75/75/25 +f 101/101/51 26/26/51 25/25/51 +f 102/101/52 75/75/52 76/76/52 +f 26/26/26 27/27/27 77/77/27 +f 26/26/26 77/77/27 76/76/26 +f 101/101/51 27/27/51 26/26/51 +f 102/101/52 76/76/52 77/77/52 +f 27/27/27 28/28/28 78/78/28 +f 27/27/27 78/78/28 77/77/27 +f 101/101/51 28/28/51 27/27/51 +f 102/101/52 77/77/52 78/78/52 +f 28/28/28 29/29/29 79/79/29 +f 28/28/28 79/79/29 78/78/28 +f 101/101/51 29/29/51 28/28/51 +f 102/101/52 78/78/52 79/79/52 +f 29/29/29 30/30/30 80/80/30 +f 29/29/29 80/80/30 79/79/29 +f 101/101/51 30/30/51 29/29/51 +f 102/101/52 79/79/52 80/80/52 +f 30/30/30 31/31/31 81/81/31 +f 30/30/30 81/81/31 80/80/30 +f 101/101/51 31/31/51 30/30/51 +f 102/101/52 80/80/52 81/81/52 +f 31/31/31 32/32/32 82/82/32 +f 31/31/31 82/82/32 81/81/31 +f 101/101/51 32/32/51 31/31/51 +f 102/101/52 81/81/52 82/82/52 +f 32/32/32 33/33/33 83/83/33 +f 32/32/32 83/83/33 82/82/32 +f 101/101/51 33/33/51 32/32/51 +f 102/101/52 82/82/52 83/83/52 +f 33/33/33 34/34/34 84/84/34 +f 33/33/33 84/84/34 83/83/33 +f 101/101/51 34/34/51 33/33/51 +f 102/101/52 83/83/52 84/84/52 +f 34/34/34 35/35/35 85/85/35 +f 34/34/34 85/85/35 84/84/34 +f 101/101/51 35/35/51 34/34/51 +f 102/101/52 84/84/52 85/85/52 +f 35/35/35 36/36/36 86/86/36 +f 35/35/35 86/86/36 85/85/35 +f 101/101/51 36/36/51 35/35/51 +f 102/101/52 85/85/52 86/86/52 +f 36/36/36 37/37/37 87/87/37 +f 36/36/36 87/87/37 86/86/36 +f 101/101/51 37/37/51 36/36/51 +f 102/101/52 86/86/52 87/87/52 +f 37/37/37 38/38/38 88/88/38 +f 37/37/37 88/88/38 87/87/37 +f 101/101/51 38/38/51 37/37/51 +f 102/101/52 87/87/52 88/88/52 +f 38/38/38 39/39/39 89/89/39 +f 38/38/38 89/89/39 88/88/38 +f 101/101/51 39/39/51 38/38/51 +f 102/101/52 88/88/52 89/89/52 +f 39/39/39 40/40/40 90/90/40 +f 39/39/39 90/90/40 89/89/39 +f 101/101/51 40/40/51 39/39/51 +f 102/101/52 89/89/52 90/90/52 +f 40/40/40 41/41/41 91/91/41 +f 40/40/40 91/91/41 90/90/40 +f 101/101/51 41/41/51 40/40/51 +f 102/101/52 90/90/52 91/91/52 +f 41/41/41 42/42/42 92/92/42 +f 41/41/41 92/92/42 91/91/41 +f 101/101/51 42/42/51 41/41/51 +f 102/101/52 91/91/52 92/92/52 +f 42/42/42 43/43/43 93/93/43 +f 42/42/42 93/93/43 92/92/42 +f 101/101/51 43/43/51 42/42/51 +f 102/101/52 92/92/52 93/93/52 +f 43/43/43 44/44/44 94/94/44 +f 43/43/43 94/94/44 93/93/43 +f 101/101/51 44/44/51 43/43/51 +f 102/101/52 93/93/52 94/94/52 +f 44/44/44 45/45/45 95/95/45 +f 44/44/44 95/95/45 94/94/44 +f 101/101/51 45/45/51 44/44/51 +f 102/101/52 94/94/52 95/95/52 +f 45/45/45 46/46/46 96/96/46 +f 45/45/45 96/96/46 95/95/45 +f 101/101/51 46/46/51 45/45/51 +f 102/101/52 95/95/52 96/96/52 +f 46/46/46 47/47/47 97/97/47 +f 46/46/46 97/97/47 96/96/46 +f 101/101/51 47/47/51 46/46/51 +f 102/101/52 96/96/52 97/97/52 +f 47/47/47 48/48/48 98/98/48 +f 47/47/47 98/98/48 97/97/47 +f 101/101/51 48/48/51 47/47/51 +f 102/101/52 97/97/52 98/98/52 +f 48/48/48 49/49/49 99/99/49 +f 48/48/48 99/99/49 98/98/48 +f 101/101/51 49/49/51 48/48/51 +f 102/101/52 98/98/52 99/99/52 +f 49/49/49 50/50/50 100/100/50 +f 49/49/49 100/100/50 99/99/49 +f 101/101/51 50/50/51 49/49/51 +f 102/101/52 99/99/52 100/100/52 +f 50/50/50 1/1/1 51/51/1 +f 50/50/50 51/51/1 100/100/50 +f 101/101/51 1/1/51 50/50/51 +f 102/101/52 100/100/52 51/51/52 diff --git a/mod/data/mac-fallback-assets/stadium_snail.obj b/mod/data/mac-fallback-assets/stadium_snail.obj index e39f79447..84b04623d 100644 --- a/mod/data/mac-fallback-assets/stadium_snail.obj +++ b/mod/data/mac-fallback-assets/stadium_snail.obj @@ -101,203 +101,356 @@ v -1.95166 1.00000 -2.22545 v -1.96850 1.00000 -1.96851 v 0.00000 0.00000 0.00000 v 0.00000 1.00000 0.00000 -f 1 2 52 -f 1 52 51 -f 101 2 1 -f 102 51 52 -f 2 3 53 -f 2 53 52 -f 101 3 2 -f 102 52 53 -f 3 4 54 -f 3 54 53 -f 101 4 3 -f 102 53 54 -f 4 5 55 -f 4 55 54 -f 101 5 4 -f 102 54 55 -f 5 6 56 -f 5 56 55 -f 101 6 5 -f 102 55 56 -f 6 7 57 -f 6 57 56 -f 101 7 6 -f 102 56 57 -f 7 8 58 -f 7 58 57 -f 101 8 7 -f 102 57 58 -f 8 9 59 -f 8 59 58 -f 101 9 8 -f 102 58 59 -f 9 10 60 -f 9 60 59 -f 101 10 9 -f 102 59 60 -f 10 11 61 -f 10 61 60 -f 101 11 10 -f 102 60 61 -f 11 12 62 -f 11 62 61 -f 101 12 11 -f 102 61 62 -f 12 13 63 -f 12 63 62 -f 101 13 12 -f 102 62 63 -f 13 14 64 -f 13 64 63 -f 101 14 13 -f 102 63 64 -f 14 15 65 -f 14 65 64 -f 101 15 14 -f 102 64 65 -f 15 16 66 -f 15 66 65 -f 101 16 15 -f 102 65 66 -f 16 17 67 -f 16 67 66 -f 101 17 16 -f 102 66 67 -f 17 18 68 -f 17 68 67 -f 101 18 17 -f 102 67 68 -f 18 19 69 -f 18 69 68 -f 101 19 18 -f 102 68 69 -f 19 20 70 -f 19 70 69 -f 101 20 19 -f 102 69 70 -f 20 21 71 -f 20 71 70 -f 101 21 20 -f 102 70 71 -f 21 22 72 -f 21 72 71 -f 101 22 21 -f 102 71 72 -f 22 23 73 -f 22 73 72 -f 101 23 22 -f 102 72 73 -f 23 24 74 -f 23 74 73 -f 101 24 23 -f 102 73 74 -f 24 25 75 -f 24 75 74 -f 101 25 24 -f 102 74 75 -f 25 26 76 -f 25 76 75 -f 101 26 25 -f 102 75 76 -f 26 27 77 -f 26 77 76 -f 101 27 26 -f 102 76 77 -f 27 28 78 -f 27 78 77 -f 101 28 27 -f 102 77 78 -f 28 29 79 -f 28 79 78 -f 101 29 28 -f 102 78 79 -f 29 30 80 -f 29 80 79 -f 101 30 29 -f 102 79 80 -f 30 31 81 -f 30 81 80 -f 101 31 30 -f 102 80 81 -f 31 32 82 -f 31 82 81 -f 101 32 31 -f 102 81 82 -f 32 33 83 -f 32 83 82 -f 101 33 32 -f 102 82 83 -f 33 34 84 -f 33 84 83 -f 101 34 33 -f 102 83 84 -f 34 35 85 -f 34 85 84 -f 101 35 34 -f 102 84 85 -f 35 36 86 -f 35 86 85 -f 101 36 35 -f 102 85 86 -f 36 37 87 -f 36 87 86 -f 101 37 36 -f 102 86 87 -f 37 38 88 -f 37 88 87 -f 101 38 37 -f 102 87 88 -f 38 39 89 -f 38 89 88 -f 101 39 38 -f 102 88 89 -f 39 40 90 -f 39 90 89 -f 101 40 39 -f 102 89 90 -f 40 41 91 -f 40 91 90 -f 101 41 40 -f 102 90 91 -f 41 42 92 -f 41 92 91 -f 101 42 41 -f 102 91 92 -f 42 43 93 -f 42 93 92 -f 101 43 42 -f 102 92 93 -f 43 44 94 -f 43 94 93 -f 101 44 43 -f 102 93 94 -f 44 45 95 -f 44 95 94 -f 101 45 44 -f 102 94 95 -f 45 46 96 -f 45 96 95 -f 101 46 45 -f 102 95 96 -f 46 47 97 -f 46 97 96 -f 101 47 46 -f 102 96 97 -f 47 48 98 -f 47 98 97 -f 101 48 47 -f 102 97 98 -f 48 49 99 -f 48 99 98 -f 101 49 48 -f 102 98 99 -f 49 50 100 -f 49 100 99 -f 101 50 49 -f 102 99 100 -f 50 1 51 -f 50 51 100 -f 101 1 50 -f 102 100 51 +vt 0.00000 0.0 +vt 0.01273 0.0 +vt 0.02545 0.0 +vt 0.03818 0.0 +vt 0.05090 0.0 +vt 0.06363 0.0 +vt 0.07636 0.0 +vt 0.08908 0.0 +vt 0.10181 0.0 +vt 0.11453 0.0 +vt 0.12726 0.0 +vt 0.13999 0.0 +vt 0.15271 0.0 +vt 0.16544 0.0 +vt 0.17816 0.0 +vt 0.19089 0.0 +vt 0.20361 0.0 +vt 0.21634 0.0 +vt 0.22907 0.0 +vt 0.24179 0.0 +vt 0.25452 0.0 +vt 0.26724 0.0 +vt 0.27997 0.0 +vt 0.29270 0.0 +vt 0.30542 0.0 +vt 0.50000 0.0 +vt 0.51273 0.0 +vt 0.52545 0.0 +vt 0.53818 0.0 +vt 0.55090 0.0 +vt 0.56363 0.0 +vt 0.57636 0.0 +vt 0.58908 0.0 +vt 0.60181 0.0 +vt 0.61453 0.0 +vt 0.62726 0.0 +vt 0.63999 0.0 +vt 0.65271 0.0 +vt 0.66544 0.0 +vt 0.67816 0.0 +vt 0.69089 0.0 +vt 0.70361 0.0 +vt 0.71634 0.0 +vt 0.72907 0.0 +vt 0.74179 0.0 +vt 0.75452 0.0 +vt 0.76724 0.0 +vt 0.77997 0.0 +vt 0.79270 0.0 +vt 0.80542 0.0 +vt 0.00000 1.0 +vt 0.01273 1.0 +vt 0.02545 1.0 +vt 0.03818 1.0 +vt 0.05090 1.0 +vt 0.06363 1.0 +vt 0.07636 1.0 +vt 0.08908 1.0 +vt 0.10181 1.0 +vt 0.11453 1.0 +vt 0.12726 1.0 +vt 0.13999 1.0 +vt 0.15271 1.0 +vt 0.16544 1.0 +vt 0.17816 1.0 +vt 0.19089 1.0 +vt 0.20361 1.0 +vt 0.21634 1.0 +vt 0.22907 1.0 +vt 0.24179 1.0 +vt 0.25452 1.0 +vt 0.26724 1.0 +vt 0.27997 1.0 +vt 0.29270 1.0 +vt 0.30542 1.0 +vt 0.50000 1.0 +vt 0.51273 1.0 +vt 0.52545 1.0 +vt 0.53818 1.0 +vt 0.55090 1.0 +vt 0.56363 1.0 +vt 0.57636 1.0 +vt 0.58908 1.0 +vt 0.60181 1.0 +vt 0.61453 1.0 +vt 0.62726 1.0 +vt 0.63999 1.0 +vt 0.65271 1.0 +vt 0.66544 1.0 +vt 0.67816 1.0 +vt 0.69089 1.0 +vt 0.70361 1.0 +vt 0.71634 1.0 +vt 0.72907 1.0 +vt 0.74179 1.0 +vt 0.75452 1.0 +vt 0.76724 1.0 +vt 0.77997 1.0 +vt 0.79270 1.0 +vt 0.80542 1.0 +vt 0.5 0.5 +vn -1.00000 0.00000 0.00000 +vn -0.99144 0.00000 0.13053 +vn -0.96593 0.00000 0.25882 +vn -0.92388 0.00000 0.38268 +vn -0.86603 0.00000 0.50000 +vn -0.79335 0.00000 0.60876 +vn -0.70711 0.00000 0.70711 +vn -0.60876 0.00000 0.79335 +vn -0.50000 0.00000 0.86603 +vn -0.38268 0.00000 0.92388 +vn -0.25882 0.00000 0.96593 +vn -0.13053 0.00000 0.99144 +vn -0.00000 0.00000 1.00000 +vn 0.13053 0.00000 0.99144 +vn 0.25882 0.00000 0.96593 +vn 0.38268 0.00000 0.92388 +vn 0.50000 0.00000 0.86603 +vn 0.60876 0.00000 0.79335 +vn 0.70711 0.00000 0.70711 +vn 0.79335 0.00000 0.60876 +vn 0.86603 0.00000 0.50000 +vn 0.92388 0.00000 0.38268 +vn 0.96593 0.00000 0.25882 +vn 0.99144 0.00000 0.13053 +vn 1.00000 0.00000 0.00000 +vn 1.00000 0.00000 -0.00000 +vn 0.99144 0.00000 -0.13053 +vn 0.96593 0.00000 -0.25882 +vn 0.92388 0.00000 -0.38268 +vn 0.86603 0.00000 -0.50000 +vn 0.79335 0.00000 -0.60876 +vn 0.70711 0.00000 -0.70711 +vn 0.60876 0.00000 -0.79335 +vn 0.50000 0.00000 -0.86603 +vn 0.38268 0.00000 -0.92388 +vn 0.25882 0.00000 -0.96593 +vn 0.13053 0.00000 -0.99144 +vn 0.00000 0.00000 -1.00000 +vn -0.13053 0.00000 -0.99144 +vn -0.25882 0.00000 -0.96593 +vn -0.38268 0.00000 -0.92388 +vn -0.50000 0.00000 -0.86603 +vn -0.60876 0.00000 -0.79335 +vn -0.70711 0.00000 -0.70711 +vn -0.79335 0.00000 -0.60876 +vn -0.86603 0.00000 -0.50000 +vn -0.92388 0.00000 -0.38268 +vn -0.96593 0.00000 -0.25882 +vn -0.99144 0.00000 -0.13053 +vn -1.00000 0.00000 -0.00000 +vn 0 -1 0 +vn 0 1 0 +f 1/1/1 2/2/2 52/52/2 +f 1/1/1 52/52/2 51/51/1 +f 101/101/51 2/2/51 1/1/51 +f 102/101/52 51/51/52 52/52/52 +f 2/2/2 3/3/3 53/53/3 +f 2/2/2 53/53/3 52/52/2 +f 101/101/51 3/3/51 2/2/51 +f 102/101/52 52/52/52 53/53/52 +f 3/3/3 4/4/4 54/54/4 +f 3/3/3 54/54/4 53/53/3 +f 101/101/51 4/4/51 3/3/51 +f 102/101/52 53/53/52 54/54/52 +f 4/4/4 5/5/5 55/55/5 +f 4/4/4 55/55/5 54/54/4 +f 101/101/51 5/5/51 4/4/51 +f 102/101/52 54/54/52 55/55/52 +f 5/5/5 6/6/6 56/56/6 +f 5/5/5 56/56/6 55/55/5 +f 101/101/51 6/6/51 5/5/51 +f 102/101/52 55/55/52 56/56/52 +f 6/6/6 7/7/7 57/57/7 +f 6/6/6 57/57/7 56/56/6 +f 101/101/51 7/7/51 6/6/51 +f 102/101/52 56/56/52 57/57/52 +f 7/7/7 8/8/8 58/58/8 +f 7/7/7 58/58/8 57/57/7 +f 101/101/51 8/8/51 7/7/51 +f 102/101/52 57/57/52 58/58/52 +f 8/8/8 9/9/9 59/59/9 +f 8/8/8 59/59/9 58/58/8 +f 101/101/51 9/9/51 8/8/51 +f 102/101/52 58/58/52 59/59/52 +f 9/9/9 10/10/10 60/60/10 +f 9/9/9 60/60/10 59/59/9 +f 101/101/51 10/10/51 9/9/51 +f 102/101/52 59/59/52 60/60/52 +f 10/10/10 11/11/11 61/61/11 +f 10/10/10 61/61/11 60/60/10 +f 101/101/51 11/11/51 10/10/51 +f 102/101/52 60/60/52 61/61/52 +f 11/11/11 12/12/12 62/62/12 +f 11/11/11 62/62/12 61/61/11 +f 101/101/51 12/12/51 11/11/51 +f 102/101/52 61/61/52 62/62/52 +f 12/12/12 13/13/13 63/63/13 +f 12/12/12 63/63/13 62/62/12 +f 101/101/51 13/13/51 12/12/51 +f 102/101/52 62/62/52 63/63/52 +f 13/13/13 14/14/14 64/64/14 +f 13/13/13 64/64/14 63/63/13 +f 101/101/51 14/14/51 13/13/51 +f 102/101/52 63/63/52 64/64/52 +f 14/14/14 15/15/15 65/65/15 +f 14/14/14 65/65/15 64/64/14 +f 101/101/51 15/15/51 14/14/51 +f 102/101/52 64/64/52 65/65/52 +f 15/15/15 16/16/16 66/66/16 +f 15/15/15 66/66/16 65/65/15 +f 101/101/51 16/16/51 15/15/51 +f 102/101/52 65/65/52 66/66/52 +f 16/16/16 17/17/17 67/67/17 +f 16/16/16 67/67/17 66/66/16 +f 101/101/51 17/17/51 16/16/51 +f 102/101/52 66/66/52 67/67/52 +f 17/17/17 18/18/18 68/68/18 +f 17/17/17 68/68/18 67/67/17 +f 101/101/51 18/18/51 17/17/51 +f 102/101/52 67/67/52 68/68/52 +f 18/18/18 19/19/19 69/69/19 +f 18/18/18 69/69/19 68/68/18 +f 101/101/51 19/19/51 18/18/51 +f 102/101/52 68/68/52 69/69/52 +f 19/19/19 20/20/20 70/70/20 +f 19/19/19 70/70/20 69/69/19 +f 101/101/51 20/20/51 19/19/51 +f 102/101/52 69/69/52 70/70/52 +f 20/20/20 21/21/21 71/71/21 +f 20/20/20 71/71/21 70/70/20 +f 101/101/51 21/21/51 20/20/51 +f 102/101/52 70/70/52 71/71/52 +f 21/21/21 22/22/22 72/72/22 +f 21/21/21 72/72/22 71/71/21 +f 101/101/51 22/22/51 21/21/51 +f 102/101/52 71/71/52 72/72/52 +f 22/22/22 23/23/23 73/73/23 +f 22/22/22 73/73/23 72/72/22 +f 101/101/51 23/23/51 22/22/51 +f 102/101/52 72/72/52 73/73/52 +f 23/23/23 24/24/24 74/74/24 +f 23/23/23 74/74/24 73/73/23 +f 101/101/51 24/24/51 23/23/51 +f 102/101/52 73/73/52 74/74/52 +f 24/24/24 25/25/25 75/75/25 +f 24/24/24 75/75/25 74/74/24 +f 101/101/51 25/25/51 24/24/51 +f 102/101/52 74/74/52 75/75/52 +f 25/25/25 26/26/26 76/76/26 +f 25/25/25 76/76/26 75/75/25 +f 101/101/51 26/26/51 25/25/51 +f 102/101/52 75/75/52 76/76/52 +f 26/26/26 27/27/27 77/77/27 +f 26/26/26 77/77/27 76/76/26 +f 101/101/51 27/27/51 26/26/51 +f 102/101/52 76/76/52 77/77/52 +f 27/27/27 28/28/28 78/78/28 +f 27/27/27 78/78/28 77/77/27 +f 101/101/51 28/28/51 27/27/51 +f 102/101/52 77/77/52 78/78/52 +f 28/28/28 29/29/29 79/79/29 +f 28/28/28 79/79/29 78/78/28 +f 101/101/51 29/29/51 28/28/51 +f 102/101/52 78/78/52 79/79/52 +f 29/29/29 30/30/30 80/80/30 +f 29/29/29 80/80/30 79/79/29 +f 101/101/51 30/30/51 29/29/51 +f 102/101/52 79/79/52 80/80/52 +f 30/30/30 31/31/31 81/81/31 +f 30/30/30 81/81/31 80/80/30 +f 101/101/51 31/31/51 30/30/51 +f 102/101/52 80/80/52 81/81/52 +f 31/31/31 32/32/32 82/82/32 +f 31/31/31 82/82/32 81/81/31 +f 101/101/51 32/32/51 31/31/51 +f 102/101/52 81/81/52 82/82/52 +f 32/32/32 33/33/33 83/83/33 +f 32/32/32 83/83/33 82/82/32 +f 101/101/51 33/33/51 32/32/51 +f 102/101/52 82/82/52 83/83/52 +f 33/33/33 34/34/34 84/84/34 +f 33/33/33 84/84/34 83/83/33 +f 101/101/51 34/34/51 33/33/51 +f 102/101/52 83/83/52 84/84/52 +f 34/34/34 35/35/35 85/85/35 +f 34/34/34 85/85/35 84/84/34 +f 101/101/51 35/35/51 34/34/51 +f 102/101/52 84/84/52 85/85/52 +f 35/35/35 36/36/36 86/86/36 +f 35/35/35 86/86/36 85/85/35 +f 101/101/51 36/36/51 35/35/51 +f 102/101/52 85/85/52 86/86/52 +f 36/36/36 37/37/37 87/87/37 +f 36/36/36 87/87/37 86/86/36 +f 101/101/51 37/37/51 36/36/51 +f 102/101/52 86/86/52 87/87/52 +f 37/37/37 38/38/38 88/88/38 +f 37/37/37 88/88/38 87/87/37 +f 101/101/51 38/38/51 37/37/51 +f 102/101/52 87/87/52 88/88/52 +f 38/38/38 39/39/39 89/89/39 +f 38/38/38 89/89/39 88/88/38 +f 101/101/51 39/39/51 38/38/51 +f 102/101/52 88/88/52 89/89/52 +f 39/39/39 40/40/40 90/90/40 +f 39/39/39 90/90/40 89/89/39 +f 101/101/51 40/40/51 39/39/51 +f 102/101/52 89/89/52 90/90/52 +f 40/40/40 41/41/41 91/91/41 +f 40/40/40 91/91/41 90/90/40 +f 101/101/51 41/41/51 40/40/51 +f 102/101/52 90/90/52 91/91/52 +f 41/41/41 42/42/42 92/92/42 +f 41/41/41 92/92/42 91/91/41 +f 101/101/51 42/42/51 41/41/51 +f 102/101/52 91/91/52 92/92/52 +f 42/42/42 43/43/43 93/93/43 +f 42/42/42 93/93/43 92/92/42 +f 101/101/51 43/43/51 42/42/51 +f 102/101/52 92/92/52 93/93/52 +f 43/43/43 44/44/44 94/94/44 +f 43/43/43 94/94/44 93/93/43 +f 101/101/51 44/44/51 43/43/51 +f 102/101/52 93/93/52 94/94/52 +f 44/44/44 45/45/45 95/95/45 +f 44/44/44 95/95/45 94/94/44 +f 101/101/51 45/45/51 44/44/51 +f 102/101/52 94/94/52 95/95/52 +f 45/45/45 46/46/46 96/96/46 +f 45/45/45 96/96/46 95/95/45 +f 101/101/51 46/46/51 45/45/51 +f 102/101/52 95/95/52 96/96/52 +f 46/46/46 47/47/47 97/97/47 +f 46/46/46 97/97/47 96/96/46 +f 101/101/51 47/47/51 46/46/51 +f 102/101/52 96/96/52 97/97/52 +f 47/47/47 48/48/48 98/98/48 +f 47/47/47 98/98/48 97/97/47 +f 101/101/51 48/48/51 47/47/51 +f 102/101/52 97/97/52 98/98/52 +f 48/48/48 49/49/49 99/99/49 +f 48/48/48 99/99/49 98/98/48 +f 101/101/51 49/49/51 48/48/51 +f 102/101/52 98/98/52 99/99/52 +f 49/49/49 50/50/50 100/100/50 +f 49/49/49 100/100/50 99/99/49 +f 101/101/51 50/50/51 49/49/51 +f 102/101/52 99/99/52 100/100/52 +f 50/50/50 1/1/1 51/51/1 +f 50/50/50 51/51/1 100/100/50 +f 101/101/51 1/1/51 50/50/51 +f 102/101/52 100/100/52 51/51/52 From df82ec7da4134b273c8fcb8819607c3ff1e7747a Mon Sep 17 00:00:00 2001 From: Martin Pourrat Date: Tue, 11 Aug 2026 05:27:24 +0200 Subject: [PATCH 07/42] Rename stadium meshes to _2 (TTS caches by URL, smooth-normal rebuild) Co-Authored-By: Claude Fable 5 --- .../mac-fallback-assets/{stadium_long.obj => stadium_long_2.obj} | 0 .../{stadium_snail.obj => stadium_snail_2.obj} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename mod/data/mac-fallback-assets/{stadium_long.obj => stadium_long_2.obj} (100%) rename mod/data/mac-fallback-assets/{stadium_snail.obj => stadium_snail_2.obj} (100%) diff --git a/mod/data/mac-fallback-assets/stadium_long.obj b/mod/data/mac-fallback-assets/stadium_long_2.obj similarity index 100% rename from mod/data/mac-fallback-assets/stadium_long.obj rename to mod/data/mac-fallback-assets/stadium_long_2.obj diff --git a/mod/data/mac-fallback-assets/stadium_snail.obj b/mod/data/mac-fallback-assets/stadium_snail_2.obj similarity index 100% rename from mod/data/mac-fallback-assets/stadium_snail.obj rename to mod/data/mac-fallback-assets/stadium_snail_2.obj From a942325ba1ed68488463f27c1bfb02fb138d07ba Mon Sep 17 00:00:00 2001 From: Martin Pourrat Date: Tue, 11 Aug 2026 05:32:26 +0200 Subject: [PATCH 08/42] Stadium meshes v3: split-and-stretch of the marker cylinder mesh Same normals/UVs/caps as the round silhouettes, so the look matches. Co-Authored-By: Claude Fable 5 --- .../mac-fallback-assets/stadium_long_3.obj | 374 ++++++++++++++++++ .../mac-fallback-assets/stadium_snail_3.obj | 374 ++++++++++++++++++ 2 files changed, 748 insertions(+) create mode 100644 mod/data/mac-fallback-assets/stadium_long_3.obj create mode 100644 mod/data/mac-fallback-assets/stadium_snail_3.obj diff --git a/mod/data/mac-fallback-assets/stadium_long_3.obj b/mod/data/mac-fallback-assets/stadium_long_3.obj new file mode 100644 index 000000000..7a9e6c3b2 --- /dev/null +++ b/mod/data/mac-fallback-assets/stadium_long_3.obj @@ -0,0 +1,374 @@ +# This file uses centimeters as units for non-parametric coordinates. + +mtllib silhouette_shorter.mtl +v 1.15608 -0.00000 -3.06758 +v 1.59120 -0.00000 -2.63246 +v -0.00000 -0.00000 -0.00000 +v -1.15608 -0.00000 -3.06758 +v -1.59120 -0.00000 -2.63246 +v -1.59120 1.00023 -2.63246 +v -1.15608 1.00023 -3.06758 +v -0.60778 -0.00000 3.34695 +v -1.15608 -0.00000 3.06758 +v 1.87057 -0.00000 -2.08416 +v -0.60778 -0.00000 -3.34695 +v -0.60778 1.00023 -3.34695 +v -1.87057 -0.00000 -2.08416 +v -1.87057 1.00023 -2.08416 +v -0.00000 -0.00000 3.44321 +v 1.96683 -0.00000 -0.00000 +v 1.87057 -0.00000 2.08416 +v 0.60778 -0.00000 3.34695 +v -0.00000 -0.00000 -3.44321 +v -0.00000 1.00023 -3.44321 +v -1.96683 -0.00000 -0.00000 +v -1.96683 1.00023 -0.00000 +v 1.59120 -0.00000 2.63245 +v 1.15607 -0.00000 3.06758 +v 0.60778 -0.00000 -3.34695 +v 0.60778 1.00023 -3.34695 +v -1.87057 -0.00000 2.08416 +v -1.87057 1.00023 2.08416 +v 1.15608 1.00023 -3.06758 +v -1.59120 -0.00000 2.63245 +v -1.59120 1.00023 2.63245 +v -1.15608 1.00023 3.06758 +v 1.59120 1.00023 -2.63246 +v -0.11787 0.92084 -1.56202 +v -0.00000 0.92084 -0.00000 +v -0.08564 0.92084 -1.59425 +v -0.04502 0.92084 -1.61494 +v -0.13856 0.92084 -1.52140 +v -0.00000 0.92084 -1.62207 +v -0.14569 0.92084 -0.00000 +v 0.04502 0.92084 -1.61494 +v -0.13856 0.92084 1.52140 +v 0.08564 0.92084 -1.59425 +v -0.11787 0.92084 1.56202 +v -0.08564 0.92084 1.59425 +v 0.11787 0.92084 -1.56202 +v -0.04502 0.92084 1.61494 +v 0.13856 0.92084 -1.52140 +v -0.00000 0.92084 1.62207 +v 0.14569 0.92084 -0.00000 +v 0.13856 0.92084 1.52140 +v 0.04502 0.92084 1.61494 +v 0.08564 0.92084 1.59425 +v 0.11787 0.92084 1.56202 +v -0.60778 1.00023 3.34695 +v 1.87057 1.00023 -2.08416 +v -0.08564 1.00023 -1.59425 +v -0.11787 1.00023 -1.56202 +v -0.00000 1.00023 3.44321 +v 1.96683 1.00023 -0.00000 +v -0.04502 1.00023 -1.61494 +v -0.13856 1.00023 -1.52140 +v -0.00000 1.00023 -1.62207 +v -0.14569 1.00023 -0.00000 +v 0.04502 1.00023 -1.61494 +v -0.13856 1.00023 1.52140 +v 1.87057 1.00023 2.08416 +v 0.60778 1.00023 3.34695 +v 0.08564 1.00023 -1.59425 +v -0.11787 1.00023 1.56202 +v 1.59120 1.00023 2.63245 +v 1.15607 1.00023 3.06758 +v -0.08564 1.00023 1.59425 +v 0.11787 1.00023 -1.56202 +v -0.04502 1.00023 1.61494 +v 0.13856 1.00023 -1.52140 +v -0.00000 1.00023 1.62207 +v 0.14569 1.00023 -0.00000 +v 0.13856 1.00023 1.52140 +v 0.04502 1.00023 1.61494 +v 0.08564 1.00023 1.59425 +v 0.11787 1.00023 1.56202 +vt 0.266842 0.029841 +vt 0.301409 0.064408 +vt 0.175000 0.150000 +vt 0.125000 0.312500 +vt 0.137500 0.312500 +vt 0.137500 0.688440 +vt 0.125000 0.688440 +vt 0.126716 0.304853 +vt 0.083159 0.282659 +vt 0.323603 0.107966 +vt 0.112500 0.312500 +vt 0.112500 0.688440 +vt 0.150000 0.312500 +vt 0.150000 0.688440 +vt 0.175000 0.312500 +vt 0.331250 0.156250 +vt 0.323603 0.204534 +vt 0.223284 0.304853 +vt 0.100000 0.312500 +vt 0.100000 0.688440 +vt 0.162500 0.312500 +vt 0.162500 0.688440 +vt 0.301409 0.248091 +vt 0.266841 0.282659 +vt 0.087500 0.312500 +vt 0.087500 0.688440 +vt 0.175000 0.312500 +vt 0.175000 0.688440 +vt 0.075000 0.312500 +vt 0.075000 0.688440 +vt 0.187500 0.312500 +vt 0.187500 0.688440 +vt 0.200000 0.312500 +vt 0.200000 0.688440 +vt 0.062500 0.312500 +vt 0.062500 0.688440 +vt 0.048591 0.064409 +vt 0.175000 0.150000 +vt 0.083159 0.029841 +vt 0.126716 0.007647 +vt 0.026397 0.107966 +vt 0.175000 -0.000000 +vt 0.018750 0.156250 +vt 0.223284 0.007647 +vt 0.026397 0.204534 +vt 0.266842 0.029841 +vt 0.048591 0.248091 +vt 0.083159 0.282659 +vt 0.301409 0.064408 +vt 0.126716 0.304853 +vt 0.323603 0.107966 +vt 0.175000 0.312500 +vt 0.331250 0.156250 +vt 0.323603 0.204534 +vt 0.223284 0.304853 +vt 0.266841 0.282659 +vt 0.301409 0.248091 +vt 0.212500 0.312500 +vt 0.212500 0.688440 +vt 0.050000 0.312500 +vt 0.050000 0.688440 +vt 0.168197 0.847327 +vt 0.083159 0.970159 +vt 0.048591 0.935591 +vt 0.165636 0.844766 +vt 0.225000 0.312500 +vt 0.225000 0.688440 +vt 0.287500 0.312500 +vt 0.300000 0.312500 +vt 0.300000 0.688440 +vt 0.287500 0.688440 +vt 0.171423 0.848971 +vt 0.126716 0.992353 +vt 0.026397 0.892034 +vt 0.163992 0.841540 +vt 0.175000 0.849537 +vt 0.175000 1.000000 +vt 0.018750 0.843750 +vt 0.163426 0.837963 +vt 0.178577 0.848971 +vt 0.223284 0.992353 +vt 0.026397 0.795466 +vt 0.163992 0.834386 +vt 0.275000 0.312500 +vt 0.275000 0.688440 +vt 0.237500 0.312500 +vt 0.237500 0.688440 +vt 0.181803 0.847327 +vt 0.266841 0.970159 +vt 0.048591 0.751909 +vt 0.165636 0.831160 +vt 0.262500 0.312500 +vt 0.262500 0.688440 +vt 0.250000 0.312500 +vt 0.250000 0.688440 +vt 0.125000 0.312500 +vt 0.125000 0.688440 +vt 0.137500 0.688440 +vt 0.137500 0.312500 +vt 0.112500 0.312500 +vt 0.112500 0.688440 +vt 0.150000 0.688440 +vt 0.150000 0.312500 +vt 0.100000 0.312500 +vt 0.100000 0.688440 +vt 0.162500 0.688440 +vt 0.162500 0.312500 +vt 0.087500 0.312500 +vt 0.087500 0.688440 +vt 0.175000 0.688440 +vt 0.175000 0.312500 +vt 0.075000 0.312500 +vt 0.075000 0.688440 +vt 0.187500 0.688440 +vt 0.187500 0.312500 +vt 0.200000 0.688440 +vt 0.200000 0.312500 +vt 0.062500 0.312500 +vt 0.062500 0.688440 +vt 0.212500 0.688440 +vt 0.212500 0.312500 +vt 0.050000 0.312500 +vt 0.050000 0.688440 +vt 0.225000 0.688440 +vt 0.225000 0.312500 +vt 0.287500 0.312500 +vt 0.287500 0.688440 +vt 0.300000 0.688440 +vt 0.300000 0.312500 +vt 0.275000 0.312500 +vt 0.275000 0.688440 +vt 0.237500 0.688440 +vt 0.237500 0.312500 +vt 0.250000 0.688440 +vt 0.250000 0.312500 +vt 0.262500 0.312500 +vt 0.262500 0.688440 +vt 0.083159 0.717341 +vt 0.168197 0.828599 +vt 0.184364 0.844766 +vt 0.301409 0.935591 +vt 0.126716 0.695147 +vt 0.171423 0.826955 +vt 0.186008 0.841540 +vt 0.323603 0.892034 +vt 0.175000 0.687500 +vt 0.175000 0.826389 +vt 0.186574 0.837963 +vt 0.331250 0.843750 +vt 0.186008 0.834386 +vt 0.323603 0.795466 +vt 0.223284 0.695147 +vt 0.178577 0.826955 +vt 0.184364 0.831160 +vt 0.301409 0.751908 +vt 0.266842 0.717341 +vt 0.181803 0.828599 +vt 0.048591 0.248091 +vt 0.026397 0.204534 +vt 0.223284 0.007647 +vt 0.018750 0.156250 +vt 0.175000 -0.000000 +vt 0.026397 0.107966 +vt 0.126716 0.007647 +vt 0.048591 0.064409 +vt 0.083159 0.029841 +s 1 +g silhouette_shorter +usemtl lambert2SG +f 1/1 2/2 3/3 +s 2 +f 4/4 5/5 6/6 7/7 +s 1 +f 8/8 9/9 3/3 +f 2/2 10/10 3/3 +s 2 +f 11/11 4/4 7/7 12/12 +f 5/5 13/13 14/14 6/6 +s 1 +f 15/15 8/8 3/3 +f 10/10 16/16 3/3 +f 16/16 17/17 3/3 +f 18/18 15/15 3/3 +s 2 +f 19/19 11/11 12/12 20/20 +f 13/13 21/21 22/22 14/14 +s 1 +f 17/17 23/23 3/3 +f 24/24 18/18 3/3 +f 23/23 24/24 3/3 +s 2 +f 25/25 19/19 20/20 26/26 +f 21/21 27/27 28/28 22/22 +f 1/29 25/25 26/26 29/30 +f 27/27 30/31 31/32 28/28 +f 30/31 9/33 32/34 31/32 +f 2/35 1/29 29/30 33/36 +s 4 +f 34/37 35/38 36/39 +f 36/39 35/38 37/40 +f 38/41 35/38 34/37 +f 37/40 35/38 39/42 +f 40/43 35/38 38/41 +f 39/42 35/38 41/44 +f 42/45 35/38 40/43 +f 41/44 35/38 43/46 +f 44/47 35/38 42/45 +f 45/48 35/38 44/47 +f 43/46 35/38 46/49 +f 47/50 35/38 45/48 +f 46/49 35/38 48/51 +f 49/52 35/38 47/50 +f 48/51 35/38 50/53 +f 50/53 35/38 51/54 +f 52/55 35/38 49/52 +f 53/56 35/38 52/55 +f 51/54 35/38 54/57 +f 54/57 35/38 53/56 +s 2 +f 9/33 8/58 55/59 32/34 +f 10/60 2/35 33/36 56/61 +s 5 +f 57/62 7/63 6/64 58/65 +s 2 +f 8/58 15/66 59/67 55/59 +f 16/68 10/69 56/70 60/71 +s 5 +f 61/72 12/73 7/63 57/62 +f 58/65 6/64 14/74 62/75 +f 63/76 20/77 12/73 61/72 +f 62/75 14/74 22/78 64/79 +f 65/80 26/81 20/77 63/76 +f 64/79 22/78 28/82 66/83 +s 2 +f 17/84 16/68 60/71 67/85 +f 15/66 18/86 68/87 59/67 +s 5 +f 69/88 29/89 26/81 65/80 +f 66/83 28/82 31/90 70/91 +s 2 +f 23/92 17/84 67/85 71/93 +f 18/86 24/94 72/95 68/87 +s 6 +f 36/96 57/97 58/98 34/99 +f 37/100 61/101 57/97 36/96 +f 34/99 58/98 62/102 38/103 +f 39/104 63/105 61/101 37/100 +f 38/103 62/102 64/106 40/107 +f 41/108 65/109 63/105 39/104 +f 40/107 64/106 66/110 42/111 +s 2 +f 24/94 23/92 71/93 72/95 +s 6 +f 43/112 69/113 65/109 41/108 +f 42/111 66/110 70/114 44/115 +f 44/115 70/114 73/116 45/117 +f 46/118 74/119 69/113 43/112 +f 45/117 73/116 75/120 47/121 +f 48/122 76/123 74/119 46/118 +f 47/121 75/120 77/124 49/125 +f 50/126 78/127 76/128 48/129 +f 51/130 79/131 78/127 50/126 +f 49/125 77/124 80/132 52/133 +f 52/133 80/132 81/134 53/135 +f 54/136 82/137 79/131 51/130 +f 53/135 81/134 82/137 54/136 +s 5 +f 70/91 31/90 32/138 73/139 +f 74/140 33/141 29/89 69/88 +f 73/139 32/138 55/142 75/143 +f 76/144 56/145 33/141 74/140 +f 75/143 55/142 59/146 77/147 +f 78/148 60/149 56/145 76/144 +f 79/150 67/151 60/149 78/148 +f 77/147 59/146 68/152 80/153 +f 82/154 71/155 67/151 79/150 +f 80/153 68/152 72/156 81/157 +f 81/157 72/156 71/155 82/154 +s 1 +f 9/9 30/158 3/3 +f 30/158 27/159 3/3 +f 25/160 1/1 3/3 +f 27/159 21/161 3/3 +f 19/162 25/160 3/3 +f 21/161 13/163 3/3 +f 11/164 19/162 3/3 +f 13/163 5/165 3/3 +f 4/166 11/164 3/3 +f 5/165 4/166 3/3 diff --git a/mod/data/mac-fallback-assets/stadium_snail_3.obj b/mod/data/mac-fallback-assets/stadium_snail_3.obj new file mode 100644 index 000000000..01d49a74d --- /dev/null +++ b/mod/data/mac-fallback-assets/stadium_snail_3.obj @@ -0,0 +1,374 @@ +# This file uses centimeters as units for non-parametric coordinates. + +mtllib silhouette_shorter.mtl +v 1.15608 -0.00000 -3.55971 +v 1.59120 -0.00000 -3.12459 +v -0.00000 -0.00000 -0.00000 +v -1.15608 -0.00000 -3.55971 +v -1.59120 -0.00000 -3.12459 +v -1.59120 1.00023 -3.12459 +v -1.15608 1.00023 -3.55971 +v -0.60778 -0.00000 3.83908 +v -1.15608 -0.00000 3.55971 +v 1.87057 -0.00000 -2.57629 +v -0.60778 -0.00000 -3.83908 +v -0.60778 1.00023 -3.83908 +v -1.87057 -0.00000 -2.57629 +v -1.87057 1.00023 -2.57629 +v -0.00000 -0.00000 3.93534 +v 1.96683 -0.00000 -0.00000 +v 1.87057 -0.00000 2.57629 +v 0.60778 -0.00000 3.83908 +v -0.00000 -0.00000 -3.93534 +v -0.00000 1.00023 -3.93534 +v -1.96683 -0.00000 -0.00000 +v -1.96683 1.00023 -0.00000 +v 1.59120 -0.00000 3.12458 +v 1.15607 -0.00000 3.55971 +v 0.60778 -0.00000 -3.83908 +v 0.60778 1.00023 -3.83908 +v -1.87057 -0.00000 2.57629 +v -1.87057 1.00023 2.57629 +v 1.15608 1.00023 -3.55971 +v -1.59120 -0.00000 3.12458 +v -1.59120 1.00023 3.12458 +v -1.15608 1.00023 3.55971 +v 1.59120 1.00023 -3.12459 +v -0.11787 0.92084 -2.05415 +v -0.00000 0.92084 -0.00000 +v -0.08564 0.92084 -2.08638 +v -0.04502 0.92084 -2.10707 +v -0.13856 0.92084 -2.01353 +v -0.00000 0.92084 -2.11420 +v -0.14569 0.92084 -0.00000 +v 0.04502 0.92084 -2.10707 +v -0.13856 0.92084 2.01353 +v 0.08564 0.92084 -2.08638 +v -0.11787 0.92084 2.05415 +v -0.08564 0.92084 2.08638 +v 0.11787 0.92084 -2.05415 +v -0.04502 0.92084 2.10707 +v 0.13856 0.92084 -2.01353 +v -0.00000 0.92084 2.11420 +v 0.14569 0.92084 -0.00000 +v 0.13856 0.92084 2.01353 +v 0.04502 0.92084 2.10707 +v 0.08564 0.92084 2.08638 +v 0.11787 0.92084 2.05415 +v -0.60778 1.00023 3.83908 +v 1.87057 1.00023 -2.57629 +v -0.08564 1.00023 -2.08638 +v -0.11787 1.00023 -2.05415 +v -0.00000 1.00023 3.93534 +v 1.96683 1.00023 -0.00000 +v -0.04502 1.00023 -2.10707 +v -0.13856 1.00023 -2.01353 +v -0.00000 1.00023 -2.11420 +v -0.14569 1.00023 -0.00000 +v 0.04502 1.00023 -2.10707 +v -0.13856 1.00023 2.01353 +v 1.87057 1.00023 2.57629 +v 0.60778 1.00023 3.83908 +v 0.08564 1.00023 -2.08638 +v -0.11787 1.00023 2.05415 +v 1.59120 1.00023 3.12458 +v 1.15607 1.00023 3.55971 +v -0.08564 1.00023 2.08638 +v 0.11787 1.00023 -2.05415 +v -0.04502 1.00023 2.10707 +v 0.13856 1.00023 -2.01353 +v -0.00000 1.00023 2.11420 +v 0.14569 1.00023 -0.00000 +v 0.13856 1.00023 2.01353 +v 0.04502 1.00023 2.10707 +v 0.08564 1.00023 2.08638 +v 0.11787 1.00023 2.05415 +vt 0.266842 0.029841 +vt 0.301409 0.064408 +vt 0.175000 0.150000 +vt 0.125000 0.312500 +vt 0.137500 0.312500 +vt 0.137500 0.688440 +vt 0.125000 0.688440 +vt 0.126716 0.304853 +vt 0.083159 0.282659 +vt 0.323603 0.107966 +vt 0.112500 0.312500 +vt 0.112500 0.688440 +vt 0.150000 0.312500 +vt 0.150000 0.688440 +vt 0.175000 0.312500 +vt 0.331250 0.156250 +vt 0.323603 0.204534 +vt 0.223284 0.304853 +vt 0.100000 0.312500 +vt 0.100000 0.688440 +vt 0.162500 0.312500 +vt 0.162500 0.688440 +vt 0.301409 0.248091 +vt 0.266841 0.282659 +vt 0.087500 0.312500 +vt 0.087500 0.688440 +vt 0.175000 0.312500 +vt 0.175000 0.688440 +vt 0.075000 0.312500 +vt 0.075000 0.688440 +vt 0.187500 0.312500 +vt 0.187500 0.688440 +vt 0.200000 0.312500 +vt 0.200000 0.688440 +vt 0.062500 0.312500 +vt 0.062500 0.688440 +vt 0.048591 0.064409 +vt 0.175000 0.150000 +vt 0.083159 0.029841 +vt 0.126716 0.007647 +vt 0.026397 0.107966 +vt 0.175000 -0.000000 +vt 0.018750 0.156250 +vt 0.223284 0.007647 +vt 0.026397 0.204534 +vt 0.266842 0.029841 +vt 0.048591 0.248091 +vt 0.083159 0.282659 +vt 0.301409 0.064408 +vt 0.126716 0.304853 +vt 0.323603 0.107966 +vt 0.175000 0.312500 +vt 0.331250 0.156250 +vt 0.323603 0.204534 +vt 0.223284 0.304853 +vt 0.266841 0.282659 +vt 0.301409 0.248091 +vt 0.212500 0.312500 +vt 0.212500 0.688440 +vt 0.050000 0.312500 +vt 0.050000 0.688440 +vt 0.168197 0.847327 +vt 0.083159 0.970159 +vt 0.048591 0.935591 +vt 0.165636 0.844766 +vt 0.225000 0.312500 +vt 0.225000 0.688440 +vt 0.287500 0.312500 +vt 0.300000 0.312500 +vt 0.300000 0.688440 +vt 0.287500 0.688440 +vt 0.171423 0.848971 +vt 0.126716 0.992353 +vt 0.026397 0.892034 +vt 0.163992 0.841540 +vt 0.175000 0.849537 +vt 0.175000 1.000000 +vt 0.018750 0.843750 +vt 0.163426 0.837963 +vt 0.178577 0.848971 +vt 0.223284 0.992353 +vt 0.026397 0.795466 +vt 0.163992 0.834386 +vt 0.275000 0.312500 +vt 0.275000 0.688440 +vt 0.237500 0.312500 +vt 0.237500 0.688440 +vt 0.181803 0.847327 +vt 0.266841 0.970159 +vt 0.048591 0.751909 +vt 0.165636 0.831160 +vt 0.262500 0.312500 +vt 0.262500 0.688440 +vt 0.250000 0.312500 +vt 0.250000 0.688440 +vt 0.125000 0.312500 +vt 0.125000 0.688440 +vt 0.137500 0.688440 +vt 0.137500 0.312500 +vt 0.112500 0.312500 +vt 0.112500 0.688440 +vt 0.150000 0.688440 +vt 0.150000 0.312500 +vt 0.100000 0.312500 +vt 0.100000 0.688440 +vt 0.162500 0.688440 +vt 0.162500 0.312500 +vt 0.087500 0.312500 +vt 0.087500 0.688440 +vt 0.175000 0.688440 +vt 0.175000 0.312500 +vt 0.075000 0.312500 +vt 0.075000 0.688440 +vt 0.187500 0.688440 +vt 0.187500 0.312500 +vt 0.200000 0.688440 +vt 0.200000 0.312500 +vt 0.062500 0.312500 +vt 0.062500 0.688440 +vt 0.212500 0.688440 +vt 0.212500 0.312500 +vt 0.050000 0.312500 +vt 0.050000 0.688440 +vt 0.225000 0.688440 +vt 0.225000 0.312500 +vt 0.287500 0.312500 +vt 0.287500 0.688440 +vt 0.300000 0.688440 +vt 0.300000 0.312500 +vt 0.275000 0.312500 +vt 0.275000 0.688440 +vt 0.237500 0.688440 +vt 0.237500 0.312500 +vt 0.250000 0.688440 +vt 0.250000 0.312500 +vt 0.262500 0.312500 +vt 0.262500 0.688440 +vt 0.083159 0.717341 +vt 0.168197 0.828599 +vt 0.184364 0.844766 +vt 0.301409 0.935591 +vt 0.126716 0.695147 +vt 0.171423 0.826955 +vt 0.186008 0.841540 +vt 0.323603 0.892034 +vt 0.175000 0.687500 +vt 0.175000 0.826389 +vt 0.186574 0.837963 +vt 0.331250 0.843750 +vt 0.186008 0.834386 +vt 0.323603 0.795466 +vt 0.223284 0.695147 +vt 0.178577 0.826955 +vt 0.184364 0.831160 +vt 0.301409 0.751908 +vt 0.266842 0.717341 +vt 0.181803 0.828599 +vt 0.048591 0.248091 +vt 0.026397 0.204534 +vt 0.223284 0.007647 +vt 0.018750 0.156250 +vt 0.175000 -0.000000 +vt 0.026397 0.107966 +vt 0.126716 0.007647 +vt 0.048591 0.064409 +vt 0.083159 0.029841 +s 1 +g silhouette_shorter +usemtl lambert2SG +f 1/1 2/2 3/3 +s 2 +f 4/4 5/5 6/6 7/7 +s 1 +f 8/8 9/9 3/3 +f 2/2 10/10 3/3 +s 2 +f 11/11 4/4 7/7 12/12 +f 5/5 13/13 14/14 6/6 +s 1 +f 15/15 8/8 3/3 +f 10/10 16/16 3/3 +f 16/16 17/17 3/3 +f 18/18 15/15 3/3 +s 2 +f 19/19 11/11 12/12 20/20 +f 13/13 21/21 22/22 14/14 +s 1 +f 17/17 23/23 3/3 +f 24/24 18/18 3/3 +f 23/23 24/24 3/3 +s 2 +f 25/25 19/19 20/20 26/26 +f 21/21 27/27 28/28 22/22 +f 1/29 25/25 26/26 29/30 +f 27/27 30/31 31/32 28/28 +f 30/31 9/33 32/34 31/32 +f 2/35 1/29 29/30 33/36 +s 4 +f 34/37 35/38 36/39 +f 36/39 35/38 37/40 +f 38/41 35/38 34/37 +f 37/40 35/38 39/42 +f 40/43 35/38 38/41 +f 39/42 35/38 41/44 +f 42/45 35/38 40/43 +f 41/44 35/38 43/46 +f 44/47 35/38 42/45 +f 45/48 35/38 44/47 +f 43/46 35/38 46/49 +f 47/50 35/38 45/48 +f 46/49 35/38 48/51 +f 49/52 35/38 47/50 +f 48/51 35/38 50/53 +f 50/53 35/38 51/54 +f 52/55 35/38 49/52 +f 53/56 35/38 52/55 +f 51/54 35/38 54/57 +f 54/57 35/38 53/56 +s 2 +f 9/33 8/58 55/59 32/34 +f 10/60 2/35 33/36 56/61 +s 5 +f 57/62 7/63 6/64 58/65 +s 2 +f 8/58 15/66 59/67 55/59 +f 16/68 10/69 56/70 60/71 +s 5 +f 61/72 12/73 7/63 57/62 +f 58/65 6/64 14/74 62/75 +f 63/76 20/77 12/73 61/72 +f 62/75 14/74 22/78 64/79 +f 65/80 26/81 20/77 63/76 +f 64/79 22/78 28/82 66/83 +s 2 +f 17/84 16/68 60/71 67/85 +f 15/66 18/86 68/87 59/67 +s 5 +f 69/88 29/89 26/81 65/80 +f 66/83 28/82 31/90 70/91 +s 2 +f 23/92 17/84 67/85 71/93 +f 18/86 24/94 72/95 68/87 +s 6 +f 36/96 57/97 58/98 34/99 +f 37/100 61/101 57/97 36/96 +f 34/99 58/98 62/102 38/103 +f 39/104 63/105 61/101 37/100 +f 38/103 62/102 64/106 40/107 +f 41/108 65/109 63/105 39/104 +f 40/107 64/106 66/110 42/111 +s 2 +f 24/94 23/92 71/93 72/95 +s 6 +f 43/112 69/113 65/109 41/108 +f 42/111 66/110 70/114 44/115 +f 44/115 70/114 73/116 45/117 +f 46/118 74/119 69/113 43/112 +f 45/117 73/116 75/120 47/121 +f 48/122 76/123 74/119 46/118 +f 47/121 75/120 77/124 49/125 +f 50/126 78/127 76/128 48/129 +f 51/130 79/131 78/127 50/126 +f 49/125 77/124 80/132 52/133 +f 52/133 80/132 81/134 53/135 +f 54/136 82/137 79/131 51/130 +f 53/135 81/134 82/137 54/136 +s 5 +f 70/91 31/90 32/138 73/139 +f 74/140 33/141 29/89 69/88 +f 73/139 32/138 55/142 75/143 +f 76/144 56/145 33/141 74/140 +f 75/143 55/142 59/146 77/147 +f 78/148 60/149 56/145 76/144 +f 79/150 67/151 60/149 78/148 +f 77/147 59/146 68/152 80/153 +f 82/154 71/155 67/151 79/150 +f 80/153 68/152 72/156 81/157 +f 81/157 72/156 71/155 82/154 +s 1 +f 9/9 30/158 3/3 +f 30/158 27/159 3/3 +f 25/160 1/1 3/3 +f 27/159 21/161 3/3 +f 19/162 25/160 3/3 +f 21/161 13/163 3/3 +f 11/164 19/162 3/3 +f 13/163 5/165 3/3 +f 4/166 11/164 3/3 +f 5/165 4/166 3/3 From c4cd234c5d80fa757df151f8f4069618787e8e4d Mon Sep 17 00:00:00 2001 From: Martin Pourrat Date: Tue, 11 Aug 2026 13:06:02 +0200 Subject: [PATCH 09/42] Overlays: filter ground raycasts through macHitIsGround A ray hit only counts as ground if it is not the ignored object, not an object still in motion (movement template falling into place the frame the overlay spawns), and not the hovering "Maximum Move" Windows bundle (floats at +20 in windows mode and caught the center ray). Applied to all 6 raycast sites; fixes the MaxMove fill decal floating above its border ring on first spawn. Co-Authored-By: Claude Fable 5 --- mod/src/includes/Overlays.ttslua | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/mod/src/includes/Overlays.ttslua b/mod/src/includes/Overlays.ttslua index 6af43dd7a..26e44364c 100644 --- a/mod/src/includes/Overlays.ttslua +++ b/mod/src/includes/Overlays.ttslua @@ -138,7 +138,24 @@ local DEPLOYMENT_CELL_SIZES = { rcc = {3, 3}, bcc = {3, 3}, -- opposite corner quarter } -local function macRayGroundY(x, z, offset) +-- A ray hit counts as "ground" only if it is not the ignored object and not +-- a transient object: anything still in motion (e.g. a movement template +-- falling into place the frame the overlay spawns) or the hovering +-- "Maximum Move" Windows bundle would otherwise catch the center ray and +-- float the fill decal above its border ring. +local function macHitIsGround(h, ignoreObj) + local obj = h.hit_object + if obj == nil then return true end + if obj == ignoreObj then return false end + if obj.getName and obj.getName() == "Maximum Move" then return false end + local ok, v = pcall(function() return obj.getVelocity() end) + if ok and v and (math.abs(v.x) + math.abs(v.y) + math.abs(v.z)) > 0.05 then + return false + end + return true +end + +local function macRayGroundY(x, z, offset, ignoreObj) local hits = Physics.cast({ origin = {x, 30, z}, direction = {0, -1, 0}, @@ -146,7 +163,9 @@ local function macRayGroundY(x, z, offset) max_distance = 50, }) for _, h in ipairs(hits) do - return h.point.y + (offset or 0.05) + if macHitIsGround(h, ignoreObj) then + return h.point.y + (offset or 0.05) + end end return offset or 0.05 end @@ -188,7 +207,7 @@ local function macBuildRing(centerPos, radius, color, thickness, ignoreObj) }) local y = centerPos.y + 0.05 for _, h in ipairs(hits) do - if h.hit_object ~= ignoreObj then + if macHitIsGround(h, ignoreObj) then y = h.point.y + 0.05 break end @@ -237,7 +256,7 @@ macBuilders.range = function(fig, params) }) local groundY = pos.y for _, h in ipairs(hits) do - if h.hit_object ~= fig then groundY = h.point.y; break end + if macHitIsGround(h, fig) then groundY = h.point.y; break end end local effectiveMaxR = maxR + br @@ -276,7 +295,7 @@ macBuilders.maxmove = function(fig, params) }) local groundY = pos.y for _, h in ipairs(hits) do - if h.hit_object ~= fig then groundY = h.point.y; break end + if macHitIsGround(h, fig) then groundY = h.point.y; break end end return { From b49099f8cc3f8c304feed48ab0a7e78abe30fb31 Mon Sep 17 00:00:00 2001 From: Martin Pourrat Date: Tue, 11 Aug 2026 14:13:02 +0200 Subject: [PATCH 10/42] Add the vanilla oblong silhouette meshes extracted from the bundles The Mac fallback spawns silhouettes as Custom_Model because the bundles' embedded shaders do not load on Metal. Oblong bases used hand-built stadium meshes approximated from the marker cylinder, whose outline reads as less precise than the Windows original. These are the real meshes (silh_new_long_1in / silh_new_snail_1in) pulled out of the vanilla bundles with UnityPy, so the Mac path changes only the rendering, not the geometry. Faces rewritten as v//vn: the meshes carry no UVs and UnityPy emitted dangling vt indices that TTS would reject. Co-Authored-By: Claude Fable 5 --- .../silh_vanilla_long_1.obj | 190 ++++++++++++++++++ .../silh_vanilla_snail_1.obj | 190 ++++++++++++++++++ 2 files changed, 380 insertions(+) create mode 100644 mod/data/mac-fallback-assets/silh_vanilla_long_1.obj create mode 100644 mod/data/mac-fallback-assets/silh_vanilla_snail_1.obj diff --git a/mod/data/mac-fallback-assets/silh_vanilla_long_1.obj b/mod/data/mac-fallback-assets/silh_vanilla_long_1.obj new file mode 100644 index 000000000..5663009dd --- /dev/null +++ b/mod/data/mac-fallback-assets/silh_vanilla_long_1.obj @@ -0,0 +1,190 @@ +g silh_new_long_1in +v -0 0.000321194326 -1.90383077 +v 1.79507375 -3.19731583E-07 -2.40114331 +v 1.47036397 -3.79383408E-07 -2.84912109 +v 2.00016642 0.000321194326 -1.90383077 +v 1.04253602 -4.21221131E-07 -3.16331697 +v 2.00016642 0.000321702857 1.91503835 +v 0.61488086 -4.4783468E-07 -3.36318135 +v -0 0.000321702857 1.91503823 +v 1.47036397 0.999999642 -2.84912133 +v 1.04253602 0.999999583 -3.1633172 +v 1.79507375 0.999999702 -2.40114355 +v 0.61488086 0.999999523 -3.36318159 +v -0 0.999678314 -1.90383089 +v 2.00016642 0.999678314 -1.90383089 +v -0 0.999999523 -3.46068621 +v -0 0.999678791 1.91503811 +v 2.00016642 0.999678791 1.91503823 +v -0 -4.608182E-07 -3.46068597 +v 1.82142329 3.1795102E-07 2.38777161 +v 1.82142329 1.00000036 2.38777137 +v -0.61488086 0.999999523 -3.36318159 +v 1.52951431 3.70640919E-07 2.7834661 +v 1.52951431 1.00000036 2.78346586 +v 1.07117271 1.00000048 3.16235137 +v -2.00004268 0.999678791 1.91503823 +v 1.07117271 4.21092579E-07 3.16235161 +v 0.61488086 4.48775808E-07 3.37024903 +v -0 4.61759583E-07 3.46775556 +v 0.61488086 1.00000048 3.37024879 +v -0.61488086 -4.4783468E-07 -3.36318135 +v -0 1.00000048 3.46775532 +v -1.04253602 0.999999583 -3.1633172 +v -0.61488086 4.48775808E-07 3.37024903 +v -1.04253602 -4.21221131E-07 -3.16331697 +v -0.61488086 1.00000048 3.37024879 +v -1.47036397 0.999999642 -2.84912133 +v -1.07117271 4.21092579E-07 3.16235161 +v -1.47036397 -3.79383408E-07 -2.84912109 +v -1.79507375 0.999999702 -2.40114355 +v -1.07117271 1.00000048 3.16235137 +v -1.79507375 -3.19731583E-07 -2.40114331 +v -2.00004268 0.999678314 -1.90383089 +v -2.00004268 0.000321194326 -1.90383077 +v -2.00004268 0.000321702857 1.91503835 +v -1.52951431 3.70640919E-07 2.7834661 +v -1.52951431 1.00000036 2.78346586 +v -1.82142329 1.00000036 2.38777137 +v -1.82142329 3.1795102E-07 2.38777161 +vn -0 -1 0 +vn 0.702909827 -0.673609495 -0.228403121 +vn 0.597922504 -0.673625469 -0.434416264 +vn 0.739097834 -0.673598051 0 +vn 0.434390396 -0.673585176 -0.597986639 +vn 0.739097834 -0.673598051 0 +vn 0.228402525 -0.673507571 -0.703007638 +vn -0 -1 0 +vn 0.597922444 0.67362529 -0.434416443 +vn 0.434390366 0.673584998 -0.597986817 +vn 0.702909887 0.673609436 -0.2284033 +vn 0.228402525 0.673507333 -0.703007877 +vn -0 1 0 +vn 0.739097834 0.673598051 0 +vn -0 0.673597932 -0.739097953 +vn -0 1 0 +vn 0.739097834 0.673598051 0 +vn -0 -0.67359823 -0.739097774 +vn 0.702909887 -0.673609436 0.2284033 +vn 0.702909827 0.673609495 0.228403121 +vn -0.228403196 0.673609316 -0.702909946 +vn 0.597986698 -0.673584998 0.434390455 +vn 0.597986758 0.673585176 0.434390277 +vn 0.434416384 0.673625469 0.597922385 +vn -0.739097834 0.673598051 0 +vn 0.434416354 -0.67362529 0.597922564 +vn 0.228403196 -0.673609316 0.702909946 +vn -0 -0.673493445 0.739193082 +vn 0.228403226 0.673609614 0.702909768 +vn -0.228403226 -0.673609614 -0.702909768 +vn -0 0.673493803 0.739192903 +vn -0.434500784 0.673501134 -0.598001182 +vn -0.228402525 -0.673507333 0.703007877 +vn -0.434500784 -0.673501253 -0.598000944 +vn -0.228402525 0.673507571 0.703007638 +vn -0.598001063 0.673501134 -0.434500873 +vn -0.434500784 -0.673501134 0.598001182 +vn -0.598001063 -0.673501253 -0.434500694 +vn -0.702909887 0.673609436 -0.2284033 +vn -0.434500784 0.673501253 0.598000944 +vn -0.702909827 -0.673609495 -0.228403121 +vn -0.739097834 0.673598051 0 +vn -0.739097834 -0.673598051 0 +vn -0.739097834 -0.673598051 0 +vn -0.598001063 -0.673501134 0.434500873 +vn -0.598001063 0.673501253 0.434500694 +vn -0.702909827 0.673609495 0.228403121 +vn -0.702909887 -0.673609436 0.2284033 +g silh_new_long_1in_0 +f 3//3 2//2 1//1 +f 2//2 4//4 1//1 +f 5//5 3//3 1//1 +f 1//1 4//4 6//6 +f 7//7 5//5 1//1 +f 8//8 1//1 6//6 +f 3//3 9//9 2//2 +f 5//5 10//10 3//3 +f 10//10 9//9 3//3 +f 9//9 11//11 2//2 +f 2//2 11//11 4//4 +f 12//12 10//10 5//5 +f 7//7 12//12 5//5 +f 9//9 10//10 13//13 +f 11//11 9//9 13//13 +f 10//10 12//12 13//13 +f 14//14 11//11 13//13 +f 11//11 14//14 4//4 +f 12//12 15//15 13//13 +f 15//15 12//12 7//7 +f 14//14 13//13 16//16 +f 4//4 14//14 17//17 +f 17//17 14//14 16//16 +f 6//6 4//4 17//17 +f 18//18 15//15 7//7 +f 18//18 7//7 1//1 +f 6//6 17//17 19//19 +f 6//6 19//19 8//8 +f 20//20 17//17 16//16 +f 17//17 20//20 19//19 +f 21//21 15//15 18//18 +f 15//15 21//21 13//13 +f 19//19 22//22 8//8 +f 19//19 20//20 22//22 +f 23//23 20//20 16//16 +f 20//20 23//23 22//22 +f 24//24 23//23 16//16 +f 16//16 13//13 25//25 +f 22//22 26//26 8//8 +f 22//22 23//23 26//26 +f 23//23 24//24 26//26 +f 26//26 27//27 8//8 +f 26//26 24//24 27//27 +f 27//27 28//28 8//8 +f 24//24 29//29 27//27 +f 29//29 24//24 16//16 +f 27//27 29//29 28//28 +f 30//30 21//21 18//18 +f 30//30 18//18 1//1 +f 29//29 31//31 28//28 +f 31//31 29//29 16//16 +f 32//32 21//21 30//30 +f 21//21 32//32 13//13 +f 28//28 31//31 33//33 +f 28//28 33//33 8//8 +f 34//34 32//32 30//30 +f 34//34 30//30 1//1 +f 31//31 35//35 33//33 +f 35//35 31//31 16//16 +f 36//36 32//32 34//34 +f 32//32 36//36 13//13 +f 33//33 35//35 37//37 +f 33//33 37//37 8//8 +f 38//38 36//36 34//34 +f 38//38 34//34 1//1 +f 36//36 39//39 13//13 +f 39//39 36//36 38//38 +f 35//35 40//40 37//37 +f 40//40 35//35 16//16 +f 41//41 38//38 1//1 +f 41//41 39//39 38//38 +f 39//39 42//42 13//13 +f 42//42 39//39 41//41 +f 13//13 42//42 25//25 +f 43//43 41//41 1//1 +f 43//43 42//42 41//41 +f 43//43 1//1 8//8 +f 42//42 43//43 44//44 +f 25//25 42//42 44//44 +f 44//44 43//43 8//8 +f 37//37 45//45 8//8 +f 37//37 40//40 45//45 +f 46//46 40//40 16//16 +f 40//40 46//46 45//45 +f 47//47 16//16 25//25 +f 47//47 25//25 44//44 +f 47//47 46//46 16//16 +f 48//48 44//44 8//8 +f 45//45 48//48 8//8 +f 45//45 46//46 48//48 +f 48//48 47//47 44//44 +f 46//46 47//47 48//48 diff --git a/mod/data/mac-fallback-assets/silh_vanilla_snail_1.obj b/mod/data/mac-fallback-assets/silh_vanilla_snail_1.obj new file mode 100644 index 000000000..2d6a45220 --- /dev/null +++ b/mod/data/mac-fallback-assets/silh_vanilla_snail_1.obj @@ -0,0 +1,190 @@ +g silh_new_snail_1in +v -0 0.000321137864 -2.32793117 +v 1.79507375 -3.76203957E-07 -2.82524371 +v 1.47036397 -4.3585581E-07 -3.27322149 +v 2.00016642 0.000321137864 -2.32793117 +v 1.04253602 -4.77693504E-07 -3.58741736 +v 2.00016642 0.000321757863 2.32819009 +v 0.61488086 -5.04307081E-07 -3.78728175 +v -0 0.000321757863 2.32818985 +v 1.47036397 0.999999583 -3.27322173 +v 1.04253602 0.999999523 -3.5874176 +v 1.79507375 0.999999642 -2.82524395 +v 0.61488086 0.999999523 -3.78728199 +v -0 0.999678254 -2.3279314 +v 2.00016642 0.999678254 -2.3279314 +v -0 0.999999464 -3.88478661 +v -0 0.99967885 2.32818961 +v 2.00016642 0.99967885 2.32818985 +v -0 -5.17290573E-07 -3.88478637 +v 1.82142329 3.72965502E-07 2.80092335 +v 1.82142329 1.00000036 2.80092311 +v -0.61488086 0.999999523 -3.78728199 +v 1.52951431 4.25655401E-07 3.19661784 +v 1.52951431 1.00000048 3.1966176 +v 1.07117271 1.00000048 3.57550311 +v -2.00004268 0.99967885 2.32818985 +v 1.07117271 4.76107061E-07 3.57550335 +v 0.61488086 5.03790261E-07 3.78340077 +v -0 5.16774094E-07 3.8809073 +v 0.61488086 1.00000048 3.78340054 +v -0.61488086 -5.04307081E-07 -3.78728175 +v -0 1.00000048 3.88090706 +v -1.04253602 0.999999523 -3.5874176 +v -0.61488086 5.03790261E-07 3.78340077 +v -1.04253602 -4.77693504E-07 -3.58741736 +v -0.61488086 1.00000048 3.78340054 +v -1.47036397 0.999999583 -3.27322173 +v -1.07117271 4.76107061E-07 3.57550335 +v -1.47036397 -4.3585581E-07 -3.27322149 +v -1.79507375 0.999999642 -2.82524395 +v -1.07117271 1.00000048 3.57550311 +v -1.79507375 -3.76203957E-07 -2.82524371 +v -2.00004268 0.999678254 -2.3279314 +v -2.00004268 0.000321137864 -2.32793117 +v -2.00004268 0.000321757863 2.32819009 +v -1.52951431 4.25655401E-07 3.19661784 +v -1.52951431 1.00000048 3.1966176 +v -1.82142329 1.00000036 2.80092311 +v -1.82142329 3.72965502E-07 2.80092335 +vn -0 -1 0 +vn 0.702909827 -0.673609495 -0.228403121 +vn 0.597922504 -0.673625469 -0.434416264 +vn 0.739097834 -0.673598051 0 +vn 0.434390396 -0.673585176 -0.597986639 +vn 0.739097834 -0.673598051 0 +vn 0.228402525 -0.673507571 -0.703007638 +vn -0 -1 0 +vn 0.597922444 0.67362529 -0.434416443 +vn 0.434390366 0.673584998 -0.597986817 +vn 0.702909887 0.673609436 -0.2284033 +vn 0.228402525 0.673507333 -0.703007877 +vn -0 1 0 +vn 0.739097834 0.673598051 0 +vn -0 0.673597932 -0.739097953 +vn -0 1 0 +vn 0.739097834 0.673598051 0 +vn -0 -0.67359823 -0.739097774 +vn 0.702909887 -0.673609436 0.2284033 +vn 0.702909827 0.673609495 0.228403121 +vn -0.228403196 0.673609316 -0.702909946 +vn 0.597986698 -0.673584998 0.434390455 +vn 0.597986758 0.673585176 0.434390277 +vn 0.434416384 0.673625469 0.597922385 +vn -0.739097834 0.673598051 0 +vn 0.434416354 -0.67362529 0.597922564 +vn 0.228403196 -0.673609316 0.702909946 +vn -0 -0.673493445 0.739193082 +vn 0.228403226 0.673609614 0.702909768 +vn -0.228403226 -0.673609614 -0.702909768 +vn -0 0.673493803 0.739192903 +vn -0.434500784 0.673501134 -0.598001182 +vn -0.228402525 -0.673507333 0.703007877 +vn -0.434500784 -0.673501253 -0.598000944 +vn -0.228402525 0.673507571 0.703007638 +vn -0.598001063 0.673501134 -0.434500873 +vn -0.434500784 -0.673501134 0.598001182 +vn -0.598001063 -0.673501253 -0.434500694 +vn -0.702909887 0.673609436 -0.2284033 +vn -0.434500784 0.673501253 0.598000944 +vn -0.702909827 -0.673609495 -0.228403121 +vn -0.739097834 0.673598051 0 +vn -0.739097834 -0.673598051 0 +vn -0.739097834 -0.673598051 0 +vn -0.598001063 -0.673501134 0.434500873 +vn -0.598001063 0.673501253 0.434500694 +vn -0.702909827 0.673609495 0.228403121 +vn -0.702909887 -0.673609436 0.2284033 +g silh_new_snail_1in_0 +f 3//3 2//2 1//1 +f 2//2 4//4 1//1 +f 5//5 3//3 1//1 +f 1//1 4//4 6//6 +f 7//7 5//5 1//1 +f 8//8 1//1 6//6 +f 3//3 9//9 2//2 +f 5//5 10//10 3//3 +f 10//10 9//9 3//3 +f 9//9 11//11 2//2 +f 2//2 11//11 4//4 +f 12//12 10//10 5//5 +f 7//7 12//12 5//5 +f 9//9 10//10 13//13 +f 11//11 9//9 13//13 +f 10//10 12//12 13//13 +f 14//14 11//11 13//13 +f 11//11 14//14 4//4 +f 12//12 15//15 13//13 +f 15//15 12//12 7//7 +f 14//14 13//13 16//16 +f 4//4 14//14 17//17 +f 17//17 14//14 16//16 +f 6//6 4//4 17//17 +f 18//18 15//15 7//7 +f 18//18 7//7 1//1 +f 6//6 17//17 19//19 +f 6//6 19//19 8//8 +f 20//20 17//17 16//16 +f 17//17 20//20 19//19 +f 21//21 15//15 18//18 +f 15//15 21//21 13//13 +f 19//19 22//22 8//8 +f 19//19 20//20 22//22 +f 23//23 20//20 16//16 +f 20//20 23//23 22//22 +f 24//24 23//23 16//16 +f 16//16 13//13 25//25 +f 22//22 26//26 8//8 +f 22//22 23//23 26//26 +f 23//23 24//24 26//26 +f 26//26 27//27 8//8 +f 26//26 24//24 27//27 +f 27//27 28//28 8//8 +f 24//24 29//29 27//27 +f 29//29 24//24 16//16 +f 27//27 29//29 28//28 +f 30//30 21//21 18//18 +f 30//30 18//18 1//1 +f 29//29 31//31 28//28 +f 31//31 29//29 16//16 +f 32//32 21//21 30//30 +f 21//21 32//32 13//13 +f 28//28 31//31 33//33 +f 28//28 33//33 8//8 +f 34//34 32//32 30//30 +f 34//34 30//30 1//1 +f 31//31 35//35 33//33 +f 35//35 31//31 16//16 +f 36//36 32//32 34//34 +f 32//32 36//36 13//13 +f 33//33 35//35 37//37 +f 33//33 37//37 8//8 +f 38//38 36//36 34//34 +f 38//38 34//34 1//1 +f 36//36 39//39 13//13 +f 39//39 36//36 38//38 +f 35//35 40//40 37//37 +f 40//40 35//35 16//16 +f 41//41 38//38 1//1 +f 41//41 39//39 38//38 +f 39//39 42//42 13//13 +f 42//42 39//39 41//41 +f 13//13 42//42 25//25 +f 43//43 41//41 1//1 +f 43//43 42//42 41//41 +f 43//43 1//1 8//8 +f 42//42 43//43 44//44 +f 25//25 42//42 44//44 +f 44//44 43//43 8//8 +f 37//37 45//45 8//8 +f 37//37 40//40 45//45 +f 46//46 40//40 16//16 +f 40//40 46//46 45//45 +f 47//47 16//16 25//25 +f 47//47 25//25 44//44 +f 47//47 46//46 16//16 +f 48//48 44//44 8//8 +f 45//45 48//48 8//8 +f 45//45 46//46 48//48 +f 48//48 47//47 44//44 +f 46//46 47//47 48//48 From 1624b248ba1bbb2a9df165d68737b7be19b33ead Mon Sep 17 00:00:00 2001 From: Martin Pourrat Date: Tue, 11 Aug 2026 14:35:40 +0200 Subject: [PATCH 11/42] Silhouette meshes: strip baked normals, add cylindrical UVs The meshes lifted straight out of the vanilla bundles rendered faceted as Custom_Models: their baked per-vertex normals fight the player's shader. The hand-built stadiums that looked right shipped no normals at all, so TTS computed and smoothed them itself. Same treatment here, plus the UVs the raw export lacked. Geometry is untouched, so the outline stays the Windows one (elliptical caps, not the semicircles the stadiums assumed). Co-Authored-By: Claude Fable 5 --- .../silh_vanilla_long_2.obj | 190 ++++++++++++++++++ .../silh_vanilla_snail_2.obj | 190 ++++++++++++++++++ 2 files changed, 380 insertions(+) create mode 100644 mod/data/mac-fallback-assets/silh_vanilla_long_2.obj create mode 100644 mod/data/mac-fallback-assets/silh_vanilla_snail_2.obj diff --git a/mod/data/mac-fallback-assets/silh_vanilla_long_2.obj b/mod/data/mac-fallback-assets/silh_vanilla_long_2.obj new file mode 100644 index 000000000..6fdc4bf89 --- /dev/null +++ b/mod/data/mac-fallback-assets/silh_vanilla_long_2.obj @@ -0,0 +1,190 @@ +g silh_new_long_1in +v -0 0.000321194326 -1.90383077 +v 1.79507375 -3.19731583E-07 -2.40114331 +v 1.47036397 -3.79383408E-07 -2.84912109 +v 2.00016642 0.000321194326 -1.90383077 +v 1.04253602 -4.21221131E-07 -3.16331697 +v 2.00016642 0.000321702857 1.91503835 +v 0.61488086 -4.4783468E-07 -3.36318135 +v -0 0.000321702857 1.91503823 +v 1.47036397 0.999999642 -2.84912133 +v 1.04253602 0.999999583 -3.1633172 +v 1.79507375 0.999999702 -2.40114355 +v 0.61488086 0.999999523 -3.36318159 +v -0 0.999678314 -1.90383089 +v 2.00016642 0.999678314 -1.90383089 +v -0 0.999999523 -3.46068621 +v -0 0.999678791 1.91503811 +v 2.00016642 0.999678791 1.91503823 +v -0 -4.608182E-07 -3.46068597 +v 1.82142329 3.1795102E-07 2.38777161 +v 1.82142329 1.00000036 2.38777137 +v -0.61488086 0.999999523 -3.36318159 +v 1.52951431 3.70640919E-07 2.7834661 +v 1.52951431 1.00000036 2.78346586 +v 1.07117271 1.00000048 3.16235137 +v -2.00004268 0.999678791 1.91503823 +v 1.07117271 4.21092579E-07 3.16235161 +v 0.61488086 4.48775808E-07 3.37024903 +v -0 4.61759583E-07 3.46775556 +v 0.61488086 1.00000048 3.37024879 +v -0.61488086 -4.4783468E-07 -3.36318135 +v -0 1.00000048 3.46775532 +v -1.04253602 0.999999583 -3.1633172 +v -0.61488086 4.48775808E-07 3.37024903 +v -1.04253602 -4.21221131E-07 -3.16331697 +v -0.61488086 1.00000048 3.37024879 +v -1.47036397 0.999999642 -2.84912133 +v -1.07117271 4.21092579E-07 3.16235161 +v -1.47036397 -3.79383408E-07 -2.84912109 +v -1.79507375 0.999999702 -2.40114355 +v -1.07117271 1.00000048 3.16235137 +v -1.79507375 -3.19731583E-07 -2.40114331 +v -2.00004268 0.999678314 -1.90383089 +v -2.00004268 0.000321194326 -1.90383077 +v -2.00004268 0.000321702857 1.91503835 +v -1.52951431 3.70640919E-07 2.7834661 +v -1.52951431 1.00000036 2.78346586 +v -1.82142329 1.00000036 2.38777137 +v -1.82142329 3.1795102E-07 2.38777161 +vt 0.250000 0.000322 +vt 0.352171 0.000000 +vt 0.325826 0.000000 +vt 0.378927 0.000322 +vt 0.300669 0.000000 +vt 0.621540 0.000322 +vt 0.278780 0.000000 +vt 0.750000 0.000322 +vt 0.325826 0.999999 +vt 0.300669 0.999999 +vt 0.352171 0.999999 +vt 0.278780 0.999999 +vt 0.250000 0.999678 +vt 0.378927 0.999678 +vt 0.250000 0.999999 +vt 0.750000 0.999678 +vt 0.621540 0.999678 +vt 0.250000 0.000000 +vt 0.646286 0.000001 +vt 0.646286 1.000000 +vt 0.221220 0.999999 +vt 0.670031 0.000001 +vt 0.670031 1.000000 +vt 0.698021 1.000000 +vt 0.878455 0.999678 +vt 0.698021 0.000001 +vt 0.721279 0.000001 +vt 0.750000 0.000001 +vt 0.721279 1.000000 +vt 0.221220 0.000000 +vt 0.750000 1.000000 +vt 0.199331 0.999999 +vt 0.778721 0.000001 +vt 0.199331 0.000000 +vt 0.778721 1.000000 +vt 0.174174 0.999999 +vt 0.801979 0.000001 +vt 0.174174 0.000000 +vt 0.147829 0.999999 +vt 0.801979 1.000000 +vt 0.147829 0.000000 +vt 0.121078 0.999678 +vt 0.121078 0.000322 +vt 0.878455 0.000322 +vt 0.829969 0.000001 +vt 0.829969 1.000000 +vt 0.853714 1.000000 +vt 0.853714 0.000001 +g silh_new_long_1in_0 +f 3/3 2/2 1/1 +f 2/2 4/4 1/1 +f 5/5 3/3 1/1 +f 1/1 4/4 6/6 +f 7/7 5/5 1/1 +f 8/8 1/1 6/6 +f 3/3 9/9 2/2 +f 5/5 10/10 3/3 +f 10/10 9/9 3/3 +f 9/9 11/11 2/2 +f 2/2 11/11 4/4 +f 12/12 10/10 5/5 +f 7/7 12/12 5/5 +f 9/9 10/10 13/13 +f 11/11 9/9 13/13 +f 10/10 12/12 13/13 +f 14/14 11/11 13/13 +f 11/11 14/14 4/4 +f 12/12 15/15 13/13 +f 15/15 12/12 7/7 +f 14/14 13/13 16/16 +f 4/4 14/14 17/17 +f 17/17 14/14 16/16 +f 6/6 4/4 17/17 +f 18/18 15/15 7/7 +f 18/18 7/7 1/1 +f 6/6 17/17 19/19 +f 6/6 19/19 8/8 +f 20/20 17/17 16/16 +f 17/17 20/20 19/19 +f 21/21 15/15 18/18 +f 15/15 21/21 13/13 +f 19/19 22/22 8/8 +f 19/19 20/20 22/22 +f 23/23 20/20 16/16 +f 20/20 23/23 22/22 +f 24/24 23/23 16/16 +f 16/16 13/13 25/25 +f 22/22 26/26 8/8 +f 22/22 23/23 26/26 +f 23/23 24/24 26/26 +f 26/26 27/27 8/8 +f 26/26 24/24 27/27 +f 27/27 28/28 8/8 +f 24/24 29/29 27/27 +f 29/29 24/24 16/16 +f 27/27 29/29 28/28 +f 30/30 21/21 18/18 +f 30/30 18/18 1/1 +f 29/29 31/31 28/28 +f 31/31 29/29 16/16 +f 32/32 21/21 30/30 +f 21/21 32/32 13/13 +f 28/28 31/31 33/33 +f 28/28 33/33 8/8 +f 34/34 32/32 30/30 +f 34/34 30/30 1/1 +f 31/31 35/35 33/33 +f 35/35 31/31 16/16 +f 36/36 32/32 34/34 +f 32/32 36/36 13/13 +f 33/33 35/35 37/37 +f 33/33 37/37 8/8 +f 38/38 36/36 34/34 +f 38/38 34/34 1/1 +f 36/36 39/39 13/13 +f 39/39 36/36 38/38 +f 35/35 40/40 37/37 +f 40/40 35/35 16/16 +f 41/41 38/38 1/1 +f 41/41 39/39 38/38 +f 39/39 42/42 13/13 +f 42/42 39/39 41/41 +f 13/13 42/42 25/25 +f 43/43 41/41 1/1 +f 43/43 42/42 41/41 +f 43/43 1/1 8/8 +f 42/42 43/43 44/44 +f 25/25 42/42 44/44 +f 44/44 43/43 8/8 +f 37/37 45/45 8/8 +f 37/37 40/40 45/45 +f 46/46 40/40 16/16 +f 40/40 46/46 45/45 +f 47/47 16/16 25/25 +f 47/47 25/25 44/44 +f 47/47 46/46 16/16 +f 48/48 44/44 8/8 +f 45/45 48/48 8/8 +f 45/45 46/46 48/48 +f 48/48 47/47 44/44 +f 46/46 47/47 48/48 diff --git a/mod/data/mac-fallback-assets/silh_vanilla_snail_2.obj b/mod/data/mac-fallback-assets/silh_vanilla_snail_2.obj new file mode 100644 index 000000000..273151d66 --- /dev/null +++ b/mod/data/mac-fallback-assets/silh_vanilla_snail_2.obj @@ -0,0 +1,190 @@ +g silh_new_snail_1in +v -0 0.000321137864 -2.32793117 +v 1.79507375 -3.76203957E-07 -2.82524371 +v 1.47036397 -4.3585581E-07 -3.27322149 +v 2.00016642 0.000321137864 -2.32793117 +v 1.04253602 -4.77693504E-07 -3.58741736 +v 2.00016642 0.000321757863 2.32819009 +v 0.61488086 -5.04307081E-07 -3.78728175 +v -0 0.000321757863 2.32818985 +v 1.47036397 0.999999583 -3.27322173 +v 1.04253602 0.999999523 -3.5874176 +v 1.79507375 0.999999642 -2.82524395 +v 0.61488086 0.999999523 -3.78728199 +v -0 0.999678254 -2.3279314 +v 2.00016642 0.999678254 -2.3279314 +v -0 0.999999464 -3.88478661 +v -0 0.99967885 2.32818961 +v 2.00016642 0.99967885 2.32818985 +v -0 -5.17290573E-07 -3.88478637 +v 1.82142329 3.72965502E-07 2.80092335 +v 1.82142329 1.00000036 2.80092311 +v -0.61488086 0.999999523 -3.78728199 +v 1.52951431 4.25655401E-07 3.19661784 +v 1.52951431 1.00000048 3.1966176 +v 1.07117271 1.00000048 3.57550311 +v -2.00004268 0.99967885 2.32818985 +v 1.07117271 4.76107061E-07 3.57550335 +v 0.61488086 5.03790261E-07 3.78340077 +v -0 5.16774094E-07 3.8809073 +v 0.61488086 1.00000048 3.78340054 +v -0.61488086 -5.04307081E-07 -3.78728175 +v -0 1.00000048 3.88090706 +v -1.04253602 0.999999523 -3.5874176 +v -0.61488086 5.03790261E-07 3.78340077 +v -1.04253602 -4.77693504E-07 -3.58741736 +v -0.61488086 1.00000048 3.78340054 +v -1.47036397 0.999999583 -3.27322173 +v -1.07117271 4.76107061E-07 3.57550335 +v -1.47036397 -4.3585581E-07 -3.27322149 +v -1.79507375 0.999999642 -2.82524395 +v -1.07117271 1.00000048 3.57550311 +v -1.79507375 -3.76203957E-07 -2.82524371 +v -2.00004268 0.999678254 -2.3279314 +v -2.00004268 0.000321137864 -2.32793117 +v -2.00004268 0.000321757863 2.32819009 +v -1.52951431 4.25655401E-07 3.19661784 +v -1.52951431 1.00000048 3.1966176 +v -1.82142329 1.00000036 2.80092311 +v -1.82142329 3.72965502E-07 2.80092335 +vt 0.250000 0.000322 +vt 0.340085 0.000000 +vt 0.317195 0.000000 +vt 0.362970 0.000322 +vt 0.295012 0.000000 +vt 0.637039 0.000322 +vt 0.275616 0.000000 +vt 0.750000 0.000322 +vt 0.317195 0.999999 +vt 0.295012 0.999999 +vt 0.340085 0.999999 +vt 0.275616 0.999999 +vt 0.250000 0.999678 +vt 0.362970 0.999678 +vt 0.250000 0.999999 +vt 0.750000 0.999678 +vt 0.637039 0.999678 +vt 0.250000 0.000000 +vt 0.658234 0.000001 +vt 0.658234 1.000000 +vt 0.224384 0.999999 +vt 0.678972 0.000001 +vt 0.678972 1.000000 +vt 0.703674 1.000000 +vt 0.862957 0.999678 +vt 0.703674 0.000001 +vt 0.724358 0.000001 +vt 0.750000 0.000001 +vt 0.724358 1.000000 +vt 0.224384 0.000000 +vt 0.750000 1.000000 +vt 0.204988 0.999999 +vt 0.775642 0.000001 +vt 0.204988 0.000000 +vt 0.775642 1.000000 +vt 0.182805 0.999999 +vt 0.796326 0.000001 +vt 0.182805 0.000000 +vt 0.159915 0.999999 +vt 0.796326 1.000000 +vt 0.159915 0.000000 +vt 0.137035 0.999678 +vt 0.137035 0.000322 +vt 0.862957 0.000322 +vt 0.821028 0.000001 +vt 0.821028 1.000000 +vt 0.841766 1.000000 +vt 0.841766 0.000001 +g silh_new_snail_1in_0 +f 3/3 2/2 1/1 +f 2/2 4/4 1/1 +f 5/5 3/3 1/1 +f 1/1 4/4 6/6 +f 7/7 5/5 1/1 +f 8/8 1/1 6/6 +f 3/3 9/9 2/2 +f 5/5 10/10 3/3 +f 10/10 9/9 3/3 +f 9/9 11/11 2/2 +f 2/2 11/11 4/4 +f 12/12 10/10 5/5 +f 7/7 12/12 5/5 +f 9/9 10/10 13/13 +f 11/11 9/9 13/13 +f 10/10 12/12 13/13 +f 14/14 11/11 13/13 +f 11/11 14/14 4/4 +f 12/12 15/15 13/13 +f 15/15 12/12 7/7 +f 14/14 13/13 16/16 +f 4/4 14/14 17/17 +f 17/17 14/14 16/16 +f 6/6 4/4 17/17 +f 18/18 15/15 7/7 +f 18/18 7/7 1/1 +f 6/6 17/17 19/19 +f 6/6 19/19 8/8 +f 20/20 17/17 16/16 +f 17/17 20/20 19/19 +f 21/21 15/15 18/18 +f 15/15 21/21 13/13 +f 19/19 22/22 8/8 +f 19/19 20/20 22/22 +f 23/23 20/20 16/16 +f 20/20 23/23 22/22 +f 24/24 23/23 16/16 +f 16/16 13/13 25/25 +f 22/22 26/26 8/8 +f 22/22 23/23 26/26 +f 23/23 24/24 26/26 +f 26/26 27/27 8/8 +f 26/26 24/24 27/27 +f 27/27 28/28 8/8 +f 24/24 29/29 27/27 +f 29/29 24/24 16/16 +f 27/27 29/29 28/28 +f 30/30 21/21 18/18 +f 30/30 18/18 1/1 +f 29/29 31/31 28/28 +f 31/31 29/29 16/16 +f 32/32 21/21 30/30 +f 21/21 32/32 13/13 +f 28/28 31/31 33/33 +f 28/28 33/33 8/8 +f 34/34 32/32 30/30 +f 34/34 30/30 1/1 +f 31/31 35/35 33/33 +f 35/35 31/31 16/16 +f 36/36 32/32 34/34 +f 32/32 36/36 13/13 +f 33/33 35/35 37/37 +f 33/33 37/37 8/8 +f 38/38 36/36 34/34 +f 38/38 34/34 1/1 +f 36/36 39/39 13/13 +f 39/39 36/36 38/38 +f 35/35 40/40 37/37 +f 40/40 35/35 16/16 +f 41/41 38/38 1/1 +f 41/41 39/39 38/38 +f 39/39 42/42 13/13 +f 42/42 39/39 41/41 +f 13/13 42/42 25/25 +f 43/43 41/41 1/1 +f 43/43 42/42 41/41 +f 43/43 1/1 8/8 +f 42/42 43/43 44/44 +f 25/25 42/42 44/44 +f 44/44 43/43 8/8 +f 37/37 45/45 8/8 +f 37/37 40/40 45/45 +f 46/46 40/40 16/16 +f 40/40 46/46 45/45 +f 47/47 16/16 25/25 +f 47/47 25/25 44/44 +f 47/47 46/46 16/16 +f 48/48 44/44 8/8 +f 45/45 48/48 8/8 +f 45/45 46/46 48/48 +f 48/48 47/47 44/44 +f 46/46 47/47 48/48 From e2ad8e129670c98bd73b2b2c0feeff1bf034b99d Mon Sep 17 00:00:00 2001 From: Martin Pourrat Date: Tue, 11 Aug 2026 14:45:25 +0200 Subject: [PATCH 12/42] Stadium meshes: keep the marker topology, adopt the vanilla outline The meshes lifted from the vanilla bundles render badly as Custom_Models whatever we do to their normals: their topology differs from the marker's, and it is the marker topology (82 verts, 100 faces, UVs, no baked normals) that makes the round bases light correctly. So move the stadium vertices onto the vanilla outline instead. Splitting a cylinder left semicircular caps; the real bases are elliptical and about 20% shallower (cap depth 1.55 for a 2.0 half-width). Width, cap start and tip now match the bundle meshes to within a thousandth. Co-Authored-By: Claude Fable 5 --- .../silh_shaped_long_1.obj | 374 ++++++++++++++++++ .../silh_shaped_snail_1.obj | 374 ++++++++++++++++++ 2 files changed, 748 insertions(+) create mode 100644 mod/data/mac-fallback-assets/silh_shaped_long_1.obj create mode 100644 mod/data/mac-fallback-assets/silh_shaped_snail_1.obj diff --git a/mod/data/mac-fallback-assets/silh_shaped_long_1.obj b/mod/data/mac-fallback-assets/silh_shaped_long_1.obj new file mode 100644 index 000000000..3377f3a52 --- /dev/null +++ b/mod/data/mac-fallback-assets/silh_shaped_long_1.obj @@ -0,0 +1,374 @@ +# This file uses centimeters as units for non-parametric coordinates. + +mtllib silhouette_shorter.mtl +v 1.175695 -0.000000 -3.171242 +v 1.618197 -0.000000 -2.827718 +v -0.000000 -0.000000 0.749407 +v -1.175695 -0.000000 -3.171242 +v -1.618197 -0.000000 -2.827718 +v -1.618197 1.000230 -2.827718 +v -1.175695 1.000230 -3.171242 +v -0.618092 -0.000000 3.391803 +v -1.175695 -0.000000 3.171242 +v 1.902307 -0.000000 -2.394839 +v -0.618092 -0.000000 -3.391803 +v -0.618092 1.000230 -3.391803 +v -1.902307 -0.000000 -2.394839 +v -1.902307 1.000230 -2.394839 +v -0.000000 -0.000000 3.467800 +v 2.000200 -0.000000 0.749407 +v 1.902307 -0.000000 2.394839 +v 0.618092 -0.000000 3.391803 +v -0.000000 -0.000000 -3.467800 +v -0.000000 1.000230 -3.467800 +v -2.000200 -0.000000 0.749407 +v -2.000200 1.000230 0.749407 +v 1.618197 -0.000000 2.827710 +v 1.175684 -0.000000 3.171242 +v 0.618092 -0.000000 -3.391803 +v 0.618092 1.000230 -3.391803 +v -1.902307 -0.000000 2.394839 +v -1.902307 1.000230 2.394839 +v 1.175695 1.000230 -3.171242 +v -1.618197 -0.000000 2.827710 +v -1.618197 1.000230 2.827710 +v -1.175695 1.000230 3.171242 +v 1.618197 1.000230 -2.827718 +v -0.119870 0.920840 -1.982612 +v -0.000000 0.920840 0.749407 +v -0.087093 0.920840 -2.008058 +v -0.045784 0.920840 -2.024392 +v -0.140911 0.920840 -1.950543 +v -0.000000 0.920840 -2.030021 +v -0.148162 0.920840 0.749407 +v 0.045784 0.920840 -2.024392 +v -0.140911 0.920840 1.950543 +v 0.087093 0.920840 -2.008058 +v -0.119870 0.920840 1.982612 +v -0.087093 0.920840 2.008058 +v 0.119870 0.920840 -1.982612 +v -0.045784 0.920840 2.024392 +v 0.140911 0.920840 -1.950543 +v -0.000000 0.920840 2.030021 +v 0.148162 0.920840 0.749407 +v 0.140911 0.920840 1.950543 +v 0.045784 0.920840 2.024392 +v 0.087093 0.920840 2.008058 +v 0.119870 0.920840 1.982612 +v -0.618092 1.000230 3.391803 +v 1.902307 1.000230 -2.394839 +v -0.087093 1.000230 -2.008058 +v -0.119870 1.000230 -1.982612 +v -0.000000 1.000230 3.467800 +v 2.000200 1.000230 0.749407 +v -0.045784 1.000230 -2.024392 +v -0.140911 1.000230 -1.950543 +v -0.000000 1.000230 -2.030021 +v -0.148162 1.000230 0.749407 +v 0.045784 1.000230 -2.024392 +v -0.140911 1.000230 1.950543 +v 1.902307 1.000230 2.394839 +v 0.618092 1.000230 3.391803 +v 0.087093 1.000230 -2.008058 +v -0.119870 1.000230 1.982612 +v 1.618197 1.000230 2.827710 +v 1.175684 1.000230 3.171242 +v -0.087093 1.000230 2.008058 +v 0.119870 1.000230 -1.982612 +v -0.045784 1.000230 2.024392 +v 0.140911 1.000230 -1.950543 +v -0.000000 1.000230 2.030021 +v 0.148162 1.000230 0.749407 +v 0.140911 1.000230 1.950543 +v 0.045784 1.000230 2.024392 +v 0.087093 1.000230 2.008058 +v 0.119870 1.000230 1.982612 +vt 0.266842 0.029841 +vt 0.301409 0.064408 +vt 0.175000 0.150000 +vt 0.125000 0.312500 +vt 0.137500 0.312500 +vt 0.137500 0.688440 +vt 0.125000 0.688440 +vt 0.126716 0.304853 +vt 0.083159 0.282659 +vt 0.323603 0.107966 +vt 0.112500 0.312500 +vt 0.112500 0.688440 +vt 0.150000 0.312500 +vt 0.150000 0.688440 +vt 0.175000 0.312500 +vt 0.331250 0.156250 +vt 0.323603 0.204534 +vt 0.223284 0.304853 +vt 0.100000 0.312500 +vt 0.100000 0.688440 +vt 0.162500 0.312500 +vt 0.162500 0.688440 +vt 0.301409 0.248091 +vt 0.266841 0.282659 +vt 0.087500 0.312500 +vt 0.087500 0.688440 +vt 0.175000 0.312500 +vt 0.175000 0.688440 +vt 0.075000 0.312500 +vt 0.075000 0.688440 +vt 0.187500 0.312500 +vt 0.187500 0.688440 +vt 0.200000 0.312500 +vt 0.200000 0.688440 +vt 0.062500 0.312500 +vt 0.062500 0.688440 +vt 0.048591 0.064409 +vt 0.175000 0.150000 +vt 0.083159 0.029841 +vt 0.126716 0.007647 +vt 0.026397 0.107966 +vt 0.175000 -0.000000 +vt 0.018750 0.156250 +vt 0.223284 0.007647 +vt 0.026397 0.204534 +vt 0.266842 0.029841 +vt 0.048591 0.248091 +vt 0.083159 0.282659 +vt 0.301409 0.064408 +vt 0.126716 0.304853 +vt 0.323603 0.107966 +vt 0.175000 0.312500 +vt 0.331250 0.156250 +vt 0.323603 0.204534 +vt 0.223284 0.304853 +vt 0.266841 0.282659 +vt 0.301409 0.248091 +vt 0.212500 0.312500 +vt 0.212500 0.688440 +vt 0.050000 0.312500 +vt 0.050000 0.688440 +vt 0.168197 0.847327 +vt 0.083159 0.970159 +vt 0.048591 0.935591 +vt 0.165636 0.844766 +vt 0.225000 0.312500 +vt 0.225000 0.688440 +vt 0.287500 0.312500 +vt 0.300000 0.312500 +vt 0.300000 0.688440 +vt 0.287500 0.688440 +vt 0.171423 0.848971 +vt 0.126716 0.992353 +vt 0.026397 0.892034 +vt 0.163992 0.841540 +vt 0.175000 0.849537 +vt 0.175000 1.000000 +vt 0.018750 0.843750 +vt 0.163426 0.837963 +vt 0.178577 0.848971 +vt 0.223284 0.992353 +vt 0.026397 0.795466 +vt 0.163992 0.834386 +vt 0.275000 0.312500 +vt 0.275000 0.688440 +vt 0.237500 0.312500 +vt 0.237500 0.688440 +vt 0.181803 0.847327 +vt 0.266841 0.970159 +vt 0.048591 0.751909 +vt 0.165636 0.831160 +vt 0.262500 0.312500 +vt 0.262500 0.688440 +vt 0.250000 0.312500 +vt 0.250000 0.688440 +vt 0.125000 0.312500 +vt 0.125000 0.688440 +vt 0.137500 0.688440 +vt 0.137500 0.312500 +vt 0.112500 0.312500 +vt 0.112500 0.688440 +vt 0.150000 0.688440 +vt 0.150000 0.312500 +vt 0.100000 0.312500 +vt 0.100000 0.688440 +vt 0.162500 0.688440 +vt 0.162500 0.312500 +vt 0.087500 0.312500 +vt 0.087500 0.688440 +vt 0.175000 0.688440 +vt 0.175000 0.312500 +vt 0.075000 0.312500 +vt 0.075000 0.688440 +vt 0.187500 0.688440 +vt 0.187500 0.312500 +vt 0.200000 0.688440 +vt 0.200000 0.312500 +vt 0.062500 0.312500 +vt 0.062500 0.688440 +vt 0.212500 0.688440 +vt 0.212500 0.312500 +vt 0.050000 0.312500 +vt 0.050000 0.688440 +vt 0.225000 0.688440 +vt 0.225000 0.312500 +vt 0.287500 0.312500 +vt 0.287500 0.688440 +vt 0.300000 0.688440 +vt 0.300000 0.312500 +vt 0.275000 0.312500 +vt 0.275000 0.688440 +vt 0.237500 0.688440 +vt 0.237500 0.312500 +vt 0.250000 0.688440 +vt 0.250000 0.312500 +vt 0.262500 0.312500 +vt 0.262500 0.688440 +vt 0.083159 0.717341 +vt 0.168197 0.828599 +vt 0.184364 0.844766 +vt 0.301409 0.935591 +vt 0.126716 0.695147 +vt 0.171423 0.826955 +vt 0.186008 0.841540 +vt 0.323603 0.892034 +vt 0.175000 0.687500 +vt 0.175000 0.826389 +vt 0.186574 0.837963 +vt 0.331250 0.843750 +vt 0.186008 0.834386 +vt 0.323603 0.795466 +vt 0.223284 0.695147 +vt 0.178577 0.826955 +vt 0.184364 0.831160 +vt 0.301409 0.751908 +vt 0.266842 0.717341 +vt 0.181803 0.828599 +vt 0.048591 0.248091 +vt 0.026397 0.204534 +vt 0.223284 0.007647 +vt 0.018750 0.156250 +vt 0.175000 -0.000000 +vt 0.026397 0.107966 +vt 0.126716 0.007647 +vt 0.048591 0.064409 +vt 0.083159 0.029841 +s 1 +g silhouette_shorter +usemtl lambert2SG +f 1/1 2/2 3/3 +s 2 +f 4/4 5/5 6/6 7/7 +s 1 +f 8/8 9/9 3/3 +f 2/2 10/10 3/3 +s 2 +f 11/11 4/4 7/7 12/12 +f 5/5 13/13 14/14 6/6 +s 1 +f 15/15 8/8 3/3 +f 10/10 16/16 3/3 +f 16/16 17/17 3/3 +f 18/18 15/15 3/3 +s 2 +f 19/19 11/11 12/12 20/20 +f 13/13 21/21 22/22 14/14 +s 1 +f 17/17 23/23 3/3 +f 24/24 18/18 3/3 +f 23/23 24/24 3/3 +s 2 +f 25/25 19/19 20/20 26/26 +f 21/21 27/27 28/28 22/22 +f 1/29 25/25 26/26 29/30 +f 27/27 30/31 31/32 28/28 +f 30/31 9/33 32/34 31/32 +f 2/35 1/29 29/30 33/36 +s 4 +f 34/37 35/38 36/39 +f 36/39 35/38 37/40 +f 38/41 35/38 34/37 +f 37/40 35/38 39/42 +f 40/43 35/38 38/41 +f 39/42 35/38 41/44 +f 42/45 35/38 40/43 +f 41/44 35/38 43/46 +f 44/47 35/38 42/45 +f 45/48 35/38 44/47 +f 43/46 35/38 46/49 +f 47/50 35/38 45/48 +f 46/49 35/38 48/51 +f 49/52 35/38 47/50 +f 48/51 35/38 50/53 +f 50/53 35/38 51/54 +f 52/55 35/38 49/52 +f 53/56 35/38 52/55 +f 51/54 35/38 54/57 +f 54/57 35/38 53/56 +s 2 +f 9/33 8/58 55/59 32/34 +f 10/60 2/35 33/36 56/61 +s 5 +f 57/62 7/63 6/64 58/65 +s 2 +f 8/58 15/66 59/67 55/59 +f 16/68 10/69 56/70 60/71 +s 5 +f 61/72 12/73 7/63 57/62 +f 58/65 6/64 14/74 62/75 +f 63/76 20/77 12/73 61/72 +f 62/75 14/74 22/78 64/79 +f 65/80 26/81 20/77 63/76 +f 64/79 22/78 28/82 66/83 +s 2 +f 17/84 16/68 60/71 67/85 +f 15/66 18/86 68/87 59/67 +s 5 +f 69/88 29/89 26/81 65/80 +f 66/83 28/82 31/90 70/91 +s 2 +f 23/92 17/84 67/85 71/93 +f 18/86 24/94 72/95 68/87 +s 6 +f 36/96 57/97 58/98 34/99 +f 37/100 61/101 57/97 36/96 +f 34/99 58/98 62/102 38/103 +f 39/104 63/105 61/101 37/100 +f 38/103 62/102 64/106 40/107 +f 41/108 65/109 63/105 39/104 +f 40/107 64/106 66/110 42/111 +s 2 +f 24/94 23/92 71/93 72/95 +s 6 +f 43/112 69/113 65/109 41/108 +f 42/111 66/110 70/114 44/115 +f 44/115 70/114 73/116 45/117 +f 46/118 74/119 69/113 43/112 +f 45/117 73/116 75/120 47/121 +f 48/122 76/123 74/119 46/118 +f 47/121 75/120 77/124 49/125 +f 50/126 78/127 76/128 48/129 +f 51/130 79/131 78/127 50/126 +f 49/125 77/124 80/132 52/133 +f 52/133 80/132 81/134 53/135 +f 54/136 82/137 79/131 51/130 +f 53/135 81/134 82/137 54/136 +s 5 +f 70/91 31/90 32/138 73/139 +f 74/140 33/141 29/89 69/88 +f 73/139 32/138 55/142 75/143 +f 76/144 56/145 33/141 74/140 +f 75/143 55/142 59/146 77/147 +f 78/148 60/149 56/145 76/144 +f 79/150 67/151 60/149 78/148 +f 77/147 59/146 68/152 80/153 +f 82/154 71/155 67/151 79/150 +f 80/153 68/152 72/156 81/157 +f 81/157 72/156 71/155 82/154 +s 1 +f 9/9 30/158 3/3 +f 30/158 27/159 3/3 +f 25/160 1/1 3/3 +f 27/159 21/161 3/3 +f 19/162 25/160 3/3 +f 21/161 13/163 3/3 +f 11/164 19/162 3/3 +f 13/163 5/165 3/3 +f 4/166 11/164 3/3 +f 5/165 4/166 3/3 diff --git a/mod/data/mac-fallback-assets/silh_shaped_snail_1.obj b/mod/data/mac-fallback-assets/silh_shaped_snail_1.obj new file mode 100644 index 000000000..5c6086c11 --- /dev/null +++ b/mod/data/mac-fallback-assets/silh_shaped_snail_1.obj @@ -0,0 +1,374 @@ +# This file uses centimeters as units for non-parametric coordinates. + +mtllib silhouette_shorter.mtl +v 1.175695 -0.000000 -3.587517 +v 1.618197 -0.000000 -3.243152 +v -0.000000 -0.000000 0.770270 +v -1.175695 -0.000000 -3.587517 +v -1.618197 -0.000000 -3.243152 +v -1.618197 1.000230 -3.243152 +v -1.175695 1.000230 -3.587517 +v -0.618092 -0.000000 3.808617 +v -1.175695 -0.000000 3.587517 +v 1.902307 -0.000000 -2.809213 +v -0.618092 -0.000000 -3.808617 +v -0.618092 1.000230 -3.808617 +v -1.902307 -0.000000 -2.809213 +v -1.902307 1.000230 -2.809213 +v -0.000000 -0.000000 3.884800 +v 2.000200 -0.000000 0.770270 +v 1.902307 -0.000000 2.809213 +v 0.618092 -0.000000 3.808617 +v -0.000000 -0.000000 -3.884800 +v -0.000000 1.000230 -3.884800 +v -2.000200 -0.000000 0.770270 +v -2.000200 1.000230 0.770270 +v 1.618197 -0.000000 3.243144 +v 1.175684 -0.000000 3.587517 +v 0.618092 -0.000000 -3.808617 +v 0.618092 1.000230 -3.808617 +v -1.902307 -0.000000 2.809213 +v -1.902307 1.000230 2.809213 +v 1.175695 1.000230 -3.587517 +v -1.618197 -0.000000 3.243144 +v -1.618197 1.000230 3.243144 +v -1.175695 1.000230 3.587517 +v 1.618197 1.000230 -3.243152 +v -0.119870 0.920840 -2.395978 +v -0.000000 0.920840 0.770270 +v -0.087093 0.920840 -2.421485 +v -0.045784 0.920840 -2.437860 +v -0.140911 0.920840 -2.363830 +v -0.000000 0.920840 -2.443503 +v -0.148162 0.920840 0.770270 +v 0.045784 0.920840 -2.437860 +v -0.140911 0.920840 2.363830 +v 0.087093 0.920840 -2.421485 +v -0.119870 0.920840 2.395978 +v -0.087093 0.920840 2.421485 +v 0.119870 0.920840 -2.395978 +v -0.045784 0.920840 2.437860 +v 0.140911 0.920840 -2.363830 +v -0.000000 0.920840 2.443503 +v 0.148162 0.920840 0.770270 +v 0.140911 0.920840 2.363830 +v 0.045784 0.920840 2.437860 +v 0.087093 0.920840 2.421485 +v 0.119870 0.920840 2.395978 +v -0.618092 1.000230 3.808617 +v 1.902307 1.000230 -2.809213 +v -0.087093 1.000230 -2.421485 +v -0.119870 1.000230 -2.395978 +v -0.000000 1.000230 3.884800 +v 2.000200 1.000230 0.770270 +v -0.045784 1.000230 -2.437860 +v -0.140911 1.000230 -2.363830 +v -0.000000 1.000230 -2.443503 +v -0.148162 1.000230 0.770270 +v 0.045784 1.000230 -2.437860 +v -0.140911 1.000230 2.363830 +v 1.902307 1.000230 2.809213 +v 0.618092 1.000230 3.808617 +v 0.087093 1.000230 -2.421485 +v -0.119870 1.000230 2.395978 +v 1.618197 1.000230 3.243144 +v 1.175684 1.000230 3.587517 +v -0.087093 1.000230 2.421485 +v 0.119870 1.000230 -2.395978 +v -0.045784 1.000230 2.437860 +v 0.140911 1.000230 -2.363830 +v -0.000000 1.000230 2.443503 +v 0.148162 1.000230 0.770270 +v 0.140911 1.000230 2.363830 +v 0.045784 1.000230 2.437860 +v 0.087093 1.000230 2.421485 +v 0.119870 1.000230 2.395978 +vt 0.266842 0.029841 +vt 0.301409 0.064408 +vt 0.175000 0.150000 +vt 0.125000 0.312500 +vt 0.137500 0.312500 +vt 0.137500 0.688440 +vt 0.125000 0.688440 +vt 0.126716 0.304853 +vt 0.083159 0.282659 +vt 0.323603 0.107966 +vt 0.112500 0.312500 +vt 0.112500 0.688440 +vt 0.150000 0.312500 +vt 0.150000 0.688440 +vt 0.175000 0.312500 +vt 0.331250 0.156250 +vt 0.323603 0.204534 +vt 0.223284 0.304853 +vt 0.100000 0.312500 +vt 0.100000 0.688440 +vt 0.162500 0.312500 +vt 0.162500 0.688440 +vt 0.301409 0.248091 +vt 0.266841 0.282659 +vt 0.087500 0.312500 +vt 0.087500 0.688440 +vt 0.175000 0.312500 +vt 0.175000 0.688440 +vt 0.075000 0.312500 +vt 0.075000 0.688440 +vt 0.187500 0.312500 +vt 0.187500 0.688440 +vt 0.200000 0.312500 +vt 0.200000 0.688440 +vt 0.062500 0.312500 +vt 0.062500 0.688440 +vt 0.048591 0.064409 +vt 0.175000 0.150000 +vt 0.083159 0.029841 +vt 0.126716 0.007647 +vt 0.026397 0.107966 +vt 0.175000 -0.000000 +vt 0.018750 0.156250 +vt 0.223284 0.007647 +vt 0.026397 0.204534 +vt 0.266842 0.029841 +vt 0.048591 0.248091 +vt 0.083159 0.282659 +vt 0.301409 0.064408 +vt 0.126716 0.304853 +vt 0.323603 0.107966 +vt 0.175000 0.312500 +vt 0.331250 0.156250 +vt 0.323603 0.204534 +vt 0.223284 0.304853 +vt 0.266841 0.282659 +vt 0.301409 0.248091 +vt 0.212500 0.312500 +vt 0.212500 0.688440 +vt 0.050000 0.312500 +vt 0.050000 0.688440 +vt 0.168197 0.847327 +vt 0.083159 0.970159 +vt 0.048591 0.935591 +vt 0.165636 0.844766 +vt 0.225000 0.312500 +vt 0.225000 0.688440 +vt 0.287500 0.312500 +vt 0.300000 0.312500 +vt 0.300000 0.688440 +vt 0.287500 0.688440 +vt 0.171423 0.848971 +vt 0.126716 0.992353 +vt 0.026397 0.892034 +vt 0.163992 0.841540 +vt 0.175000 0.849537 +vt 0.175000 1.000000 +vt 0.018750 0.843750 +vt 0.163426 0.837963 +vt 0.178577 0.848971 +vt 0.223284 0.992353 +vt 0.026397 0.795466 +vt 0.163992 0.834386 +vt 0.275000 0.312500 +vt 0.275000 0.688440 +vt 0.237500 0.312500 +vt 0.237500 0.688440 +vt 0.181803 0.847327 +vt 0.266841 0.970159 +vt 0.048591 0.751909 +vt 0.165636 0.831160 +vt 0.262500 0.312500 +vt 0.262500 0.688440 +vt 0.250000 0.312500 +vt 0.250000 0.688440 +vt 0.125000 0.312500 +vt 0.125000 0.688440 +vt 0.137500 0.688440 +vt 0.137500 0.312500 +vt 0.112500 0.312500 +vt 0.112500 0.688440 +vt 0.150000 0.688440 +vt 0.150000 0.312500 +vt 0.100000 0.312500 +vt 0.100000 0.688440 +vt 0.162500 0.688440 +vt 0.162500 0.312500 +vt 0.087500 0.312500 +vt 0.087500 0.688440 +vt 0.175000 0.688440 +vt 0.175000 0.312500 +vt 0.075000 0.312500 +vt 0.075000 0.688440 +vt 0.187500 0.688440 +vt 0.187500 0.312500 +vt 0.200000 0.688440 +vt 0.200000 0.312500 +vt 0.062500 0.312500 +vt 0.062500 0.688440 +vt 0.212500 0.688440 +vt 0.212500 0.312500 +vt 0.050000 0.312500 +vt 0.050000 0.688440 +vt 0.225000 0.688440 +vt 0.225000 0.312500 +vt 0.287500 0.312500 +vt 0.287500 0.688440 +vt 0.300000 0.688440 +vt 0.300000 0.312500 +vt 0.275000 0.312500 +vt 0.275000 0.688440 +vt 0.237500 0.688440 +vt 0.237500 0.312500 +vt 0.250000 0.688440 +vt 0.250000 0.312500 +vt 0.262500 0.312500 +vt 0.262500 0.688440 +vt 0.083159 0.717341 +vt 0.168197 0.828599 +vt 0.184364 0.844766 +vt 0.301409 0.935591 +vt 0.126716 0.695147 +vt 0.171423 0.826955 +vt 0.186008 0.841540 +vt 0.323603 0.892034 +vt 0.175000 0.687500 +vt 0.175000 0.826389 +vt 0.186574 0.837963 +vt 0.331250 0.843750 +vt 0.186008 0.834386 +vt 0.323603 0.795466 +vt 0.223284 0.695147 +vt 0.178577 0.826955 +vt 0.184364 0.831160 +vt 0.301409 0.751908 +vt 0.266842 0.717341 +vt 0.181803 0.828599 +vt 0.048591 0.248091 +vt 0.026397 0.204534 +vt 0.223284 0.007647 +vt 0.018750 0.156250 +vt 0.175000 -0.000000 +vt 0.026397 0.107966 +vt 0.126716 0.007647 +vt 0.048591 0.064409 +vt 0.083159 0.029841 +s 1 +g silhouette_shorter +usemtl lambert2SG +f 1/1 2/2 3/3 +s 2 +f 4/4 5/5 6/6 7/7 +s 1 +f 8/8 9/9 3/3 +f 2/2 10/10 3/3 +s 2 +f 11/11 4/4 7/7 12/12 +f 5/5 13/13 14/14 6/6 +s 1 +f 15/15 8/8 3/3 +f 10/10 16/16 3/3 +f 16/16 17/17 3/3 +f 18/18 15/15 3/3 +s 2 +f 19/19 11/11 12/12 20/20 +f 13/13 21/21 22/22 14/14 +s 1 +f 17/17 23/23 3/3 +f 24/24 18/18 3/3 +f 23/23 24/24 3/3 +s 2 +f 25/25 19/19 20/20 26/26 +f 21/21 27/27 28/28 22/22 +f 1/29 25/25 26/26 29/30 +f 27/27 30/31 31/32 28/28 +f 30/31 9/33 32/34 31/32 +f 2/35 1/29 29/30 33/36 +s 4 +f 34/37 35/38 36/39 +f 36/39 35/38 37/40 +f 38/41 35/38 34/37 +f 37/40 35/38 39/42 +f 40/43 35/38 38/41 +f 39/42 35/38 41/44 +f 42/45 35/38 40/43 +f 41/44 35/38 43/46 +f 44/47 35/38 42/45 +f 45/48 35/38 44/47 +f 43/46 35/38 46/49 +f 47/50 35/38 45/48 +f 46/49 35/38 48/51 +f 49/52 35/38 47/50 +f 48/51 35/38 50/53 +f 50/53 35/38 51/54 +f 52/55 35/38 49/52 +f 53/56 35/38 52/55 +f 51/54 35/38 54/57 +f 54/57 35/38 53/56 +s 2 +f 9/33 8/58 55/59 32/34 +f 10/60 2/35 33/36 56/61 +s 5 +f 57/62 7/63 6/64 58/65 +s 2 +f 8/58 15/66 59/67 55/59 +f 16/68 10/69 56/70 60/71 +s 5 +f 61/72 12/73 7/63 57/62 +f 58/65 6/64 14/74 62/75 +f 63/76 20/77 12/73 61/72 +f 62/75 14/74 22/78 64/79 +f 65/80 26/81 20/77 63/76 +f 64/79 22/78 28/82 66/83 +s 2 +f 17/84 16/68 60/71 67/85 +f 15/66 18/86 68/87 59/67 +s 5 +f 69/88 29/89 26/81 65/80 +f 66/83 28/82 31/90 70/91 +s 2 +f 23/92 17/84 67/85 71/93 +f 18/86 24/94 72/95 68/87 +s 6 +f 36/96 57/97 58/98 34/99 +f 37/100 61/101 57/97 36/96 +f 34/99 58/98 62/102 38/103 +f 39/104 63/105 61/101 37/100 +f 38/103 62/102 64/106 40/107 +f 41/108 65/109 63/105 39/104 +f 40/107 64/106 66/110 42/111 +s 2 +f 24/94 23/92 71/93 72/95 +s 6 +f 43/112 69/113 65/109 41/108 +f 42/111 66/110 70/114 44/115 +f 44/115 70/114 73/116 45/117 +f 46/118 74/119 69/113 43/112 +f 45/117 73/116 75/120 47/121 +f 48/122 76/123 74/119 46/118 +f 47/121 75/120 77/124 49/125 +f 50/126 78/127 76/128 48/129 +f 51/130 79/131 78/127 50/126 +f 49/125 77/124 80/132 52/133 +f 52/133 80/132 81/134 53/135 +f 54/136 82/137 79/131 51/130 +f 53/135 81/134 82/137 54/136 +s 5 +f 70/91 31/90 32/138 73/139 +f 74/140 33/141 29/89 69/88 +f 73/139 32/138 55/142 75/143 +f 76/144 56/145 33/141 74/140 +f 75/143 55/142 59/146 77/147 +f 78/148 60/149 56/145 76/144 +f 79/150 67/151 60/149 78/148 +f 77/147 59/146 68/152 80/153 +f 82/154 71/155 67/151 79/150 +f 80/153 68/152 72/156 81/157 +f 81/157 72/156 71/155 82/154 +s 1 +f 9/9 30/158 3/3 +f 30/158 27/159 3/3 +f 25/160 1/1 3/3 +f 27/159 21/161 3/3 +f 19/162 25/160 3/3 +f 21/161 13/163 3/3 +f 11/164 19/162 3/3 +f 13/163 5/165 3/3 +f 4/166 11/164 3/3 +f 5/165 4/166 3/3 From 48931c32de54ce5da3363e70b45fc4dee1f7d258 Mon Sep 17 00:00:00 2001 From: Martin Pourrat Date: Tue, 11 Aug 2026 14:51:27 +0200 Subject: [PATCH 13/42] Silhouette meshes: vanilla geometry with smoothing-angle normals Keeps the bundle geometry vertex for vertex and only rebuilds the normals. The bundles' baked normals render the curved flanks faceted; shipping none at all makes TTS average across the rim where the fan caps share the flank vertices, so the sides light up like the top. Cluster each vertex's faces by a 45-degree threshold instead: the flanks smooth along the arc, the rim stays a hard edge. 48 vertices become 92, geometry unchanged. Co-Authored-By: Claude Fable 5 --- .../mac-fallback-assets/silh_exact_long_1.obj | 369 ++++++++++++++++++ .../silh_exact_snail_1.obj | 369 ++++++++++++++++++ 2 files changed, 738 insertions(+) create mode 100644 mod/data/mac-fallback-assets/silh_exact_long_1.obj create mode 100644 mod/data/mac-fallback-assets/silh_exact_snail_1.obj diff --git a/mod/data/mac-fallback-assets/silh_exact_long_1.obj b/mod/data/mac-fallback-assets/silh_exact_long_1.obj new file mode 100644 index 000000000..964564c5c --- /dev/null +++ b/mod/data/mac-fallback-assets/silh_exact_long_1.obj @@ -0,0 +1,369 @@ +# rebuilt from silh_vanilla_long_2.obj with a 45deg smoothing angle +v 1.470364 -0.000000 -2.849121 +v 1.470364 -0.000000 -2.849121 +v 1.795074 -0.000000 -2.401143 +v 1.795074 -0.000000 -2.401143 +v -0.000000 0.000321 -1.903831 +v 2.000166 0.000321 -1.903831 +v 2.000166 0.000321 -1.903831 +v 1.042536 -0.000000 -3.163317 +v 1.042536 -0.000000 -3.163317 +v 2.000166 0.000322 1.915038 +v 2.000166 0.000322 1.915038 +v 0.614881 -0.000000 -3.363181 +v 0.614881 -0.000000 -3.363181 +v -0.000000 0.000322 1.915038 +v 1.470364 1.000000 -2.849121 +v 1.470364 1.000000 -2.849121 +v 1.042536 1.000000 -3.163317 +v 1.042536 1.000000 -3.163317 +v 1.795074 1.000000 -2.401144 +v 1.795074 1.000000 -2.401144 +v 0.614881 1.000000 -3.363182 +v 0.614881 1.000000 -3.363182 +v -0.000000 0.999678 -1.903831 +v 2.000166 0.999678 -1.903831 +v 2.000166 0.999678 -1.903831 +v -0.000000 1.000000 -3.460686 +v -0.000000 1.000000 -3.460686 +v -0.000000 0.999679 1.915038 +v 2.000166 0.999679 1.915038 +v 2.000166 0.999679 1.915038 +v -0.000000 -0.000000 -3.460686 +v -0.000000 -0.000000 -3.460686 +v 1.821423 0.000000 2.387772 +v 1.821423 0.000000 2.387772 +v 1.821423 1.000000 2.387771 +v 1.821423 1.000000 2.387771 +v -0.614881 1.000000 -3.363182 +v -0.614881 1.000000 -3.363182 +v 1.529514 0.000000 2.783466 +v 1.529514 0.000000 2.783466 +v 1.529514 1.000000 2.783466 +v 1.529514 1.000000 2.783466 +v 1.071173 1.000000 3.162351 +v 1.071173 1.000000 3.162351 +v -2.000043 0.999679 1.915038 +v -2.000043 0.999679 1.915038 +v 1.071173 0.000000 3.162352 +v 1.071173 0.000000 3.162352 +v 0.614881 0.000000 3.370249 +v 0.614881 0.000000 3.370249 +v -0.000000 0.000000 3.467756 +v -0.000000 0.000000 3.467756 +v 0.614881 1.000000 3.370249 +v 0.614881 1.000000 3.370249 +v -0.614881 -0.000000 -3.363181 +v -0.614881 -0.000000 -3.363181 +v -0.000000 1.000000 3.467755 +v -0.000000 1.000000 3.467755 +v -1.042536 1.000000 -3.163317 +v -1.042536 1.000000 -3.163317 +v -0.614881 0.000000 3.370249 +v -0.614881 0.000000 3.370249 +v -1.042536 -0.000000 -3.163317 +v -1.042536 -0.000000 -3.163317 +v -0.614881 1.000000 3.370249 +v -0.614881 1.000000 3.370249 +v -1.470364 1.000000 -2.849121 +v -1.470364 1.000000 -2.849121 +v -1.071173 0.000000 3.162352 +v -1.071173 0.000000 3.162352 +v -1.470364 -0.000000 -2.849121 +v -1.470364 -0.000000 -2.849121 +v -1.795074 1.000000 -2.401144 +v -1.795074 1.000000 -2.401144 +v -1.071173 1.000000 3.162351 +v -1.071173 1.000000 3.162351 +v -1.795074 -0.000000 -2.401143 +v -1.795074 -0.000000 -2.401143 +v -2.000043 0.999678 -1.903831 +v -2.000043 0.999678 -1.903831 +v -2.000043 0.000321 -1.903831 +v -2.000043 0.000321 -1.903831 +v -2.000043 0.000322 1.915038 +v -2.000043 0.000322 1.915038 +v -1.529514 0.000000 2.783466 +v -1.529514 0.000000 2.783466 +v -1.529514 1.000000 2.783466 +v -1.529514 1.000000 2.783466 +v -1.821423 1.000000 2.387771 +v -1.821423 1.000000 2.387771 +v -1.821423 0.000000 2.387772 +v -1.821423 0.000000 2.387772 +vt 0.325826 0.000000 +vt 0.325826 0.000000 +vt 0.352171 0.000000 +vt 0.352171 0.000000 +vt 0.250000 0.000322 +vt 0.378927 0.000322 +vt 0.378927 0.000322 +vt 0.300669 0.000000 +vt 0.300669 0.000000 +vt 0.621540 0.000322 +vt 0.621540 0.000322 +vt 0.278780 0.000000 +vt 0.278780 0.000000 +vt 0.750000 0.000322 +vt 0.325826 0.999999 +vt 0.325826 0.999999 +vt 0.300669 0.999999 +vt 0.300669 0.999999 +vt 0.352171 0.999999 +vt 0.352171 0.999999 +vt 0.278780 0.999999 +vt 0.278780 0.999999 +vt 0.250000 0.999678 +vt 0.378927 0.999678 +vt 0.378927 0.999678 +vt 0.250000 0.999999 +vt 0.250000 0.999999 +vt 0.750000 0.999678 +vt 0.621540 0.999678 +vt 0.621540 0.999678 +vt 0.250000 0.000000 +vt 0.250000 0.000000 +vt 0.646286 0.000001 +vt 0.646286 0.000001 +vt 0.646286 1.000000 +vt 0.646286 1.000000 +vt 0.221220 0.999999 +vt 0.221220 0.999999 +vt 0.670031 0.000001 +vt 0.670031 0.000001 +vt 0.670031 1.000000 +vt 0.670031 1.000000 +vt 0.698021 1.000000 +vt 0.698021 1.000000 +vt 0.878455 0.999678 +vt 0.878455 0.999678 +vt 0.698021 0.000001 +vt 0.698021 0.000001 +vt 0.721279 0.000001 +vt 0.721279 0.000001 +vt 0.750000 0.000001 +vt 0.750000 0.000001 +vt 0.721279 1.000000 +vt 0.721279 1.000000 +vt 0.221220 0.000000 +vt 0.221220 0.000000 +vt 0.750000 1.000000 +vt 0.750000 1.000000 +vt 0.199331 0.999999 +vt 0.199331 0.999999 +vt 0.778721 0.000001 +vt 0.778721 0.000001 +vt 0.199331 0.000000 +vt 0.199331 0.000000 +vt 0.778721 1.000000 +vt 0.778721 1.000000 +vt 0.174174 0.999999 +vt 0.174174 0.999999 +vt 0.801979 0.000001 +vt 0.801979 0.000001 +vt 0.174174 0.000000 +vt 0.174174 0.000000 +vt 0.147829 0.999999 +vt 0.147829 0.999999 +vt 0.801979 1.000000 +vt 0.801979 1.000000 +vt 0.147829 0.000000 +vt 0.147829 0.000000 +vt 0.121078 0.999678 +vt 0.121078 0.999678 +vt 0.121078 0.000322 +vt 0.121078 0.000322 +vt 0.878455 0.000322 +vt 0.878455 0.000322 +vt 0.829969 0.000001 +vt 0.829969 0.000001 +vt 0.829969 1.000000 +vt 0.829969 1.000000 +vt 0.853714 1.000000 +vt 0.853714 1.000000 +vt 0.853714 0.000001 +vt 0.853714 0.000001 +vn -0.000133 -1.000000 0.000134 +vn 0.671666 -0.000000 -0.740855 +vn -0.000075 -1.000000 0.000377 +vn 0.853214 -0.000000 -0.521562 +vn -0.000000 -1.000000 0.000201 +vn 0.000000 -1.000000 0.000323 +vn 0.980936 -0.000000 -0.194331 +vn -0.000101 -1.000000 0.000172 +vn 0.481628 -0.000000 -0.876376 +vn 0.000000 -1.000000 -0.000227 +vn 0.983710 0.000000 0.179763 +vn -0.000059 -1.000000 0.000195 +vn 0.247695 -0.000000 -0.968838 +vn -0.000000 -1.000000 -0.000205 +vn 0.745032 -0.000000 -0.667029 +vn -0.000133 1.000000 0.000133 +vn 0.538045 -0.000000 -0.842916 +vn -0.000101 1.000000 0.000171 +vn 0.891717 -0.000000 -0.452593 +vn -0.000075 1.000000 0.000377 +vn 0.337399 -0.000000 -0.941362 +vn -0.000059 1.000000 0.000195 +vn -0.000000 1.000000 0.000200 +vn 0.000000 1.000000 0.000215 +vn 0.980936 -0.000000 -0.194331 +vn 0.000000 1.000000 0.000206 +vn 0.052785 -0.000000 -0.998606 +vn -0.000000 1.000000 -0.000205 +vn 0.983710 0.000000 0.179763 +vn 0.000000 1.000000 -0.000340 +vn -0.052785 -0.000000 -0.998606 +vn -0.000000 -1.000000 0.000207 +vn 0.899312 0.000000 0.437307 +vn -0.000074 -1.000000 -0.000394 +vn -0.000074 1.000000 -0.000395 +vn 0.855397 0.000000 0.517973 +vn -0.247695 -0.000000 -0.968838 +vn 0.000059 1.000000 0.000195 +vn -0.000136 -1.000000 -0.000130 +vn 0.753856 0.000000 0.657040 +vn -0.000136 1.000000 -0.000130 +vn 0.697622 0.000000 0.716466 +vn -0.000104 1.000000 -0.000168 +vn 0.492575 0.000000 0.870270 +vn -0.000000 1.000000 -0.000227 +vn -0.983731 0.000000 0.179650 +vn -0.000104 -1.000000 -0.000168 +vn 0.567323 0.000000 0.823495 +vn -0.000059 -1.000000 -0.000196 +vn 0.331301 0.000000 0.943525 +vn 0.000000 -1.000000 -0.000207 +vn 0.052786 0.000000 0.998606 +vn 0.244600 0.000000 0.969624 +vn -0.000059 1.000000 -0.000196 +vn -0.337399 -0.000000 -0.941362 +vn 0.000059 -1.000000 0.000195 +vn -0.052786 0.000000 0.998606 +vn 0.000000 1.000000 -0.000207 +vn -0.481628 -0.000000 -0.876376 +vn 0.000101 1.000000 0.000171 +vn -0.244600 0.000000 0.969624 +vn 0.000059 -1.000000 -0.000196 +vn -0.538045 -0.000000 -0.842916 +vn 0.000101 -1.000000 0.000172 +vn -0.331301 0.000000 0.943525 +vn 0.000059 1.000000 -0.000196 +vn -0.671666 -0.000000 -0.740855 +vn 0.000133 1.000000 0.000133 +vn -0.492575 0.000000 0.870270 +vn 0.000104 -1.000000 -0.000168 +vn -0.745032 -0.000000 -0.667029 +vn 0.000133 -1.000000 0.000134 +vn 0.000075 1.000000 0.000377 +vn -0.853250 -0.000000 -0.521502 +vn -0.567323 0.000000 0.823495 +vn 0.000104 1.000000 -0.000168 +vn 0.000075 -1.000000 0.000377 +vn -0.891781 -0.000000 -0.452466 +vn 0.000000 1.000000 0.000323 +vn -0.980957 -0.000000 -0.194227 +vn 0.000000 -1.000000 0.000216 +vn -0.980957 -0.000000 -0.194227 +vn -0.983731 0.000000 0.179650 +vn -0.000000 -1.000000 -0.000340 +vn 0.000136 -1.000000 -0.000130 +vn -0.697622 0.000000 0.716466 +vn 0.000136 1.000000 -0.000130 +vn -0.753856 0.000000 0.657040 +vn 0.000074 1.000000 -0.000395 +vn -0.899379 0.000000 0.437169 +vn 0.000074 -1.000000 -0.000394 +vn -0.855436 0.000000 0.517909 +f 1/1/1 3/3/3 5/5/5 +f 3/3/3 6/6/6 5/5/5 +f 8/8/8 1/1/1 5/5/5 +f 5/5/5 6/6/6 10/10/10 +f 12/12/12 8/8/8 5/5/5 +f 14/14/14 5/5/5 10/10/10 +f 2/2/2 15/15/15 4/4/4 +f 9/9/9 17/17/17 2/2/2 +f 17/17/17 15/15/15 2/2/2 +f 15/15/15 19/19/19 4/4/4 +f 4/4/4 19/19/19 7/7/7 +f 21/21/21 17/17/17 9/9/9 +f 13/13/13 21/21/21 9/9/9 +f 16/16/16 18/18/18 23/23/23 +f 20/20/20 16/16/16 23/23/23 +f 18/18/18 22/22/22 23/23/23 +f 24/24/24 20/20/20 23/23/23 +f 19/19/19 25/25/25 7/7/7 +f 22/22/22 26/26/26 23/23/23 +f 27/27/27 21/21/21 13/13/13 +f 24/24/24 23/23/23 28/28/28 +f 7/7/7 25/25/25 29/29/29 +f 30/30/30 24/24/24 28/28/28 +f 11/11/11 7/7/7 29/29/29 +f 31/31/31 27/27/27 13/13/13 +f 32/32/32 12/12/12 5/5/5 +f 11/11/11 29/29/29 33/33/33 +f 10/10/10 34/34/34 14/14/14 +f 35/35/35 30/30/30 28/28/28 +f 29/29/29 36/36/36 33/33/33 +f 37/37/37 27/27/27 31/31/31 +f 26/26/26 38/38/38 23/23/23 +f 34/34/34 39/39/39 14/14/14 +f 33/33/33 36/36/36 40/40/40 +f 41/41/41 35/35/35 28/28/28 +f 36/36/36 42/42/42 40/40/40 +f 43/43/43 41/41/41 28/28/28 +f 28/28/28 23/23/23 45/45/45 +f 39/39/39 47/47/47 14/14/14 +f 40/40/40 42/42/42 48/48/48 +f 42/42/42 44/44/44 48/48/48 +f 47/47/47 49/49/49 14/14/14 +f 48/48/48 44/44/44 50/50/50 +f 49/49/49 51/51/51 14/14/14 +f 44/44/44 53/53/53 50/50/50 +f 54/54/54 43/43/43 28/28/28 +f 50/50/50 53/53/53 52/52/52 +f 55/55/55 37/37/37 31/31/31 +f 56/56/56 32/32/32 5/5/5 +f 53/53/53 57/57/57 52/52/52 +f 58/58/58 54/54/54 28/28/28 +f 59/59/59 37/37/37 55/55/55 +f 38/38/38 60/60/60 23/23/23 +f 52/52/52 57/57/57 61/61/61 +f 51/51/51 62/62/62 14/14/14 +f 63/63/63 59/59/59 55/55/55 +f 64/64/64 56/56/56 5/5/5 +f 57/57/57 65/65/65 61/61/61 +f 66/66/66 58/58/58 28/28/28 +f 67/67/67 59/59/59 63/63/63 +f 60/60/60 68/68/68 23/23/23 +f 61/61/61 65/65/65 69/69/69 +f 62/62/62 70/70/70 14/14/14 +f 71/71/71 67/67/67 63/63/63 +f 72/72/72 64/64/64 5/5/5 +f 68/68/68 73/73/73 23/23/23 +f 74/74/74 67/67/67 71/71/71 +f 65/65/65 75/75/75 69/69/69 +f 76/76/76 66/66/66 28/28/28 +f 77/77/77 72/72/72 5/5/5 +f 78/78/78 74/74/74 71/71/71 +f 73/73/73 79/79/79 23/23/23 +f 80/80/80 74/74/74 78/78/78 +f 23/23/23 79/79/79 45/45/45 +f 81/81/81 77/77/77 5/5/5 +f 82/82/82 80/80/80 78/78/78 +f 81/81/81 5/5/5 14/14/14 +f 80/80/80 82/82/82 83/83/83 +f 46/46/46 80/80/80 83/83/83 +f 84/84/84 81/81/81 14/14/14 +f 70/70/70 85/85/85 14/14/14 +f 69/69/69 75/75/75 86/86/86 +f 87/87/87 76/76/76 28/28/28 +f 75/75/75 88/88/88 86/86/86 +f 89/89/89 28/28/28 45/45/45 +f 90/90/90 46/46/46 83/83/83 +f 89/89/89 87/87/87 28/28/28 +f 91/91/91 84/84/84 14/14/14 +f 85/85/85 91/91/91 14/14/14 +f 86/86/86 88/88/88 92/92/92 +f 92/92/92 90/90/90 83/83/83 +f 88/88/88 90/90/90 92/92/92 diff --git a/mod/data/mac-fallback-assets/silh_exact_snail_1.obj b/mod/data/mac-fallback-assets/silh_exact_snail_1.obj new file mode 100644 index 000000000..33f916f49 --- /dev/null +++ b/mod/data/mac-fallback-assets/silh_exact_snail_1.obj @@ -0,0 +1,369 @@ +# rebuilt from silh_vanilla_snail_2.obj with a 45deg smoothing angle +v 1.470364 -0.000000 -3.273221 +v 1.470364 -0.000000 -3.273221 +v 1.795074 -0.000000 -2.825244 +v 1.795074 -0.000000 -2.825244 +v -0.000000 0.000321 -2.327931 +v 2.000166 0.000321 -2.327931 +v 2.000166 0.000321 -2.327931 +v 1.042536 -0.000000 -3.587417 +v 1.042536 -0.000000 -3.587417 +v 2.000166 0.000322 2.328190 +v 2.000166 0.000322 2.328190 +v 0.614881 -0.000001 -3.787282 +v 0.614881 -0.000001 -3.787282 +v -0.000000 0.000322 2.328190 +v 1.470364 1.000000 -3.273222 +v 1.470364 1.000000 -3.273222 +v 1.042536 1.000000 -3.587418 +v 1.042536 1.000000 -3.587418 +v 1.795074 1.000000 -2.825244 +v 1.795074 1.000000 -2.825244 +v 0.614881 1.000000 -3.787282 +v 0.614881 1.000000 -3.787282 +v -0.000000 0.999678 -2.327931 +v 2.000166 0.999678 -2.327931 +v 2.000166 0.999678 -2.327931 +v -0.000000 0.999999 -3.884787 +v -0.000000 0.999999 -3.884787 +v -0.000000 0.999679 2.328190 +v 2.000166 0.999679 2.328190 +v 2.000166 0.999679 2.328190 +v -0.000000 -0.000001 -3.884786 +v -0.000000 -0.000001 -3.884786 +v 1.821423 0.000000 2.800923 +v 1.821423 0.000000 2.800923 +v 1.821423 1.000000 2.800923 +v 1.821423 1.000000 2.800923 +v -0.614881 1.000000 -3.787282 +v -0.614881 1.000000 -3.787282 +v 1.529514 0.000000 3.196618 +v 1.529514 0.000000 3.196618 +v 1.529514 1.000000 3.196618 +v 1.529514 1.000000 3.196618 +v 1.071173 1.000000 3.575503 +v 1.071173 1.000000 3.575503 +v -2.000043 0.999679 2.328190 +v -2.000043 0.999679 2.328190 +v 1.071173 0.000000 3.575503 +v 1.071173 0.000000 3.575503 +v 0.614881 0.000001 3.783401 +v 0.614881 0.000001 3.783401 +v -0.000000 0.000001 3.880907 +v -0.000000 0.000001 3.880907 +v 0.614881 1.000000 3.783401 +v 0.614881 1.000000 3.783401 +v -0.614881 -0.000001 -3.787282 +v -0.614881 -0.000001 -3.787282 +v -0.000000 1.000000 3.880907 +v -0.000000 1.000000 3.880907 +v -1.042536 1.000000 -3.587418 +v -1.042536 1.000000 -3.587418 +v -0.614881 0.000001 3.783401 +v -0.614881 0.000001 3.783401 +v -1.042536 -0.000000 -3.587417 +v -1.042536 -0.000000 -3.587417 +v -0.614881 1.000000 3.783401 +v -0.614881 1.000000 3.783401 +v -1.470364 1.000000 -3.273222 +v -1.470364 1.000000 -3.273222 +v -1.071173 0.000000 3.575503 +v -1.071173 0.000000 3.575503 +v -1.470364 -0.000000 -3.273221 +v -1.470364 -0.000000 -3.273221 +v -1.795074 1.000000 -2.825244 +v -1.795074 1.000000 -2.825244 +v -1.071173 1.000000 3.575503 +v -1.071173 1.000000 3.575503 +v -1.795074 -0.000000 -2.825244 +v -1.795074 -0.000000 -2.825244 +v -2.000043 0.999678 -2.327931 +v -2.000043 0.999678 -2.327931 +v -2.000043 0.000321 -2.327931 +v -2.000043 0.000321 -2.327931 +v -2.000043 0.000322 2.328190 +v -2.000043 0.000322 2.328190 +v -1.529514 0.000000 3.196618 +v -1.529514 0.000000 3.196618 +v -1.529514 1.000000 3.196618 +v -1.529514 1.000000 3.196618 +v -1.821423 1.000000 2.800923 +v -1.821423 1.000000 2.800923 +v -1.821423 0.000000 2.800923 +v -1.821423 0.000000 2.800923 +vt 0.317195 0.000000 +vt 0.317195 0.000000 +vt 0.340085 0.000000 +vt 0.340085 0.000000 +vt 0.250000 0.000322 +vt 0.362970 0.000322 +vt 0.362970 0.000322 +vt 0.295012 0.000000 +vt 0.295012 0.000000 +vt 0.637039 0.000322 +vt 0.637039 0.000322 +vt 0.275616 0.000000 +vt 0.275616 0.000000 +vt 0.750000 0.000322 +vt 0.317195 0.999999 +vt 0.317195 0.999999 +vt 0.295012 0.999999 +vt 0.295012 0.999999 +vt 0.340085 0.999999 +vt 0.340085 0.999999 +vt 0.275616 0.999999 +vt 0.275616 0.999999 +vt 0.250000 0.999678 +vt 0.362970 0.999678 +vt 0.362970 0.999678 +vt 0.250000 0.999999 +vt 0.250000 0.999999 +vt 0.750000 0.999678 +vt 0.637039 0.999678 +vt 0.637039 0.999678 +vt 0.250000 0.000000 +vt 0.250000 0.000000 +vt 0.658234 0.000001 +vt 0.658234 0.000001 +vt 0.658234 1.000000 +vt 0.658234 1.000000 +vt 0.224384 0.999999 +vt 0.224384 0.999999 +vt 0.678972 0.000001 +vt 0.678972 0.000001 +vt 0.678972 1.000000 +vt 0.678972 1.000000 +vt 0.703674 1.000000 +vt 0.703674 1.000000 +vt 0.862957 0.999678 +vt 0.862957 0.999678 +vt 0.703674 0.000001 +vt 0.703674 0.000001 +vt 0.724358 0.000001 +vt 0.724358 0.000001 +vt 0.750000 0.000001 +vt 0.750000 0.000001 +vt 0.724358 1.000000 +vt 0.724358 1.000000 +vt 0.224384 0.000000 +vt 0.224384 0.000000 +vt 0.750000 1.000000 +vt 0.750000 1.000000 +vt 0.204988 0.999999 +vt 0.204988 0.999999 +vt 0.775642 0.000001 +vt 0.775642 0.000001 +vt 0.204988 0.000000 +vt 0.204988 0.000000 +vt 0.775642 1.000000 +vt 0.775642 1.000000 +vt 0.182805 0.999999 +vt 0.182805 0.999999 +vt 0.796326 0.000001 +vt 0.796326 0.000001 +vt 0.182805 0.000000 +vt 0.182805 0.000000 +vt 0.159915 0.999999 +vt 0.159915 0.999999 +vt 0.796326 1.000000 +vt 0.796326 1.000000 +vt 0.159915 0.000000 +vt 0.159915 0.000000 +vt 0.137035 0.999678 +vt 0.137035 0.999678 +vt 0.137035 0.000322 +vt 0.137035 0.000322 +vt 0.862957 0.000322 +vt 0.862957 0.000322 +vt 0.821028 0.000001 +vt 0.821028 0.000001 +vt 0.821028 1.000000 +vt 0.821028 1.000000 +vt 0.841766 1.000000 +vt 0.841766 1.000000 +vt 0.841766 0.000001 +vt 0.841766 0.000001 +vn -0.000133 -1.000000 0.000134 +vn 0.671666 -0.000000 -0.740855 +vn -0.000075 -1.000000 0.000377 +vn 0.853214 -0.000000 -0.521562 +vn -0.000000 -1.000000 0.000201 +vn 0.000000 -1.000000 0.000323 +vn 0.980936 -0.000000 -0.194331 +vn -0.000101 -1.000000 0.000172 +vn 0.481628 -0.000000 -0.876376 +vn 0.000000 -1.000000 -0.000227 +vn 0.983710 0.000000 0.179763 +vn -0.000059 -1.000000 0.000195 +vn 0.247695 -0.000000 -0.968838 +vn -0.000000 -1.000000 -0.000205 +vn 0.745032 -0.000000 -0.667029 +vn -0.000133 1.000000 0.000133 +vn 0.538045 -0.000000 -0.842916 +vn -0.000101 1.000000 0.000171 +vn 0.891717 -0.000000 -0.452593 +vn -0.000075 1.000000 0.000377 +vn 0.337399 -0.000000 -0.941362 +vn -0.000059 1.000000 0.000195 +vn -0.000000 1.000000 0.000200 +vn 0.000000 1.000000 0.000215 +vn 0.980936 -0.000000 -0.194331 +vn -0.000000 1.000000 0.000206 +vn 0.052785 -0.000000 -0.998606 +vn -0.000000 1.000000 -0.000205 +vn 0.983710 0.000000 0.179763 +vn 0.000000 1.000000 -0.000340 +vn -0.052785 -0.000000 -0.998606 +vn -0.000000 -1.000000 0.000207 +vn 0.899312 0.000000 0.437307 +vn -0.000074 -1.000000 -0.000394 +vn -0.000074 1.000000 -0.000395 +vn 0.855397 0.000000 0.517973 +vn -0.247695 -0.000000 -0.968838 +vn 0.000059 1.000000 0.000195 +vn -0.000136 -1.000000 -0.000130 +vn 0.753856 0.000000 0.657040 +vn -0.000136 1.000000 -0.000130 +vn 0.697622 0.000000 0.716466 +vn -0.000105 1.000000 -0.000168 +vn 0.492575 0.000000 0.870270 +vn -0.000000 1.000000 -0.000227 +vn -0.983731 0.000000 0.179650 +vn -0.000104 -1.000000 -0.000168 +vn 0.567323 0.000000 0.823495 +vn -0.000059 -1.000000 -0.000196 +vn 0.331301 0.000000 0.943525 +vn 0.000000 -1.000000 -0.000207 +vn 0.052786 0.000000 0.998606 +vn 0.244600 0.000000 0.969624 +vn -0.000059 1.000000 -0.000196 +vn -0.337399 -0.000000 -0.941362 +vn 0.000059 -1.000000 0.000195 +vn -0.052786 0.000000 0.998606 +vn 0.000000 1.000000 -0.000207 +vn -0.481628 -0.000000 -0.876376 +vn 0.000101 1.000000 0.000171 +vn -0.244600 0.000000 0.969624 +vn 0.000059 -1.000000 -0.000196 +vn -0.538045 -0.000000 -0.842916 +vn 0.000101 -1.000000 0.000172 +vn -0.331301 0.000000 0.943525 +vn 0.000059 1.000000 -0.000196 +vn -0.671666 -0.000000 -0.740855 +vn 0.000133 1.000000 0.000133 +vn -0.492575 0.000000 0.870270 +vn 0.000104 -1.000000 -0.000168 +vn -0.745032 -0.000000 -0.667029 +vn 0.000133 -1.000000 0.000134 +vn 0.000075 1.000000 0.000377 +vn -0.853250 -0.000000 -0.521502 +vn -0.567323 0.000000 0.823495 +vn 0.000105 1.000000 -0.000168 +vn 0.000075 -1.000000 0.000377 +vn -0.891781 -0.000000 -0.452466 +vn 0.000000 1.000000 0.000323 +vn -0.980957 -0.000000 -0.194227 +vn 0.000000 -1.000000 0.000216 +vn -0.980957 -0.000000 -0.194227 +vn -0.983731 0.000000 0.179650 +vn -0.000000 -1.000000 -0.000340 +vn 0.000136 -1.000000 -0.000130 +vn -0.697622 0.000000 0.716466 +vn 0.000136 1.000000 -0.000130 +vn -0.753856 0.000000 0.657040 +vn 0.000074 1.000000 -0.000395 +vn -0.899379 0.000000 0.437169 +vn 0.000074 -1.000000 -0.000394 +vn -0.855436 0.000000 0.517909 +f 1/1/1 3/3/3 5/5/5 +f 3/3/3 6/6/6 5/5/5 +f 8/8/8 1/1/1 5/5/5 +f 5/5/5 6/6/6 10/10/10 +f 12/12/12 8/8/8 5/5/5 +f 14/14/14 5/5/5 10/10/10 +f 2/2/2 15/15/15 4/4/4 +f 9/9/9 17/17/17 2/2/2 +f 17/17/17 15/15/15 2/2/2 +f 15/15/15 19/19/19 4/4/4 +f 4/4/4 19/19/19 7/7/7 +f 21/21/21 17/17/17 9/9/9 +f 13/13/13 21/21/21 9/9/9 +f 16/16/16 18/18/18 23/23/23 +f 20/20/20 16/16/16 23/23/23 +f 18/18/18 22/22/22 23/23/23 +f 24/24/24 20/20/20 23/23/23 +f 19/19/19 25/25/25 7/7/7 +f 22/22/22 26/26/26 23/23/23 +f 27/27/27 21/21/21 13/13/13 +f 24/24/24 23/23/23 28/28/28 +f 7/7/7 25/25/25 29/29/29 +f 30/30/30 24/24/24 28/28/28 +f 11/11/11 7/7/7 29/29/29 +f 31/31/31 27/27/27 13/13/13 +f 32/32/32 12/12/12 5/5/5 +f 11/11/11 29/29/29 33/33/33 +f 10/10/10 34/34/34 14/14/14 +f 35/35/35 30/30/30 28/28/28 +f 29/29/29 36/36/36 33/33/33 +f 37/37/37 27/27/27 31/31/31 +f 26/26/26 38/38/38 23/23/23 +f 34/34/34 39/39/39 14/14/14 +f 33/33/33 36/36/36 40/40/40 +f 41/41/41 35/35/35 28/28/28 +f 36/36/36 42/42/42 40/40/40 +f 43/43/43 41/41/41 28/28/28 +f 28/28/28 23/23/23 45/45/45 +f 39/39/39 47/47/47 14/14/14 +f 40/40/40 42/42/42 48/48/48 +f 42/42/42 44/44/44 48/48/48 +f 47/47/47 49/49/49 14/14/14 +f 48/48/48 44/44/44 50/50/50 +f 49/49/49 51/51/51 14/14/14 +f 44/44/44 53/53/53 50/50/50 +f 54/54/54 43/43/43 28/28/28 +f 50/50/50 53/53/53 52/52/52 +f 55/55/55 37/37/37 31/31/31 +f 56/56/56 32/32/32 5/5/5 +f 53/53/53 57/57/57 52/52/52 +f 58/58/58 54/54/54 28/28/28 +f 59/59/59 37/37/37 55/55/55 +f 38/38/38 60/60/60 23/23/23 +f 52/52/52 57/57/57 61/61/61 +f 51/51/51 62/62/62 14/14/14 +f 63/63/63 59/59/59 55/55/55 +f 64/64/64 56/56/56 5/5/5 +f 57/57/57 65/65/65 61/61/61 +f 66/66/66 58/58/58 28/28/28 +f 67/67/67 59/59/59 63/63/63 +f 60/60/60 68/68/68 23/23/23 +f 61/61/61 65/65/65 69/69/69 +f 62/62/62 70/70/70 14/14/14 +f 71/71/71 67/67/67 63/63/63 +f 72/72/72 64/64/64 5/5/5 +f 68/68/68 73/73/73 23/23/23 +f 74/74/74 67/67/67 71/71/71 +f 65/65/65 75/75/75 69/69/69 +f 76/76/76 66/66/66 28/28/28 +f 77/77/77 72/72/72 5/5/5 +f 78/78/78 74/74/74 71/71/71 +f 73/73/73 79/79/79 23/23/23 +f 80/80/80 74/74/74 78/78/78 +f 23/23/23 79/79/79 45/45/45 +f 81/81/81 77/77/77 5/5/5 +f 82/82/82 80/80/80 78/78/78 +f 81/81/81 5/5/5 14/14/14 +f 80/80/80 82/82/82 83/83/83 +f 46/46/46 80/80/80 83/83/83 +f 84/84/84 81/81/81 14/14/14 +f 70/70/70 85/85/85 14/14/14 +f 69/69/69 75/75/75 86/86/86 +f 87/87/87 76/76/76 28/28/28 +f 75/75/75 88/88/88 86/86/86 +f 89/89/89 28/28/28 45/45/45 +f 90/90/90 46/46/46 83/83/83 +f 89/89/89 87/87/87 28/28/28 +f 91/91/91 84/84/84 14/14/14 +f 85/85/85 91/91/91 14/14/14 +f 86/86/86 88/88/88 92/92/92 +f 92/92/92 90/90/90 83/83/83 +f 88/88/88 90/90/90 92/92/92 From 30b1e3fa6aa7f8c4964f8b7f742d4c4cea6921e0 Mon Sep 17 00:00:00 2001 From: Martin Pourrat Date: Wed, 12 Aug 2026 00:46:41 +0200 Subject: [PATCH 14/42] Order Token: make the Mac range and cohesion toggles deterministic gRangeTrigger and gCohesionTrigger toggle by fig GUID, so a stale overlay left by the hover hotkey made the button's first click turn it OFF instead of ON. Clear the overlay before triggering, and clear it again on the OFF branch: exitTargetingMode/clearRangeRulers only reach the vanilla bundle ruler, so without it the Mac rings stayed on screen. Also guard both entry points against a nil selectedUnitObj. Co-Authored-By: Claude Opus 5 (1M context) --- mod/src/StarWarsLegion/Order_Token.a57c41.lua | 14 ++++++++++++-- mod/src/StarWarsLegion/SETUP_CONTROLLER.1cb552.lua | 2 +- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/mod/src/StarWarsLegion/Order_Token.a57c41.lua b/mod/src/StarWarsLegion/Order_Token.a57c41.lua index 17eee6fde..a0ffab22c 100644 --- a/mod/src/StarWarsLegion/Order_Token.a57c41.lua +++ b/mod/src/StarWarsLegion/Order_Token.a57c41.lua @@ -368,9 +368,12 @@ end function toggleCohesionRuler(_, playerColor) -- Mac fallback: capture playerColor (TTS passes it as 2nd arg on click) - -- and route through gCohesionTrigger so the per-seat router picks the - -- right renderer for the clicking player. + -- and route through gCohesionTrigger (the mode router). + if not selectedUnitObj then return end if not rulerOn then + -- Deterministic ON: gCohesionTrigger toggles by GUID, so clear any + -- stale Mac overlay first (e.g., drawn via the hover hotkey). + Global.call("gClearCohesion", { figGUID = selectedUnitObj.getGUID() }) Global.call("gCohesionTrigger", { figGUID = selectedUnitObj.getGUID(), playerColor = playerColor, @@ -952,9 +955,13 @@ end function targetingMode(_, playerColor) -- Mac fallback: capture playerColor and route through gRangeTrigger. + if not selectedUnitObj then return end if not enemyHighlighted then exitAttackMode() highlightEnemies() + -- Deterministic ON: gRangeTrigger toggles by GUID, so clear any + -- stale Mac overlay first to guarantee this click draws. + Global.call("gClearRange", { figGUID = selectedUnitObj.getGUID() }) Global.call("gRangeTrigger", { figGUID = selectedUnitObj.getGUID(), playerColor = playerColor, @@ -962,6 +969,9 @@ function targetingMode(_, playerColor) enemyHighlighted = true resetRangeButtons() else + -- exitTargetingMode/clearRangeRulers only clears the vanilla bundle + -- ruler; clear the Mac overlay too so OFF really hides the rings. + Global.call("gClearRange", { figGUID = selectedUnitObj.getGUID() }) exitTargetingMode() end end diff --git a/mod/src/StarWarsLegion/SETUP_CONTROLLER.1cb552.lua b/mod/src/StarWarsLegion/SETUP_CONTROLLER.1cb552.lua index 399273af3..6878e6400 100644 --- a/mod/src/StarWarsLegion/SETUP_CONTROLLER.1cb552.lua +++ b/mod/src/StarWarsLegion/SETUP_CONTROLLER.1cb552.lua @@ -251,7 +251,7 @@ function spawnBoundaryCell(cell, x, z) pos = AddVectors(pos, offset) - -- Mac fallback dual-path: branch on the table-wide deploymentMode toggle. + -- Mac fallback dual-path: branch on the table-wide mode toggle (gGetDeploymentMode). local _macDeployMode = Global.call("gGetDeploymentMode") local projector = nil if _macDeployMode == "windows" then From ae0a9045628bf2636707b6256d31b8b4747045f0 Mon Sep 17 00:00:00 2001 From: Martin Pourrat Date: Wed, 12 Aug 2026 00:46:41 +0200 Subject: [PATCH 15/42] Declare the Mac toggle's apple logo as a CustomUIAsset A text U+F8FF glyph renders as a missing-glyph box on Windows clients, so the button uses a white PNG sprite tinted per state instead. Co-Authored-By: Claude Opus 5 (1M context) --- mod/src/StarWarsLegion.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mod/src/StarWarsLegion.json b/mod/src/StarWarsLegion.json index 1b7f385c5..fc3045292 100644 --- a/mod/src/StarWarsLegion.json +++ b/mod/src/StarWarsLegion.json @@ -317,6 +317,10 @@ { "Name": "rangeRuler", "URL": "http://cloud-3.steamusercontent.com/ugc/966480765118137238/1157F7217EB80F31A92427567B377F857576DAE9/" + }, + { + "Name": "macAppleLogo", + "URL": "https://raw.githubusercontent.com/ironsquadronfr-hub/tts/mac-projector-fallback/mod/data/mac-fallback-assets/apple_logo.png" } ], "ObjectStates": [] From ef3f36bcd646714b6c5b4c42ba1b9d723af71503 Mon Sep 17 00:00:00 2001 From: Martin Pourrat Date: Wed, 12 Aug 2026 00:47:05 +0200 Subject: [PATCH 16/42] Overlays: make Windows mode render the original mod again In Windows (OFF) mode the fallback was supposed to step aside and let the vanilla mod draw. It did not, in three distinct ways: - Range: the vanilla bundle ruler is spawned from the GLOBAL scope (!/RangeRulers is required by Global; figs only require !/Cohesion), so fig.call("spawnRangeRulerOriginal", fig) always raised "no such function". The pcall swallowed it and we fell through to the Mac renderer -- Windows mode silently drew Mac overlays. Call the Global alias, resolved at call time since !/RangeRulers loads after us. - Cohesion: vanilla spawnCohesionRuler RESPAWNS rather than toggling, so a second click just redrew the ruler and it could never be turned off. Read and clear the Projector in the fig scope, where it lives. - Silhouettes: the dual path was missing outright, and the bundle URL was rewritten even in OFF mode. Also collapse the per-seat mode plumbing into one table-wide overlayMode: the Lua runs on the host only, so a per-player renderer was never reachable (see the per-seat POC). gGetMode and gGetDeploymentMode now both read it, macModeToggle wipes both renderers' overlays so nothing stale lingers across a switch, and the legacy mode-picker panel is dropped from saves that still carry one. Co-Authored-By: Claude Opus 5 (1M context) --- mod/src/includes/Overlays.ttslua | 341 ++++++++++++------------------- 1 file changed, 131 insertions(+), 210 deletions(-) diff --git a/mod/src/includes/Overlays.ttslua b/mod/src/includes/Overlays.ttslua index 26e44364c..844c8cc9d 100644 --- a/mod/src/includes/Overlays.ttslua +++ b/mod/src/includes/Overlays.ttslua @@ -497,6 +497,13 @@ function gClearRange(params) local fig = getObjectFromGUID(params.figGUID) if not fig then return end activeOverlays[fig.getGUID() .. ":range"] = nil + -- Windows mode: also destroy the vanilla bundle this fig owns. It was + -- spawned in the Global scope by gRangeTrigger, so the token's own + -- exitTargetingMode/clearRangeRulers cannot reach it. + if macWinRangeGUID == params.figGUID then + pcall(clearRangeRulersOriginal) + macWinRangeGUID = nil + end macRedrawAll() end @@ -618,71 +625,105 @@ end -- URLs as invisible decals far below the table. No separate preload needed. -- ============================================ --- PER-SEAT MODE TOGGLE (Cohesion + Range) --- Each seated player picks their renderer: "mac" (this patch) or --- "windows" (original bundle Projector). When a player triggers an overlay, --- the router checks THEIR mode and uses that renderer. The rendered overlay --- is visible to everyone (TTS engine limitation). +-- TABLE-WIDE MODE TOGGLE (Cohesion + Range + Deployment) +-- One switch for the whole table: "windows" (original bundle Projectors) or +-- "mac" (this patch). Per-seat modes were dropped on purpose: any rendered +-- overlay is visible to every player (TTS engine limitation), so a Windows +-- player triggering an original Projector still shows magenta to Mac +-- players. The switch is the Apple-logo button in the bottom-right menu: +-- default grey = off (originals), green = on (Mac-safe fallback). -- ============================================ -playerOverlayMode = playerOverlayMode or {} -- color -> "mac" | "windows" -deploymentMode = deploymentMode or "mac" -- table-wide setting - -function gGetMode(params) - return playerOverlayMode[params.color] or "mac" -end - -function gGetDeploymentMode() - return deploymentMode -end +overlayMode = overlayMode or "windows" -- "windows" | "mac", table-wide -function gToggleDeploymentMode() - deploymentMode = (deploymentMode == "mac") and "windows" or "mac" - macRefreshModeUI() -end +function gGetMode(_) return overlayMode end +function gGetDeploymentMode() return overlayMode end function gCohesionTrigger(params) if not params or not params.figGUID then return end local fig = getObjectFromGUID(params.figGUID) if not fig then return end - local mode = playerOverlayMode[params.playerColor] or "mac" - if mode == "windows" then - -- Object may not have the original alias (e.g., hovered non-fig object). - -- pcall guards against "no such function" errors that would otherwise - -- propagate out of the hotkey/button callback. - local ok = pcall(function() fig.call("spawnCohesionRulerOriginal", fig) end) - if not ok then gToggleCohesion({figGUID = params.figGUID}) end - else + if overlayMode ~= "windows" then + gToggleCohesion({figGUID = params.figGUID}) + return + end + -- Windows mode: the vanilla Projector lives in the FIG scope (every fig + -- requires !/Cohesion), so read and clear it there. Vanilla + -- spawnCohesionRuler RESPAWNS instead of toggling, so without this a + -- second click just redrew the ruler and it could never be turned off. + -- pcall guards objects that carry no such function (e.g. a hovered + -- non-fig object), which fall back to the Mac renderer. + local ok, isOn = pcall(function() return fig.getVar("cohesionRuler") ~= nil end) + if not ok then + gToggleCohesion({figGUID = params.figGUID}) + return + end + if isOn then + pcall(function() fig.call("clearCohesionRulerOriginal", fig) end) + elseif not pcall(function() fig.call("spawnCohesionRulerOriginal", fig) end) then gToggleCohesion({figGUID = params.figGUID}) end end +-- Which fig currently owns the vanilla (Windows-mode) Range bundle, so a +-- second trigger on the same fig turns it off like vanilla +-- showRangeOnHoveredModel does. +macWinRangeGUID = macWinRangeGUID or nil + function gRangeTrigger(params) if not params or not params.figGUID then return end local fig = getObjectFromGUID(params.figGUID) if not fig then return end - local mode = playerOverlayMode[params.playerColor] or "mac" - if mode == "windows" then - local ok = pcall(function() fig.call("spawnRangeRulerOriginal", fig) end) - if not ok then gToggleRange({figGUID = params.figGUID}) end - else + if overlayMode ~= "windows" then gToggleRange({figGUID = params.figGUID}) + return + end + -- The vanilla bundle Range lives in the GLOBAL scope: !/RangeRulers is + -- required by Global, while figs only require !/Cohesion. Calling + -- fig.call("spawnRangeRulerOriginal", fig) therefore ALWAYS raised + -- "no such function"; the pcall swallowed it and we fell through to the + -- Mac renderer, so Windows mode silently drew Mac overlays instead of + -- the original Projector. spawnRangeRulerOriginal is the Global alias + -- set by !/RangeRulers, resolved at call time (it loads after us). + local wasOn = (macWinRangeGUID == params.figGUID) + pcall(clearRangeRulersOriginal) + macWinRangeGUID = nil + if not wasOn then + if pcall(function() spawnRangeRulerOriginal(fig) end) then + macWinRangeGUID = params.figGUID + else + gToggleRange({figGUID = params.figGUID}) + end end end --- UI: floating panel with one toggle button per seated player -function macModeClick(player, _, id) - local color = id:sub(9) -- "macmode_Red" -> "Red" - if player.color ~= color then - broadcastToColor("Only the player at this seat can toggle their mode.", - player.color, {1, 0.5, 0.5}) - return +function macModeToggle(_, _, _) + overlayMode = (overlayMode == "mac") and "windows" or "mac" + -- Wipe both renderers' overlays so stale visuals don't linger after the + -- toggle; each player just re-triggers their hotkey. + for k, e in pairs(activeOverlays) do + if e.type == "cohesion" or e.type == "range" then + activeOverlays[k] = nil + end end - local cur = playerOverlayMode[color] or "mac" - playerOverlayMode[color] = (cur == "mac") and "windows" or "mac" - -- Wipe any active Cohesion/Range overlays for this player so the next - -- trigger redraws in the chosen mode without stale visuals. - macRefreshModeUI() + macRedrawAll() + for _, obj in ipairs(getAllObjects()) do + if obj.getVar and obj.getVar("cohesionRuler") then + pcall(function() obj.call("clearCohesionRulerOriginal", obj) end) + end + if obj.getVar and obj.getVar("rangeRuler") then + pcall(function() obj.call("clearRangeRulersOriginal", obj) end) + end + end + -- The Windows-mode Range bundle is spawned from the Global scope, which + -- getAllObjects() above does not cover. + pcall(clearRangeRulersOriginal) + macWinRangeGUID = nil + broadcastToAll( + (overlayMode == "mac") and "Mac patch ON: Mac-safe overlays for the whole table." + or "Mac patch OFF: original Windows overlays.", + (overlayMode == "mac") and {0.55, 0.9, 0.6} or {0.9, 0.75, 0.55}) + macDeferRefresh() end local function macFindNodeById(tree, id) @@ -696,198 +737,78 @@ local function macFindNodeById(tree, id) return nil, nil end --- Tracks the panel's desired active state across refreshes. Persists so a --- click on the close X before the initial refresh is honored. -macModePanelActive = (macModePanelActive == nil) and true or macModePanelActive - -function macModeToggleVisibility() - macModePanelActive = not macModePanelActive - local tree = UI.getXmlTable() or {} - local panel = macFindNodeById(tree, "macModePanel") - if panel then - panel.attributes.active = macModePanelActive and "true" or "false" - UI.setXmlTable(tree) - else - macRefreshModeUI() - end -end - +-- UI: single Apple-logo toggle button in the bottom-right legionFloatingMenu. function macRefreshModeUI() - local seated = Player.getPlayers() - local rows = {{ - tag = "Panel", - attributes = { - color = "transparent", - preferredHeight = "24", - }, - children = { - { - tag = "Text", - attributes = { - text = "Mac TTS U6 Patch", - fontSize = "16", - color = "white", - alignment = "MiddleLeft", - rectAlignment = "MiddleLeft", - }, - }, - { - tag = "Button", - attributes = { - id = "macModePanelClose", - text = "X", - onClick = "macModeToggleVisibility", - color = "#3a1e1e", - textColor = "white", - fontSize = "12", - width = "24", - height = "20", - rectAlignment = "MiddleRight", - }, - }, - }, - }, { - tag = "Text", - attributes = { - text = "Cohesion & Range: pick your renderer", - fontSize = "12", - color = "#bbbbbb", - alignment = "MiddleCenter", - }, - }} - if #seated == 0 then - table.insert(rows, { - tag = "Text", - attributes = { - text = "(no seated players)", - fontSize = "12", - color = "#888888", - alignment = "MiddleCenter", - }, - }) - end - for _, p in ipairs(seated) do - local mode = playerOverlayMode[p.color] or "mac" - local label = p.color .. " - " .. - (mode == "mac" and "MAC FALLBACK" or "WINDOWS ORIGINAL") - local bg = (mode == "mac") and "#1e7a3a" or "#7a3a1e" - table.insert(rows, { - tag = "Button", - attributes = { - id = "macmode_" .. p.color, - text = label, - onClick = "macModeClick", - color = bg, - fontSize = "13", - textColor = "white", - preferredHeight = "28", - }, - }) - end - -- Deployment is table-wide (everyone sees the same zones); use a single - -- global toggle rather than per-seat. - table.insert(rows, { - tag = "Text", - attributes = { - text = "Deployment (table-wide)", - fontSize = "12", - color = "#bbbbbb", - alignment = "MiddleCenter", - }, - }) - table.insert(rows, { - tag = "Button", - attributes = { - id = "macmode_deployment", - text = (deploymentMode == "mac") and "DEPLOYMENT: MAC FALLBACK" - or "DEPLOYMENT: WINDOWS ORIGINAL", - onClick = "macDeploymentClick", - color = (deploymentMode == "mac") and "#1e3a7a" or "#7a3a1e", - fontSize = "13", - textColor = "white", - preferredHeight = "28", - }, - }) - -- Build my panel (will be merged into the existing UI tree below so we - -- don't clobber legionFloatingMenu / Welcome / Chess Clocks etc.). - local panel = { - tag = "Panel", - attributes = { - id = "macModePanel", - active = macModePanelActive and "true" or "false", - rectAlignment = "MiddleRight", - offsetXY = "-10 80", - width = "260", - height = "320", - color = "rgba(0.06,0.06,0.06,0.9)", - padding = "8 8 8 8", - outlineSize = "1 1", - outline = "#303030", - }, - children = {{ - tag = "VerticalLayout", - attributes = { - spacing = "4", - childForceExpandHeight = "false", - childForceExpandWidth = "true", - }, - children = rows, - }}, - } - local tree = UI.getXmlTable() or {} - -- Remove any stale macModePanel before reinserting the fresh one. + -- Drop the legacy mode-picker panel if this save still carries one. for i = #tree, 1, -1 do if tree[i].attributes and tree[i].attributes.id == "macModePanel" then table.remove(tree, i) end end - table.insert(tree, panel) - - -- Inject a "Mac Patch" button into the bottom-right legionFloatingMenu - -- (replaces the first interactable=false placeholder button). local menu = macFindNodeById(tree, "legionFloatingMenu") if menu and menu.children then - local hasMine = false - for _, c in ipairs(menu.children) do + local isMac = (overlayMode == "mac") + local attrs = { + id = "macModeMenuButton", + onClick = "macModeToggle", + tooltip = isMac + and "Mac TTS U6 patch ON (table-wide). Click for original overlays." + or "Mac TTS U6 patch OFF. Click for Mac-safe overlays (table-wide).", + } + -- OFF keeps the sibling buttons' default light-grey look (Welcome, + -- Chess Clocks); ON switches to green. + if isMac then attrs.color = "#1e7a3a" end + local button = { + tag = "Button", + attributes = attrs, + children = {{ + -- White PNG sprite (CustomUIAssets "macAppleLogo"), tinted + -- per state: dark on the grey button, white on green. A text + -- U+F8FF glyph would render as a missing-glyph box on + -- Windows clients. + tag = "Image", + attributes = { + image = "macAppleLogo", + color = isMac and "#FFFFFF" or "#2b2b2b", + preserveAspect = "true", + raycastTarget = "false", + }, + }}, + } + local placed = false + for i, c in ipairs(menu.children) do if c.attributes and c.attributes.id == "macModeMenuButton" then - hasMine = true; break + menu.children[i] = button + placed = true + break end end - if not hasMine then + if not placed then for i, c in ipairs(menu.children) do if c.attributes and c.attributes.interactable == "false" then - menu.children[i] = { - tag = "Button", - attributes = { - id = "macModeMenuButton", - fontSize = "10", - onClick = "macModeToggleVisibility", - tooltip = "Toggle Mac TTS U6 Patch panel", - }, - value = "Mac Patch", - } + menu.children[i] = button + placed = true break end end end end - UI.setXmlTable(tree) end -function macDeploymentClick(_, _, _) - gToggleDeploymentMode() +-- Defer one frame: TTS throws a UTF-8 byte-buffer encoding error if we +-- rebuild the UI XML synchronously inside a click handler. pcall guards +-- against any residual race. +function macDeferRefresh() + Wait.frames(function() pcall(macRefreshModeUI) end, 1) end -function onPlayerChangeColor(_) macRefreshModeUI() end -function onPlayerConnect(_) macRefreshModeUI() end -function onPlayerDisconnect(_) macRefreshModeUI() end - -Wait.time(macRefreshModeUI, 2) +-- Initial UI build, deferred + pcalled like the rest. +Wait.time(function() pcall(macRefreshModeUI) end, 2) -- Override hotkey init functions to capture playerColor and route through --- the per-seat trigger. Defining initCohesionHotkeys/initRangebandHotkeys +-- the mode router. Defining initCohesionHotkeys/initRangebandHotkeys -- here SHADOWS the originals - when the original onLoad runs init*(), our -- versions register the hotkey instead. From 7ec8cb189b594762b0e164fd99460773fca69768 Mon Sep 17 00:00:00 2001 From: Martin Pourrat Date: Wed, 12 Aug 2026 00:47:05 +0200 Subject: [PATCH 17/42] mac-patcher: single global toggle, ground-only raycasts, coalesced redraw Backport of the engine work validated in game on 11 August: - Replace the mode modal with one table-wide toggle button in legionFloatingMenu (grey OFF like Welcome and Chess Clock, green ON), carrying the macAppleLogo sprite. Per-seat is abandoned: the overlay is visible to everyone, so a Windows player in original mode shows magenta to the Mac player regardless. - Share a macHitIsGround filter across the six raycast sites, so the MaxMove fill no longer lands one spawn late. It ignores figures, moving objects, and the "Maximum Move" bundle that hovers at +20 in Windows mode. - Coalesce macRedrawAll (one-frame defer plus a sorted signature, skipped when identical) so re-clicking at the same speed stops reprojecting the decals and the shadows stop shifting. - Suffix the save name with [MAC PATCH] behind a guard instead of renaming outright. Co-Authored-By: Claude Opus 5 (1M context) --- mac-patcher/patch_save_for_mac.py | 852 +++++++++++++++++------------- 1 file changed, 483 insertions(+), 369 deletions(-) diff --git a/mac-patcher/patch_save_for_mac.py b/mac-patcher/patch_save_for_mac.py index 24bd5e227..47890d282 100644 --- a/mac-patcher/patch_save_for_mac.py +++ b/mac-patcher/patch_save_for_mac.py @@ -43,7 +43,6 @@ clearCohesionRulerOriginalGlobal = clearCohesionRuler activeOverlays = activeOverlays or {} -hiddenWhilePickedUp = hiddenWhilePickedUp or {} local ASSETS_BASE = "https://raw.githubusercontent.com/ironsquadronfr-hub/tts/mac-projector-fallback/mod/data/mac-fallback-assets/" local COHESION_HALO_URL = ASSETS_BASE .. "cohesion_halo.png" @@ -212,7 +211,24 @@ rcc = {3, 3}, bcc = {3, 3}, -- opposite corner quarter } -local function macRayGroundY(x, z, offset) +-- A ray hit counts as "ground" only if it is not the ignored object and not +-- a transient object: anything still in motion (e.g. a movement template +-- falling into place the frame the overlay spawns) or the hovering +-- "Maximum Move" Windows bundle would otherwise catch the center ray and +-- float the fill decal above its border ring. +local function macHitIsGround(h, ignoreObj) + local obj = h.hit_object + if obj == nil then return true end + if obj == ignoreObj then return false end + if obj.getName and obj.getName() == "Maximum Move" then return false end + local ok, v = pcall(function() return obj.getVelocity() end) + if ok and v and (math.abs(v.x) + math.abs(v.y) + math.abs(v.z)) > 0.05 then + return false + end + return true +end + +local function macRayGroundY(x, z, offset, ignoreObj) local hits = Physics.cast({ origin = {x, 30, z}, direction = {0, -1, 0}, @@ -220,7 +236,9 @@ max_distance = 50, }) for _, h in ipairs(hits) do - return h.point.y + (offset or 0.05) + if macHitIsGround(h, ignoreObj) then + return h.point.y + (offset or 0.05) + end end return offset or 0.05 end @@ -262,7 +280,7 @@ }) local y = centerPos.y + 0.05 for _, h in ipairs(hits) do - if h.hit_object ~= ignoreObj then + if macHitIsGround(h, ignoreObj) then y = h.point.y + 0.05 break end @@ -298,7 +316,7 @@ }) local y = centerPos.y + 0.05 for _, h in ipairs(hits) do - if h.hit_object ~= ignoreObj then + if macHitIsGround(h, ignoreObj) then y = h.point.y + 0.05 break end @@ -448,7 +466,7 @@ }) local groundY = pos.y for _, h in ipairs(hits) do - if h.hit_object ~= fig then groundY = h.point.y; break end + if macHitIsGround(h, fig) then groundY = h.point.y; break end end if oblong then @@ -521,7 +539,7 @@ }) local groundY = pos.y for _, h in ipairs(hits) do - if h.hit_object ~= fig then groundY = h.point.y; break end + if macHitIsGround(h, fig) then groundY = h.point.y; break end end if oblong then @@ -624,7 +642,7 @@ }) local groundY = pos.y for _, h in ipairs(hits) do - if h.hit_object ~= fig then + if macHitIsGround(h, fig) then groundY = h.point.y break end @@ -668,7 +686,34 @@ } end -function macRedrawAll() +-- Redraws are deferred one frame and coalesced, then skipped outright when +-- the rebuilt result is identical to what is already applied. Rationale: a +-- click that clears and respawns the same overlay (e.g. re-picking the same +-- speed) would otherwise call Global.setDecals twice in one click, and every +-- setDecals re-projects every decal on the table, visibly shifting the +-- shading/shadows on scene objects. +macRedrawPending = false +macLastDrawSig = nil + +local function macDrawSignature(lines, decals) + local parts = {} + for _, l in ipairs(lines) do + local p0 = l.points and l.points[1] + parts[#parts + 1] = string.format("L%d:%s", #(l.points or {}), + p0 and string.format("%.3f,%.3f,%.3f", p0[1], p0[2], p0[3]) or "") + end + for _, d in ipairs(decals) do + parts[#parts + 1] = string.format("D%s:%.3f,%.3f,%.3f:%.2f", + d.name or "", d.position[1], d.position[2], d.position[3], + (d.scale and d.scale[1]) or 0) + end + -- pairs() iteration order over activeOverlays is not stable across + -- rebuilds; sort so identical content always yields an identical key. + table.sort(parts) + return table.concat(parts, "|") +end + +function macRedrawNow() local lines, decals = {}, {} -- Preload all texture URLs (invisible decals far below the table) so TTS -- keeps them cached and we never get the white-square flash on respawn. @@ -704,7 +749,20 @@ or type(entry.fig.getPosition) ~= "function") then stale[#stale + 1] = key else - local ok, out = pcall(b, entry.fig, entry.params) + -- Per-entry cache: only the entry whose fig moved since the + -- last poll is rebuilt (65 raycasts per ring); every other + -- overlay reuses its cached geometry. This is what keeps the + -- framerate up while dragging a fig with several overlays on. + local ok, out + if entry._cache and not entry._dirty then + ok, out = true, entry._cache + else + ok, out = pcall(b, entry.fig, entry.params) + if ok and out then + entry._cache = out + entry._dirty = nil + end + end if ok and out then for _, l in ipairs(out.lines or {}) do table.insert(lines, l) @@ -719,10 +777,22 @@ end end for _, k in ipairs(stale) do activeOverlays[k] = nil end + local sig = macDrawSignature(lines, decals) + if sig == macLastDrawSig then return end + macLastDrawSig = sig Global.setVectorLines(lines) Global.setDecals(decals) end +function macRedrawAll() + if macRedrawPending then return end + macRedrawPending = true + Wait.frames(function() + macRedrawPending = false + pcall(macRedrawNow) + end, 1) +end + function gSpawnCohesion(params) local fig = getObjectFromGUID(params.figGUID) if not fig then return end @@ -730,11 +800,22 @@ type = "cohesion", fig = fig, params = params or {} } macRedrawAll() + -- Cohesion follows its fig through the same lazy poll as Range (it used + -- to tag along only as a side effect of full-rebuild polling). + if not macRangePollingActive then + macRangePollingActive = true + Wait.frames(macRangePoll, 5) + end end function gClearCohesion(params) local fig = getObjectFromGUID(params.figGUID) if not fig then return end + -- Vanilla fig scripts clear cohesion from onPickedUp. Design choice + -- (11 aug): the Mac overlay stays visible and FOLLOWS the fig during + -- the drag, like Range does - so clears on a held fig are ignored + -- (the vanilla onPickedUp clear is the only caller in that state). + if fig.held_by_color then return end activeOverlays[fig.getGUID() .. ":cohesion"] = nil macRedrawAll() end @@ -750,18 +831,51 @@ end end --- Range polling: a slow timer (5 frames = ~12 fps) that re-draws active --- range rulers so they follow figures in real-time. Stops automatically when --- no range overlay is active anymore - avoids the overnight memory leak. +-- Overlay polling: a slow timer (5 frames = ~12 fps) that re-draws active +-- range AND cohesion overlays so they follow figures in real-time. Stops +-- automatically when none is active anymore - avoids the memory leak. macRangePollingActive = macRangePollingActive or false function macRangePoll() - local hasRange = false + -- Rebuild ONLY when a tracked fig actually moved: a full redraw re-runs + -- every builder (65 raycasts per ring, up to 6 rings per fig), and doing + -- that every 5 frames for static figs is what made Range/POI overlays + -- tank the framerate while Cohesion (no polling) stayed fluid. + local hasTracked = false + local moved = false for _, e in pairs(activeOverlays) do - if e.type == "range" then hasRange = true; break end + if e.type == "range" or e.type == "cohesion" then + hasTracked = true + local fig = e.fig + if not fig or type(fig.getPosition) ~= "function" then + moved = true -- stale entry: the redraw prunes it + else + local ok, p = pcall(function() return fig.getPosition() end) + local okr, r = pcall(function() return fig.getRotation() end) + if not ok or not p then + moved = true + elseif not e._lastPos then + -- First poll after spawn: prime the cache, the spawn + -- already drew this overlay. + e._lastPos = p + e._lastRot = okr and r or nil + else + local lp, lr = e._lastPos, e._lastRot + if math.abs(p.x - lp.x) > 0.01 + or math.abs(p.y - lp.y) > 0.01 + or math.abs(p.z - lp.z) > 0.01 + or (okr and lr and math.abs(r.y - lr.y) > 0.5) then + moved = true + e._dirty = true + end + e._lastPos = p + e._lastRot = okr and r or lr + end + end + end end - if hasRange then - macRedrawAll() + if hasTracked then + if moved then macRedrawAll() end Wait.frames(macRangePoll, 5) else macRangePollingActive = false @@ -785,6 +899,13 @@ local fig = getObjectFromGUID(params.figGUID) if not fig then return end activeOverlays[fig.getGUID() .. ":range"] = nil + -- Windows mode: also destroy the vanilla bundle this fig owns. It was + -- spawned in the Global scope by gRangeTrigger, so the token's own + -- exitTargetingMode/clearRangeRulers cannot reach it. + if macWinRangeGUID == params.figGUID then + pcall(clearRangeRulersOriginalGlobal) + macWinRangeGUID = nil + end macRedrawAll() end @@ -838,60 +959,10 @@ macRedrawAll() end -function onObjectPickUp(player_color, obj) - if not obj or not obj.getGUID then return end - local guid = obj.getGUID() - local prefix = guid .. ":" - local plen = #prefix - local changed = false - for key, entry in pairs(activeOverlays) do - if key:sub(1, plen) == prefix then - -- Cohesion: static, hide during pickup, restore on drop. - -- Range: keep visible; the polling timer redraws each tick so - -- the ruler follows the figure in real-time during the drag. - if entry.type == "cohesion" then - hiddenWhilePickedUp[key] = entry - activeOverlays[key] = nil - changed = true - end - end - end - if changed then macRedrawAll() end -end - -function onObjectDrop(player_color, obj) - if not obj or not obj.getGUID then return end - local guid = obj.getGUID() - local prefix = guid .. ":" - local plen = #prefix - - -- Defer the overlay restore until the fig has come to rest. Without this, - -- a flick-drop with residual inertia leaves the overlay anchored at the - -- release position while the fig continues to slide across the table. - local function tryRestore() - local fig = getObjectFromGUID(guid) - if not fig then return end -- destroyed during slide - if fig.held_by_color then return end -- picked up again, hold off - local v = fig.getVelocity and fig.getVelocity() - if v then - local speed = math.sqrt((v.x or 0)^2 + (v.y or 0)^2 + (v.z or 0)^2) - if speed > 0.05 then - Wait.frames(tryRestore, 3) - return - end - end - local changed = false - for key, entry in pairs(hiddenWhilePickedUp) do - if key:sub(1, plen) == prefix then - activeOverlays[key] = entry - hiddenWhilePickedUp[key] = nil - changed = true - end - end - if changed then macRedrawAll() end - end - tryRestore() -end +-- Note: no onObjectPickUp/onObjectDrop handlers (the vanilla Global defines +-- none either). Cohesion, like Range, stays visible during a drag and +-- follows via the poll; the vanilla onPickedUp clear is neutralized in +-- gClearCohesion while the fig is held. function onObjectDestroy(obj) if not obj or not obj.getGUID then return end @@ -905,11 +976,6 @@ changed = true end end - for key in pairs(hiddenWhilePickedUp) do - if key:sub(1, plen) == prefix then - hiddenWhilePickedUp[key] = nil - end - end if changed then macRedrawAll() end end @@ -917,107 +983,82 @@ -- URLs as invisible decals far below the table. No separate preload needed. -- ============================================ --- PER-SEAT MODE TOGGLE (Cohesion + Range) --- Each seated player picks their renderer: "mac" (this patch) or --- "windows" (original bundle Projector). When a player triggers an overlay, --- the router checks THEIR mode and uses that renderer. The rendered overlay --- is visible to everyone (TTS engine limitation). +-- TABLE-WIDE MODE TOGGLE (Cohesion + Range + Deployment) +-- One switch for the whole table: "windows" (original bundle Projectors) or +-- "mac" (this patch). Per-seat modes were dropped on purpose: any rendered +-- overlay is visible to every player (TTS engine limitation), so a Windows +-- player triggering an original Projector still shows magenta to Mac +-- players. The switch is the Apple-logo button in the bottom-right menu: +-- default grey = off (originals), green = on (Mac-safe fallback). -- ============================================ -playerOverlayMode = playerOverlayMode or {} -- color -> "mac" | "windows" --- Default = "windows" (majority of TTS users). Mac users toggle their seat --- via the floating panel. Same for deployment (table-wide setting). -deploymentMode = deploymentMode or "windows" - -function gGetMode(params) - return playerOverlayMode[params.color] or "windows" -end - -function gGetDeploymentMode() - return deploymentMode -end - -function gToggleDeploymentMode() - deploymentMode = (deploymentMode == "mac") and "windows" or "mac" - -- Wipe any active deployment zones so the next setup uses the new mode. - gClearAllDeployment() - macDeferRefresh() -end - --- Replicates the original showRangeOnHoveredModel toggle, calling the --- aliased Global originals so our Mac overrides don't recapture the path. -function gWindowsRangeToggle(fig) - if not fig then return end - if rangeRuler ~= nil then - pcall(clearRangeRulersOriginalGlobal) - if selectedUnitObj == fig then - selectedUnitObj = nil - return - end - end - if fig.interactable then - pcall(function() spawnRangeRulerOriginalGlobal(fig) end) - selectedUnitObj = fig - end -end +overlayMode = overlayMode or "windows" -- "windows" | "mac", table-wide --- Replicates the original showCohesionOnHoveredModel toggle. Uses Global --- aliased originals + Global cohesionRuler state (set by the original). -function gWindowsCohesionToggle(fig) - if not fig then return end - if fig.interactable and selectedUnitObj == fig and cohesionRuler ~= nil then - pcall(clearCohesionRulerOriginalGlobal) - selectedUnitObj = nil - return - end - pcall(clearCohesionRulerOriginalGlobal) - pcall(function() spawnCohesionRulerOriginalGlobal(fig) end) - selectedUnitObj = fig -end +function gGetMode(_) return overlayMode end +function gGetDeploymentMode() return overlayMode end function gCohesionTrigger(params) if not params or not params.figGUID then return end local fig = getObjectFromGUID(params.figGUID) if not fig then return end - local mode = playerOverlayMode[params.playerColor] or "windows" - if mode == "windows" then - gWindowsCohesionToggle(fig) - else + if overlayMode ~= "windows" then + gToggleCohesion({figGUID = params.figGUID}) + return + end + -- Windows mode: the vanilla Projector lives in the FIG scope (every fig + -- requires !/Cohesion), so read and clear it there. Vanilla + -- spawnCohesionRuler RESPAWNS instead of toggling, so without this a + -- second click just redrew the ruler and it could never be turned off. + -- pcall guards objects that carry no such function (e.g. a hovered + -- non-fig object), which fall back to the Mac renderer. + local ok, isOn = pcall(function() return fig.getVar("cohesionRuler") ~= nil end) + if not ok then + gToggleCohesion({figGUID = params.figGUID}) + return + end + if isOn then + pcall(function() fig.call("clearCohesionRulerOriginal", fig) end) + elseif not pcall(function() fig.call("spawnCohesionRulerOriginal", fig) end) then gToggleCohesion({figGUID = params.figGUID}) end end +-- Which fig currently owns the vanilla (Windows-mode) Range bundle, so a +-- second trigger on the same fig turns it off like vanilla +-- showRangeOnHoveredModel does. +macWinRangeGUID = macWinRangeGUID or nil + function gRangeTrigger(params) if not params or not params.figGUID then return end local fig = getObjectFromGUID(params.figGUID) if not fig then return end - local mode = playerOverlayMode[params.playerColor] or "windows" - if mode == "windows" then - gWindowsRangeToggle(fig) - else - gToggleRange({ - figGUID = params.figGUID, - forceFigMode = params.forceFigMode, - rangeKey = params.rangeKey, - }) + if overlayMode ~= "windows" then + gToggleRange({figGUID = params.figGUID}) + return + end + -- The vanilla bundle Range lives in the GLOBAL scope: !/RangeRulers is + -- required by Global, while figs only require !/Cohesion. Calling + -- fig.call("spawnRangeRulerOriginal", fig) therefore ALWAYS raised + -- "no such function"; the pcall swallowed it and we fell through to the + -- Mac renderer, so Windows mode silently drew Mac overlays instead of + -- the original Projector. Route through the Global aliases captured at + -- the top of this block instead. + local wasOn = (macWinRangeGUID == params.figGUID) + pcall(clearRangeRulersOriginalGlobal) + macWinRangeGUID = nil + if not wasOn then + if pcall(function() spawnRangeRulerOriginalGlobal(fig) end) then + macWinRangeGUID = params.figGUID + else + gToggleRange({figGUID = params.figGUID}) + end end end --- UI: floating panel with one toggle button per seated player -function macModeClick(player, _, id) - local color = id:sub(9) -- "macmode_Red" -> "Red" - if player.color ~= color then - broadcastToColor("Only the player at this seat can toggle their mode.", - player.color, {1, 0.5, 0.5}) - return - end - local cur = playerOverlayMode[color] or "windows" - playerOverlayMode[color] = (cur == "mac") and "windows" or "mac" - -- Wipe Mac-side overlays so stale visuals don't linger after the toggle. - -- We don't track per-color ownership, so this clears Cohesion+Range for - -- everyone - acceptable since each player can re-trigger their hotkey. - -- Windows-side overlays (fig-scoped cohesionRuler/rangeRuler) are - -- cleared by iterating objects with active state. +function macModeToggle(_, _, _) + overlayMode = (overlayMode == "mac") and "windows" or "mac" + -- Wipe both renderers' overlays so stale visuals don't linger after the + -- toggle; each player just re-triggers their hotkey. for k, e in pairs(activeOverlays) do if e.type == "cohesion" or e.type == "range" then activeOverlays[k] = nil @@ -1032,6 +1073,14 @@ pcall(function() obj.call("clearRangeRulersOriginal", obj) end) end end + -- The Windows-mode Range bundle is spawned from the Global scope, which + -- getAllObjects() above does not cover. + pcall(clearRangeRulersOriginalGlobal) + macWinRangeGUID = nil + broadcastToAll( + (overlayMode == "mac") and "Mac patch ON: Mac-safe overlays for the whole table." + or "Mac patch OFF: original Windows overlays.", + (overlayMode == "mac") and {0.55, 0.9, 0.6} or {0.9, 0.75, 0.55}) macDeferRefresh() end @@ -1046,215 +1095,171 @@ return nil, nil end --- Tracks the panel's desired active state across refreshes. Persists so a --- click on the close X before the initial refresh is honored. Hidden at first --- load (default = false); the floating "Mac Patch" menu button reveals it. -macModePanelActive = (macModePanelActive == nil) and false or macModePanelActive - -function macModeToggleVisibility() - macModePanelActive = not macModePanelActive - -- Defer the XML rebuild: TTS occasionally throws a UTF-8 byte-buffer - -- encoding error if UI.setXmlTable runs synchronously inside a UI - -- click handler. Deferring one frame + pcall has been reliable. - Wait.frames(function() - pcall(function() - local tree = UI.getXmlTable() or {} - local panel = macFindNodeById(tree, "macModePanel") - if panel then - panel.attributes.active = macModePanelActive and "true" or "false" - UI.setXmlTable(tree) - else - macRefreshModeUI() - end - end) - end, 1) -end - +-- UI: single Apple-logo toggle button in the bottom-right legionFloatingMenu. function macRefreshModeUI() - local seated = Player.getPlayers() - local rows = {{ - tag = "Panel", - attributes = { - color = "transparent", - preferredHeight = "24", - }, - children = { - { - tag = "Text", - attributes = { - text = "Mac TTS U6 Patch", - fontSize = "16", - color = "white", - alignment = "MiddleLeft", - rectAlignment = "MiddleLeft", - }, - }, - { - tag = "Button", - attributes = { - id = "macModePanelClose", - text = "X", - onClick = "macModeToggleVisibility", - color = "#3a1e1e", - textColor = "white", - fontSize = "12", - width = "24", - height = "20", - rectAlignment = "MiddleRight", - }, - }, - }, - }, { - tag = "Text", - attributes = { - text = "Cohesion & Range: pick your renderer", - fontSize = "12", - color = "#bbbbbb", - alignment = "MiddleCenter", - }, - }} - if #seated == 0 then - table.insert(rows, { - tag = "Text", - attributes = { - text = "(no seated players)", - fontSize = "12", - color = "#888888", - alignment = "MiddleCenter", - }, - }) - end - for _, p in ipairs(seated) do - local mode = playerOverlayMode[p.color] or "windows" - local label = p.color .. " - " .. - (mode == "mac" and "MAC FALLBACK" or "WINDOWS ORIGINAL") - local bg = (mode == "mac") and "#1e7a3a" or "#7a3a1e" - table.insert(rows, { - tag = "Button", - attributes = { - id = "macmode_" .. p.color, - text = label, - onClick = "macModeClick", - color = bg, - fontSize = "13", - textColor = "white", - preferredHeight = "28", - }, - }) - end - -- Deployment is table-wide (everyone sees the same zones); use a single - -- global toggle rather than per-seat. - table.insert(rows, { - tag = "Text", - attributes = { - text = "Deployment (table-wide)", - fontSize = "12", - color = "#bbbbbb", - alignment = "MiddleCenter", - }, - }) - table.insert(rows, { - tag = "Button", - attributes = { - id = "macmode_deployment", - text = (deploymentMode == "mac") and "DEPLOYMENT: MAC FALLBACK" - or "DEPLOYMENT: WINDOWS ORIGINAL", - onClick = "macDeploymentClick", - color = (deploymentMode == "mac") and "#1e3a7a" or "#7a3a1e", - fontSize = "13", - textColor = "white", - preferredHeight = "28", - }, - }) - -- Build my panel (will be merged into the existing UI tree below so we - -- don't clobber legionFloatingMenu / Welcome / Chess Clocks etc.). - local panel = { - tag = "Panel", - attributes = { - id = "macModePanel", - active = macModePanelActive and "true" or "false", - rectAlignment = "MiddleRight", - offsetXY = "-10 80", - width = "260", - height = "320", - color = "rgba(0.06,0.06,0.06,0.9)", - padding = "8 8 8 8", - outlineSize = "1 1", - outline = "#303030", - }, - children = {{ - tag = "VerticalLayout", - attributes = { - spacing = "4", - childForceExpandHeight = "false", - childForceExpandWidth = "true", - }, - children = rows, - }}, - } - local tree = UI.getXmlTable() or {} - -- Remove any stale macModePanel before reinserting the fresh one. + -- Drop the legacy mode-picker panel if this save still carries one. for i = #tree, 1, -1 do if tree[i].attributes and tree[i].attributes.id == "macModePanel" then table.remove(tree, i) end end - table.insert(tree, panel) - - -- Inject a "Mac Patch" button into the bottom-right legionFloatingMenu - -- (replaces the first interactable=false placeholder button). local menu = macFindNodeById(tree, "legionFloatingMenu") if menu and menu.children then - local hasMine = false - for _, c in ipairs(menu.children) do + local isMac = (overlayMode == "mac") + local attrs = { + id = "macModeMenuButton", + onClick = "macModeToggle", + tooltip = isMac + and "Mac TTS U6 patch ON (table-wide). Click for original overlays." + or "Mac TTS U6 patch OFF. Click for Mac-safe overlays (table-wide).", + } + -- OFF keeps the sibling buttons' default light-grey look (Welcome, + -- Chess Clocks); ON switches to green. + if isMac then attrs.color = "#1e7a3a" end + local button = { + tag = "Button", + attributes = attrs, + children = {{ + -- White PNG sprite (CustomUIAssets "macAppleLogo"), tinted + -- per state: dark on the grey button, white on green. A text + -- U+F8FF glyph would render as a missing-glyph box on + -- Windows clients. + tag = "Image", + attributes = { + image = "macAppleLogo", + color = isMac and "#FFFFFF" or "#2b2b2b", + preserveAspect = "true", + raycastTarget = "false", + }, + }}, + } + local placed = false + for i, c in ipairs(menu.children) do if c.attributes and c.attributes.id == "macModeMenuButton" then - hasMine = true; break + menu.children[i] = button + placed = true + break end end - if not hasMine then + if not placed then for i, c in ipairs(menu.children) do if c.attributes and c.attributes.interactable == "false" then - menu.children[i] = { - tag = "Button", - attributes = { - id = "macModeMenuButton", - fontSize = "10", - onClick = "macModeToggleVisibility", - tooltip = "Toggle Mac TTS U6 Patch panel", - }, - value = "Mac Patch", - } + menu.children[i] = button + placed = true break end end end end - UI.setXmlTable(tree) end -function macDeploymentClick(_, _, _) - gToggleDeploymentMode() -end - -- Defer one frame: TTS throws a UTF-8 byte-buffer encoding error if we --- rebuild the UI XML synchronously inside a click handler / seat change. --- pcall guards against any residual race. Promoted to a global function --- so macModeClick / macModeToggleVisibility / gToggleDeploymentMode (all --- defined before this point) can call it via name lookup at call time. +-- rebuild the UI XML synchronously inside a click handler. pcall guards +-- against any residual race. function macDeferRefresh() Wait.frames(function() pcall(macRefreshModeUI) end, 1) end -function onPlayerChangeColor(_) macDeferRefresh() end -function onPlayerConnect(_) macDeferRefresh() end -function onPlayerDisconnect(_) macDeferRefresh() end -- Initial UI build, deferred + pcalled like the rest. Wait.time(function() pcall(macRefreshModeUI) end, 2) +-- ============================================ +-- UNIT ID TOKEN NUMBERS (Mac) +-- The ID token bundle paints its number via custom materials +-- (unitIDtoken_N) that TTS U6 on Mac refuses to load ("Shader didn't load +-- correctly ... Assigning Standard shader"), so tokens go blank. Unlike the +-- Projector magenta case there is no error shader involved: TTS substitutes +-- Standard, which simply ignores the number texture slots. In mac mode we +-- attach a plain object-UI number instead (native Unity UI, no shaders); +-- the token state id IS the number (state 1..10). +-- ============================================ + +-- Empirically calibrated (diagnostics of 11 aug): the top face reads +-- correctly with rotation "0 0 180", the bottom face with "180 0 0". +-- Offsets found by ladder diagnostic (panels at z -12..+12 each showing +-- its own z): top face reads at z = -12, bottom face at z = +1. +MAC_UNITID_UI = { + zTop = -12, + zBottom = 1, + fontSize = 72, + panel = 110, + rotTop = "0 0 180", + rotBottom = "180 0 0", +} + +local function macUnitIDPanel(text, x, z, rot) + return { + tag = "Panel", + attributes = { + position = tostring(x) .. " 0 " .. tostring(z), + rotation = rot, + width = tostring(MAC_UNITID_UI.panel), + height = tostring(MAC_UNITID_UI.panel), + }, + children = {{ + tag = "Text", + attributes = { + text = text, + fontSize = tostring(MAC_UNITID_UI.fontSize), + fontStyle = "Bold", + color = "#FFFFFF", + outline = "#000000", + outlineSize = "4 4", + alignment = "MiddleCenter", + }, + }}, + } +end + +local function macUnitIDXml(n) + return { + macUnitIDPanel(tostring(n), 0, MAC_UNITID_UI.zTop, MAC_UNITID_UI.rotTop), + macUnitIDPanel(tostring(n), 0, MAC_UNITID_UI.zBottom, MAC_UNITID_UI.rotBottom), + } +end + +local function macApplyUnitIDUI(obj) + if not (obj and obj.getName and obj.getName() == "Unit ID Token") then return end + if overlayMode == "mac" then + local n = 1 + pcall(function() n = obj.getStateId() end) + if not n or n < 1 then n = 1 end + pcall(function() obj.UI.setXmlTable(macUnitIDXml(n)) end) + else + pcall(function() obj.UI.setXml("") end) + end +end + +function macRefreshUnitIDTokens() + for _, obj in ipairs(getAllObjects()) do + macApplyUnitIDUI(obj) + end +end + +-- New tokens from the infinite bag and number changes (a TTS state switch +-- spawns a fresh object) both arrive through onObjectSpawn. The live mod +-- defines no onObjectSpawn handler (verified), so defining it here is safe. +function onObjectSpawn(obj) + if overlayMode ~= "mac" then return end + if not (obj and obj.getName and obj.getName() == "Unit ID Token") then return end + Wait.frames(function() macApplyUnitIDUI(obj) end, 2) +end + +-- Numbers follow the table-wide toggle: wrap the toggle handler (defined in +-- the shared mode-toggle block above, which must stay byte-identical with +-- the mod source copy, hence the wrap instead of an inline edit). +local _macModeToggleBeforeUnitID = macModeToggle +function macModeToggle(a, b, c) + _macModeToggleBeforeUnitID(a, b, c) + Wait.frames(function() pcall(macRefreshUnitIDTokens) end, 1) +end + +Wait.time(function() pcall(macRefreshUnitIDTokens) end, 3) + -- Override hotkey init functions to capture playerColor and route through --- the per-seat trigger. Defining initCohesionHotkeys/initRangebandHotkeys +-- the mode router. Defining initCohesionHotkeys/initRangebandHotkeys -- here SHADOWS the originals - when the original onLoad runs init*(), our -- versions register the hotkey instead. @@ -1487,7 +1492,7 @@ re.DOTALL ) -DEPLOYMENT_SPAWN_REPLACEMENT = r"""-- MAC PATCH dual-path: branch on the table-wide deploymentMode toggle. +DEPLOYMENT_SPAWN_REPLACEMENT = r"""-- MAC PATCH dual-path: branch on the table-wide mode toggle (gGetDeploymentMode). local _macDeployMode = Global.call("gGetDeploymentMode") local projector = nil if _macDeployMode == "windows" then @@ -1543,8 +1548,105 @@ SILHOUETTE_BUNDLE_URL = ( "https://raw.githubusercontent.com/ironsquadronfr-hub/tts/" "mac-projector-fallback/mod/data/mac-fallback-assets/" - "silhouette_mac_fallback.unity3d" + "silhouette_mac_fallback_v2.unity3d" +) +# Silhouette spawn rebuilt as a Custom_Model that clones the Silhouette +# Marker's recipe (same mesh family, TTS-native shader): correct translucency +# on Mac with the exact marker look, instead of an AssetBundle whose shader +# can't load. Mesh is 1.062 wide x 1.485 tall (base pivot) vs the bundle's +# 1x1 unit cylinder, hence the scale factors that preserve vanilla sizing. +# Collider = degenerate 1mm triangle so the attachment can't shove minis. +SILHOUETTE_MODEL_RE = re.compile( + r"local silhouette = spawnObject\(\{\s*" + r"type = \"Custom_AssetBundle\",\s*" + r"position = pos,\s*" + r"rotation = rot,\s*" + r"scale = \{scale,height,scale\}\s*" + r"\}\)\s*" + r"silhouette\.setCustomObject\(\{\s*" + r"assetbundle = silhouetteData,\s*" + r"material = 3\s*" + r"\}\)\s*" + r"silhouette\.setColorTint\(\{([0-9., ]+)\}\)" ) +SILHOUETTE_MODEL_REPLACEMENT = r"""-- MAC PATCH silhouette dual-path: branch on the table-wide mode toggle. + local silhouette + if Global.call("gGetMode") == "windows" then + -- Original AssetBundle Projector, untouched. Opaque on Mac: that is the + -- vanilla behaviour the toggle is there to switch away from. + silhouette = spawnObject({ + type = "Custom_AssetBundle", + position = pos, + rotation = rot, + scale = {scale,height,scale} + }) + silhouette.setCustomObject({ + assetbundle = silhouetteData, + material = 3 + }) + else + -- Silhouette-as-model (marker recipe). Oblong bases reuse the ORIGINAL + -- mesh, extracted from the vanilla bundles (silh_new_long_1in / + -- silh_new_snail_1in), so the Mac path changes the rendering and + -- nothing else: same outline as Windows, at the vanilla scale + -- ({scale,height,scale} with scale = 1 for both oblong sizes). Round + -- bases keep the marker mesh with the unit-normalizing factors. + local _macMesh = "https://steamusercontent-a.akamaihd.net/ugc/1003681898505457098/962BED032738C4448CCD4B737E82876715459FE8/" + local _macSx, _macSy, _macSz = scale * 0.9416, height * 0.6734, scale * 0.9416 + local _macObl = ({ + long = "https://raw.githubusercontent.com/ironsquadronfr-hub/tts/mac-projector-fallback/mod/data/mac-fallback-assets/silh_exact_long_1.obj", + snail = "https://raw.githubusercontent.com/ironsquadronfr-hub/tts/mac-projector-fallback/mod/data/mac-fallback-assets/silh_exact_snail_1.obj", + })[(unitData and unitData.baseSize) or ""] + if _macObl then + _macMesh = _macObl + _macSx, _macSy, _macSz = scale, height, scale + end + silhouette = spawnObject({ + type = "Custom_Model", + position = pos, + rotation = rot, + scale = {_macSx, _macSy, _macSz} + }) + silhouette.setCustomObject({ + mesh = _macMesh, + collider = "https://raw.githubusercontent.com/ironsquadronfr-hub/tts/mac-projector-fallback/mod/data/mac-fallback-assets/collider_null.obj", + convex = true, + material = 0, + type = 1 + }) + end + silhouette.setColorTint({\g<1>})""" + + +# SIL/LCK button placement on oblong bases (upstream bug, both OSes): the +# vanilla offset is baseRadius/2 + 0.1 with a single per-size radius and no +# axis handling, so on long/snail bases the buttons land on top of the +# model. Raise the offset to the model's actual half-depth when bigger. +BUTTON_OFFSET_RE = re.compile( + r"(local buttonOffset = calculateButtonZOffset\(templateInfo\.baseRadius\[unitData\.baseSize\]\))" + r"(?! -- MAC PATCH)" +) +BUTTON_OFFSET_REPLACEMENT = r"""\1 -- MAC PATCH oblong + -- Deferred: at onLoad the custom mesh is not loaded yet, so bounds read + -- as zero. Re-place SIL/LCK once the model is in, oblong bases only. + if unitData and (unitData.baseSize == "long" or unitData.baseSize == "snail") then + Wait.time(function() + if self == nil then return end + local okB, b = pcall(function() return self.getBoundsNormalized() end) + local okS, sc = pcall(function() return self.getScale() end) + if not (okB and okS and b and sc and sc.z ~= 0) then return end + local half = (b.size.z / sc.z) * 0.5 + 0.15 + for _, btn in ipairs(self.getButtons() or {}) do + if (btn.label == "SIL" or btn.label == "LCK") + and (btn.position.z or 0) < half then + self.editButton({index = btn.index, + position = {btn.position.x, btn.position.y, half}}) + end + end + end, 3) + end""" + + SILHOUETTE_URL_RE = re.compile( r'(silhouetteData\s*=\s*)"https?://[^"]*/ugc/[^"]+"' ) @@ -1657,7 +1759,7 @@ -- (magenta on Mac, native on Windows) until a per-token Mac fallback -- ships - see TOKEN_BUTTON_WRAPPER for the per-token override path. -- --- The single alias below is REQUIRED: Global macModeClick calls +-- The single alias below is REQUIRED: Global macModeToggle calls -- obj.call("clearRangeRulersOriginal", obj) on every object holding a -- rangeRuler state, to wipe the vanilla ruler when toggling modes. clearRangeRulersOriginal = clearRangeRulers @@ -1670,7 +1772,11 @@ ORDER_TOKEN_BUTTON_OVERRIDES = r""" -- MAC PATCH per-seat router (Order_Token button click overrides) function toggleCohesionRuler(_, playerColor) + if not selectedUnitObj then return end if not rulerOn then + -- Deterministic ON: gCohesionTrigger toggles by GUID, so clear any + -- stale Mac overlay first (e.g., drawn via the hover hotkey). + Global.call("gClearCohesion", { figGUID = selectedUnitObj.getGUID() }) Global.call("gCohesionTrigger", { figGUID = selectedUnitObj.getGUID(), playerColor = playerColor, @@ -1683,9 +1789,13 @@ end function targetingMode(_, playerColor) + if not selectedUnitObj then return end if not enemyHighlighted then exitAttackMode() highlightEnemies() + -- Deterministic ON: gRangeTrigger toggles by GUID, so clear any + -- stale Mac overlay first to guarantee this click draws. + Global.call("gClearRange", { figGUID = selectedUnitObj.getGUID() }) Global.call("gRangeTrigger", { figGUID = selectedUnitObj.getGUID(), playerColor = playerColor, @@ -1693,6 +1803,9 @@ enemyHighlighted = true resetRangeButtons() else + -- exitTargetingMode/clearRangeRulers only clears the vanilla bundle + -- ruler; clear the Mac overlay too so OFF really hides the rings. + Global.call("gClearRange", { figGUID = selectedUnitObj.getGUID() }) exitTargetingMode() end end @@ -1968,10 +2081,19 @@ def walk(o): # (Unit_Leader 99f1c8, Bomb Cart b497e1, POI Token 761483). # Idempotent: the regex only matches Steam UGC URLs (/ugc/), # not our fork URL, so re-runs are no-ops. - new_ls, n = SILHOUETTE_URL_RE.subn(SILHOUETTE_URL_REPLACEMENT, ls) + new_ls, n = SILHOUETTE_MODEL_RE.subn(SILHOUETTE_MODEL_REPLACEMENT, ls) + if n > 0: + ls = new_ls + changed = True + new_ls, n = BUTTON_OFFSET_RE.subn(BUTTON_OFFSET_REPLACEMENT, ls) if n > 0: ls = new_ls changed = True + # NOTE: the silhouetteData URL is deliberately left alone. It + # used to be swapped for our Unity-6 bundle, but the marker + # recipe above supplanted that bundle, and rewriting the URL + # would leave Windows mode spawning our asset instead of the + # original one. # SIL button rename + forwarder. Bypasses the TTS engine # bug where the click_function name "toggleSilhouettes" is @@ -2085,6 +2207,13 @@ def rng_repl(m): return n_coh, n_rng, n_dep +ASSETS_BASE_URL = ("https://raw.githubusercontent.com/ironsquadronfr-hub/tts/" + "mac-projector-fallback/mod/data/mac-fallback-assets/") +# Flip to https://raw.githubusercontent.com/swlegion/tts/main/mod/data/ +# mac-fallback-assets/ right before upstream merge, together with the Lua +# ASSETS_BASE copies (Overlays.ttslua + the inline copy in this file). + + def main(): args = [a for a in sys.argv[1:] if not a.startswith("--")] flags = [a for a in sys.argv[1:] if a.startswith("--")] @@ -2098,8 +2227,20 @@ def main(): with src.open("r") as f: data = json.load(f) - # Rename so the patched save is recognizable in TTS load list. - data["SaveName"] = "SWL BETA - MAC PATCH" + # Leave SaveName alone: the working save is regenerated from its clean + # backup on every iteration, and a "[MAC PATCH]" suffix reappeared in the + # TTS load list each time. Strip a suffix left by an earlier run. + name = data.get("SaveName") or "" + if name.endswith("[MAC PATCH]"): + data["SaveName"] = name[: -len("[MAC PATCH]")].rstrip() + + # Register the apple-logo UI sprite for the toggle button (idempotent + # by Name). + assets = [a for a in (data.get("CustomUIAssets") or []) + if a.get("Name") != "macAppleLogo"] + assets.append({"Type": 0, "Name": "macAppleLogo", + "URL": ASSETS_BASE_URL + "apple_logo.png"}) + data["CustomUIAssets"] = assets # 1. Append manager + handlers to Global LuaScript (idempotent: remove # any previous Mac patch block first, then append fresh). @@ -2128,33 +2269,6 @@ def main(): print(f" Save Name: {data.get('SaveName', '?').strip()}") print(f" Version: {data.get('VersionNumber', '?')}") - # Mirror to TTS Saves folder so it appears in Games -> Save & Load. - # Picks the next free TS_Save_N.json slot (TTS scans these on load). - saves_dir = Path.home() / "Library" / "Tabletop Simulator" / "Saves" - if saves_dir.exists(): - existing = sorted( - int(p.stem.split("_")[-1]) - for p in saves_dir.glob("TS_Save_*.json") - if p.stem.split("_")[-1].isdigit() - ) - # Reuse the highest existing slot if its content matches the prefix - # "SWL BETA - MAC PATCH"; else pick next free number. - target = None - for n in reversed(existing): - p = saves_dir / f"TS_Save_{n}.json" - try: - with p.open("r") as f: - if '"SWL BETA - MAC PATCH"' in f.read(512): - target = p - break - except OSError: - continue - if target is None: - next_n = (existing[-1] if existing else 0) + 1 - target = saves_dir / f"TS_Save_{next_n}.json" - with target.open("w") as f: - json.dump(data, f, indent=2, ensure_ascii=False) - print(f" Mirrored to: {target}") if reload_tts: print() From 3505b1172a8e8d0574272cdf6450f95961aa4047 Mon Sep 17 00:00:00 2001 From: Martin Pourrat Date: Wed, 12 Aug 2026 01:29:02 +0200 Subject: [PATCH 18/42] Add the functional spec for the four overlay families Written before swapping the renderer from flat decals to real Projectors, so the behaviour layer survives the change and can be checked in game afterwards. Covers range, cohesion, MaxMove and deployment, object by object; silhouettes and unit-ID tokens are out of scope now that their bundles are fixed. Records two divergences found while reading: mod/src RangeRulers.ttslua overrides spawnRangeRuler/clearRangeRulers on the ~20 token scripts, which is the pattern the patcher forbids after a reproducible TTS Mac crash, and it calls gClearAllRange/gClearAllMaxMove which the patcher engine does not define. The backport therefore runs the other way: align the source on the patcher, removing overrides rather than adding them. Co-Authored-By: Claude Opus 5 (1M context) --- mac-patcher/cahier-des-charges-overlays.md | 282 +++++++++++++++++++++ 1 file changed, 282 insertions(+) create mode 100644 mac-patcher/cahier-des-charges-overlays.md diff --git a/mac-patcher/cahier-des-charges-overlays.md b/mac-patcher/cahier-des-charges-overlays.md new file mode 100644 index 000000000..3a5f2b487 --- /dev/null +++ b/mac-patcher/cahier-des-charges-overlays.md @@ -0,0 +1,282 @@ +# Cahier des charges fonctionnel, overlays Iron Squadron + +Écrit le 12 août 2026, après la validation en jeu des projectors bi-plateforme. +À ce moment-là plus rien du fix de rendu ne passe par le Lua : notre couche devient un +module de confort, et on veut la reposer sur de vrais Projectors au lieu de décals plats. +Ce document décrit **ce que chaque objet doit faire**, pour que le changement de rendu ne +perde rien en silence, et pour servir de liste de recette en jeu après. + +**Périmètre** : les quatre familles qui passent par le toggle, à savoir **Range**, +**Cohésion**, **MaxMove** et **Déploiement**. Les silhouettes et les tokens de numéro +d'unité sont **hors périmètre** (arbitrage Martin, 12/08) : leurs bundles sont réparés, +donc le vanilla suffit et le contournement Lua n'a plus lieu d'être. + +**Source** : lecture du code, pas de la mémoire. Branche `mac-projector-fallback` pour +`mod/src`, et `mac-patcher/patch_save_for_mac.py` pour le moteur à jour. Les deux ne +disent pas la même chose partout, voir la section 9. + +## 0. Vocabulaire et architecture + +**Mode** : `overlayMode`, une seule valeur pour toute la table, `"windows"` (rendu +d'origine) ou `"mac"` (le nôtre). Lu par `gGetMode` et `gGetDeploymentMode`. Le per-seat +a été abandonné pour une raison structurelle : le Lua TTS ne tourne que chez l'hôte, et +tout overlay rendu est visible de tous les joueurs. + +**Registre** : `activeOverlays`, une entrée par overlay actif, clé +`":"` pour range, cohesion et maxmove, et +`"deploy:::"` pour le déploiement, qui n'a pas de figurine. + +**Les quatre familles** : + +| famille | porte sur | suit la figurine | déclenché par | +|---|---|---|---| +| range | figurine ou token | oui, en continu | bouton RANGE, raccourci de survol, bouton R d'un token | +| cohesion | figurine meneuse d'unité | oui, y compris pendant le drag | bouton COHESION, raccourci de survol | +| maxmove | figurine meneuse d'unité | **non**, ancré au départ | boutons MOVE, DEPLOY, 1, 2, 3, F, B, L, R | +| deployment | cellules de la table | sans objet | SETUP_CONTROLLER | + +## 1. Global, le gestionnaire (`StarWarsLegion.lua` + `!/Overlays`) + +**Rôle** : détient le registre, le mode, la boucle de suivi, et l'unique point de rendu. + +**API appelée par les objets** + +| fonction | effet attendu | +|---|---| +| `gRangeTrigger{figGUID}` | allume ou éteint la range de cette figurine, en respectant le mode | +| `gSpawnRange` / `gClearRange` / `gToggleRange` | manipulation directe d'une entrée range | +| `gCohesionTrigger{figGUID}` | idem pour la cohésion | +| `gSpawnCohesion` / `gClearCohesion` / `gToggleCohesion` | idem | +| `gSpawnMaxMove{figGUID, baseSize, speed}` | pose le gabarit de mouvement maximal | +| `gClearMaxMove{figGUID}` | retire celui de cette unité **seulement** | +| `gSpawnDeployment{cell, pos}` / `gClearAllDeployment` | zones de déploiement | +| `gGetMode` / `gGetDeploymentMode` | lisent `overlayMode` | + +**Raccourcis clavier** (`StarWarsLegion.lua`, lignes 603 et 614) + +1. « Show Range On Hovered Model » : `showRangeOnHoveredModel(hoverObject)`. Sémantique + vanilla conservée : survoler à nouveau le **même** objet éteint, via la comparaison + avec `selectedUnitObj`. +2. « Show Cohesion On Hovered Model » : `showCohesionOnHoveredModel(hoverObject)`, même + sémantique. +3. Le raccourci de range force le rendu « figurine meneuse » à toutes ses bandes, via + `params.forceFigMode`, même si l'objet survolé porte un `rangeKey`. + +**Boucle de suivi** `macRangePoll`, toutes les 5 images + +- Ne reconstruit **que** si une figurine suivie a réellement bougé, seuil 0,01 en + position et 0,5 degré en lacet. Sans ce test, le suivi faisait chuter la fréquence + d'affichage sur les figurines immobiles. +- S'arrête toute seule quand plus rien n'est suivi, pas de fuite. +- Ne suit que `range` et `cohesion`. **`maxmove` ne doit jamais être suivi.** + +**Nettoyage automatique** + +- `onObjectDestroy` purge toutes les entrées préfixées par le GUID de l'objet détruit. +- Une entrée dont la figurine n'est plus valide est éliminée au redessin suivant. + +**Basculement de mode** `macModeToggle` + +- Inverse `overlayMode`, efface les overlays des **deux** moteurs, puis rafraîchit le + bouton. La range vanilla vit dans le scope Global et n'est pas couverte par + `getAllObjects()`, elle doit être effacée explicitement. +- Le bouton vit dans `legionFloatingMenu`, gris par défaut comme ses voisins Welcome et + Chess Clock, vert à l'état actif. + +## 2. Order Token (`a57c41`) + +L'objet le plus chargé : il porte trois des quatre familles. + +### Bouton COHESION, `toggleCohesionRuler(_, playerColor)` + +| | comportement attendu | +|---|---| +| garde | ne fait rien si `selectedUnitObj` est nil | +| allumage | `gClearCohesion` **d'abord**, puis `gCohesionTrigger` | +| pourquoi le clear d'abord | `gCohesionTrigger` bascule par GUID. Un overlay laissé par le raccourci de survol faisait que le premier clic du bouton **éteignait** au lieu d'allumer | +| extinction | passe par le même déclencheur | + +### Bouton RANGE, `targetingMode(_, playerColor)` + +| | comportement attendu | +|---|---| +| garde | ne fait rien si `selectedUnitObj` est nil | +| allumage | `exitAttackMode`, `highlightEnemies`, puis `gClearRange` et `gRangeTrigger` | +| extinction | `gClearRange` **puis** `exitTargetingMode` | +| pourquoi le clear à l'extinction | `exitTargetingMode` et `clearRangeRulers` n'atteignent que la règle vanilla. Sans ce clear, nos anneaux restaient affichés en position OFF | + +### Boutons de mouvement, famille MaxMove + +Chaînes : `MOVE` vers `initMove` vers `moveUnit(false)`, `DEPLOY` vers `initDeploy` vers +`moveUnit(true)`, et `1` / `2` / `3` vers `changeSpeed1..3` qui appellent `clearTemplates` +puis `moveUnit()` **sans argument**. + +| | comportement attendu | +|---|---| +| condition de pose | `isDeploy ~= true`, condition permissive qui couvre nil **et** false. Une condition `isDeploy == false` raterait les appels des boutons de vitesse, qui n'ont pas d'argument. C'est le bug du « fill décalé au premier spawn » | +| ancrage | position **et** lacet capturés au moment de la pose. Le gabarit **ne suit pas** la figurine qui glisse vers sa destination. Le lacet compte pour les socles oblongs, dont l'anneau de base doit garder son orientation pendant que la figurine pivote | +| capture du joueur | chaque bouton stocke `playerColor` dans `macActivePlayerForMove`, hérité du per-seat. Sans objet depuis que le mode est global, à retirer un jour | +| nettoyage | `clearMovementTemplates` détruit `templateA`, `templateB`, l'objet `maxMoveTemplate` du mode vanilla, **et** appelle `gClearMaxMove` pour **cette unité seulement** | +| ⚠ portée du nettoyage | ne **jamais** revenir à un effacement global : `gClearAllMaxMove` supprimait les anneaux des autres tokens quand deux joueurs avaient MOVE ouvert en même temps | + +### Filtre de sol partagé, `macHitIsGround` + +Utilisé sur les six sites de lancer de rayon. Ignore les figurines, les objets en +mouvement, et le bundle nommé « Maximum Move » qui plane à +20 en mode vanilla. +Ce filtre **disparaît** avec les décals, voir section 8. + +## 3. Unit Leader (`99f1c8`) et l'include `!/Cohesion` + +**Rôle** : la figurine meneuse d'unité porte la cohésion. L'Order Token et le raccourci +de survol l'appellent tous les deux. + +**Vanilla** : `spawnCohesionRuler` choisit le bundle selon `unitData.baseSize` parmi +`small` (27 mm), `medium` (50 mm) et `large` (70 mm), pose un `Custom_AssetBundle` 20 +unités au-dessus de la figurine, à l'échelle 0 pour cacher la boîte TTS sans gêner le +Projector, verrouillé, sans gravité, nommé « Cohesion Ruler ». + +**Iron Squadron** + +| | comportement attendu | +|---|---| +| ⚡ suivi pendant le drag | la cohésion **reste visible et suit la figurine pendant qu'on la déplace**, comme la range. Arbitrage du 11/08, contraire au vanilla qui l'efface au ramassage | +| mise en œuvre | `gClearCohesion` **ignore** la demande tant que `fig.held_by_color` est vrai. Le seul appelant dans cet état est le `onPickedUp` vanilla | +| mode vanilla : toggle et non respawn | `spawnCohesionRuler` d'origine **respawne** au lieu de basculer. Sans interception, un deuxième clic la redessinait et elle ne s'éteignait jamais. On lit `fig.getVar("cohesionRuler")` pour connaître l'état réel | +| garde | l'objet survolé peut ne pas être une figurine et n'avoir aucune de ces fonctions. Le `pcall` retombe alors sur notre moteur | + +## 4. Les tokens à `rangeKey`, et le Bomb Cart + +**Objets concernés**, 19 fichiers plus le Bomb Cart, tous via `!/TokenWithRangeRuler` ou +un `require('!/RangeRulers')` direct : + +| `rangeKey` | objets | rendu attendu | +|---|---|---| +| `token` | Objectif et ses 4 états, Condition et ses 5 états, Cad Bane (3), Charge à protons, Complete the Mission | 1 anneau, portée 1, socle 25,1 mm | +| `smokeToken` | Fumée | 1 anneau, portée 1, socle 18,8 mm | +| `tokenRangeTwo` | Graffiti | 2 anneaux, portées 1 et 2 | +| `poi` | POI | 1 anneau à 3 pouces, portée 0,5, socle 50,8 mm soit un rayon de 1,000 pouce | +| `bombCart` | Bomb Cart | 2 anneaux, portées 1 et 2, socle 50 mm | + +**Deux rendus différents selon le déclencheur.** Le bouton R d'un token rend **son** +anneau, celui de sa fiche ci-dessus. Le **raccourci de survol**, lui, force le rendu +« figurine meneuse » à toutes ses bandes via `forceFigMode`, et le dimensionne avec le +socle équivalent le plus proche, pour que le joueur voie ce que verrait une unité de +cette empreinte : + +| token | socle équivalent au survol | +|---|---| +| Fumée, Objectif, Condition, Graffiti, Cad Bane, Charge à protons | `small` (27 mm) | +| **POI**, Bomb Cart | `medium` (50 mm) | + +**Interface** : deux boutons « R » identiques, l'un à la rotation 0 et l'autre à 180, +pour que le token soit utilisable sur ses deux faces. État booléen local `rangeOn`. +`onDestroy` efface la règle. + +**Comportement attendu** + +| | | +|---|---| +| mode vanilla | délègue à la fonction d'origine **aliasée avant surcharge**, pour que le token garde **son** bundle. Sans cet alias le token recevrait le bundle de figurine meneuse, ou rien du tout | +| mode Iron Squadron | bascule via `gClearRange` et `gRangeTrigger`, et tient `rangeOn` à jour | +| dimensionnement | la famille vient de `rangeKey`, lu sur la variable de l'objet | + +**⚠ Interdit, à ne jamais réintroduire** : surcharger `spawnRangeRuler`, +`clearRangeRulers` ou `clearRangeRuler` **sur les scripts de tokens**. Ça produisait un +plantage TTS reproductible sur Mac, dans le ramasse-miettes Mono, quand le raccourci +d'une figurine posait la règle vanilla. Le routage de la range passe par Global, pas par +les tokens. Le seul alias autorisé sur ces objets est `clearRangeRulersOriginal`, dont le +basculement de mode a besoin. + +## 5. SETUP_CONTROLLER (`1cb552`), zones de déploiement + +**Rôle** : pose les cellules de la zone de déploiement d'une mission. + +| | comportement attendu | +|---|---| +| point de branchement | `spawnBoundaryCell(cell, x, z)`, après le calcul de position, sur `gGetDeploymentMode` | +| mode vanilla | pose un `Custom_AssetBundle` nommé « Deployment Boundary », verrouillé, échelle 0, orienté par `deployRotations[cell]` | +| mode Iron Squadron | `gSpawnDeployment{cell, pos}` | +| nettoyage | `clearDeploymentBoundary` appelle `gClearAllDeployment` **d'abord**, puis détruit les objets nommés « Deployment Boundary » de la zone de bataille | +| couverture | les missions d'après mars (Cauldron, Contact Contact!, Outflank, Payload) sont **déjà couvertes**, matrices en cellules `r` et `b` plus inversion bleue, spawner unique routé. Rien à convertir | + +## 6. Les projectors qui ne passent PAS par le toggle + +Deux entrées du menu du GAME_CONTROLLER (`623b03`) posent des Projectors sans jamais +consulter `gGetMode`. Ils sont hors périmètre, mais il faut savoir qu'ils existent, sinon +on croit que le toggle couvre tous les projectors du mod. + +| entrée de menu | fonction | objet posé | bundle | état sur Mac | +|---|---|---|---|---| +| « Toggle Poi Guide » | `togglePoiGuide` | « Poi Guide », posé en `{8, 30, 0}` | `projector_poiguide` | **n'a jamais été cassé** : pas de shader custom | +| « Toggle Masks : Mid » et ses variantes gauche et droite | `toggleMaskMid` / `Right` / `Left` puis `placeMask(x, z)` | « Masking Boundary », 4 par appel, posés en y = 75 | `projector_masking_3x3` | **était magenta, réparé par le bundle bi-plateforme** | + +Ces deux familles servent à la **création de cartes**, pas au jeu. Elles tiennent leur +propre état, `existingPoiGuide` et la table `existingMasks`, et leur propre nettoyage, +`clearMasks`. Elles ne sont balayées par aucune des deux fonctions de la section suivante. + +**C'est la démonstration en miniature de la direction générale** : le masking était cassé +sur Mac, personne n'a jamais écrit une ligne de Lua pour lui, et il est réparé par le seul +remplacement de son bundle. + +## 7. Les balayeuses par nom, et pourquoi elles comptent + +Deux fonctions détruisent des objets **par leur nom** : + +- `standbyTokens` (`StarWarsLegion.lua`) : « Cohesion Ruler », « Movement Template », + « Range Ruler », « Deployment Boundary » ; +- `removeLockedRulers` (`GAME_CONTROLLER.623b03`) : « Cohesion Ruler » et « Range Ruler ». + +**⚠ Conséquence directe du passage aux Projectors.** Aujourd'hui nos overlays sont des +lignes et des décals, sans objet dans la scène : les deux balayeuses ne les voient pas, +et tout notre nettoyage passe par les `gClear*`. Dès qu'on posera de vrais objets +Projector, ils deviendront balayables par nom. C'est à décider explicitement, pas à +subir : soit on les nomme comme le vanilla et on hérite du nettoyage gratuitement, soit +on les nomme autrement et on garde la main. Le piège est de les nommer par accident. + +## 8. Ce qui disparaît avec les décals + +Tout ceci n'existe que parce qu'un décal est plat et ne sait pas épouser le relief. Un +Projector drape et suit tout seul, donc le changement **supprime** du code : + +- `macRayGroundY` et les lancers de rayon au sol, 64 par anneau, 32 par calotte de stade ; +- `macBuildRect`, `macBuildRing`, `macBuildStadium`, toute la géométrie à la main ; +- le cache de géométrie par entrée, qui n'existait que pour ne pas refaire 65 lancers de + rayon par image sur les overlays immobiles ; +- la coalescence du redessin, report d'une image plus signature triée, qui évitait de + reprojeter les décals et faisait sautiller les ombres ; +- le préchargement des PNG en décals invisibles sous la table, contre le flash de carré + blanc au respawn ; +- le filtre `macHitIsGround` ; +- la boucle `macRangePoll`, puisque le Projector vanilla suit déjà nativement. + +**⚠ Deux dépendances cachées à traiter avant de supprimer** + +1. Le **MaxMove ancré** (section 2) dépend du fait que rien ne le fasse suivre. Un + Projector suit son parent par nature : il faudra le poser **détaché**, à la position et + au lacet capturés. +2. Les **socles oblongs** sont aujourd'hui rendus en stade, rectangle plus deux calottes, + avec le lacet de la figurine. Le vanilla a ses propres bundles oblongs, désormais + réparés. À vérifier en jeu : est-ce qu'ils suffisent, ou est-ce qu'on garde notre + géométrie. + +## 9. Les deux divergences source contre patcher, à trancher + +Le moteur du patcher et la source de la branche ne disent pas la même chose. Le patcher +est celui qui a été validé en jeu. + +**Divergence 1, la plus grave.** `mod/src/includes/RangeRulers.ttslua` surcharge +`spawnRangeRuler`, `clearRangeRulers` et `clearRangeRuler` sur tous les objets qui +incluent le fichier, donc sur les 20 tokens. C'est **exactement le motif que le patcher +interdit** dans un commentaire « HISTORY, do not re-introduce », pour cause de plantage +TTS Mac reproductible. Le patcher, lui, n'y pose qu'un alias. La source de la branche +porte donc un plantage latent, et un backport naïf le ferait remonter. + +**Divergence 2.** La source appelle `gClearAllRange` et `gClearAllMaxMove`, qui existent +dans `Overlays.ttslua` mais **pas** dans le moteur du patcher, où l'effacement global de +MaxMove a été délibérément remplacé par un effacement ciblé sur l'unité, parce qu'il +supprimait les anneaux des autres joueurs. Ces appels sont donc soit sans effet, soit +porteurs du bug déjà corrigé. + +**Conséquence pratique** : le backport ne doit pas se faire dans le sens qu'on croyait. +Ce n'est pas « compléter la source avec ce que le patcher a en plus », c'est **aligner la +source sur le patcher**, y compris en retirant des surcharges qu'elle porte en trop. From 50c72c7c5a741805a76a7ee1d850399da1b26495 Mon Sep 17 00:00:00 2001 From: Martin Pourrat Date: Wed, 12 Aug 2026 02:39:43 +0200 Subject: [PATCH 19/42] Sign the overlay toggle with the Iron Squadron logo The toggle no longer compensates for a platform: the bi-platform bundles render on Metal, so it is now an optional set of enriched overlays that the club offers, off by default. The Apple logo had become misleading. - new sprite iron_squadron_logo.png, 128x128, white with the mark in the alpha channel so the button can tint it dark on grey and white on green; sized to fill 116 of the 128 px because the button is only 52 px wide and the wordmark turned to mush any smaller - CustomUIAsset renamed macAppleLogo -> isqLogo with a fresh file name, TTS caching UI sprites by URL - every player-facing string reworded, tooltips and the broadcast fired on each flip, with no mention of Mac left - MaxMove now wiped along with range and cohesion when the mode flips; it used to stay on screen, drawn by the renderer just left behind Co-Authored-By: Claude Opus 5 (1M context) --- mod/data/mac-fallback-assets/apple_logo.png | Bin 1442 -> 0 bytes .../iron_squadron_logo.png | Bin 0 -> 7606 bytes mod/src/StarWarsLegion.json | 4 +- mod/src/includes/Overlays.ttslua | 42 ++++++++++-------- 4 files changed, 25 insertions(+), 21 deletions(-) delete mode 100644 mod/data/mac-fallback-assets/apple_logo.png create mode 100644 mod/data/mac-fallback-assets/iron_squadron_logo.png diff --git a/mod/data/mac-fallback-assets/apple_logo.png b/mod/data/mac-fallback-assets/apple_logo.png deleted file mode 100644 index b7bf86f9adffa32286743c2d797554d25bc7b95c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1442 zcmZ`(`9IVN0R4VvFih^+M7fO^VL$F6M`j#fw{hi&Da^Q5v##tGhDsA{MF{I!CPf-Y zsA!t8j>?dBEY%efmA>O03ZQ5;_%;{azIg$ z@7if~o(%xPkr3{TcXG+sDgU}DuOqM5W}^CQinF9S6?iPJ?f7>cR|#kiE<@UuTF5wd;f;@7^APf;Lco=9HuG0w29G&{*=BC-?^z9; zn=e`~wQLvk{Sb8q|0E)!;4wP$#~_3=@3dOkQk%Pp7$r2lo24(9U8D2Eu_7mgUcTwk z^_{CuoJy~w07spE_v46#UWsWzKl2|^d?PxF=U{W+jdwX%m(ujc!oX^{a|9`PWVZ!` z$6mzju$>zcrb3RZa5cCC1t8hspn$ak1+6Cp<>}{!;Hk)+*Qi|L<5D}B#>zR;lg##1 zLO44l?X9d~`|?u>X>u&PV;^otU)&p~fOlGs3F6|DJx5YnRDpt)ow@RvMC)HfDNh1} zzPT^8m78d==%M0*0B$V7ek7$?6-JExc~u$y47ePHB%h(~NoKt0?;16gS-V<&H&_TD zKc`ip6w#5UkcA`9hto^!Sr&%s9lFNFTGMcbs30Y9JIBbGlaxE`$n)jg&$TMp$fSKy z|Cis9=FFEP$Z<6Z*OFc#mO;trvAy8gn6wQ>=V6xM;}>32tYC?fytYdg81m1W_dtMpEw=q z%iZX3f=IZoXeW($|DAkG1%bYXqO#1~bx*XmA>c9HqV<$@_o+-{5{XHD*WqUfhSHO+7A|7(q?CBEv^+f`ykcKKEJS_ zfm|u&=83`!+dN%)r(Zi0#7*{5@d1pi{H!M*A;ZKec+qjhH}*8vNiP(5`C#w41>XuT z4_8SP8#2r9e&}3`)x`InmB#ZnTwV3O0z@`zWIT~}c<4T;R{7E)&3@Owoikz6mMA$7 zt5|F1k&?8Ngy{$qKiPRbuu3xK?DV~bibkbGb{RNO8>($+gA-`Zdv1=LfcQG;dGZy& z?S-+!9hrmEmvOkaaiva0U=~#?8$0b~&A5Ah)eB)WtG79r;-vN!Mfjius^{XFuE!rX z)pM7qT8A7g?wiAnvUOs8n3F}}tAiwpr$4tUCh)O~$8Vi4F5+lK>u#l>eRz68d$j9& z<027emUx5GYJzLNN$4p#orx|QTE1Qz*osNobg_84rQBP;$EEJLyrnUP>f~fXpf>Ns zHuNmlPb`_zcFOm{P!Mbw-l~0h->>QVq$8$NMJ?4Ee-LI6JEhhDeF&?ZHy%tD`q=WY*i1e j;P_zXP;1eT(X%DTA1XF~5mDIv{d)n(&J9PmC1m^$(xI@x diff --git a/mod/data/mac-fallback-assets/iron_squadron_logo.png b/mod/data/mac-fallback-assets/iron_squadron_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..1d0a9b4a431b840e852ffb56b8ef0434ace4d62a GIT binary patch literal 7606 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 QpN|F9m9^n@iZ&7d1K%7_YXATM literal 0 HcmV?d00001 diff --git a/mod/src/StarWarsLegion.json b/mod/src/StarWarsLegion.json index fc3045292..264382bc2 100644 --- a/mod/src/StarWarsLegion.json +++ b/mod/src/StarWarsLegion.json @@ -319,8 +319,8 @@ "URL": "http://cloud-3.steamusercontent.com/ugc/966480765118137238/1157F7217EB80F31A92427567B377F857576DAE9/" }, { - "Name": "macAppleLogo", - "URL": "https://raw.githubusercontent.com/ironsquadronfr-hub/tts/mac-projector-fallback/mod/data/mac-fallback-assets/apple_logo.png" + "Name": "isqLogo", + "URL": "https://raw.githubusercontent.com/ironsquadronfr-hub/tts/mac-projector-fallback/mod/data/mac-fallback-assets/iron_squadron_logo.png" } ], "ObjectStates": [] diff --git a/mod/src/includes/Overlays.ttslua b/mod/src/includes/Overlays.ttslua index 844c8cc9d..aa0ebaada 100644 --- a/mod/src/includes/Overlays.ttslua +++ b/mod/src/includes/Overlays.ttslua @@ -625,13 +625,13 @@ end -- URLs as invisible decals far below the table. No separate preload needed. -- ============================================ --- TABLE-WIDE MODE TOGGLE (Cohesion + Range + Deployment) --- One switch for the whole table: "windows" (original bundle Projectors) or --- "mac" (this patch). Per-seat modes were dropped on purpose: any rendered --- overlay is visible to every player (TTS engine limitation), so a Windows --- player triggering an original Projector still shows magenta to Mac --- players. The switch is the Apple-logo button in the bottom-right menu: --- default grey = off (originals), green = on (Mac-safe fallback). +-- TABLE-WIDE OVERLAY TOGGLE (Cohesion + Range + Deployment) +-- One switch for the whole table: "windows" (the mod's original Projectors) +-- or "mac" (the Iron Squadron overlays). Per-seat modes were dropped on +-- purpose: any rendered overlay is visible to every player (TTS engine +-- limitation), so one player triggering an original Projector shows it to +-- the whole table anyway. The switch is the Iron Squadron button in the +-- bottom-right menu: default grey = off (originals, untouched), green = on. -- ============================================ overlayMode = overlayMode or "windows" -- "windows" | "mac", table-wide @@ -700,9 +700,12 @@ end function macModeToggle(_, _, _) overlayMode = (overlayMode == "mac") and "windows" or "mac" -- Wipe both renderers' overlays so stale visuals don't linger after the - -- toggle; each player just re-triggers their hotkey. + -- toggle; each player just re-triggers their hotkey. Deployment is + -- deliberately spared: those zones are laid out once at setup and only + -- SETUP_CONTROLLER can put them back, so wiping them on a toggle click + -- would cost the table its board for a cosmetic reason. for k, e in pairs(activeOverlays) do - if e.type == "cohesion" or e.type == "range" then + if e.type == "cohesion" or e.type == "range" or e.type == "maxmove" then activeOverlays[k] = nil end end @@ -720,8 +723,8 @@ function macModeToggle(_, _, _) pcall(clearRangeRulersOriginal) macWinRangeGUID = nil broadcastToAll( - (overlayMode == "mac") and "Mac patch ON: Mac-safe overlays for the whole table." - or "Mac patch OFF: original Windows overlays.", + (overlayMode == "mac") and "Iron Squadron overlays ON for the whole table." + or "Iron Squadron overlays OFF: the mod's original overlays are back.", (overlayMode == "mac") and {0.55, 0.9, 0.6} or {0.9, 0.75, 0.55}) macDeferRefresh() end @@ -737,7 +740,8 @@ local function macFindNodeById(tree, id) return nil, nil end --- UI: single Apple-logo toggle button in the bottom-right legionFloatingMenu. +-- UI: single Iron Squadron toggle button in the bottom-right +-- legionFloatingMenu. function macRefreshModeUI() local tree = UI.getXmlTable() or {} -- Drop the legacy mode-picker panel if this save still carries one. @@ -753,8 +757,8 @@ function macRefreshModeUI() id = "macModeMenuButton", onClick = "macModeToggle", tooltip = isMac - and "Mac TTS U6 patch ON (table-wide). Click for original overlays." - or "Mac TTS U6 patch OFF. Click for Mac-safe overlays (table-wide).", + and "Iron Squadron overlays: ON for the whole table. Click to go back to the mod's original overlays." + or "Iron Squadron overlays: OFF, the mod's original overlays are in use. Click to turn them on for the whole table.", } -- OFF keeps the sibling buttons' default light-grey look (Welcome, -- Chess Clocks); ON switches to green. @@ -763,13 +767,13 @@ function macRefreshModeUI() tag = "Button", attributes = attrs, children = {{ - -- White PNG sprite (CustomUIAssets "macAppleLogo"), tinted - -- per state: dark on the grey button, white on green. A text - -- U+F8FF glyph would render as a missing-glyph box on - -- Windows clients. + -- White PNG sprite (CustomUIAssets "isqLogo"), tinted per + -- state: dark on the grey button, white on green. The shape + -- lives in the alpha channel, which is what makes the tint + -- work. tag = "Image", attributes = { - image = "macAppleLogo", + image = "isqLogo", color = isMac and "#FFFFFF" or "#2b2b2b", preserveAspect = "true", raycastTarget = "false", From 1b6c3a2974e2b1e09bb70f5c9357873124bb0422 Mon Sep 17 00:00:00 2001 From: Martin Pourrat Date: Wed, 12 Aug 2026 02:40:14 +0200 Subject: [PATCH 20/42] Take deployment zones out of the toggle Their bundles are repaired, so the vanilla Projector renders correctly on both platforms and the dual path has no reason to exist. spawnBoundaryCell and clearDeploymentBoundary go back to the exact upstream text, restored from origin/main rather than retyped. The toggle's scope is now three families: range, cohesion, MaxMove. The spec's section 5 is kept but marked obsolete, as the record of what the removed path used to do. Co-Authored-By: Claude Opus 5 (1M context) --- mac-patcher/cahier-des-charges-overlays.md | 17 +++++++--- .../SETUP_CONTROLLER.1cb552.lua | 32 +++++++------------ 2 files changed, 23 insertions(+), 26 deletions(-) diff --git a/mac-patcher/cahier-des-charges-overlays.md b/mac-patcher/cahier-des-charges-overlays.md index 3a5f2b487..6b242438e 100644 --- a/mac-patcher/cahier-des-charges-overlays.md +++ b/mac-patcher/cahier-des-charges-overlays.md @@ -6,10 +6,12 @@ module de confort, et on veut la reposer sur de vrais Projectors au lieu de déc Ce document décrit **ce que chaque objet doit faire**, pour que le changement de rendu ne perde rien en silence, et pour servir de liste de recette en jeu après. -**Périmètre** : les quatre familles qui passent par le toggle, à savoir **Range**, -**Cohésion**, **MaxMove** et **Déploiement**. Les silhouettes et les tokens de numéro -d'unité sont **hors périmètre** (arbitrage Martin, 12/08) : leurs bundles sont réparés, -donc le vanilla suffit et le contournement Lua n'a plus lieu d'être. +**Périmètre** : les **trois** familles qui passent par le toggle, à savoir **Range**, +**Cohésion** et **MaxMove**. Les silhouettes, les tokens de numéro d'unité et **les +zones de déploiement** en sont **sortis** (arbitrage Martin, 12/08) : leurs bundles sont +réparés, donc le vanilla suffit et le contournement Lua n'a plus lieu d'être. Le code +correspondant a été retiré du patcher et de `mod/src` le soir même. **La section 5 +ci-dessous est donc caduque**, elle est conservée pour mémoire du comportement retiré. **Source** : lecture du code, pas de la mémoire. Branche `mac-projector-fallback` pour `mod/src`, et `mac-patcher/patch_save_for_mac.py` pour le moteur à jour. Les deux ne @@ -187,7 +189,12 @@ d'une figurine posait la règle vanilla. Le routage de la range passe par Global les tokens. Le seul alias autorisé sur ces objets est `clearRangeRulersOriginal`, dont le basculement de mode a besoin. -## 5. SETUP_CONTROLLER (`1cb552`), zones de déploiement +## 5. SETUP_CONTROLLER (`1cb552`), zones de déploiement — CADUQUE + +⚠ **Sorti du toggle le 12/08 au soir.** `spawnBoundaryCell` et `clearDeploymentBoundary` +sont revenus au vanilla exact dans `mod/src`, et le patcher n'injecte plus rien ici : les +zones se posent comme dans le mod d'origine, sur les deux plateformes, leur bundle étant +réparé. La section reste pour mémoire de ce que faisait le double chemin. **Rôle** : pose les cellules de la zone de déploiement d'une mission. diff --git a/mod/src/StarWarsLegion/SETUP_CONTROLLER.1cb552.lua b/mod/src/StarWarsLegion/SETUP_CONTROLLER.1cb552.lua index 6878e6400..8c407c4c3 100644 --- a/mod/src/StarWarsLegion/SETUP_CONTROLLER.1cb552.lua +++ b/mod/src/StarWarsLegion/SETUP_CONTROLLER.1cb552.lua @@ -251,24 +251,17 @@ function spawnBoundaryCell(cell, x, z) pos = AddVectors(pos, offset) - -- Mac fallback dual-path: branch on the table-wide mode toggle (gGetDeploymentMode). - local _macDeployMode = Global.call("gGetDeploymentMode") - local projector = nil - if _macDeployMode == "windows" then - projector = spawnObject({ - type = "Custom_AssetBundle", - position = pos, - scale = {0, 0, 0}, - rotation = {0, deployRotations[cell], 0} - }) - projector.setName("Deployment Boundary") - projector.setLock(true) - projector.setCustomObject({ - assetbundle = asset, - }) - else - Global.call("gSpawnDeployment", { cell = cell, pos = pos }) - end + local projector = spawnObject({ + type = "Custom_AssetBundle", + position = pos, + scale = {0, 0, 0}, + rotation = {0, deployRotations[cell], 0} + }) + projector.setName("Deployment Boundary") + projector.setLock(true) + projector.setCustomObject({ + assetbundle = asset, + }) end function spawnDeploymentBoundary(matrix) @@ -321,9 +314,6 @@ function spawnDeploymentBoundary(matrix) end function clearDeploymentBoundary() - -- Mac fallback: clear Global Overlays manager entries first (no-op if - -- deployment ran in Windows mode and no Mac entries exist). - Global.call("gClearAllDeployment", {}) local battlefieldObjs = battlefieldZone.getObjects() for _, obj in pairs(battlefieldObjs) do if obj.getName() == "Deployment Boundary" then From a8184426264f26c8e5b757e6bd629f508ffa7d46 Mon Sep 17 00:00:00 2001 From: Martin Pourrat Date: Wed, 12 Aug 2026 03:07:38 +0200 Subject: [PATCH 21/42] Reframe the Iron Squadron button sprite Martin's placement reference: the mark needs breathing room and reads off-centre. Two changes, on a fresh file name because TTS caches UI sprites by URL and the old one is already in his client. - content down to 100 of the 128 px, so roughly 11% of margin - centred on the alpha's centre of mass rather than its bounding box. The wordmark is dense on the right and the outline thin on the left, which put the mass 4.4% right of the geometric centre and made the whole thing read as shoved right. Margins land at 10 left / 18 right, matching the framing of the reference. Co-Authored-By: Claude Opus 5 (1M context) --- .../mac-fallback-assets/iron_squadron_logo.png | Bin 7606 -> 0 bytes .../iron_squadron_logo_v2.png | Bin 0 -> 6386 bytes mod/src/StarWarsLegion.json | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) delete mode 100644 mod/data/mac-fallback-assets/iron_squadron_logo.png create mode 100644 mod/data/mac-fallback-assets/iron_squadron_logo_v2.png diff --git a/mod/data/mac-fallback-assets/iron_squadron_logo.png b/mod/data/mac-fallback-assets/iron_squadron_logo.png deleted file mode 100644 index 1d0a9b4a431b840e852ffb56b8ef0434ace4d62a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7606 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 QpN|F9m9^n@iZ&7d1K%7_YXATM diff --git a/mod/data/mac-fallback-assets/iron_squadron_logo_v2.png b/mod/data/mac-fallback-assets/iron_squadron_logo_v2.png new file mode 100644 index 0000000000000000000000000000000000000000..268e398b04726b7d062ace9dbb27853d708b406c GIT binary patch literal 6386 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 literal 0 HcmV?d00001 diff --git a/mod/src/StarWarsLegion.json b/mod/src/StarWarsLegion.json index 264382bc2..f4f71c161 100644 --- a/mod/src/StarWarsLegion.json +++ b/mod/src/StarWarsLegion.json @@ -320,7 +320,7 @@ }, { "Name": "isqLogo", - "URL": "https://raw.githubusercontent.com/ironsquadronfr-hub/tts/mac-projector-fallback/mod/data/mac-fallback-assets/iron_squadron_logo.png" + "URL": "https://raw.githubusercontent.com/ironsquadronfr-hub/tts/mac-projector-fallback/mod/data/mac-fallback-assets/iron_squadron_logo_v2.png" } ], "ObjectStates": [] From afaad1ab145af09054f1f38c4462fc9b4884122d Mon Sep 17 00:00:00 2001 From: Martin Pourrat Date: Wed, 12 Aug 2026 03:20:21 +0200 Subject: [PATCH 22/42] Write down what we would offer upstream, before building it Two gaps found while fixing the Metal rendering, neither of them macOS specific: cohesion is missing on 35 units because only three base sizes have a bundle, and the same range-0.5 offset could be shown on the range template. Written as a validation request rather than a plan: what is missing, what it would cost, what it changes for players, and the one question we cannot answer for them, whether an enriched template should reach everyone or stay behind the opt-in button. Co-Authored-By: Claude Opus 5 (1M context) --- mac-patcher/proposals-upstream.md | 108 ++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 mac-patcher/proposals-upstream.md diff --git a/mac-patcher/proposals-upstream.md b/mac-patcher/proposals-upstream.md new file mode 100644 index 000000000..a0487b690 --- /dev/null +++ b/mac-patcher/proposals-upstream.md @@ -0,0 +1,108 @@ +# Proposals for the maintainers, before we spend the time + +Iron Squadron, 12 August 2026. + +Everything below is **work we are offering to do**, not work we have done. We +would rather hear "no thanks" now than hand you a pull request you never asked +for. Each item says what is missing today, what it would cost us, and what it +changes for players. + +Context, in one line: we rebuilt the mod's custom-shader bundles so they carry a +Metal SubShader alongside the DirectX one, which fixes the magenta Projectors on +macOS. Working through that, we ran into two gaps that have nothing to do with +macOS. They affect Windows players exactly the same way. + +--- + +## 1. Cohesion is missing on 35 units + +`getCohesionLinks()` ships three bundles: 27 mm, 50 mm and 70 mm. +`spawnCohesionRuler` ends with + +```lua +if cohesionBundleToSpawn == nil then return end +``` + +so on any other base the cohesion ruler simply does not appear. Counting the +`size` field across `contrib/cards`: + +| base size | units | examples | +|---|---|---| +| `huge` (100 mm) | 16 | T-47 Airspeeder, AT-ST | +| `epic` (150 mm) | 12 | AT-AP, LAAT/i Gunship | +| `long` (100 mm oblong) | 3 | A-A5 Speeder Truck, Occupier Tank | +| `laat` (120 mm) | 2 | LAAT/LE Patrol Transport | +| `snail` (100×200 mm oblong) | 2 | Persuader-Class Tank Droid | + +**What we would build.** Cohesion is the base outline offset outwards by range +0.5, whatever the base's shape. That is not our interpretation, it is what the +existing bundles measure: their radii are 3.531, 3.984 and 4.378 inches for 27, +50 and 70 mm bases, i.e. the base radius plus **3.000 inches** in all three +cases. + +The three missing round sizes are nearly free: `BB_CohesionProjector.shader` is +procedural, driven by `_BaseSize`, so each one is a material and a prefab, with +no new art. + +The two oblong sizes need a shader that offsets a stadium rather than a circle, +and that maths already exists in this repo: `BB_OblongRangeProjector.shader` +takes a `_BaseCenterPointGap`. A cohesion variant is a merge of two shaders you +already own. + +**Cost to you: none.** We build, we test on both platforms, you review. + +--- + +## 2. The range template could carry the cohesion ring + +Same measurement, shown where players already look. A thin white ring at range +0.5 from the base edge, added to `BB_RangeProjector` and its oblong variant, on +the eight unit-leader sizes. Not on tokens: an objective or a POI is not a unit, +so cohesion means nothing there. + +This one is a genuine change to something that already works, so it is the item +we most want your opinion on before touching it. + +--- + +## 3. The question underneath both: opt-in or for everyone? + +We also maintain a small Lua layer that adds behaviours the vanilla mod does not +have — cohesion that follows a model while it is being dragged, range and +cohesion toggles that are deterministic instead of respawning, a maximum-move +template anchored where the move started. It sits behind a single table-wide +button, off by default, and it leaves the original mod strictly untouched when +off. + +Rendering, however, no longer goes through that layer: it is in the bundles now. +So an enriched range template would be seen by **everyone, in both button +states**. Keeping it optional means publishing a second set of range bundles for +the button to select, which roughly doubles what we produce. + +Three ways to go, and it is your call: + +1. **For everyone.** Simplest, and hard to argue against for item 1, since the + vanilla mod shows nothing at all on those 35 units today. +2. **Behind the button.** Nothing imposed, players compare and decide. More work + on our side, and we are fine with that. +3. **Item 1 for everyone, item 2 behind the button.** Our own preference: the + missing cohesion is a gap to fill, the enriched range template is a taste + question. + +--- + +## Separately, two upstream bugs we already carry a fix for + +Neither is macOS-specific and neither needs a decision from you. Say the word +and we will send them as their own small pull request. + +- `clearSilhouette()` dereferences `removeAttachments()[1]` without checking it. + `silhouetteState` survives a save reload while the physical attachments do + not, so loading a game saved with silhouettes up and clicking SIL crashes the + object's script. +- The SIL and LCK buttons land on top of the model on `long` and `snail` bases: + `calculateButtonZOffset` uses a single per-size radius with no axis handling. + +--- + +Contact: Iron Squadron, French Star Wars Legion association — https://iron-squadron.fr From 5c7d4b6f865dfa6c8ed846b177c9bb863d8b76ac Mon Sep 17 00:00:00 2001 From: Martin Pourrat Date: Wed, 12 Aug 2026 03:35:10 +0200 Subject: [PATCH 23/42] mac-patcher: render overlays with real Projectors Replaces the flat-decal renderer with one real Unity Projector per active overlay. A Projector drapes over table relief and tracks its figure natively, so the ground raycasts, the hand-built ring and stadium geometry, the per-entry cache, the coalesced redraw signature and the PNG preload all go away with it: 748 lines become 215. Every removal now goes through macRemove, which destroys the Projector before forgetting the entry, otherwise each click leaks an object. The Projectors carry the vanilla names on purpose, so the mod's own sweepers clean them up for free; when a sweeper destroys one we treat the overlay as switched off rather than respawning behind it. Also drops what left the toggle's scope: the unit-ID token numbers, the Mac silhouette renderer, and the deployment dual path. NOT yet validated in game. The first live run turned up two problems, one fixed here (the token R button lacked the clear-before-trigger rule, so a leftover hover overlay inverted it) and one that is a gap in the mod itself (only three base sizes have a cohesion bundle). Co-Authored-By: Claude Opus 5 (1M context) --- mac-patcher/patch_save_for_mac.py | 1395 +++++------------------------ 1 file changed, 246 insertions(+), 1149 deletions(-) diff --git a/mac-patcher/patch_save_for_mac.py b/mac-patcher/patch_save_for_mac.py index 47890d282..240b9abe1 100644 --- a/mac-patcher/patch_save_for_mac.py +++ b/mac-patcher/patch_save_for_mac.py @@ -44,113 +44,25 @@ activeOverlays = activeOverlays or {} -local ASSETS_BASE = "https://raw.githubusercontent.com/ironsquadronfr-hub/tts/mac-projector-fallback/mod/data/mac-fallback-assets/" -local COHESION_HALO_URL = ASSETS_BASE .. "cohesion_halo.png" -local MAX_MOVE_CYAN_URL = ASSETS_BASE .. "max_move_cyan.png" -local DEPLOYMENT_RED_URL = ASSETS_BASE .. "deployment_red.png" -local DEPLOYMENT_BLUE_URL = ASSETS_BASE .. "deployment_blue.png" -local RANGE_DECAL_URLS = { - smokeToken = ASSETS_BASE .. "range_smokeToken.png", - token = ASSETS_BASE .. "range_token.png", - tokenRangeTwo = ASSETS_BASE .. "range_tokenRangeTwo.png", - poi = ASSETS_BASE .. "range_poi.png", - bombCart = ASSETS_BASE .. "range_bombCart.png", - -- Fig leaders: per-base-size PNGs (bands pre-offset by the base radius so - -- the decal bands line up with the vector-line rings). - fig_leader = { - small = ASSETS_BASE .. "range_fig_leader_small.png", - medium = ASSETS_BASE .. "range_fig_leader_medium.png", - large = ASSETS_BASE .. "range_fig_leader_large.png", - huge = ASSETS_BASE .. "range_fig_leader_huge.png", - laat = ASSETS_BASE .. "range_fig_leader_laat.png", - epic = ASSETS_BASE .. "range_fig_leader_epic.png", - long = ASSETS_BASE .. "range_fig_leader_long_stadium.png", - snail = ASSETS_BASE .. "range_fig_leader_snail_stadium.png", - }, -} -local RANGE_MAX_RADIUS = { - fig_leader = 30, -- R5 max - -- SWL: Range 1 = 6", Range 2 = 12", Range 0.5 = 3". - smokeToken = 6, - token = 6, - tokenRangeTwo = 12, - poi = 3, - bombCart = 12, -} - --- Range band colors (RGBA) extracted from BB_RangeProjector material defaults --- + demi-portee blanche pour SWL Range 0.5 (3 inches) -local RANGE_COLORS = { - half = {1.0, 1.0, 1.0, 0.6}, -- 0.5 = 3" white - one = {1.0, 0.764, 0.0, 0.7}, -- R1 yellow - two = {1.0, 0.459, 0.0, 0.7}, -- R2 orange - three = {1.0, 0.079, 0.0, 0.7}, -- R3 red - four = {0.764, 0.0, 0.259, 0.7}, -- R4 magenta - five = {0.528, 0.0, 0.443, 0.7}, -- R5 violet -} - --- Per-rangeKey configurations: list of {radius_inches, color_name} -local RANGE_CONFIGS = { - -- Fig leaders: half + 4 bands at SWL standard ranges 3/6/12/18/24" - small = {{r=3,c="half"},{r=6,c="one"},{r=12,c="two"},{r=18,c="three"},{r=24,c="four"},{r=30,c="five"}}, - medium = {{r=3,c="half"},{r=6,c="one"},{r=12,c="two"},{r=18,c="three"},{r=24,c="four"},{r=30,c="five"}}, - large = {{r=3,c="half"},{r=6,c="one"},{r=12,c="two"},{r=18,c="three"},{r=24,c="four"},{r=30,c="five"}}, - huge = {{r=3,c="half"},{r=6,c="one"},{r=12,c="two"},{r=18,c="three"},{r=24,c="four"},{r=30,c="five"}}, - laat = {{r=3,c="half"},{r=6,c="one"},{r=12,c="two"},{r=18,c="three"},{r=24,c="four"},{r=30,c="five"}}, - epic = {{r=3,c="half"},{r=6,c="one"},{r=12,c="two"},{r=18,c="three"},{r=24,c="four"},{r=30,c="five"}}, - long = {{r=3,c="half"},{r=6,c="one"},{r=12,c="two"},{r=18,c="three"},{r=24,c="four"},{r=30,c="five"}}, - snail = {{r=3,c="half"},{r=6,c="one"},{r=12,c="two"},{r=18,c="three"},{r=24,c="four"},{r=30,c="five"}}, - -- Token rangeKeys (1 to 2 bands depending on use). SWL ranges in inches: - -- Range 1 = 6", Range 2 = 12", Range 0.5 (poi) = 3". - smokeToken = {{r=6,c="one"}}, - token = {{r=6,c="one"}}, - tokenRangeTwo = {{r=6,c="one"},{r=12,c="two"}}, - poi = {{r=3,c="one"}}, - bombCart = {{r=6,c="one"},{r=12,c="two"}}, -} - --- Base footprint dimensions in mm. width <= length; equal means round. --- Used to drive round vs stadium overlay shape. -local BASE_DIMENSIONS = { - small = {width = 27, length = 27}, - medium = {width = 50, length = 50}, - large = {width = 70, length = 70}, - huge = {width = 100, length = 100}, - laat = {width = 120, length = 120}, - epic = {width = 150, length = 150}, - long = {width = 100, length = 175}, -- oblong - snail = {width = 100, length = 200}, -- oblong -} - --- Base radius (inches) for round overlays. For oblong bases we use a --- stadium shape instead (see macBuildStadium), so the radius here is the --- half-width that drives the cap arcs. -local FIG_BASE_RADIUS_IN = {} -for k, d in pairs(BASE_DIMENSIONS) do - FIG_BASE_RADIUS_IN[k] = (d.width / 2) / 25.4 -end - -local function macIsOblong(baseSize) - local d = BASE_DIMENSIONS[baseSize] - return d ~= nil and d.length > d.width -end - --- Returns the stadium half-dimensions (inches) and yaw for an oblong base, --- or nil if the fig's base is round. Callers should branch on the return. -local function macOblongDims(fig, baseSize) - if not macIsOblong(baseSize) then return nil end - local d = BASE_DIMENSIONS[baseSize] - return { - halfLen = (d.length / 2) / 25.4, - halfWid = (d.width / 2) / 25.4, - rotY = fig.getRotation().y, - } -end +-- ============================================ +-- RENDERER: one real Unity Projector per active overlay. +-- +-- Replaces the flat-decal renderer. A Projector drapes over table relief and +-- tracks its figure natively, so the ground raycasts, the hand-built +-- ring/rect/stadium geometry, the per-entry geometry cache, the coalesced +-- redraw signature and the PNG preload all went away with it. +-- +-- What this layer still owns, and the vanilla mod does not: +-- * cohesion stays visible and FOLLOWS the figure during a drag; +-- * toggles are deterministic (see gRangeTrigger / gCohesionTrigger); +-- * MaxMove is anchored where the move STARTED and never follows. +-- Spec: mac-patcher/cahier-des-charges-overlays.md +-- ============================================ -- Resolve baseSize for a fig. The mod stores it as a script-local Var on the -- fig itself (set at spawn from the unit's container). unitData.baseSize is --- only populated on the Unit Leader, not on minis/vehicles - so getVar is --- the canonical read, with unitData as fallback for safety. +-- only populated on the Unit Leader, not on minis/vehicles, so getVar is the +-- canonical read with unitData as a fallback. local function macGetBaseSize(fig) if not fig then return nil end local ok, bs = pcall(function() return fig.getVar("baseSize") end) @@ -160,24 +72,9 @@ return nil end -local function macFigBaseRadius(fig) - if not fig then return 0.5315 end - local bs = macGetBaseSize(fig) - return (bs and FIG_BASE_RADIUS_IN[bs]) or 0.5315 -end - --- Token base radii (inches) - measured from token edge for range bands -local TOKEN_BASE_RADIUS = { - smokeToken = 18.8 / 2 / 25.4, -- 0.370" - token = 25.1 / 2 / 25.4, -- 0.494" - tokenRangeTwo = 25.1 / 2 / 25.4, -- 0.494" - poi = 50.8 / 2 / 25.4, -- 1.000" - bombCart = 50.0 / 2 / 25.4, -- 0.984" -} - --- Hotkey-driven range on tokens renders fig-leader-style bands using the --- closest equivalent base size (so the visual matches what a unit of that --- footprint would see). Token R button keeps the single ring (token-spec). +-- A token has no baseSize of its own. When the hover hotkey asks for the full +-- fig-leader bands on a token, size them with the closest equivalent +-- footprint. The token's own R button keeps its single-ring bundle. local TOKEN_TO_BASESIZE = { smokeToken = "small", token = "small", @@ -186,604 +83,169 @@ bombCart = "medium", } --- Maximum Move radii (inches), indexed by baseSize then speed 1..3 --- Source: ProjectorRadius from BB_MovementProjector materials (single variants) -local MAX_MOVE_RADIUS = { - small = { 4.547244, 6.515748, 8.484252}, -- 27mm - medium = { 5.669292, 7.637795, 9.606299}, -- 50mm - large = { 6.850394, 8.818897, 10.787401}, -- 70mm - huge = { 8.622047, 10.590551, 12.559055}, -- 100mm - laat = { 9.803149, 11.771653, 13.740157}, -- 120mm - epic = {11.574803, 13.543307, 15.511811}, -- 150mm - long = {13.051181, 15.019685, 16.988190}, -- oblong - snail = {14.527559, 16.496063, 18.464567}, -- snail -} - --- Deployment cell dimensions (width X, depth Z, inches). --- All cells live on a 6"x6" grid; sub-cells are halves/quarters of that cell. -local DEPLOYMENT_CELL_SIZES = { - r = {6, 6}, b = {6, 6}, -- full cell - rl = {6, 6}, bl = {6, 6}, -- large variant (also full cell) - rh = {6, 3}, bh = {6, 3}, -- horizontal half (3" deep) - rs = {3, 6}, bs = {3, 6}, -- vertical half (3" wide), x-offset +1.5 - rss = {3, 6}, bss = {3, 6}, -- vertical half (3" wide), x-offset -1.5 - rc = {3, 3}, bc = {3, 3}, -- corner quarter - rcc = {3, 3}, bcc = {3, 3}, -- opposite corner quarter +-- Per family: the name TTS gives the spawned object, whether it tracks its +-- figure, and the pitch the vanilla spawn uses. +-- +-- The names are deliberately the vanilla ones. standbyTokens (Global) and +-- removeLockedRulers (GAME_CONTROLLER) sweep by name, so our Projectors +-- inherit the mod's own cleanup; the decal renderer had no objects at all and +-- was invisible to both. +local PROJECTOR_SPEC = { + range = {name = "Range Ruler", follows = true, pitch = 90}, + cohesion = {name = "Cohesion Ruler", follows = true, pitch = 0}, + maxmove = {name = "Maximum Move", follows = false, pitch = 0}, } --- A ray hit counts as "ground" only if it is not the ignored object and not --- a transient object: anything still in motion (e.g. a movement template --- falling into place the frame the overlay spawns) or the hovering --- "Maximum Move" Windows bundle would otherwise catch the center ray and --- float the fill decal above its border ring. -local function macHitIsGround(h, ignoreObj) - local obj = h.hit_object - if obj == nil then return true end - if obj == ignoreObj then return false end - if obj.getName and obj.getName() == "Maximum Move" then return false end - local ok, v = pcall(function() return obj.getVelocity() end) - if ok and v and (math.abs(v.x) + math.abs(v.y) + math.abs(v.z)) > 0.05 then - return false - end - return true +-- Vanilla injects this into its Range ruler so it tracks the figure. Reusing +-- it for cohesion is what makes cohesion follow during a drag. Guarded +-- against a destroyed target, which the vanilla one is not. +local function macFollowScript(targetGUID) + return "targetGUID = '" .. targetGUID .. "'\n" + .. "function onFixedUpdate()\n" + .. " local t = getObjectFromGUID(targetGUID)\n" + .. " if t == nil then return end\n" + .. " local p = t.getPosition()\n" + .. " self.setPosition({p.x, p.y + 20, p.z})\n" + .. " self.setRotation({0, t.getRotation().y, 0})\n" + .. "end" end -local function macRayGroundY(x, z, offset, ignoreObj) - local hits = Physics.cast({ - origin = {x, 30, z}, - direction = {0, -1, 0}, - type = 1, - max_distance = 50, - }) - for _, h in ipairs(hits) do - if macHitIsGround(h, ignoreObj) then - return h.point.y + (offset or 0.05) - end - end - return offset or 0.05 +local function macIsLive(obj) + if obj == nil then return false end + local ok, dead = pcall(function() return obj.isDestroyed() end) + return ok and not dead end -local function macBuildRect(cx, cz, hw, hd, color, thickness) - local segPerSide = 8 - local pts = {} - local corners = { - {cx - hw, cz + hd}, {cx + hw, cz + hd}, - {cx + hw, cz - hd}, {cx - hw, cz - hd}, - } - for i = 1, 4 do - local a = corners[i] - local b = corners[i % 4 + 1] - for s = 0, segPerSide - 1 do - local t = s / segPerSide - local x = a[1] + (b[1] - a[1]) * t - local z = a[2] + (b[2] - a[2]) * t - table.insert(pts, {x, macRayGroundY(x, z), z}) - end +-- Which bundle this overlay shows. MaxMove carries its own in params: +-- getMovementLinks lives in the Order Token's scope, not reachable from +-- Global. +local function macResolveBundle(kind, fig, params) + params = params or {} + if params.bundle then return params.bundle end + + if kind == "cohesion" then + if not getCohesionLinks then return nil end + local links = getCohesionLinks() + local bs = macGetBaseSize(fig) + return (links and bs) and links[bs] or nil end - local c1 = corners[1] - table.insert(pts, {c1[1], macRayGroundY(c1[1], c1[2]), c1[2]}) - return {points = pts, color = color, thickness = thickness or 0.06} -end -local function macBuildRing(centerPos, radius, color, thickness, ignoreObj) - local nSeg = 64 - local pts = {} - for i = 0, nSeg do - local a = (i / nSeg) * 2 * math.pi - local x = centerPos.x + radius * math.cos(a) - local z = centerPos.z + radius * math.sin(a) - local hits = Physics.cast({ - origin = {x, centerPos.y + 10, z}, - direction = {0, -1, 0}, - type = 1, - max_distance = 20, - }) - local y = centerPos.y + 0.05 - for _, h in ipairs(hits) do - if macHitIsGround(h, ignoreObj) then - y = h.point.y + 0.05 - break - end - end - table.insert(pts, {x, y, z}) - end - return {points = pts, color = color, thickness = thickness or 0.05} -end + if kind == "range" then + if not getRangeRulerLinks then return nil end + local links = getRangeRulerLinks() + if not links then return nil end --- Stadium = rectangle with two semicircular caps on the long-axis ends. --- halfLen, halfWid in inches (halfLen >= halfWid). dist = expansion outwards --- from the base edge in inches (so the overlay sits at dist outside the base). --- rotYdeg rotates the stadium around Y to match the fig's orientation; the --- long axis is local Z (front-to-back of the model). -local function macBuildStadium(centerPos, halfLen, halfWid, rotYdeg, dist, color, thickness, ignoreObj) - local rotRad = math.rad(rotYdeg or 0) - local cosR, sinR = math.cos(rotRad), math.sin(rotRad) - - local capCenter = halfLen - halfWid -- distance from center to cap arc center, along long axis - local capR = halfWid + dist -- cap arc radius (= straight-side offset from long axis) - - local nSegArc = 32 -- segments per semicircle cap - local pts = {} - - local function addLocal(lx, lz) - local wx = centerPos.x + lx * cosR + lz * sinR - local wz = centerPos.z - lx * sinR + lz * cosR - local hits = Physics.cast({ - origin = {wx, centerPos.y + 10, wz}, - direction = {0, -1, 0}, - type = 1, - max_distance = 20, - }) - local y = centerPos.y + 0.05 - for _, h in ipairs(hits) do - if macHitIsGround(h, ignoreObj) then - y = h.point.y + 0.05 - break - end + local key = params.rangeKey + if not key and fig then + local ok, v = pcall(function() return fig.getVar("rangeKey") end) + if ok then key = v end end - table.insert(pts, {wx, y, wz}) - end - - -- Top cap: angle 0 to pi (right edge -> top -> left edge), centered at z=+capCenter - for i = 0, nSegArc do - local a = (i / nSegArc) * math.pi - addLocal(capR * math.cos(a), capCenter + capR * math.sin(a)) - end - -- The straight left side is implicit: the polyline jumps from - -- (-capR, +capCenter) directly to (-capR, -capCenter) - TTS draws a - -- straight segment between consecutive points. - -- Bottom cap: angle pi to 2pi, centered at z=-capCenter - for i = 0, nSegArc do - local a = math.pi + (i / nSegArc) * math.pi - addLocal(capR * math.cos(a), -capCenter + capR * math.sin(a)) + -- Token R button: its own single-ring bundle. Hover hotkey + -- (forceFigMode): the full fig-leader bands instead. + if key and not params.forceFigMode and links[key] then + return links[key] + end + local bs = macGetBaseSize(fig) or (key and TOKEN_TO_BASESIZE[key]) + return bs and links[bs] or nil end - -- Close the loop back to the top-cap start point. - addLocal(capR, capCenter) - return {points = pts, color = color, thickness = thickness or 0.05} + return nil end -local macBuilders = {} - -macBuilders.range = function(fig, params) - local pos = fig.getPosition() - -- Resolve rangeKey for token-specific single-ring rendering (R button on - -- a token). The hotkey path sets params.forceFigMode = true to bypass - -- this and always render the fig-leader 6-band overlay, using the token's - -- equivalent baseSize for sizing. - local forceFig = params and params.forceFigMode - local rangeKey = (not forceFig) and ((params and params.rangeKey) or fig.getVar("rangeKey")) or nil - local config, decalURL, maxR, br - local oblong, halfLen, halfWid, rotY - local baseSize -- hoisted: used below for firing-arc decision - if rangeKey and RANGE_CONFIGS[rangeKey] then - config = RANGE_CONFIGS[rangeKey] - decalURL = RANGE_DECAL_URLS[rangeKey] - maxR = RANGE_MAX_RADIUS[rangeKey] - br = TOKEN_BASE_RADIUS[rangeKey] or 0 +local function macSpawnProjector(kind, fig, params) + local spec = PROJECTOR_SPEC[kind] + if not spec then return nil end + local bundle = macResolveBundle(kind, fig, params) + if not bundle then return nil end + params = params or {} + + local pos, yaw + if kind == "maxmove" then + -- Anchored: position and yaw captured when the move STARTED, so the + -- template stays where it was while the figure slides away from it. + local a = params.anchorPos + if not a then return nil end + pos = {a.x, a.y + 20, a.z} + yaw = params.anchorRot or 0 else - baseSize = macGetBaseSize(fig) - local hasBaseSize = baseSize ~= nil - if not hasBaseSize then - -- Token hit from hotkey: map rangeKey to base size for sizing. - local tk = fig.getVar("rangeKey") - baseSize = (tk and TOKEN_TO_BASESIZE[tk]) or "small" - end - config = RANGE_CONFIGS[baseSize] or RANGE_CONFIGS.small - decalURL = RANGE_DECAL_URLS.fig_leader[baseSize] - or RANGE_DECAL_URLS.fig_leader.small - maxR = RANGE_MAX_RADIUS.fig_leader - if hasBaseSize then - br = macFigBaseRadius(fig) - local od = macOblongDims(fig, baseSize) - if od then - oblong, halfLen, halfWid, rotY = true, od.halfLen, od.halfWid, od.rotY - end - else - -- Token in forceFig mode: use token's measured radius for offset. - local tk = fig.getVar("rangeKey") - br = (tk and TOKEN_BASE_RADIUS[tk]) or FIG_BASE_RADIUS_IN[baseSize] or 0.5315 - end - end - - -- SWL convention: all distances are measured from the base/token edge. - - -- Vector contours: 6 concentric rings for round bases, 6 concentric - -- stadium outlines for oblong bases (each band sits at band.r outwards - -- from the base edge - same rule, just a different shape). - local lines = {} - for _, band in ipairs(config) do - if oblong then - table.insert(lines, macBuildStadium(pos, halfLen, halfWid, rotY, band.r, - RANGE_COLORS[band.c], 0.1, fig)) - else - table.insert(lines, macBuildRing(pos, band.r + br, RANGE_COLORS[band.c], 0.1, fig)) - end + if not fig then return nil end + local p = fig.getPosition() + pos = {p.x, p.y + 20, p.z} + yaw = fig.getRotation().y end - - -- Firing arc lines (4 radial lines dividing into Front/R/Rear/L quadrants). - -- Mirrors the vanilla Projector shader: ProjectorMaterial_ sets - -- _Arc=1 / shader keyword _ARC_ON for every non-27mm base (medium, large, - -- huge, laat, epic, long, snail). 27mm sets _Arc=0. - -- Round bases : lines emanate from the base edge, radial from center. - -- Oblong bases: lines emanate from the centers of the two end - -- semicircles (front cap + rear cap), front lines at +/-45 from the - -- long-axis forward, rear lines at +/-135. - local arcColor = {1, 1, 1, 0.6} - if baseSize and baseSize ~= "small" then - if oblong then - local capOffset = (halfLen or 0) - (halfWid or 0) - local rad = math.rad(rotY) - local fwdX, fwdZ = math.sin(rad), math.cos(rad) - local frontX = pos.x + capOffset * fwdX - local frontZ = pos.z + capOffset * fwdZ - local rearX = pos.x - capOffset * fwdX - local rearZ = pos.z - capOffset * fwdZ - local reach = (halfWid or 0) + (maxR or 6) - local arcs = { - {frontX, frontZ, 45}, -- front-right boundary - {frontX, frontZ, -45}, -- front-left boundary - {rearX, rearZ, 135}, -- rear-right boundary - {rearX, rearZ, -135}, -- rear-left boundary - } - for _, e in ipairs(arcs) do - local cx, cz, deg = e[1], e[2], e[3] - local a = math.rad(rotY + deg) - local sinA, cosA = math.sin(a), math.cos(a) - table.insert(lines, { - points = { - {cx, pos.y + 0.1, cz}, - {cx + reach * sinA, pos.y + 0.1, cz + reach * cosA}, - }, - color = arcColor, - thickness = 0.05, - }) - end - else - local figRotY = fig.getRotation().y - local outerR = (maxR or 6) + br - for _, deg in ipairs({45, 135, 225, 315}) do - local a = math.rad(deg + figRotY) - local sinA, cosA = math.sin(a), math.cos(a) - table.insert(lines, { - points = { - {pos.x + br * sinA, pos.y + 0.1, pos.z + br * cosA}, - {pos.x + outerR * sinA, pos.y + 0.1, pos.z + outerR * cosA}, - }, - color = arcColor, - thickness = 0.05, - }) - end - end - end - - -- Decal halo (filled bands) - flat on the ground under the fig - local hits = Physics.cast({ - origin = {pos.x, pos.y + 10, pos.z}, - direction = {0, -1, 0}, - type = 1, - max_distance = 20, + if not pos then return nil end + + local obj = spawnObject({ + type = "Custom_AssetBundle", + position = pos, + rotation = {spec.pitch, yaw, 0}, + -- Scale 0 hides the TTS placeholder box without touching the + -- Projector itself, exactly as the vanilla spawns do. + scale = {0, 0, 0}, }) - local groundY = pos.y - for _, h in ipairs(hits) do - if macHitIsGround(h, fig) then groundY = h.point.y; break end + obj.setCustomObject({type = 0, assetbundle = bundle}) + obj.setLock(true) + obj.use_gravity = false + obj.setName(spec.name) + if spec.follows and fig then + obj.setLuaScript(macFollowScript(fig.getGUID())) end - - if oblong then - -- Stadium-shape PNGs are authored per oblong base size: the 6 bands - -- inside the PNG already match the stadium vector outlines because - -- the PNG was generated with the same halfWid/halfLen + dist math. - -- Decal scale = footprint of the outermost band (2*(half + maxR)) - -- in each axis, so the PNG stretches to exactly the right size. - local longSpan = 2 * (halfLen + maxR) - local shortSpan = 2 * (halfWid + maxR) - return { - lines = lines, - decals = { - { - name = "range_decal_" .. fig.getGUID(), - url = decalURL, - position = {pos.x, groundY + 0.02, pos.z}, - rotation = {90, rotY, 0}, - scale = {shortSpan, longSpan, 1}, - } - }, - } - end - - local effectiveMaxR = maxR + br - return { - lines = lines, - decals = { - { - name = "range_decal_" .. fig.getGUID(), - url = decalURL, - position = {pos.x, groundY + 0.02, pos.z}, -- below cohesion halo - rotation = {90, 0, 0}, - scale = {effectiveMaxR * 2, effectiveMaxR * 2, effectiveMaxR * 2}, - } - }, - } + return obj end -macBuilders.maxmove = function(fig, params) - -- Use the anchor position stored at spawn time so the ring stays put - -- when the fig slides toward the destination, instead of tracking it. - local pos = (params and params.anchorPos) or fig.getPosition() - local baseSize = (params and params.baseSize) or "small" - local speed = (params and params.speed) or 1 - local radii = MAX_MOVE_RADIUS[baseSize] or MAX_MOVE_RADIUS.small - local r = radii[speed] or radii[1] - local color = {0.333, 0.800, 1.000, 0.7} - -- Base ring: small white outline matching the figure's base - -- (BB_MovementProjector renders a base ring on top of the cyan max-move). - local br = FIG_BASE_RADIUS_IN[baseSize] or FIG_BASE_RADIUS_IN.small - local baseColor = {1, 1, 1, 0.8} - -- Oblong base dimensions for the stadium base ring. Use the rotation - -- captured at spawn-time so the ring keeps its orientation even after - -- the fig pivots toward its destination. - local od = macOblongDims(fig, baseSize) - local oblong = od ~= nil - local halfLen, halfWid, rotY - if oblong then - halfLen, halfWid = od.halfLen, od.halfWid - rotY = (params and params.anchorRot) or od.rotY +-- Destroy the Projector an entry owns, then forget the entry. EVERY removal +-- must go through here: dropping the entry alone leaks the object. +function macRemove(key) + local entry = activeOverlays[key] + if entry == nil then return end + if macIsLive(entry.obj) then + pcall(function() entry.obj.destruct() end) end - - -- Ground raycast for decal position - local hits = Physics.cast({ - origin = {pos.x, pos.y + 10, pos.z}, - direction = {0, -1, 0}, - type = 1, - max_distance = 20, - }) - local groundY = pos.y - for _, h in ipairs(hits) do - if macHitIsGround(h, fig) then groundY = h.point.y; break end - end - - if oblong then - -- Oblong base: the cyan max-move envelope stays a round ring (isotropic - -- - any rotation reaches the same radius from the pivot), but the - -- inner white base ring follows the rectangular footprint as a - -- stadium hugging the actual base edge. - return { - lines = { - macBuildRing(pos, r, color, 0.1, fig), - macBuildStadium(pos, halfLen, halfWid, rotY, 0, - baseColor, 0.06, fig), - }, - decals = { - { - name = "maxmove_decal_" .. fig.getGUID(), - url = MAX_MOVE_CYAN_URL, - position = {pos.x, groundY + 0.025, pos.z}, - rotation = {90, 0, 0}, - scale = {r * 2, r * 2, r * 2}, - } - }, - } - end - - return { - lines = { - macBuildRing(pos, r, color, 0.1, fig), -- outer cyan max-move - macBuildRing(pos, br, baseColor, 0.06, fig), -- inner white base ring - }, - decals = { - { - name = "maxmove_decal_" .. fig.getGUID(), - url = MAX_MOVE_CYAN_URL, - position = {pos.x, groundY + 0.025, pos.z}, - rotation = {90, 0, 0}, - scale = {r * 2, r * 2, r * 2}, - } - }, - } + activeOverlays[key] = nil end -macBuilders.deployment = function(_, params) - local pos = params.pos -- {x, y, z} cell center (after offset) - local cell = params.cell -- "r"/"b"/"rh"/... key - local size = DEPLOYMENT_CELL_SIZES[cell] or {6, 6} - local w, d = size[1], size[2] - local cx, cz = pos[1], pos[3] - local hw, hd = w / 2, d / 2 - - local isRed = cell:sub(1, 1) == "r" - local lineColor = isRed and {1, 0.15, 0.15, 0.9} or {0.15, 0.4, 1, 0.9} - local url = isRed and DEPLOYMENT_RED_URL or DEPLOYMENT_BLUE_URL - - local groundY = macRayGroundY(cx, cz, 0) - - return { - lines = { macBuildRect(cx, cz, hw, hd, lineColor, 0.08) }, - decals = { - { - name = "deployment_decal_" .. cell .. "_" .. tostring(cx) .. "_" .. tostring(cz), - url = url, - position = {cx, groundY + 0.03, cz}, - rotation = {90, 0, 0}, - scale = {w, d, 1}, - } - }, - } -end - -macBuilders.cohesion = function(fig, params) - local pos = fig.getPosition() - -- Cohesion overlay = base edge + 3 inches (half Range 1). Round bases get - -- a ring; oblong bases (long/snail) get a stadium-shape concentric to the - -- footprint so the offset stays a constant 3" from the edge. - local rangeKey = fig.getVar("rangeKey") - local oblong, halfLen, halfWid, rotY, r - if rangeKey and TOKEN_BASE_RADIUS[rangeKey] then - r = TOKEN_BASE_RADIUS[rangeKey] + 3.0 - else - local baseSize = macGetBaseSize(fig) or "small" - local od = macOblongDims(fig, baseSize) - if od then - oblong, halfLen, halfWid, rotY = true, od.halfLen, od.halfWid, od.rotY - else - r = (FIG_BASE_RADIUS_IN[baseSize] or FIG_BASE_RADIUS_IN.small) + 3.0 - end - end - if params and params.radius then - oblong, r = false, params.radius - end - - -- Find ground level under the fig so the flat decal sits on the table, - -- not at the fig pivot (which is above the base). - local hits = Physics.cast({ - origin = {pos.x, pos.y + 10, pos.z}, - direction = {0, -1, 0}, - type = 1, - max_distance = 20, - }) - local groundY = pos.y - for _, h in ipairs(hits) do - if macHitIsGround(h, fig) then - groundY = h.point.y - break - end - end - - if oblong then - -- Halo decal: stretch the round halo PNG into an ellipse aligned with - -- the fig's long axis. Approximates the stadium fade (a true stadium - -- halo would need a custom PNG); good enough visually since the - -- vector stadium outline carries the precise boundary. - local longSpan = 2 * (halfLen + 3.0) - local shortSpan = 2 * (halfWid + 3.0) - return { - lines = { macBuildStadium(pos, halfLen, halfWid, rotY, 3.0, - {1, 1, 1, 0.8}, 0.06, fig) }, - decals = { - { - name = "cohesion_halo_" .. fig.getGUID(), - url = COHESION_HALO_URL, - position = {pos.x, groundY + 0.04, pos.z}, - -- 90 deg pitch lays the decal flat on the table; rotY (yaw) - -- aligns its local Y with the fig's long axis. - rotation = {90, rotY, 0}, - scale = {shortSpan, longSpan, 1}, - } - }, - } +function macRemoveAllOfType(kind) + local keys = {} + for key, entry in pairs(activeOverlays) do + if entry.type == kind then keys[#keys + 1] = key end end - - return { - lines = { macBuildRing(pos, r, {1, 1, 1, 0.8}, 0.06, fig) }, - decals = { - { - name = "cohesion_halo_" .. fig.getGUID(), - url = COHESION_HALO_URL, - position = {pos.x, groundY + 0.04, pos.z}, - rotation = {90, 0, 0}, - scale = {r * 2, r * 2, r * 2}, - } - }, - } + for _, key in ipairs(keys) do macRemove(key) end end --- Redraws are deferred one frame and coalesced, then skipped outright when --- the rebuilt result is identical to what is already applied. Rationale: a --- click that clears and respawns the same overlay (e.g. re-picking the same --- speed) would otherwise call Global.setDecals twice in one click, and every --- setDecals re-projects every decal on the table, visibly shifting the --- shading/shadows on scene objects. -macRedrawPending = false -macLastDrawSig = nil - -local function macDrawSignature(lines, decals) - local parts = {} - for _, l in ipairs(lines) do - local p0 = l.points and l.points[1] - parts[#parts + 1] = string.format("L%d:%s", #(l.points or {}), - p0 and string.format("%.3f,%.3f,%.3f", p0[1], p0[2], p0[3]) or "") - end - for _, d in ipairs(decals) do - parts[#parts + 1] = string.format("D%s:%.3f,%.3f,%.3f:%.2f", - d.name or "", d.position[1], d.position[2], d.position[3], - (d.scale and d.scale[1]) or 0) - end - -- pairs() iteration order over activeOverlays is not stable across - -- rebuilds; sort so identical content always yields an identical key. - table.sort(parts) - return table.concat(parts, "|") +function macRemoveAll() + local keys = {} + for key in pairs(activeOverlays) do keys[#keys + 1] = key end + for _, key in ipairs(keys) do macRemove(key) end end +-- Reconcile the scene with the registry: give a Projector to every entry that +-- has never had one, and drop entries that lost theirs. function macRedrawNow() - local lines, decals = {}, {} - -- Preload all texture URLs (invisible decals far below the table) so TTS - -- keeps them cached and we never get the white-square flash on respawn. - local preloadURLs = { - COHESION_HALO_URL, - RANGE_DECAL_URLS.smokeToken, - RANGE_DECAL_URLS.token, RANGE_DECAL_URLS.tokenRangeTwo, - RANGE_DECAL_URLS.poi, RANGE_DECAL_URLS.bombCart, - RANGE_DECAL_URLS.fig_leader.small, RANGE_DECAL_URLS.fig_leader.medium, - RANGE_DECAL_URLS.fig_leader.large, RANGE_DECAL_URLS.fig_leader.huge, - RANGE_DECAL_URLS.fig_leader.laat, RANGE_DECAL_URLS.fig_leader.epic, - RANGE_DECAL_URLS.fig_leader.long, RANGE_DECAL_URLS.fig_leader.snail, - MAX_MOVE_CYAN_URL, - DEPLOYMENT_RED_URL, DEPLOYMENT_BLUE_URL, - } - for i, url in ipairs(preloadURLs) do - table.insert(decals, { - name = "preload_" .. i, - url = url, - position = {0, -200 - i * 0.01, 0}, - rotation = {90, 0, 0}, - scale = {0.01, 0.01, 0.01}, - }) - end local stale = {} for key, entry in pairs(activeOverlays) do - local b = macBuilders[entry.type] - if b then - -- Deployment entries have no fig (params-driven). Others need a - -- live Object - drop them silently if destroyed/invalid. - local needsFig = (entry.type ~= "deployment") - if needsFig and (not entry.fig - or type(entry.fig.getPosition) ~= "function") then - stale[#stale + 1] = key + if not entry.fig or type(entry.fig.getPosition) ~= "function" then + stale[#stale + 1] = key + elseif entry.objGUID == nil then + local ok, obj = pcall(macSpawnProjector, entry.type, entry.fig, entry.params) + if ok and obj then + entry.obj = obj + entry.objGUID = obj.getGUID() else - -- Per-entry cache: only the entry whose fig moved since the - -- last poll is rebuilt (65 raycasts per ring); every other - -- overlay reuses its cached geometry. This is what keeps the - -- framerate up while dragging a fig with several overlays on. - local ok, out - if entry._cache and not entry._dirty then - ok, out = true, entry._cache - else - ok, out = pcall(b, entry.fig, entry.params) - if ok and out then - entry._cache = out - entry._dirty = nil - end - end - if ok and out then - for _, l in ipairs(out.lines or {}) do - table.insert(lines, l) - end - for _, d in ipairs(out.decals or {}) do - table.insert(decals, d) - end - else - stale[#stale + 1] = key - end + stale[#stale + 1] = key end + elseif not macIsLive(entry.obj) then + -- The Projector is gone and we did not remove it, so a sweeper + -- did: standbyTokens, removeLockedRulers or Clear Map. Those are + -- explicit "wipe the table" commands, so treat it as the overlay + -- having been switched off rather than respawn behind them. + stale[#stale + 1] = key end end - for _, k in ipairs(stale) do activeOverlays[k] = nil end - local sig = macDrawSignature(lines, decals) - if sig == macLastDrawSig then return end - macLastDrawSig = sig - Global.setVectorLines(lines) - Global.setDecals(decals) + for _, k in ipairs(stale) do macRemove(k) end end +-- Deferred by one frame so a single click touching several entries +-- reconciles once. function macRedrawAll() if macRedrawPending then return end macRedrawPending = true @@ -796,28 +258,25 @@ function gSpawnCohesion(params) local fig = getObjectFromGUID(params.figGUID) if not fig then return end - activeOverlays[fig.getGUID() .. ":cohesion"] = { + -- macRemove first: re-spawning over a live entry would orphan its + -- Projector, which nothing would ever destroy. + local key = fig.getGUID() .. ":cohesion" + macRemove(key) + activeOverlays[key] = { type = "cohesion", fig = fig, params = params or {} } macRedrawAll() - -- Cohesion follows its fig through the same lazy poll as Range (it used - -- to tag along only as a side effect of full-rebuild polling). - if not macRangePollingActive then - macRangePollingActive = true - Wait.frames(macRangePoll, 5) - end end function gClearCohesion(params) local fig = getObjectFromGUID(params.figGUID) if not fig then return end -- Vanilla fig scripts clear cohesion from onPickedUp. Design choice - -- (11 aug): the Mac overlay stays visible and FOLLOWS the fig during - -- the drag, like Range does - so clears on a held fig are ignored - -- (the vanilla onPickedUp clear is the only caller in that state). + -- (11 aug): our cohesion stays visible and FOLLOWS the fig during the + -- drag, like Range does, so clears on a held fig are ignored (the + -- vanilla onPickedUp clear is the only caller in that state). if fig.held_by_color then return end - activeOverlays[fig.getGUID() .. ":cohesion"] = nil - macRedrawAll() + macRemove(fig.getGUID() .. ":cohesion") end function gToggleCohesion(params) @@ -831,74 +290,21 @@ end end --- Overlay polling: a slow timer (5 frames = ~12 fps) that re-draws active --- range AND cohesion overlays so they follow figures in real-time. Stops --- automatically when none is active anymore - avoids the memory leak. -macRangePollingActive = macRangePollingActive or false - -function macRangePoll() - -- Rebuild ONLY when a tracked fig actually moved: a full redraw re-runs - -- every builder (65 raycasts per ring, up to 6 rings per fig), and doing - -- that every 5 frames for static figs is what made Range/POI overlays - -- tank the framerate while Cohesion (no polling) stayed fluid. - local hasTracked = false - local moved = false - for _, e in pairs(activeOverlays) do - if e.type == "range" or e.type == "cohesion" then - hasTracked = true - local fig = e.fig - if not fig or type(fig.getPosition) ~= "function" then - moved = true -- stale entry: the redraw prunes it - else - local ok, p = pcall(function() return fig.getPosition() end) - local okr, r = pcall(function() return fig.getRotation() end) - if not ok or not p then - moved = true - elseif not e._lastPos then - -- First poll after spawn: prime the cache, the spawn - -- already drew this overlay. - e._lastPos = p - e._lastRot = okr and r or nil - else - local lp, lr = e._lastPos, e._lastRot - if math.abs(p.x - lp.x) > 0.01 - or math.abs(p.y - lp.y) > 0.01 - or math.abs(p.z - lp.z) > 0.01 - or (okr and lr and math.abs(r.y - lr.y) > 0.5) then - moved = true - e._dirty = true - end - e._lastPos = p - e._lastRot = okr and r or lr - end - end - end - end - if hasTracked then - if moved then macRedrawAll() end - Wait.frames(macRangePoll, 5) - else - macRangePollingActive = false - end -end - function gSpawnRange(params) local fig = getObjectFromGUID(params.figGUID) if not fig then return end - activeOverlays[fig.getGUID() .. ":range"] = { + local key = fig.getGUID() .. ":range" + macRemove(key) + activeOverlays[key] = { type = "range", fig = fig, params = params or {} } macRedrawAll() - if not macRangePollingActive then - macRangePollingActive = true - Wait.frames(macRangePoll, 5) - end end function gClearRange(params) local fig = getObjectFromGUID(params.figGUID) if not fig then return end - activeOverlays[fig.getGUID() .. ":range"] = nil + macRemove(fig.getGUID() .. ":range") -- Windows mode: also destroy the vanilla bundle this fig owns. It was -- spawned in the Global scope by gRangeTrigger, so the token's own -- exitTargetingMode/clearRangeRulers cannot reach it. @@ -906,7 +312,6 @@ pcall(clearRangeRulersOriginalGlobal) macWinRangeGUID = nil end - macRedrawAll() end function gToggleRange(params) @@ -920,33 +325,19 @@ end end -function gSpawnDeployment(params) - -- params: { cell = "r" | "b" | ..., pos = {x, y, z} } - if not params or not params.cell or not params.pos then return end - local key = "deploy:" .. params.cell .. ":" - .. tostring(params.pos[1]) .. ":" .. tostring(params.pos[3]) - activeOverlays[key] = {type = "deployment", fig = nil, params = params} - macRedrawAll() -end - -function gClearAllDeployment() - for k, e in pairs(activeOverlays) do - if e.type == "deployment" then activeOverlays[k] = nil end - end - macRedrawAll() -end - function gSpawnMaxMove(params) local fig = getObjectFromGUID(params.figGUID) if not fig then return end - -- Capture the spawn-time position + yaw. MaxMove is anchored to where - -- the move STARTED - it must not follow the fig as it slides toward - -- the destination. The yaw matters for oblong stadium overlays so the - -- white base ring keeps its orientation while the fig pivots. + -- Capture the spawn-time position and yaw. MaxMove is anchored to where + -- the move STARTED: it must not follow the fig as it slides toward the + -- destination. A Projector tracks its target by default, so this one is + -- deliberately spawned with no follow script (see PROJECTOR_SPEC). local p = (params and params.params) or params or {} p.anchorPos = fig.getPosition() p.anchorRot = fig.getRotation().y - activeOverlays[fig.getGUID() .. ":maxmove"] = { + local key = fig.getGUID() .. ":maxmove" + macRemove(key) + activeOverlays[key] = { type = "maxmove", fig = fig, params = p } macRedrawAll() @@ -955,47 +346,44 @@ function gClearMaxMove(params) local fig = getObjectFromGUID(params.figGUID) if not fig then return end - activeOverlays[fig.getGUID() .. ":maxmove"] = nil - macRedrawAll() + macRemove(fig.getGUID() .. ":maxmove") end -- Note: no onObjectPickUp/onObjectDrop handlers (the vanilla Global defines --- none either). Cohesion, like Range, stays visible during a drag and --- follows via the poll; the vanilla onPickedUp clear is neutralized in --- gClearCohesion while the fig is held. +-- none either). Cohesion, like Range, stays visible during a drag and follows +-- because its Projector carries the tracking script; the vanilla onPickedUp +-- clear is neutralized in gClearCohesion while the fig is held. function onObjectDestroy(obj) if not obj or not obj.getGUID then return end local guid = obj.getGUID() local prefix = guid .. ":" local plen = #prefix - local changed = false - for key in pairs(activeOverlays) do - if key:sub(1, plen) == prefix then - activeOverlays[key] = nil - changed = true + local doomed = {} + for key, entry in pairs(activeOverlays) do + -- The destroyed object is either the figure an overlay belongs to, + -- or the overlay's own Projector (a sweeper, or a player deleting it + -- by hand). + if key:sub(1, plen) == prefix or entry.objGUID == guid then + doomed[#doomed + 1] = key end end - if changed then macRedrawAll() end + for _, key in ipairs(doomed) do macRemove(key) end end --- Texture preload is handled by macRedrawAll which always includes all PNG --- URLs as invisible decals far below the table. No separate preload needed. - -- ============================================ --- TABLE-WIDE MODE TOGGLE (Cohesion + Range + Deployment) --- One switch for the whole table: "windows" (original bundle Projectors) or --- "mac" (this patch). Per-seat modes were dropped on purpose: any rendered --- overlay is visible to every player (TTS engine limitation), so a Windows --- player triggering an original Projector still shows magenta to Mac --- players. The switch is the Apple-logo button in the bottom-right menu: --- default grey = off (originals), green = on (Mac-safe fallback). +-- TABLE-WIDE OVERLAY TOGGLE (Range + Cohesion + MaxMove) +-- One switch for the whole table: "windows" (the mod's original Projectors) +-- or "mac" (the Iron Squadron overlays). Per-seat modes were dropped on +-- purpose: any rendered overlay is visible to every player (TTS engine +-- limitation), so one player triggering an original Projector shows it to +-- the whole table anyway. The switch is the Iron Squadron button in the +-- bottom-right menu: default grey = off (originals, untouched), green = on. -- ============================================ overlayMode = overlayMode or "windows" -- "windows" | "mac", table-wide -function gGetMode(_) return overlayMode end -function gGetDeploymentMode() return overlayMode end +function gGetMode(_) return overlayMode end function gCohesionTrigger(params) if not params or not params.figGUID then return end @@ -1059,12 +447,9 @@ overlayMode = (overlayMode == "mac") and "windows" or "mac" -- Wipe both renderers' overlays so stale visuals don't linger after the -- toggle; each player just re-triggers their hotkey. - for k, e in pairs(activeOverlays) do - if e.type == "cohesion" or e.type == "range" then - activeOverlays[k] = nil - end - end - macRedrawAll() + macRemoveAllOfType("cohesion") + macRemoveAllOfType("range") + macRemoveAllOfType("maxmove") for _, obj in ipairs(getAllObjects()) do if obj.getVar and obj.getVar("cohesionRuler") then pcall(function() obj.call("clearCohesionRulerOriginal", obj) end) @@ -1078,8 +463,8 @@ pcall(clearRangeRulersOriginalGlobal) macWinRangeGUID = nil broadcastToAll( - (overlayMode == "mac") and "Mac patch ON: Mac-safe overlays for the whole table." - or "Mac patch OFF: original Windows overlays.", + (overlayMode == "mac") and "Iron Squadron overlays ON for the whole table." + or "Iron Squadron overlays OFF: the mod's original overlays are back.", (overlayMode == "mac") and {0.55, 0.9, 0.6} or {0.9, 0.75, 0.55}) macDeferRefresh() end @@ -1095,7 +480,8 @@ return nil, nil end --- UI: single Apple-logo toggle button in the bottom-right legionFloatingMenu. +-- UI: single Iron Squadron toggle button in the bottom-right +-- legionFloatingMenu. function macRefreshModeUI() local tree = UI.getXmlTable() or {} -- Drop the legacy mode-picker panel if this save still carries one. @@ -1111,8 +497,8 @@ id = "macModeMenuButton", onClick = "macModeToggle", tooltip = isMac - and "Mac TTS U6 patch ON (table-wide). Click for original overlays." - or "Mac TTS U6 patch OFF. Click for Mac-safe overlays (table-wide).", + and "Iron Squadron overlays: ON for the whole table. Click to go back to the mod's original overlays." + or "Iron Squadron overlays: OFF, the mod's original overlays are in use. Click to turn them on for the whole table.", } -- OFF keeps the sibling buttons' default light-grey look (Welcome, -- Chess Clocks); ON switches to green. @@ -1121,13 +507,13 @@ tag = "Button", attributes = attrs, children = {{ - -- White PNG sprite (CustomUIAssets "macAppleLogo"), tinted - -- per state: dark on the grey button, white on green. A text - -- U+F8FF glyph would render as a missing-glyph box on - -- Windows clients. + -- White PNG sprite (CustomUIAssets "isqLogo"), tinted per + -- state: dark on the grey button, white on green. The shape + -- lives in the alpha channel, which is what makes the tint + -- work. tag = "Image", attributes = { - image = "macAppleLogo", + image = "isqLogo", color = isMac and "#FFFFFF" or "#2b2b2b", preserveAspect = "true", raycastTarget = "false", @@ -1165,99 +551,6 @@ -- Initial UI build, deferred + pcalled like the rest. Wait.time(function() pcall(macRefreshModeUI) end, 2) --- ============================================ --- UNIT ID TOKEN NUMBERS (Mac) --- The ID token bundle paints its number via custom materials --- (unitIDtoken_N) that TTS U6 on Mac refuses to load ("Shader didn't load --- correctly ... Assigning Standard shader"), so tokens go blank. Unlike the --- Projector magenta case there is no error shader involved: TTS substitutes --- Standard, which simply ignores the number texture slots. In mac mode we --- attach a plain object-UI number instead (native Unity UI, no shaders); --- the token state id IS the number (state 1..10). --- ============================================ - --- Empirically calibrated (diagnostics of 11 aug): the top face reads --- correctly with rotation "0 0 180", the bottom face with "180 0 0". --- Offsets found by ladder diagnostic (panels at z -12..+12 each showing --- its own z): top face reads at z = -12, bottom face at z = +1. -MAC_UNITID_UI = { - zTop = -12, - zBottom = 1, - fontSize = 72, - panel = 110, - rotTop = "0 0 180", - rotBottom = "180 0 0", -} - -local function macUnitIDPanel(text, x, z, rot) - return { - tag = "Panel", - attributes = { - position = tostring(x) .. " 0 " .. tostring(z), - rotation = rot, - width = tostring(MAC_UNITID_UI.panel), - height = tostring(MAC_UNITID_UI.panel), - }, - children = {{ - tag = "Text", - attributes = { - text = text, - fontSize = tostring(MAC_UNITID_UI.fontSize), - fontStyle = "Bold", - color = "#FFFFFF", - outline = "#000000", - outlineSize = "4 4", - alignment = "MiddleCenter", - }, - }}, - } -end - -local function macUnitIDXml(n) - return { - macUnitIDPanel(tostring(n), 0, MAC_UNITID_UI.zTop, MAC_UNITID_UI.rotTop), - macUnitIDPanel(tostring(n), 0, MAC_UNITID_UI.zBottom, MAC_UNITID_UI.rotBottom), - } -end - -local function macApplyUnitIDUI(obj) - if not (obj and obj.getName and obj.getName() == "Unit ID Token") then return end - if overlayMode == "mac" then - local n = 1 - pcall(function() n = obj.getStateId() end) - if not n or n < 1 then n = 1 end - pcall(function() obj.UI.setXmlTable(macUnitIDXml(n)) end) - else - pcall(function() obj.UI.setXml("") end) - end -end - -function macRefreshUnitIDTokens() - for _, obj in ipairs(getAllObjects()) do - macApplyUnitIDUI(obj) - end -end - --- New tokens from the infinite bag and number changes (a TTS state switch --- spawns a fresh object) both arrive through onObjectSpawn. The live mod --- defines no onObjectSpawn handler (verified), so defining it here is safe. -function onObjectSpawn(obj) - if overlayMode ~= "mac" then return end - if not (obj and obj.getName and obj.getName() == "Unit ID Token") then return end - Wait.frames(function() macApplyUnitIDUI(obj) end, 2) -end - --- Numbers follow the table-wide toggle: wrap the toggle handler (defined in --- the shared mode-toggle block above, which must stay byte-identical with --- the mod source copy, hence the wrap instead of an inline edit). -local _macModeToggleBeforeUnitID = macModeToggle -function macModeToggle(a, b, c) - _macModeToggleBeforeUnitID(a, b, c) - Wait.frames(function() pcall(macRefreshUnitIDTokens) end, 1) -end - -Wait.time(function() pcall(macRefreshUnitIDTokens) end, 3) - -- Override hotkey init functions to capture playerColor and route through -- the mode router. Defining initCohesionHotkeys/initRangebandHotkeys -- here SHADOWS the originals - when the original onLoad runs init*(), our @@ -1431,11 +724,14 @@ maxMoveTemplate.use_gravity = false maxMoveTemplate.setName("Maximum Move") else - -- MAC FALLBACK: route through the Global Overlays manager + -- IRON SQUADRON: route through the Global Overlays manager. + -- The bundle travels with the call: getMovementLinks() is + -- required by this object, not by Global. Global.call("gSpawnMaxMove", { figGUID = selectedUnitObj.getGUID(), baseSize = unitData.baseSize, speed = unitData.selectedSpeed, + bundle = maxMoveTemplateBundleToSpawn, }) maxMoveTemplate = nil end @@ -1474,149 +770,6 @@ maxMoveTemplate = nil end""" -# Deployment Boundary: replace the Custom_AssetBundle Projector spawn inside -# spawnBoundaryCell (SETUP_CONTROLLER 1cb552) with a Global.call to the manager. -# Idempotent: matches both the vanilla form AND a previously-injected patched -# form (between the MAC PATCH dual-path marker and the closing ` end`). The -# patched alternative is listed first so re-runs prefer it. -DEPLOYMENT_SPAWN_RE = re.compile( - r"(?:" - r"-- MAC PATCH dual-path:.*?\r?\n end" - r"|" - r"local projector = spawnObject\(\{\r?\n" - r" type = \"Custom_AssetBundle\",.*?" - r"projector\.setCustomObject\(\{\r?\n" - r" assetbundle = asset,\r?\n" - r" \}\)" - r")", - re.DOTALL -) - -DEPLOYMENT_SPAWN_REPLACEMENT = r"""-- MAC PATCH dual-path: branch on the table-wide mode toggle (gGetDeploymentMode). - local _macDeployMode = Global.call("gGetDeploymentMode") - local projector = nil - if _macDeployMode == "windows" then - projector = spawnObject({ - type = "Custom_AssetBundle", - position = pos, - scale = {0, 0, 0}, - rotation = {0, deployRotations[cell], 0} - }) - projector.setName("Deployment Boundary") - projector.setLock(true) - projector.setCustomObject({ - assetbundle = asset, - }) - else - Global.call("gSpawnDeployment", { cell = cell, pos = pos }) - end""" - -# clearDeploymentBoundary: also clear manager entries. -CLEAR_DEPLOYMENT_RE = re.compile( - r"function clearDeploymentBoundary\(\)\r?\n" - r" local battlefieldObjs = battlefieldZone\.getObjects\(\).*?\r?\n" - r" end\r?\nend", - re.DOTALL -) - -CLEAR_DEPLOYMENT_REPLACEMENT = r"""function clearDeploymentBoundary() - -- MAC PATCH: clear Global Overlays manager entries first. - Global.call("gClearAllDeployment", {}) - local battlefieldObjs = battlefieldZone.getObjects() - for _, obj in pairs(battlefieldObjs) do - if obj.getName() == "Deployment Boundary" then - destroyObject(obj) - end - end -end""" - -# Silhouette URL swap to our Unity-6-compiled bundle. -# -# The upstream BucketheadBits_Silhouette bundle uses Allen White's custom -# Silhouette shader compiled under Unity 2019.4. TTS U6 on Mac fails to -# load that shader at runtime (console: "Shader didn't load correctly for -# AssetBundle material BucketheadBits_Silhouette. Assigning Standard -# shader.") and falls back to Standard, which renders the cylinder opaque. -# -# Our fork-hosted bundle uses the SAME prefab + material + shader source -# (Assets/Sihl/), only the compile target differs (Unity 6 instead of -# Unity 2019.4). Path A from Dicewrench's analysis. -# -# We swap ALL silhouette URLs (default cylinder, snail, long) to the same -# fork URL. Snail/long visual fidelity is acceptable for now (cylinder -# placeholder); per-base meshes are a separate follow-up. -SILHOUETTE_BUNDLE_URL = ( - "https://raw.githubusercontent.com/ironsquadronfr-hub/tts/" - "mac-projector-fallback/mod/data/mac-fallback-assets/" - "silhouette_mac_fallback_v2.unity3d" -) -# Silhouette spawn rebuilt as a Custom_Model that clones the Silhouette -# Marker's recipe (same mesh family, TTS-native shader): correct translucency -# on Mac with the exact marker look, instead of an AssetBundle whose shader -# can't load. Mesh is 1.062 wide x 1.485 tall (base pivot) vs the bundle's -# 1x1 unit cylinder, hence the scale factors that preserve vanilla sizing. -# Collider = degenerate 1mm triangle so the attachment can't shove minis. -SILHOUETTE_MODEL_RE = re.compile( - r"local silhouette = spawnObject\(\{\s*" - r"type = \"Custom_AssetBundle\",\s*" - r"position = pos,\s*" - r"rotation = rot,\s*" - r"scale = \{scale,height,scale\}\s*" - r"\}\)\s*" - r"silhouette\.setCustomObject\(\{\s*" - r"assetbundle = silhouetteData,\s*" - r"material = 3\s*" - r"\}\)\s*" - r"silhouette\.setColorTint\(\{([0-9., ]+)\}\)" -) -SILHOUETTE_MODEL_REPLACEMENT = r"""-- MAC PATCH silhouette dual-path: branch on the table-wide mode toggle. - local silhouette - if Global.call("gGetMode") == "windows" then - -- Original AssetBundle Projector, untouched. Opaque on Mac: that is the - -- vanilla behaviour the toggle is there to switch away from. - silhouette = spawnObject({ - type = "Custom_AssetBundle", - position = pos, - rotation = rot, - scale = {scale,height,scale} - }) - silhouette.setCustomObject({ - assetbundle = silhouetteData, - material = 3 - }) - else - -- Silhouette-as-model (marker recipe). Oblong bases reuse the ORIGINAL - -- mesh, extracted from the vanilla bundles (silh_new_long_1in / - -- silh_new_snail_1in), so the Mac path changes the rendering and - -- nothing else: same outline as Windows, at the vanilla scale - -- ({scale,height,scale} with scale = 1 for both oblong sizes). Round - -- bases keep the marker mesh with the unit-normalizing factors. - local _macMesh = "https://steamusercontent-a.akamaihd.net/ugc/1003681898505457098/962BED032738C4448CCD4B737E82876715459FE8/" - local _macSx, _macSy, _macSz = scale * 0.9416, height * 0.6734, scale * 0.9416 - local _macObl = ({ - long = "https://raw.githubusercontent.com/ironsquadronfr-hub/tts/mac-projector-fallback/mod/data/mac-fallback-assets/silh_exact_long_1.obj", - snail = "https://raw.githubusercontent.com/ironsquadronfr-hub/tts/mac-projector-fallback/mod/data/mac-fallback-assets/silh_exact_snail_1.obj", - })[(unitData and unitData.baseSize) or ""] - if _macObl then - _macMesh = _macObl - _macSx, _macSy, _macSz = scale, height, scale - end - silhouette = spawnObject({ - type = "Custom_Model", - position = pos, - rotation = rot, - scale = {_macSx, _macSy, _macSz} - }) - silhouette.setCustomObject({ - mesh = _macMesh, - collider = "https://raw.githubusercontent.com/ironsquadronfr-hub/tts/mac-projector-fallback/mod/data/mac-fallback-assets/collider_null.obj", - convex = true, - material = 0, - type = 1 - }) - end - silhouette.setColorTint({\g<1>})""" - # SIL/LCK button placement on oblong bases (upstream bug, both OSes): the # vanilla offset is baseRadius/2 + 0.1 with a single per-size radius and no @@ -1647,35 +800,6 @@ end""" -SILHOUETTE_URL_RE = re.compile( - r'(silhouetteData\s*=\s*)"https?://[^"]*/ugc/[^"]+"' -) -SILHOUETTE_URL_REPLACEMENT = r'\1"' + SILHOUETTE_BUNDLE_URL + '"' - - -# Cleanup of debug prints and corrupted signatures from earlier sessions. -# Safe no-op on a clean save. Matches both the legacy `print("[SIL DEBUG] ...)` -# form AND the chat-visible `printToAll("[SIL] ...", {...})` form. -SIL_DEBUG_STRIP_RE = re.compile( - # Match leading horizontal whitespace only (NOT \s* which would also eat - # the newline before, mashing the function signature against the next - # statement - that was a real bug we hit earlier this session). - r'[ \t]*(?:print\("\[SIL DEBUG\][^\n]*\)|' - r'printToAll\("\[SIL\][^"]*",\s*\{[^}]*\}\))\r?\n' -) -# Repair function signatures that were mashed by the previous \s*-glob bug. -# Idempotent: target the specific mashed patterns; matches are zero on a -# clean save. -SIL_REPAIR_TOGGLE_RE = re.compile( - r'(function toggleSilhouettes\(\))( if silhouetteState then)' -) -SIL_REPAIR_SHOW_RE = re.compile( - r'(function showSilhouette\(\))( for k, guid in pairs\(miniGUIDs)' -) -SIL_REPAIR_SPAWN_RE = re.compile( - r'(function spawnSilhouette\(obj, pos, rot\))( local globals)' -) - # Silhouette state-desync fix (upstream bug). # @@ -1722,23 +846,29 @@ ONLOAD_OPEN_RE = re.compile(r"function onload\(\)\r?\n") -# SIL button rename (root cause: TTS engine intercepts the click_function -# name "toggleSilhouettes" silently in Mac mode; LCK/R buttons unaffected -# because their click_function names differ. Confirmed empirically 17 mai -# 2026: renaming to "macToggleSil" + forwarder unblocks Mac mode entirely). +# SIL button rename. On macOS the click_function name "toggleSilhouettes" +# was silently swallowed by TTS: the button played its sound and animation +# but the function was never called, while LCK and R (different names) kept +# working. Renaming it + forwarding unblocked it, confirmed empirically on +# 17 may 2026. # -# We swap the click_function name on the SIL button definition AND inject a -# forwarder function that simply calls toggleSilhouettes(). The original -# toggleSilhouettes is untouched, so Windows mode behavior is identical. +# KEPT even though silhouettes left the toggle's scope (12 aug). Reverting +# our silhouette code to vanilla back then did NOT lift the mute, so the +# leading suspect is a side effect of the Global patch itself, which we do +# still inject. Behaviour is unchanged either way: the button calls the +# untouched vanilla toggleSilhouettes through a one-line forwarder. Worth a +# single in-game click to find out whether it can go: patch a save without +# it and press SIL on a Unit Leader. # Idempotent: re-runs detect both markers and skip. SIL_BUTTON_CLICKFN_OLD = 'click_function = "toggleSilhouettes"' SIL_BUTTON_CLICKFN_NEW = 'click_function = "macToggleSil"' SIL_FORWARDER = ''' --- MAC PATCH: rebuilt SIL button click handler. The original click_function --- name "toggleSilhouettes" is silently intercepted by TTS in Mac mode (the --- SIL button plays its click sound/animation but the function is never --- called). Renaming the click_function on the button definition + adding --- this forwarder restores the routing. +-- MAC PATCH: rebuilt SIL button click handler. On macOS the original +-- click_function name "toggleSilhouettes" is silently intercepted by TTS +-- (the SIL button plays its click sound and animation but the function is +-- never called). Renaming the click_function on the button definition and +-- adding this forwarder restores the routing. The silhouette code itself is +-- vanilla. function macToggleSil() toggleSilhouettes() end @@ -1923,6 +1053,12 @@ Global.call("gClearRange", { figGUID = self.getGUID() }) rangeOn = false else + -- Clear BEFORE triggering, same rule as the Order Token's COHESION + -- and RANGE buttons. gRangeTrigger toggles by GUID, and the hover + -- hotkey writes to the very same key on this token, so without this + -- the first click on R would turn that overlay OFF while we set + -- rangeOn = true, leaving the button inverted from then on. + Global.call("gClearRange", { figGUID = self.getGUID() }) Global.call("gRangeTrigger", { figGUID = self.getGUID(), playerColor = playerColor, @@ -2039,12 +1175,12 @@ def patch_object_scripts(data: dict) -> tuple: Range block: on every object containing the !/RangeRulers include (Order_Token, Tokens, POI, bomb_cart, etc. - ~20 objects). - Returns (n_cohesion_patched, n_range_patched, n_dep_patched). + Returns (n_cohesion_patched, n_range_patched). """ - n_coh, n_rng, n_dep = 0, 0, 0 + n_coh, n_rng = 0, 0 def walk(o): - nonlocal n_coh, n_rng, n_dep + nonlocal n_coh, n_rng if isinstance(o, dict): guid = o.get("GUID", "").lower() if "LuaScript" in o: @@ -2059,45 +1195,19 @@ def walk(o): ls = new_ls changed = True - # Cleanup: strip stale debug prints + repair any signatures - # mashed by an earlier (overzealous) strip pass. Both are - # no-ops on a clean save. - new_ls, n = SIL_DEBUG_STRIP_RE.subn("", ls) - if n > 0: - ls = new_ls - changed = True - for rx in (SIL_REPAIR_TOGGLE_RE, SIL_REPAIR_SHOW_RE, SIL_REPAIR_SPAWN_RE): - new_ls, n = rx.subn(r'\1\n\2', ls) - if n > 0: - ls = new_ls - changed = True - - # (Diagnostic SIL prints removed 17 mai 2026 once mute Mac - # mode confirmed. SIL_DEBUG_STRIP_RE above stays as a cleanup - # pass for older saves that still carry the prints.) - - # Silhouette URL swap to our Unity-6-compiled bundle. - # Applies to any object that defines spawnSilhouette - # (Unit_Leader 99f1c8, Bomb Cart b497e1, POI Token 761483). - # Idempotent: the regex only matches Steam UGC URLs (/ugc/), - # not our fork URL, so re-runs are no-ops. - new_ls, n = SILHOUETTE_MODEL_RE.subn(SILHOUETTE_MODEL_REPLACEMENT, ls) - if n > 0: - ls = new_ls - changed = True + # Silhouettes are OUT of the toggle's scope (12 aug): their + # bundles are repaired, so vanilla renders them correctly on + # both platforms and the Lua fallback is gone. What stays + # below are fixes to upstream bugs that happen to live on the + # same objects, none of which branch on the mode. new_ls, n = BUTTON_OFFSET_RE.subn(BUTTON_OFFSET_REPLACEMENT, ls) if n > 0: ls = new_ls changed = True - # NOTE: the silhouetteData URL is deliberately left alone. It - # used to be swapped for our Unity-6 bundle, but the marker - # recipe above supplanted that bundle, and rewriting the URL - # would leave Windows mode spawning our asset instead of the - # original one. - - # SIL button rename + forwarder. Bypasses the TTS engine - # bug where the click_function name "toggleSilhouettes" is - # silently muted in Mac mode. Idempotent: replace() is no-op + + # SIL button rename + forwarder. Bypasses the TTS engine bug + # where the click_function name "toggleSilhouettes" is + # silently muted on macOS. Idempotent: replace() is no-op # once swap is done, marker check prevents double-injection. if SIL_BUTTON_CLICKFN_OLD in ls: ls = ls.replace(SIL_BUTTON_CLICKFN_OLD, SIL_BUTTON_CLICKFN_NEW) @@ -2182,18 +1292,6 @@ def rng_repl(m): ls = ls + TOKEN_BUTTON_WRAPPER changed = True - # Deployment Boundary (only in SETUP_CONTROLLER 1cb552) - Mac only - if guid == "1cb552": - new_ls, n = DEPLOYMENT_SPAWN_RE.subn(DEPLOYMENT_SPAWN_REPLACEMENT, ls, count=1) - if n > 0: - ls = new_ls - n_dep += 1 - changed = True - new_ls, n = CLEAR_DEPLOYMENT_RE.subn(CLEAR_DEPLOYMENT_REPLACEMENT, ls, count=1) - if n > 0: - ls = new_ls - changed = True - if changed: o["LuaScript"] = ls @@ -2204,7 +1302,7 @@ def rng_repl(m): walk(x) walk(data) - return n_coh, n_rng, n_dep + return n_coh, n_rng ASSETS_BASE_URL = ("https://raw.githubusercontent.com/ironsquadronfr-hub/tts/" @@ -2234,12 +1332,12 @@ def main(): if name.endswith("[MAC PATCH]"): data["SaveName"] = name[: -len("[MAC PATCH]")].rstrip() - # Register the apple-logo UI sprite for the toggle button (idempotent - # by Name). + # Register the Iron Squadron UI sprite for the toggle button (idempotent + # by Name; macAppleLogo is the retired name and is dropped on the way). assets = [a for a in (data.get("CustomUIAssets") or []) - if a.get("Name") != "macAppleLogo"] - assets.append({"Type": 0, "Name": "macAppleLogo", - "URL": ASSETS_BASE_URL + "apple_logo.png"}) + if a.get("Name") not in ("isqLogo", "macAppleLogo")] + assets.append({"Type": 0, "Name": "isqLogo", + "URL": ASSETS_BASE_URL + "iron_squadron_logo_v2.png"}) data["CustomUIAssets"] = assets # 1. Append manager + handlers to Global LuaScript (idempotent: remove @@ -2255,10 +1353,9 @@ def main(): # 2. Replace Cohesion + Range + Deployment blocks in object scripts. print("Object script patches:") - n_coh, n_rng, n_dep = patch_object_scripts(data) + n_coh, n_rng = patch_object_scripts(data) print(f" Cohesion blocks replaced: {n_coh}") print(f" Range blocks replaced: {n_rng}") - print(f" Deployment blocks replaced: {n_dep}") print() dst.parent.mkdir(parents=True, exist_ok=True) From d26ce401f993d461d9e7ce3a58d789e06becff82 Mon Sep 17 00:00:00 2001 From: Martin Pourrat Date: Wed, 12 Aug 2026 03:45:50 +0200 Subject: [PATCH 24/42] Add the Mac bundle procedure the PR was already pointing at The package existed but only on our disk, so the pull request described a folder that was not in the branch. It is the durable half of the work: with a model shipping every couple of weeks, whoever builds the bundles needs to produce bi-platform ones without us. - README: the cause, the one-line precision change to make in the shader sources, the build-twice-and-merge procedure, and the trap that cost us the most time (merging variants inside a single pass looks fine and renders wrong, because parameter binding tables are per pass, not per platform) - BuildBiPlatformBundle.cs: an Editor menu entry plus a batch-mode entry point - merge_subshader_bundles.py: the merge itself Co-Authored-By: Claude Opus 5 (1M context) --- mac-support-package/BuildBiPlatformBundle.cs | 93 ++++++++++++++ mac-support-package/README.md | 103 +++++++++++++++ .../merge_subshader_bundles.py | 120 ++++++++++++++++++ 3 files changed, 316 insertions(+) create mode 100644 mac-support-package/BuildBiPlatformBundle.cs create mode 100644 mac-support-package/README.md create mode 100644 mac-support-package/merge_subshader_bundles.py diff --git a/mac-support-package/BuildBiPlatformBundle.cs b/mac-support-package/BuildBiPlatformBundle.cs new file mode 100644 index 000000000..a250dbfb9 --- /dev/null +++ b/mac-support-package/BuildBiPlatformBundle.cs @@ -0,0 +1,93 @@ +using System; +using System.IO; +using UnityEditor; +using UnityEngine; + +// Builds the selected prefab(s) as AssetBundles for BOTH Windows and macOS, so +// the two can be merged into a single file that renders on either platform. +// +// Put this in any Editor/ folder of the Unity project, then either: +// - select prefabs in the Project window and use Assets > Build Bundle (Windows + macOS) +// - or run it in batch mode: +// Unity -batchmode -quit -projectPath . \ +// -executeMethod BuildBiPlatformBundle.Run -logFile build.log +// (batch mode builds every asset that already has an AssetBundle name) +// +// Output: BiPlatformBundles/win/ and BiPlatformBundles/mac/. +// Then merge each pair: +// python3 merge_subshader_bundles.py BiPlatformBundles/win/ \ +// BiPlatformBundles/mac/ +// and upload the merged file. Windows players get the exact same rendering as +// before, Mac players stop seeing magenta and raw team-colour masks. +public static class BuildBiPlatformBundle +{ + const string OutRoot = "BiPlatformBundles"; + + [MenuItem("Assets/Build Bundle (Windows + macOS)")] + static void BuildSelection() + { + var builds = new System.Collections.Generic.List(); + + foreach (var obj in Selection.objects) + { + string path = AssetDatabase.GetAssetPath(obj); + if (string.IsNullOrEmpty(path)) continue; + + // Reuse the bundle name already set on the asset when there is one, + // so the output matches what the mod expects. + var importer = AssetImporter.GetAtPath(path); + string name = importer != null && !string.IsNullOrEmpty(importer.assetBundleName) + ? importer.assetBundleName + : Path.GetFileNameWithoutExtension(path).ToLowerInvariant(); + + builds.Add(new AssetBundleBuild { assetBundleName = name, assetNames = new[] { path } }); + } + + if (builds.Count == 0) + { + Debug.LogError("Select at least one prefab in the Project window."); + return; + } + + BuildBoth(builds.ToArray()); + } + + [MenuItem("Assets/Build Bundle (Windows + macOS)", true)] + static bool BuildSelectionValidate() + { + return Selection.objects != null && Selection.objects.Length > 0; + } + + public static void Run() + { + // Batch mode: build everything that already carries an AssetBundle name. + BuildBoth(null); + } + + static void BuildBoth(AssetBundleBuild[] builds) + { + BuildOne(builds, BuildTarget.StandaloneWindows64, Path.Combine(OutRoot, "win")); + BuildOne(builds, BuildTarget.StandaloneOSX, Path.Combine(OutRoot, "mac")); + Debug.Log("BIPLATFORM: done. Now merge each pair with merge_subshader_bundles.py"); + } + + static void BuildOne(AssetBundleBuild[] builds, BuildTarget target, string outputPath) + { + Directory.CreateDirectory(outputPath); + var started = DateTime.Now; + + AssetBundleManifest manifest = builds == null + ? BuildPipeline.BuildAssetBundles(outputPath, BuildAssetBundleOptions.None, target) + : BuildPipeline.BuildAssetBundles(outputPath, builds, BuildAssetBundleOptions.None, target); + + if (manifest == null) + { + Debug.LogError("BIPLATFORM: build failed for " + target); + return; + } + + Debug.Log(string.Format("BIPLATFORM: {0} -> {1} ({2} bundles, {3:F1} min)", + target, outputPath, manifest.GetAllAssetBundles().Length, + (DateTime.Now - started).TotalMinutes)); + } +} diff --git a/mac-support-package/README.md b/mac-support-package/README.md new file mode 100644 index 000000000..84f5895ea --- /dev/null +++ b/mac-support-package/README.md @@ -0,0 +1,103 @@ +# Making the mod's AssetBundles work on Mac + +Short version: **build each bundle twice and merge the two files.** One extra step +in whoever builds the bundles, and every mini from then on renders correctly on +both platforms. Nothing changes for Windows players. + +--- + +## What is broken and why + +Shader variants inside an AssetBundle are compiled **per graphics API**, decided +by the build target. The mod's bundles were built for Windows, so they carry +`d3d11` and `glcore` variants (we scanned them: 60 of 62 shaders are exactly that +pair). That was correct at the time, and it is why the mod used to work on Mac: +TTS ran OpenGL there. + +Since **TTS v14** the Mac player runs **Metal** and has no usable OpenGL path +left. `-force-glcore` reaches the process and is silently ignored. So the custom +shaders never find a variant they can load. TTS substitutes the Standard shader +where it can, which is why minis show their raw team-colour mask, and renders +**magenta** where it cannot, which is why the projectors look worst. + +Nothing is wrong with the shader code. It was simply never compiled for Metal. + +## The fix, in two parts + +### 1. One shader-source change, worth doing once and for all + +In `ColorReplacer.shader` (and the other `BucketheadBits` shaders), the team +colour swap is computed in `fixed` precision: + +```hlsl +fixed ramp = 1.0 - distance(c.rgb, _SwapColor.rgb); +fixed swapMask = saturate((ramp - _SwapCutoff) * _SwapContrast); +``` + +On DirectX, `fixed` and `half` are treated as **32-bit floats**. On Metal, `half` +is a real **16-bit float**. The mask is a near-binary threshold amplified by +`_SwapContrast` (5.0 by default), so in 16 bits the pixels sitting near the +threshold flip at random: speckled bases, cape linings left green, magenta +fringes along the swapped areas. + +**Changing `fixed` and `half` to `float` in these shaders is a no-op on Windows** +(they were already 32-bit there) and fixes Metal for good. That is the cleanest +place to fix it: once, in the source. + +### 2. Build each bundle twice, then merge + +Unity cannot produce a single bundle covering both platforms: ask for Metal in a +Windows build and it silently drops it. But a `Shader` object can declare several +**SubShaders**, and Unity falls through to the next one when the first has no +variant for the current graphics API. + +So: build the prefab for `StandaloneWindows64`, build it again for +`StandaloneOSX`, and stack the macOS SubShader behind the Windows one in the same +file. + +``` +# 1. build both (Editor menu: Assets > Build Bundle (Windows + macOS)) +# -> BiPlatformBundles/win/ and BiPlatformBundles/mac/ + +# 2. merge +pip install UnityPy +python3 merge_subshader_bundles.py BiPlatformBundles/win/ \ + BiPlatformBundles/mac/ + +# 3. upload as usual +``` + +The Windows SubShader stays first and byte-identical, so Windows players get +exactly what they get today. The extra SubShader is inert for them. + +## Files here + +- `BuildBiPlatformBundle.cs` — drop into any `Editor/` folder. Adds + **Assets > Build Bundle (Windows + macOS)**, and works in batch mode via + `-executeMethod BuildBiPlatformBundle.Run`. +- `merge_subshader_bundles.py` — the merge step. Requires `UnityPy`. + +## One trap, if you go digging + +Merging the variants **inside a single pass** does not work. The parameter +binding tables (`m_NameIndices`, `m_CommonParameters`, +`m_ConstantBufferBindings`) are stored once per pass and shared by every platform +in it, and Metal lays them out differently from DirectX (`VGlobals`/`FGlobals` +instead of `$Globals`, offsets reset to zero). The result loads, logs nothing, +and renders wrong, which costs a lot of time to diagnose. A SubShader carries its +own tables. It is also why `d3d11` and `glcore` coexist happily in the current +bundles: those two share the layout. + +## Status on our side + +Tested in game on **both** platforms with the same merged file: an A-A5 Speeder +Truck renders correctly on Mac and on Windows. + +Of the 190 bundles the mod references, 105 use no custom shader and were never +broken. 85 are affected, and 77 of those are already rebuilt and running. The +remaining 8 belong to seven older units nobody has the sources for any more +(Yoda, the Wookiee Warriors line, the Wookiee Chieftain, the Raddaugh Gnasp +Fluttercraft, the Infantry Support Platform, and the shared materials bundle used +by Kalani and Kraken). Those need a different route, or their sources. + +Happy to help wire this into your build, or to hand over the rebuilt bundles. diff --git a/mac-support-package/merge_subshader_bundles.py b/mac-support-package/merge_subshader_bundles.py new file mode 100644 index 000000000..382bc7cc6 --- /dev/null +++ b/mac-support-package/merge_subshader_bundles.py @@ -0,0 +1,120 @@ +#!/usr/bin/env python3 +"""Merge a Windows and a macOS AssetBundle into one file that renders on both. + +Why this exists +--------------- +AssetBundle shader variants are compiled per graphics API, decided by the build +target. A StandaloneWindows64 build carries DirectX (and OpenGL) variants only; a +StandaloneOSX build carries Metal only. Since TTS v14 the Mac player runs Metal +and has no usable OpenGL path left, so bundles built for Windows cannot load +their custom shaders there: TTS falls back to Standard where it can, and renders +magenta where it cannot. + +Unity cannot produce one bundle covering both platforms: it silently drops any +graphics API that is foreign to the build target. But a Shader object can declare +several SubShaders, and Unity falls through to the next one when the first has no +variant for the current graphics API. So we build twice and stack the macOS +SubShader behind the Windows one. + +The Windows SubShader stays first and byte-identical, so Windows players get +exactly what they get today. The extra SubShader is inert for them. + +⚠ Do NOT try to merge the variants inside a single pass. The parameter binding +tables (m_NameIndices, m_CommonParameters, m_ConstantBufferBindings) are stored +once per pass and shared by every platform in it, and Metal lays them out +differently from DirectX (VGlobals/FGlobals instead of $Globals, offsets reset to +zero). The result loads, logs nothing, and renders wrong. A SubShader carries its +own tables, which is why this works. It is also why d3d11 and glcore coexist +happily in the current bundles: those two share the layout. + +Requirements: pip install UnityPy + +Usage: + merge_subshader_bundles.py + +Both bundles must come from the same prefab, built twice with only the target +changed. Shaders are matched by name. +""" + +import sys + +import UnityPy + +GPU = {4: "d3d11", 9: "gles3", 14: "metal", 15: "glcore", 18: "vulkan"} + + +def shaders_by_name(env): + out = {} + for obj in env.objects: + if obj.type.name != "Shader": + continue + tree = obj.read_typetree() + out[tree["m_ParsedForm"]["m_Name"]] = tree + return out + + +def merge(base_tree, donor_tree): + """Concatenate the blobs, then append the donor's SubShaders. Returns platforms added.""" + added = 0 + blob = bytes(base_tree["compressedBlob"]) + + for i, platform in enumerate(donor_tree["platforms"]): + if platform in base_tree["platforms"]: + continue + # The donor's offsets are relative to its own blob, so rebase them. + shift = len(blob) + base_tree["platforms"].append(platform) + base_tree["offsets"].append([o + shift for o in donor_tree["offsets"][i]]) + base_tree["compressedLengths"].append(list(donor_tree["compressedLengths"][i])) + base_tree["decompressedLengths"].append(list(donor_tree["decompressedLengths"][i])) + base_tree["stageCounts"].append(donor_tree["stageCounts"][i]) + blob += bytes(donor_tree["compressedBlob"]) + added += 1 + + if added: + base_tree["compressedBlob"] = list(blob) + # The donor's SubShader arrives with its own parameter tables. That is the + # whole point of doing it this way. + base_tree["m_ParsedForm"]["m_SubShaders"].extend(donor_tree["m_ParsedForm"]["m_SubShaders"]) + + return added + + +def main(base_path, donor_path, out_path): + base_env = UnityPy.load(base_path) + donors = shaders_by_name(UnityPy.load(donor_path)) + total = 0 + + for obj in base_env.objects: + if obj.type.name != "Shader": + continue + tree = obj.read_typetree() + name = tree["m_ParsedForm"]["m_Name"] + if name not in donors: + print(f" {name}: not in the macOS bundle, left as is") + continue + + before = [GPU.get(p, p) for p in tree["platforms"]] + subshaders_before = len(tree["m_ParsedForm"]["m_SubShaders"]) + added = merge(tree, donors[name]) + after = [GPU.get(p, p) for p in tree["platforms"]] + + if added: + obj.save_typetree(tree) + total += added + print(f" {name}: {before} -> {after}, " + f"SubShaders {subshaders_before} -> {len(tree['m_ParsedForm']['m_SubShaders'])}") + + if not total: + print(" nothing to merge (no shared shader between the two bundles)") + + with open(out_path, "wb") as fh: + fh.write(base_env.file.save(packer="lzma")) + print(f" wrote {out_path}") + + +if __name__ == "__main__": + if len(sys.argv) != 4: + print(__doc__) + sys.exit(1) + main(sys.argv[1], sys.argv[2], sys.argv[3]) From 3ce28eb12fad0a5e42ed2eff3535d16588888f5d Mon Sep 17 00:00:00 2001 From: Martin Pourrat Date: Wed, 12 Aug 2026 14:01:36 +0200 Subject: [PATCH 25/42] Add the Mac repair toolchain, and fix the unlit glow effects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two root causes, not one. The known one is the missing Metal variant in bundles built for Windows only. The second surfaced today: the glow shaders read a vertex colour channel that no mesh in the mod actually has (1 of 408, and it carries no custom shader). DirectX and OpenGL substitute white for a missing channel, Metal substitutes black — and since those passes are Blend One One, multiplying by zero adds nothing. Lightsabers, eyes and shields were dark on Mac across 12 bundles, and nobody noticed because they were no longer magenta. patch_shader_vertexcolor.py neutralises that read for the macOS build only, so the Windows SubShader stays byte for byte what it is today. graft_metal_2019_1.py covers the units whose sources are lost: it grafts a Metal SubShader into the published bundle, leaving meshes, textures and materials untouched. It is a sibling of merge_subshader_platforms.py, not a replacement — Unity changed the shader blob layout between 2019.1 and 2019.4, and each script refuses the other's format. The published bundles span five Unity versions, so the graft has to be built by the editor that produced the target. README.md carries the full chain, the reasoning behind stacking a whole SubShader rather than merging a pass, and the traps met along the way. Co-Authored-By: Claude Opus 5 (1M context) --- mac-patcher/tools/README.md | 109 ++++++++++ .../BuildMetalGraft.cs | 99 +++++++++ mac-patcher/tools/graft_metal_2019_1.py | 117 +++++++++++ mac-patcher/tools/install_dual_to_cache.py | 154 ++++++++++++++ mac-patcher/tools/install_grafted_to_cache.py | 127 ++++++++++++ mac-patcher/tools/inventaire-bundles.csv | 191 ++++++++++++++++++ mac-patcher/tools/inventory_mod_bundles.py | 166 +++++++++++++++ .../tools/merge_subshader_platforms.py | 102 ++++++++++ mac-patcher/tools/patch_shader_vertexcolor.py | 115 +++++++++++ 9 files changed, 1180 insertions(+) create mode 100644 mac-patcher/tools/README.md create mode 100644 mac-patcher/tools/UnityProject-2019.1-Editor/BuildMetalGraft.cs create mode 100644 mac-patcher/tools/graft_metal_2019_1.py create mode 100644 mac-patcher/tools/install_dual_to_cache.py create mode 100644 mac-patcher/tools/install_grafted_to_cache.py create mode 100644 mac-patcher/tools/inventaire-bundles.csv create mode 100644 mac-patcher/tools/inventory_mod_bundles.py create mode 100644 mac-patcher/tools/merge_subshader_platforms.py create mode 100644 mac-patcher/tools/patch_shader_vertexcolor.py diff --git a/mac-patcher/tools/README.md b/mac-patcher/tools/README.md new file mode 100644 index 000000000..8a50ecab7 --- /dev/null +++ b/mac-patcher/tools/README.md @@ -0,0 +1,109 @@ +# Outils de réparation Mac des AssetBundles + +Ces scripts ont produit la réparation Mac du mod. Ils sont ici pour être +retrouvables et reproductibles, pas pour être jolis : ce sont des outils +d'atelier, en français, à usage interne Iron Squadron. + +Le paquet destiné aux développeurs du mod, en anglais, est ailleurs : +`mac-support-package/`. + +## Les deux causes racines + +**1. Pas de variante Metal.** Les bundles ont été compilés pour +`StandaloneWindows64` uniquement, entre 2019 et 2022. Quand TTS est passé à +Metal sur Mac, leurs shaders custom n'avaient aucune variante pour cette API : +figurines magenta. Rien à voir avec Unity 6, contrairement à ce qu'on a cru +pendant des semaines. + +**2. La couleur de sommet vaut zéro sur Metal.** Les shaders d'effets lumineux +lisent `v.color`, un canal que **aucun mesh du mod ne possède** (mesuré : 1 seul +sur 408, et il n'a pas de shader custom). DirectX et OpenGL remplacent un canal +absent par du blanc, Metal par du noir. Les passes étant en `Blend One One`, +multipliées par zéro elles n'ajoutent rien : sabres, yeux et boucliers éteints, +sans que rien ne paraisse cassé. Touche 12 bundles. + +## La chaîne, dans l'ordre + +Deux voies selon qu'on a les sources du modèle ou non. + +### Voie rebuild — quand les sources existent + +``` +patch_shader_precision.py --apply # fixed/half -> float (précision Metal) +patch_shader_vertexcolor.py --apply # v.color -> blanc (effets lumineux) +Unity 6 -executeMethod BuildAllTargets.Run -target mac -out AssetBundles-mac +merge_all_bundles.py AssetBundles-win AssetBundles-mac AssetBundles-dual +patch_shader_precision.py --restore # remet les sources d'origine +DUAL_DIR=AssetBundles-dual install_dual_to_cache.py --install +``` + +On ne rebuilde que la cible macOS : le SubShader Windows du bundle publié reste +bit pour bit celui d'aujourd'hui. + +### Voie greffe — quand il n'y a pas de sources + +C'est la voie des 8 orphelins, et la seule à dérive nulle : le bundle publié +garde ses maillages, ses textures et ses matériaux inchangés, on ne lui ajoute +qu'un SubShader. + +``` +Unity 2019.1.9f1 -executeMethod BuildMetalGraft.Run -out AssetBundles-graft +graft_metal_2019_1.py +install_grafted_to_cache.py --install +``` + +**La version d'Unity doit correspondre à celle du bundle publié.** Les 248 +bundles se répartissent sur cinq versions : 2019.4.19f1 (144), 2019.1.9f1 (83), +2019.1.0f2 (11), 2019.4.40f1 (9), 5.3.4f1 (1). Elle se lit dans les 200 premiers +octets du fichier, en clair après la signature `UnityFS`. + +Entre 2019.1 et 2019.4, la sérialisation des shaders change : les tables du blob +passent de plates à imbriquées. D'où deux scripts de fusion qui refusent chacun +le format de l'autre : + +| script | format | produit par | +|---|---|---| +| `merge_subshader_platforms.py` | listes imbriquées, champ `stageCounts` | Unity 6 | +| `graft_metal_2019_1.py` | listes plates | Unity 2019.1 | + +## Pourquoi un SubShader entier et pas une passe fusionnée + +Les tables de liaison de paramètres (`m_NameIndices`, `m_CommonParameters`, +`m_ConstantBufferBindings`) sont stockées **une fois par passe** et partagées par +toutes les plateformes. DirectX et OpenGL cohabitent parce qu'ils partagent +cette disposition. Metal, lui, éclate les globals en `VGlobals`/`FGlobals` et +remet les offsets à zéro : greffer un programme Metal dans une passe DirectX lui +donne les mauvaises liaisons, et il rend faux **sans aucun message d'erreur**. + +Un shader peut en revanche déclarer plusieurs SubShaders, chacun avec ses +propres passes donc ses propres tables. On empile donc le SubShader macOS +derrière celui d'origine : Unity descend au suivant quand le premier n'a pas de +variante pour l'API courante. + +## Pièges rencontrés + +- **La sauvegarde ne se juge pas à son existence mais à son contenu.** Un bundle + simplement *déposé* au premier passage existe au second et se fait sauvegarder + alors que c'est déjà le nôtre. 60 entrées sur 114 étaient dans ce cas. Le + garde-fou est `is_ours()` : aucun bundle publié ne porte de variante Metal, + donc en trouver une prouve que le fichier vient de nous. +- **Toujours greffer depuis le bundle publié**, jamais depuis un bundle déjà + greffé, sinon on empile les SubShaders à chaque passage. +- **macOS tue les vieux éditeurs Unity** au lancement (`SIGKILL`, aucun log + écrit), avec une alerte « Unity est endommagé ». Ce n'est pas une quarantaine : + la réponse est Réglages Système → Confidentialité et sécurité → « Ouvrir quand + même ». Ne jamais cliquer « Placer dans la corbeille ». +- **Certains shaders sont en latin-1** (l'en-tête « © Allen White ») : lire en + binaire, ne pas réencoder. +- **UnityPy** : `m_Colors` donne des dictionnaires modifiables, `m_Floats` des + tuples immuables. Pour modifier un float, reconstruire la liste. +- **zsh ne découpe pas les variables non quotées** : pour une longue liste de + chemins, passer par `bash -c` avec un tableau. + +## Ce qu'on ne touche jamais + +- Les bundles **sans shader custom** : ils n'ont jamais été cassés. +- `stunt_double_bot_1` : son rebuild ajoute un socle absent du bundle publié. +- Les **Custom Models** (`mesh` + `diffuse` au lieu de `bundle`) : TTS leur + applique son propre matériau, ils ne peuvent pas être magenta. Ils sont + majoritaires dans le mod. diff --git a/mac-patcher/tools/UnityProject-2019.1-Editor/BuildMetalGraft.cs b/mac-patcher/tools/UnityProject-2019.1-Editor/BuildMetalGraft.cs new file mode 100644 index 000000000..2b8131fe9 --- /dev/null +++ b/mac-patcher/tools/UnityProject-2019.1-Editor/BuildMetalGraft.cs @@ -0,0 +1,99 @@ +using System; +using System.IO; +using UnityEditor; +using UnityEngine; + +// Greffon Metal au format de serialisation Unity 2019, 12 aout 2026. +// +// But : produire un bundle qui ne contient RIEN d'autre que les shaders du mod, +// compiles pour Metal. merge_subshader_platforms.py empile ensuite leur +// SubShader derriere celui du bundle PUBLIE, qui ne connait que d3d11/glcore. +// Le bundle publie garde donc ses maillages, ses textures et ses materiaux bit +// pour bit : c'est la voie zero-derive, et la seule ouverte pour les 8 +// orphelins dont on n'a pas les sources. +// +// Un shader n'entre dans un bundle que s'il est reference : on cree donc un +// materiau par shader, porte par un quad, et c'est tout. +// +// Usage : +// -executeMethod BuildMetalGraft.Run [-out ] +public static class BuildMetalGraft +{ + const string BundleName = "metal_graft"; + const string StageDir = "Assets/_Graft"; + + public static void Run() + { + string outputPath = Arg("-out", "AssetBundles-graft"); + + if (!Directory.Exists(StageDir)) + AssetDatabase.CreateFolder("Assets", "_Graft"); + + string[] shaderGuids = AssetDatabase.FindAssets("t:Shader", new[] { "Assets/Shaders" }); + if (shaderGuids.Length == 0) + { + Debug.LogError("GRAFT: aucun shader dans Assets/Shaders"); + EditorApplication.Exit(1); + return; + } + + foreach (string guid in shaderGuids) + { + string shaderPath = AssetDatabase.GUIDToAssetPath(guid); + Shader shader = AssetDatabase.LoadAssetAtPath(shaderPath); + if (shader == null) + { + Debug.LogError("GRAFT: illisible " + shaderPath); + EditorApplication.Exit(2); + return; + } + if (shader.name.StartsWith("Hidden/InternalErrorShader")) + { + Debug.LogError("GRAFT: " + shaderPath + " ne compile pas (InternalErrorShader)"); + EditorApplication.Exit(3); + return; + } + + string matPath = StageDir + "/" + Path.GetFileNameWithoutExtension(shaderPath) + ".mat"; + var mat = new Material(shader); + AssetDatabase.CreateAsset(mat, matPath); + + var importer = AssetImporter.GetAtPath(matPath); + importer.assetBundleName = BundleName; + + Debug.Log("GRAFT: " + shader.name + " <- " + shaderPath); + } + + AssetDatabase.SaveAssets(); + AssetDatabase.Refresh(); + + Directory.CreateDirectory(outputPath); + var manifest = BuildPipeline.BuildAssetBundles( + outputPath, BuildAssetBundleOptions.None, BuildTarget.StandaloneOSX); + + if (manifest == null) + { + Debug.LogError("GRAFT: build echoue"); + EditorApplication.Exit(4); + return; + } + + string produced = Path.Combine(outputPath, BundleName); + if (!File.Exists(produced)) + { + Debug.LogError("GRAFT: " + produced + " absent apres build"); + EditorApplication.Exit(5); + return; + } + + Debug.Log(string.Format("GRAFT: termine, {0} shaders, {1} octets -> {2}", + shaderGuids.Length, new FileInfo(produced).Length, produced)); + } + + static string Arg(string name, string fallback) + { + var args = Environment.GetCommandLineArgs(); + int i = Array.IndexOf(args, name); + return (i >= 0 && i + 1 < args.Length) ? args[i + 1] : fallback; + } +} diff --git a/mac-patcher/tools/graft_metal_2019_1.py b/mac-patcher/tools/graft_metal_2019_1.py new file mode 100644 index 000000000..e2504f6a6 --- /dev/null +++ b/mac-patcher/tools/graft_metal_2019_1.py @@ -0,0 +1,117 @@ +#!/usr/bin/env python3 +"""Greffe un SubShader Metal dans un bundle PUBLIE serialise par Unity 2019.1. + +Pourquoi un second script a cote de merge_subshader_platforms.py : celui-ci a +ete ecrit pour des bundles produits par Unity 6, ou les tables du blob sont des +listes DE LISTES (un tableau par plateforme, un element par sous-programme) et +ou il existe un champ stageCounts. En 2019.1 ces tables sont PLATES, un entier +par plateforme, et stageCounts n'existe pas — d'ou le KeyError qu'on obtient en +lui donnant un bundle publie. + +Le principe reste le meme et il est explique en detail dans l'autre script : on +n'essaie pas de faire cohabiter Metal et DirectX dans la MEME passe, parce que +les tables de liaison de parametres y sont partagees et que Metal eclate les +globals en VGlobals/FGlobals. On empile un SubShader entier, qui arrive avec ses +propres tables. + +Interet ici : le bundle publie garde ses maillages, ses textures et ses +materiaux bit pour bit. C'est la seule voie pour les 8 orphelins, dont on n'a +pas les sources. + +Usage: + graft_metal_2019_1.py +""" + +import sys + +import UnityPy + +GPU = {4: "d3d11", 9: "gles3", 14: "metal", 15: "glcore", 18: "vulkan"} +FLAT_TABLES = ("offsets", "compressedLengths", "decompressedLengths") + + +def shaders_by_name(env): + out = {} + for obj in env.objects: + if obj.type.name != "Shader": + continue + tree = obj.read_typetree() + out[tree["m_ParsedForm"]["m_Name"]] = tree + return out + + +def check_flat(tree, label): + """Garde-fou : refuser un bundle qui n'est pas au format plat 2019.1.""" + if "stageCounts" in tree: + raise SystemExit(f"{label}: format Unity 6 (stageCounts present), utiliser merge_subshader_platforms.py") + for key in FLAT_TABLES: + if tree[key] and isinstance(tree[key][0], list): + raise SystemExit(f"{label}: table '{key}' imbriquee, ce bundle n'est pas en 2019.1") + + +def graft(base_tree, donor_tree): + """Ajoute les plateformes du donneur absentes de la base. Renvoie leurs noms.""" + added = [] + blob = bytes(base_tree["compressedBlob"]) + + for i, platform in enumerate(donor_tree["platforms"]): + if platform in base_tree["platforms"]: + continue + shift = len(blob) + base_tree["platforms"].append(platform) + base_tree["offsets"].append(donor_tree["offsets"][i] + shift) + base_tree["compressedLengths"].append(donor_tree["compressedLengths"][i]) + base_tree["decompressedLengths"].append(donor_tree["decompressedLengths"][i]) + blob += bytes(donor_tree["compressedBlob"]) + added.append(GPU.get(platform, platform)) + + if added: + base_tree["compressedBlob"] = list(blob) + base_tree["m_ParsedForm"]["m_SubShaders"].extend(donor_tree["m_ParsedForm"]["m_SubShaders"]) + + return added + + +def main(base_path, donor_path, out_path): + base_env = UnityPy.load(base_path) + donors = shaders_by_name(UnityPy.load(donor_path)) + for name, tree in donors.items(): + check_flat(tree, f"greffon/{name}") + + total = 0 + for obj in base_env.objects: + if obj.type.name != "Shader": + continue + tree = obj.read_typetree() + name = tree["m_ParsedForm"]["m_Name"] + if name not in donors: + print(f" {name}: absent du greffon, laisse tel quel") + continue + + check_flat(tree, f"publie/{name}") + before = [GPU.get(p, p) for p in tree["platforms"]] + nsub_before = len(tree["m_ParsedForm"]["m_SubShaders"]) + added = graft(tree, donors[name]) + after = [GPU.get(p, p) for p in tree["platforms"]] + nsub = len(tree["m_ParsedForm"]["m_SubShaders"]) + + if added: + obj.save_typetree(tree) + total += len(added) + print(f" {name}: {before} -> {after}, SubShaders {nsub_before} -> {nsub}") + + if not total: + print(" rien a greffer") + return 1 + + with open(out_path, "wb") as fh: + fh.write(base_env.file.save(packer="lzma")) + print(f" ecrit {out_path}") + return 0 + + +if __name__ == "__main__": + if len(sys.argv) != 4: + print(__doc__) + sys.exit(1) + sys.exit(main(sys.argv[1], sys.argv[2], sys.argv[3])) diff --git a/mac-patcher/tools/install_dual_to_cache.py b/mac-patcher/tools/install_dual_to_cache.py new file mode 100644 index 000000000..6248eef06 --- /dev/null +++ b/mac-patcher/tools/install_dual_to_cache.py @@ -0,0 +1,154 @@ +#!/usr/bin/env python3 +"""Installe les bundles bi-plateforme dans le cache TTS local, pour une repetition generale. + +Permet d'essayer le fix a l'echelle du mod entier, en jeu, sans rien heberger ni +pousser : TTS lit son cache avant de telecharger, donc un fichier depose au bon +nom est servi tel quel. + +Nom de cache : TTS reecrit l'URL du mod (cloud-3.steamusercontent.com) vers +l'hote Akamai, puis aplatit l'URL en ne gardant que l'alphanumerique. Verifie +contre les fichiers deja presents dans le cache de Martin. + +Ne touche qu'aux bundles qui embarquent un shader custom ET dont un rebuild +existe (colonnes du CSV d'inventaire). Sauvegarde systematique avant ecriture. + +Usage: + install_dual_to_cache.py --dry-run # montre ce qui serait fait + install_dual_to_cache.py --install # installe (TTS doit etre ferme) + install_dual_to_cache.py --restore # remet les originaux +""" + +import argparse +import csv +import os +import re +import shutil +import sys + +CSV = os.environ.get("INVENTAIRE", "inventaire-bundles.csv") +DUAL = os.environ.get("DUAL_DIR", "UnityProject-U6/AssetBundles-dual") +CACHE = os.path.expanduser("~/Library/Tabletop Simulator/Mods/Assetbundles") +BACKUP = "bundle_backups/cache-avant-dual" + +# Bundles dont le rebuild a DERIVE du publie (cf compare_published_vs_rebuild.py +# et memoire registre-valide-invalide V15) : les installer introduirait une +# regression visible, sur Mac comme sur Windows. Ils restent donc cassés sur Mac +# tant qu'on ne les repare pas autrement (greffe dans le bundle publie). +DERIVES = { + "stunt_double_bot_1", # le rebuild ajoute un socle base_small + Default-Material absents du publie +} + + +METAL = 14 + + +def is_ours(path): + """Vrai si ce bundle porte une variante Metal, donc s'il sort de chez nous.""" + try: + import UnityPy + except ImportError: + return False # sans UnityPy on garde l'ancien comportement + try: + for obj in UnityPy.load(path).objects: + if obj.type.name == "Shader" and METAL in obj.read_typetree()["platforms"]: + return True + except Exception: + return False + return False + + +def cache_filename(url): + """Nom sous lequel TTS met ce bundle en cache.""" + akamai = re.sub(r"^https?://[^/]+", "https://steamusercontent-a.akamaihd.net", url) + return re.sub(r"[^a-zA-Z0-9]", "", akamai) + ".unity3d" + + +def targets(): + """[(nom_bundle, chemin_source, chemin_cache)] pour les bundles a remplacer.""" + out = [] + with open(CSV, encoding="utf-8") as fh: + for row in csv.DictReader(fh): + if row["besoin_fix"] != "oui" or row["rebuild_dispo"] != "oui": + continue + if row["bundle"] in DERIVES: + print(f" ⊘ {row['bundle']} : rebuild derive du publie, ecarte") + continue + source = os.path.join(DUAL, row["bundle"]) + if not os.path.exists(source): + print(f" ⚠ {row['bundle']} : fusion absente de {DUAL}, ignore") + continue + out.append((row["bundle"], source, os.path.join(CACHE, cache_filename(row["url"])))) + return out + + +def install(rows, dry_run): + os.makedirs(BACKUP, exist_ok=True) + installed = saved = 0 + + for name, source, dest in rows: + if dry_run: + state = "remplace" if os.path.exists(dest) else "depose" + print(f" {state:9s} {name:38s} -> {os.path.basename(dest)[:52]}") + continue + + # Sauvegarde de l'original AVANT toute ecriture, une seule fois : + # relancer l'installation ne doit pas ecraser la sauvegarde par un fichier deja modifie. + # + # ⚠ "une seule fois" ne suffit PAS, et ca s'est produit le 12/08 : un + # bundle DEPOSE au premier passage (absent du cache, donc rien a + # sauvegarder) existe au second, et se fait sauvegarder alors que c'est + # deja le notre. 60 des 114 entrees etaient dans ce cas. Comme aucun + # bundle publie ne porte de variante Metal, en trouver une est la preuve + # qu'on a affaire a notre propre travail : on ne sauvegarde pas. + if os.path.exists(dest): + keep = os.path.join(BACKUP, os.path.basename(dest)) + if not os.path.exists(keep) and not is_ours(dest): + shutil.copy2(dest, keep) + saved += 1 + + shutil.copy2(source, dest) + installed += 1 + + if dry_run: + print(f"\n{len(rows)} bundles seraient installes (aucune ecriture faite)") + else: + print(f"\n{installed} bundles installes, {saved} originaux sauvegardes dans {BACKUP}") + + +def restore(): + if not os.path.isdir(BACKUP): + print(f"aucune sauvegarde dans {BACKUP}") + return 1 + count = 0 + for entry in os.listdir(BACKUP): + shutil.copy2(os.path.join(BACKUP, entry), os.path.join(CACHE, entry)) + count += 1 + print(f"{count} bundles d'origine restaures dans le cache") + # Les bundles qui n'etaient pas en cache avant restent en place : ils ne + # remplacent rien, TTS les aurait telecharges de toute facon. + return 0 + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + group = parser.add_mutually_exclusive_group(required=True) + group.add_argument("--dry-run", action="store_true", help="montre sans rien ecrire") + group.add_argument("--install", action="store_true", help="installe dans le cache TTS") + group.add_argument("--restore", action="store_true", help="remet les originaux") + args = parser.parse_args() + + if args.restore: + return restore() + + rows = targets() + if not rows: + print("rien a installer") + return 1 + + print(f"{len(rows)} bundles a shader custom, fusion disponible\n") + install(rows, args.dry_run) + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/mac-patcher/tools/install_grafted_to_cache.py b/mac-patcher/tools/install_grafted_to_cache.py new file mode 100644 index 000000000..d5f45f187 --- /dev/null +++ b/mac-patcher/tools/install_grafted_to_cache.py @@ -0,0 +1,127 @@ +#!/usr/bin/env python3 +"""Installe les bundles GREFFES (orphelins) dans le cache TTS local. + +Pourquoi pas install_dual_to_cache.py : celui-ci ne prend que les bundles dont +un rebuild existe (colonne rebuild_dispo du CSV), ce qui exclut par construction +les 8 orphelins — ils n'ont pas de sources, c'est toute la raison de la greffe. + +Sauvegarde dans un dossier DISTINCT de cache-avant-dual, pour ne pas melanger +les deux campagnes et pour qu'une restauration de l'une ne defasse pas l'autre. + +Garde-fou : on refuse d'ecraser un fichier du cache qui contient DEJA une +variante Metal — ce serait le signe qu'on repasse sur notre propre travail et +qu'on sauvegarderait une copie greffee comme si c'etait l'original. + +Usage: + install_grafted_to_cache.py --dry-run + install_grafted_to_cache.py --install # TTS doit etre ferme + install_grafted_to_cache.py --restore +""" + +import argparse +import csv +import hashlib +import os +import re +import shutil +import sys + +import UnityPy + +CSV = os.environ.get("INVENTAIRE", "inventaire-bundles.csv") +GRAFTED = os.environ.get("GRAFTED_DIR", "tts-assets/grafted") +CACHE = os.path.expanduser("~/Library/Tabletop Simulator/Mods/Assetbundles") +BACKUP = "bundle_backups/cache-avant-greffe" +METAL = 14 + + +def cache_filename(url): + """Nom sous lequel TTS met ce bundle en cache (meme regle que l'autre installeur).""" + akamai = re.sub(r"^https?://[^/]+", "https://steamusercontent-a.akamaihd.net", url) + return re.sub(r"[^a-zA-Z0-9]", "", akamai) + ".unity3d" + + +def has_metal(path): + for obj in UnityPy.load(path).objects: + if obj.type.name == "Shader" and METAL in obj.read_typetree()["platforms"]: + return True + return False + + +def targets(): + """[(nom, source_greffee, chemin_cache, url)] pour les bundles greffes disponibles.""" + out, seen = [], set() + with open(CSV, encoding="utf-8") as fh: + for row in csv.DictReader(fh): + name = row["bundle"] + if name in seen: + continue + source = os.path.join(GRAFTED, name + ".unity3d") + if not os.path.exists(source): + continue + seen.add(name) + out.append((name, source, os.path.join(CACHE, cache_filename(row["url"])), row["url"])) + return out + + +def main(): + ap = argparse.ArgumentParser() + g = ap.add_mutually_exclusive_group(required=True) + g.add_argument("--dry-run", action="store_true") + g.add_argument("--install", action="store_true") + g.add_argument("--restore", action="store_true") + args = ap.parse_args() + + if args.restore: + if not os.path.isdir(BACKUP): + sys.exit(f"pas de sauvegarde dans {BACKUP}") + n = 0 + for f in sorted(os.listdir(BACKUP)): + shutil.copy2(os.path.join(BACKUP, f), os.path.join(CACHE, f)) + n += 1 + print(f"{n} fichiers restaures depuis {BACKUP}") + return + + rows = targets() + if not rows: + sys.exit(f"aucun bundle greffe dans {GRAFTED}") + + todo, skipped = [], [] + for name, source, dest, url in rows: + # Absent du cache = unite jamais posee sur la table par ce joueur. On + # depose quand meme : TTS lit son cache avant de telecharger, donc le + # fichier sera servi tel quel au premier spawn. Rien a sauvegarder, + # il n'y a rien a ecraser. + if not os.path.exists(dest): + todo.append((name, source, dest, "depose")) + continue + # Aucun bundle PUBLIE ne porte de Metal — c'est tout le probleme qu'on + # repare. Donc un fichier de cache qui en porte est forcement l'un des + # notres : on le remplace sans le sauvegarder, sinon la sauvegarde + # finirait par contenir notre propre travail au lieu de l'original. + if has_metal(dest): + todo.append((name, source, dest, "rejoue")) + continue + todo.append((name, source, dest, "remplace")) + + for name, source, dest, action in todo: + print(f" {action:9s} {name:45s} -> {os.path.basename(dest)[:40]}...") + for name, why in skipped: + print(f" ⊘ {name:45s} {why}") + print(f"\n{len(todo)} a installer, {len(skipped)} ecartes") + + if not args.install: + return + + os.makedirs(BACKUP, exist_ok=True) + for name, source, dest, action in todo: + if action == "remplace": + keep = os.path.join(BACKUP, os.path.basename(dest)) + if not os.path.exists(keep): + shutil.copy2(dest, keep) + shutil.copy2(source, dest) + print(f"installe {len(todo)} bundles, originaux ecrases sauvegardes dans {BACKUP}") + + +if __name__ == "__main__": + main() diff --git a/mac-patcher/tools/inventaire-bundles.csv b/mac-patcher/tools/inventaire-bundles.csv new file mode 100644 index 000000000..d7d04d61e --- /dev/null +++ b/mac-patcher/tools/inventaire-bundles.csv @@ -0,0 +1,191 @@ +url,role,origine,bundle,shaders,besoin_fix,rebuild_dispo,note +http://cloud-3.steamusercontent.com/ugc/1009315641457799750/AE83DC038BA8AAF48678D07E1F9734D4A9944C1D/,principal,telecharge,arc_1,,non,oui, +http://cloud-3.steamusercontent.com/ugc/1009315641457800134/88E2FEC812AD5E7B7570836120992252AC758BF8/,principal,telecharge,arc_2,Particles/Standard Unlit,oui,oui, +http://cloud-3.steamusercontent.com/ugc/1009315641457800538/06BBAAAAC7FB68DAA9351F12008475068A96BFFB/,principal,telecharge,arc_3,Particles/Standard Unlit,oui,oui, +http://cloud-3.steamusercontent.com/ugc/1009315641457800878/34EC84D7ECD99E073417866A9BEC4288E00F5359/,principal,telecharge,arc_dc15x,Particles/Standard Unlit,oui,oui, +http://cloud-3.steamusercontent.com/ugc/1009315641457801321/CED1CD80F307683E79B9A4ED87CECAED7C070EBF/,principal,telecharge,arc_echo,,non,oui, +http://cloud-3.steamusercontent.com/ugc/1009315641457802221/506D704E232C1BFD85F063A24EBF24C5914C2C40/,principal,telecharge,arc_fives,,non,oui, +http://cloud-3.steamusercontent.com/ugc/1009315641457802621/01F605D855048F823A0ECA6C46D2A62B56C04124/,principal,telecharge,arc_leader,,non,oui, +http://cloud-3.steamusercontent.com/ugc/1009315641457845802/AE70766EAA85C875B023FB980A5A5CEEFB98B1D9/,principal,cache,bx_droid_1,,non,oui, +http://cloud-3.steamusercontent.com/ugc/1009315641457846188/D7F348E890430AA319DDDFA513D99DC2783ECF91/,principal,cache,bx_droid_2,,non,oui, +http://cloud-3.steamusercontent.com/ugc/1009315641457846574/F169D9E2E45B73D1E21B17E32D3B4B4D9AACB196/,principal,cache,bx_droid_3,,non,oui, +http://cloud-3.steamusercontent.com/ugc/1009315641457847081/F7D4E8D3EC85BAEEB5C1B5B913B7F484CC28FC10/,principal,cache,bx_droid_leader,,non,oui, +http://cloud-3.steamusercontent.com/ugc/1009315641457847567/079157D001A1520085C6A30620750817C6C01BFF/,principal,telecharge,bx_droid_saboteur,,non,oui, +http://cloud-3.steamusercontent.com/ugc/1009315641457847963/0EA6BE014DA494689FF32F9570C6A73CD88F1894/,principal,telecharge,bx_droid_sniper,,non,oui, +http://cloud-3.steamusercontent.com/ugc/1617345381346377755/75D0ACFDFFCA5A08D7CAB59DA941B226D1563D46/,principal,telecharge,yoda,BucketheadBits/Units/Glow Geometry,oui,non, +http://cloud-3.steamusercontent.com/ugc/1618437692581074585/1C74BEB92DC42D3585BFC1185A77DE14EC3249CA/,principal,telecharge,isf_delmeeko,,non,oui, +http://cloud-3.steamusercontent.com/ugc/1618437692581075349/6265F81E1BAA090FFA813270A8E3126CF8AD6CC5/,principal,telecharge,isf_gideon_hask,,non,oui, +http://cloud-3.steamusercontent.com/ugc/1618438238122996093/C79160007FD884C2B8737DCA888D61C955073141/,principal,telecharge,isf_1,,non,oui, +http://cloud-3.steamusercontent.com/ugc/1618438238122996656/AAD706C50446522C98259A20C03E757C4F7B98B1/,principal,telecharge,isf_2,,non,oui, +http://cloud-3.steamusercontent.com/ugc/1618438238122997115/F100B28E5DBF4A56FB22D3410270BEE4EF344FEF/,principal,telecharge,isf_3,,non,oui, +http://cloud-3.steamusercontent.com/ugc/1618438238122999341/C1AEEE50112F060BA8E5CAFBC16F417A0EF7C3C0/,principal,telecharge,isf_inferno,,non,oui, +http://cloud-3.steamusercontent.com/ugc/1618438238122999812/779C9D69CA440F970DD0B7C6394A812732F9C588/,principal,telecharge,isf_leader,,non,oui, +http://cloud-3.steamusercontent.com/ugc/1618438238123000906/C64EAD02CA22F8BFB59320925DAD7D89BA1E7AD6/,principal,telecharge,isf_t21,,non,oui, +http://cloud-3.steamusercontent.com/ugc/1618438238123043414/B7E9660E470DC070545782406C29F1E1356A5685/,secondaire,telecharge,isf_materials,,non,oui, +http://cloud-3.steamusercontent.com/ugc/1619598366706113202/449F19DA94D42DAD0F0B4D0B77A8E9AD45C320E5/,principal,telecharge,std_kraken,,non,non, +http://cloud-3.steamusercontent.com/ugc/1619598366706441824/97EB6FA096B824294EE48FE762380CCBE866F3E2/,principal,telecharge,std_kalani,,non,non, +http://cloud-3.steamusercontent.com/ugc/1619598366706441991/04B29BB48A98AF8D79FC1414548496BAD49CCB28/,secondaire,telecharge,std_materials,BucketheadBits/Units/Color Replacer,oui,non, +http://cloud-3.steamusercontent.com/ugc/1619598366708042667/2DABB5788E51006EDB3FCB03400ACD4CE07755F3/,principal,telecharge,wookiee_warriors_long_gun_wookiee_model,BucketheadBits/Units/Color Replacer,oui,non, +http://cloud-3.steamusercontent.com/ugc/1619598366708043779/0D96CE1619F4B27F583257A366431E3BAD428F19/,principal,telecharge,kashyyyk_defenders_leader_model,BucketheadBits/Units/Color Replacer,oui,non, +http://cloud-3.steamusercontent.com/ugc/1619598366708043883/1EA1B3C21A50C20D4D168AB91ECFE1C01A4F7DF5/,principal,telecharge,kashyyyk_defenders_model,BucketheadBits/Units/Color Replacer,oui,non, +http://cloud-3.steamusercontent.com/ugc/1619598523372467360/2810096383D51B0939DC3FFCBC83155C6D08CB53/,principal,telecharge,wookiee_chieftain_model,BucketheadBits/Units/Color Replacer,oui,non, +http://cloud-3.steamusercontent.com/ugc/1619598523372505515/1191E8089B37C0CC4BBE8283EF6B7F9C5A74A13C/,principal,telecharge,fluttercraft,BucketheadBits/Units/Color Replacer,oui,non, +http://cloud-3.steamusercontent.com/ugc/1619598523372574861/CCF68AF1C35F52A714AB0344FCB170F5BAA1672A/,principal,telecharge,infantry_support_platform_model,BucketheadBits/Units/Color Replacer,oui,non, +http://cloud-3.steamusercontent.com/ugc/1621849308236386470/4D5227051DEEED77303985CE6D34CDBFB27FD472/,principal,telecharge,ig-100_magnagaurd_1_model,,non,oui, +http://cloud-3.steamusercontent.com/ugc/1621849308236386513/AC53B9F503C0B353AE7AA797072F7EBA15A1214C/,principal,telecharge,ig-100_magnagaurd_2_model,,non,oui, +http://cloud-3.steamusercontent.com/ugc/1621849308236386555/F47418A458CF12C80756A80B842817EA1CCC62CF/,principal,telecharge,ig-100_magnagaurd_3_model,,non,oui, +http://cloud-3.steamusercontent.com/ugc/1621849308236386662/7ABB72B5A8A301611033E4A424FD61271024FB4C/,principal,telecharge,ig-100_magnaguard_electrowhip_model,,non,oui, +http://cloud-3.steamusercontent.com/ugc/1621849308236386731/FA50237A0BF717ED06EA3020D5F4089D452ADCD6/,principal,telecharge,ig-100_magnaguard_leader_model,,non,oui, +http://cloud-3.steamusercontent.com/ugc/1621849308236386787/E93D6E65A61C9262B5934C5A419736B45B50D75B/,principal,telecharge,ig-100_magnaguard_rps-6_model,,non,oui, +http://cloud-3.steamusercontent.com/ugc/1621849308236386933/DCD62751F06157E85CE575C8BB1CCF86379BB7DE/,principal,telecharge,wookiee_warriors_battle_shield_model,BucketheadBits/Units/Color Replacer,oui,oui, +http://cloud-3.steamusercontent.com/ugc/1621849538641208262/A0E48F7D9C94617C81BAD4D649717BAC7A8B9B64/,secondaire,telecharge,ig-100_magnagaurd_mat,BucketheadBits/Units/Color Replacer,oui,oui, +http://cloud-3.steamusercontent.com/ugc/1621849538645161033/A69093521055BB5CA008D3DDE5F6EBEB990D0AF2/,principal,cache,dsd-1_dwarf_spider_droid_model,BucketheadBits/Units/Color Replacer,oui,oui, +http://cloud-3.steamusercontent.com/ugc/1686023073179090715/187094FD9EBAFB6FF44A65F2D411D68154C0FAC7/,principal,telecharge,t47_airspeeder_model,BucketheadBits/Units/Color Replacer,oui,oui, +http://cloud-3.steamusercontent.com/ugc/1686023445067146269/A9189AC12193D3BD24624F7A5137C4E69FADDBBF/,principal,cache,droideka,BucketheadBits/Units/Color Replacer,oui,oui, +http://cloud-3.steamusercontent.com/ugc/1686023445067146631/305531F34B6598A008F5925D828457DF1A8195F6/,secondaire,telecharge,droideka_fx,BucketheadBits/Units/Glow Geometry | BucketheadBits/Units/Rim Glow Geometry Shield,oui,oui, +http://cloud-3.steamusercontent.com/ugc/1686023445067168845/FBADA8EDE2ED248CA7F50C1DB3BFF46215E0360B/,principal,cache,droideka_leader,BucketheadBits/Units/Color Replacer,oui,oui, +http://cloud-3.steamusercontent.com/ugc/1745728387706845389/0D7DFE0C5BF5CDD527A619B75A25A2177D417BD0/,principal,telecharge,pyke_syndicate_foot_soldiers_trooper_3_model,,non,oui, +http://cloud-3.steamusercontent.com/ugc/1745728387706845475/01738B0D52E2D9C2870D6E33A2D05ECD12201C85/,principal,telecharge,black_sun_enforcers_leader_model,BucketheadBits/Units/Color Replacer,oui,oui, +http://cloud-3.steamusercontent.com/ugc/1745728387706845513/BB3CD9624D6F43250D0406D099819E497A1A70BE/,principal,telecharge,pyke_syndicate_foot_soldiers_electrowhip_model,,non,oui, +http://cloud-3.steamusercontent.com/ugc/1745728387706845548/FD104F41509A53EA1C888862A3C5F0B98F609F1F/,principal,telecharge,pyke_syndicate_foot_soldiers_leader_model,,non,oui, +http://cloud-3.steamusercontent.com/ugc/1745728387706845607/4B1530CF96F9DB8F172B02676F1D8B347CFD862A/,principal,telecharge,pyke_syndicate_foot_soldiers_p13-m_disruptor_model,,non,oui, +http://cloud-3.steamusercontent.com/ugc/1745728387706845646/BE0DEED782F96BD44C389DEDEA41EBEA0C7A6D04/,principal,telecharge,pyke_syndicate_foot_soldiers_trooper_1_model,,non,oui, +http://cloud-3.steamusercontent.com/ugc/1745728387706845697/15B6DCCA8D8D76E1CB78219C58790E40DDD7CE8A/,principal,telecharge,pyke_syndicate_foot_soldiers_trooper_2_model,,non,oui, +http://cloud-3.steamusercontent.com/ugc/1745728519554838398/33764317D1BE774E1F978082C1A97681C1183C01/,principal,telecharge,boba_fett_the_old_and_wise_model_1,BucketheadBits/Units/Color Replacer,oui,oui, +http://cloud-3.steamusercontent.com/ugc/1747939379132611640/1EEBEB993635A56525283FAFA0D62D347FB3121C/,principal,telecharge,laat_le,,non,oui, +http://cloud-3.steamusercontent.com/ugc/1785135125810942830/666860D7C34C83C500C62BDDE115F30C59A42C74/,principal,telecharge,darktrooper_leader,BucketheadBits/Units/Glow Geometry | BucketheadBits/Units/Rim Glow Geometry Shield,oui,oui, +http://cloud-3.steamusercontent.com/ugc/1785135125810942938/E77EC5970DA310A2E1D96F796E98D82813AE0891/,principal,cache,darktrooper_trooper1,,non,oui, +http://cloud-3.steamusercontent.com/ugc/1785135125810943021/4B5888D461F54C2C281B108233D1F1D8D8C2A679/,principal,telecharge,darktrooper_trooper2,,non,oui, +http://cloud-3.steamusercontent.com/ugc/1785135165610974498/47B1C8B92A0E945388F7773EAB2F73B0A81E761E/,principal,telecharge,grogu_model,BucketheadBits/Units/Color Replacer,oui,oui, +http://cloud-3.steamusercontent.com/ugc/1789640371717200769/60353F40BAE6D92D6F6ED24E2883EB9CC2EA74C4/,secondaire,telecharge,mauldelorian_cpt_mat,BucketheadBits/Units/Color Replacer,oui,oui, +http://cloud-3.steamusercontent.com/ugc/1789640371717200823/B886D3157AA2F2528F4E5F76F26DF44A41496615/,secondaire,telecharge,mauldelorian_trooper_mat,BucketheadBits/Units/Color Replacer,oui,oui, +http://cloud-3.steamusercontent.com/ugc/1789640371719006177/3A456EB29012BFBE4322E020CBC08CF6F915BBF3/,principal,telecharge,mauldelorian_rook_kast_model,BucketheadBits/Units/Color Replacer | BucketheadBits/Units/Glow Geometry | BucketheadBits/Units/Rim Glow Geometry Shield,oui,oui, +http://cloud-3.steamusercontent.com/ugc/1789640371719014130/7A59CCE5B8A8C87DD3952C15819FAA8921708A75/,principal,telecharge,maul_a_rival_model,BucketheadBits/Units/Color Replacer | BucketheadBits/Units/Glow Geometry | BucketheadBits/Units/Rim Glow Geometry Shield,oui,oui, +http://cloud-3.steamusercontent.com/ugc/1789640371719058670/9E6B82A0BF8367F2C6D369BD3464DA5E9D0C7917/,principal,telecharge,ig-88_model,BucketheadBits/Units/Color Replacer | BucketheadBits/Units/Glow Geometry,oui,oui, +http://cloud-3.steamusercontent.com/ugc/1802024425338475441/730DE7AD6E1A55EA9F9264DADC1DDC0AC2CCA565/,principal,telecharge,aa5_scan,BucketheadBits/Units/Color Replacer | BucketheadBits/Units/Glow Geometry,oui,oui, +http://cloud-3.steamusercontent.com/ugc/1802024425338475527/29D3660FA84E5B9F804B840C18E68F5631EE6462/,principal,telecharge,aa5_scan_shadow,BucketheadBits/Units/Color Replacer | BucketheadBits/Units/Glow Geometry,oui,oui, +http://cloud-3.steamusercontent.com/ugc/1856061112420143285/F206D67AFF9379B68AD0795767DA378CE80D44AE/,principal,telecharge,mauldelorian_trooper_2_model,,non,oui, +http://cloud-3.steamusercontent.com/ugc/1856061112420143328/3D6F3C2E8DFB78B9B748FFC8F339B9C568D7408E/,secondaire,telecharge,black_sun_enforcers_mat,BucketheadBits/Units/Color Replacer,oui,oui, +http://cloud-3.steamusercontent.com/ugc/1856061112420143366/41AB7DFFD2FCF20E2BCC3F899F728863C30F6343/,principal,telecharge,mauldelorian_gunsligner_model,,non,oui, +http://cloud-3.steamusercontent.com/ugc/1856061112420143408/F4A88228E11334545EACA86B36E6B2008E76B0D3/,principal,telecharge,mauldelorian_leader_model,,non,oui, +http://cloud-3.steamusercontent.com/ugc/1856061112420143451/3DFD9C8BD5D504D3A2F7934678D1A0A7C2285863/,principal,telecharge,mauldelorian_marksman_model,,non,oui, +http://cloud-3.steamusercontent.com/ugc/1856061112420143500/4BDEA7F5B523FC06641B3D71D1E112DC14BD7F81/,principal,telecharge,mauldelorian_trooper_1_model,,non,oui, +http://cloud-3.steamusercontent.com/ugc/1856061112420143543/CBAC94E0D1731CB8D1034D24F58987E854A8596A/,secondaire,telecharge,pyke_syndicate_mat,BucketheadBits/Units/Color Replacer,oui,oui, +http://cloud-3.steamusercontent.com/ugc/1856061112420143649/BBBA0D26FB46EAD96421C4B77FE779B5F0F848AA/,principal,telecharge,black_sun_enforcers_mag_det_model,,non,oui, +http://cloud-3.steamusercontent.com/ugc/1856061112420143685/C75388115AFCF42ACC79E2C16FEF36755C975AA0/,principal,telecharge,black_sun_enforcers_scattergun_model,,non,oui, +http://cloud-3.steamusercontent.com/ugc/1856061112420143724/48B5A35E10B4977E255D889A8FCAEA8C980A11A9/,principal,telecharge,black_sun_enforcers_trooper_model,,non,oui, +http://cloud-3.steamusercontent.com/ugc/1856061112420143763/E93BA6716A05CA95AE2EA3B7C0DFD8AF145D5C22/,principal,telecharge,black_sun_vigo_model,BucketheadBits/Units/Color Replacer,oui,oui, +http://cloud-3.steamusercontent.com/ugc/1856061112420143862/CF491C11176E40BD786A89E1D0C20D3316448188/,principal,telecharge,gar_saxon_model,BucketheadBits/Units/Color Replacer | BucketheadBits/Units/Glow Geometry,oui,oui, +http://cloud-3.steamusercontent.com/ugc/1856061112420351237/706DEA645FEE2EC9787F05F4FF2926632E2C4894/,principal,telecharge,pyke_capo_model,BucketheadBits/Units/Color Replacer,oui,oui, +http://cloud-3.steamusercontent.com/ugc/1924743543116067434/0A068914BDD35AE6F63D7E29EBC7E0B5F712DA1F/,principal,telecharge,swoop _bikes_leader_model,BucketheadBits/Units/Color Replacer,oui,oui, +http://cloud-3.steamusercontent.com/ugc/1924743543116067490/87719312BE33C493B97B0915DB8C89FDC57D3F38/,principal,telecharge,swoop_bikes_rider_model,BucketheadBits/Units/Color Replacer,oui,oui, +http://cloud-3.steamusercontent.com/ugc/1924743543116068132/37BCE99DCF06BEFA1119FEA911188695F9C48079/,principal,telecharge,nr-n99_persuader-class_tank_droid_model,BucketheadBits/Units/Color Replacer,oui,oui, +http://cloud-3.steamusercontent.com/ugc/2004698291313160948/23CA698C8F2AF1C08D2DED3564B138E72E2ABCBF/,principal,telecharge,darktrooper_hvyminigun,,non,oui, +http://cloud-3.steamusercontent.com/ugc/2004698291313161010/1873BCD554A553BC2FF25A2BE16116EDEBFDCEF4/,principal,telecharge,darktrooper_hvyrocket,,non,oui, +http://cloud-3.steamusercontent.com/ugc/2004698291313161066/7BD340C7AAB594CDA1644D900F606FEC8A0165A1/,principal,telecharge,darktrooper_hvysword,,non,oui, +http://cloud-3.steamusercontent.com/ugc/2004698291313176203/E77892ADB668EA0CB548F6ED71BE44CA3FB730E7/,secondaire,cache,darktrooper_mat,BucketheadBits/Units/Color Replacer | BucketheadBits/Units/Glow Geometry,oui,oui, +http://cloud-3.steamusercontent.com/ugc/2008089545867128356/9E8C70962F9D5BF853BD9310F2BB1E1A3F80DB5D/,principal,telecharge,ewok_skirmisher4,,non,oui, +http://cloud-3.steamusercontent.com/ugc/2008089545867128445/EBB56734DB6527B3566C317F6F4F0E84471D6776/,principal,cache,ewok_skirmisher5,,non,oui, +http://cloud-3.steamusercontent.com/ugc/2008089545867128506/B24F2402EDC36C64688B7F492B382D972ABA30F1/,principal,cache,ewok_slinger1,,non,oui, +http://cloud-3.steamusercontent.com/ugc/2008089545867128565/24D88975D67E46B5FA9294EB6DCC146912D61F2F/,principal,telecharge,ewok_slinger2,,non,oui, +http://cloud-3.steamusercontent.com/ugc/2008089545867128627/19AC5B05F3A355226EE783B9F239B3B285EA077A/,principal,telecharge,ewok_slinger3,,non,oui, +http://cloud-3.steamusercontent.com/ugc/2008089545867128715/CB52DA6C0FC1DF3511C2A2D62CB2B3A13A9D4F8F/,principal,cache,ewok_slinger4,,non,oui, +http://cloud-3.steamusercontent.com/ugc/2008089545867128778/1D5BCB551375F1A7988C434F0B52E18434BB4747/,principal,telecharge,ewok_slinger5,,non,oui, +http://cloud-3.steamusercontent.com/ugc/2008089545867128844/558E1277513B0AF48911A68B5FAAB981BC0A56A1/,principal,telecharge,ewok_trapper,,non,oui, +http://cloud-3.steamusercontent.com/ugc/2008089545867128895/152E8A0BE0A0FB98FAD48338552C6282DD8954B7/,principal,telecharge,ewok_axe,,non,oui, +http://cloud-3.steamusercontent.com/ugc/2008089545867128972/9388116F0C7BE70B991CC7715943BF9FF08D3890/,principal,telecharge,ewok_leader,,non,oui, +http://cloud-3.steamusercontent.com/ugc/2008089545867129049/686925E47D218727E1C79A25E0F44FC80FAEE43F/,secondaire,telecharge,ewok_sharedmat,BucketheadBits/Units/Color Replacer,oui,oui, +http://cloud-3.steamusercontent.com/ugc/2008089545867129131/D612F1B1EBDA3172B69BEE40159CE5D999045A62/,principal,cache,ewok_skirmisher1,,non,oui, +http://cloud-3.steamusercontent.com/ugc/2008089545867129196/6EED0C8AAF8F50751EE4206471D1273B6C0F4B5A/,principal,telecharge,ewok_skirmisher2,,non,oui, +http://cloud-3.steamusercontent.com/ugc/2008089545867129252/FC0A6247B6AB21A99919659C1F9069186C6D82ED/,principal,cache,ewok_skirmisher3,,non,oui, +http://cloud-3.steamusercontent.com/ugc/2008089545867129309/3D6C219F243BDE984C42BB3444B01DB09B522CBB/,principal,telecharge,logray_model,BucketheadBits/Units/Color Replacer,oui,oui, +http://cloud-3.steamusercontent.com/ugc/2017090166650140825/D8AE1D1F27B97F359916236DA163DA7EC4B517C1/,principal,telecharge,storm4,,non,oui, +http://cloud-3.steamusercontent.com/ugc/2017090166650140913/ADEED3994E6F70777B939A89B18FF520765DCDC4/,principal,telecharge,stormcpt,,non,oui, +http://cloud-3.steamusercontent.com/ugc/2017090166650141001/FF62545FC3DEF499BA8A0C04F07917C6CAA9E30D/,principal,telecharge,stormdlt,,non,oui, +http://cloud-3.steamusercontent.com/ugc/2017090166650141088/7342269A721DF49D0C38F1469E8463093734EF66/,principal,telecharge,stormhh12,,non,oui, +http://cloud-3.steamusercontent.com/ugc/2017090166650141156/BF26D516EA8F33C72822FF9AB369FF7CA444C403/,principal,telecharge,stormleader,,non,oui, +http://cloud-3.steamusercontent.com/ugc/2017090166650141221/5D4DAEED517F52EE2ECBC631301C97422F519AB9/,principal,telecharge,stormrt97,,non,oui, +http://cloud-3.steamusercontent.com/ugc/2017090166650141284/6D59924E68B2B1640C0AC479B8DE95F434056650/,principal,telecharge,stormspec,,non,oui, +http://cloud-3.steamusercontent.com/ugc/2017090166650141339/1EB723D5FCF6655CFFF7EF700EE7108274E1A6C7/,principal,telecharge,stormt21,,non,oui, +http://cloud-3.steamusercontent.com/ugc/2017090166650141545/30BEFE4E87E379AA361AFF5FD24A8F5D3F0BA4C0/,principal,telecharge,storm1,,non,oui, +http://cloud-3.steamusercontent.com/ugc/2017090166650141624/1366A6A4D84D9FE597EEA2736AFC187F392418DA/,principal,telecharge,storm2,,non,oui, +http://cloud-3.steamusercontent.com/ugc/2017090166650141692/8E06789B4D2003055108ED85D76E875729254757/,principal,telecharge,storm3,,non,oui, +http://cloud-3.steamusercontent.com/ugc/2017090166650141746/A8FD77EB51C50C64CD924BDAEEDB70D8839E0EF3/,secondaire,telecharge,stormtrooper_mat,BucketheadBits/Units/Color Replacer,oui,oui, +http://cloud-3.steamusercontent.com/ugc/2022718494181455957/4BB3E42AA412A7ED2ED6F26BFDFA25414F127B71/,principal,telecharge,assajventress,BucketheadBits/Units/Color Replacer | BucketheadBits/Units/Glow Geometry,oui,oui, +http://cloud-3.steamusercontent.com/ugc/2023850162084443471/517A8997FB85780B040DD3017147753F438137CC/,principal,telecharge,ahsoka,BucketheadBits/Units/Color Replacer | BucketheadBits/Units/Glow Geometry,oui,oui, +http://cloud-3.steamusercontent.com/ugc/2023850162090106066/B6E661CAB8049A1B1CE975B53BB57B337E2C5DEE/,principal,telecharge,wicket_model,BucketheadBits/Units/Color Replacer,oui,oui, +http://cloud-3.steamusercontent.com/ugc/2058763770177195589/5E52A1E47746FF179ED6327F681D51D92C47D1D5/,principal,telecharge,bugsonic,BucketheadBits/Units/Color Replacer,oui,oui, +http://cloud-3.steamusercontent.com/ugc/2058763770177195724/233E75C81DB511291B2B95015510DF1B48B2A8DB/,principal,telecharge,sunfac,BucketheadBits/Units/Color Replacer,oui,oui, +http://cloud-3.steamusercontent.com/ugc/2058763770177195807/C1E3DCF8DC0772F56B22E42E89DECC9F30110E8D/,principal,telecharge,bugpike,BucketheadBits/Units/Color Replacer,oui,oui, +http://cloud-3.steamusercontent.com/ugc/2058763770177195881/84020A8311904050DC9309FE9109D47BC41FE4AA/,secondaire,telecharge,bugshared,BucketheadBits/Units/Color Replacer,oui,oui, +http://cloud-3.steamusercontent.com/ugc/2058763770177195973/1D70D4C8D0C6A06E14A7A875228E3CD49D5E0807/,principal,telecharge,poggle,BucketheadBits/Units/Color Replacer,oui,oui, +http://cloud-3.steamusercontent.com/ugc/2058763770177201554/7AEA5B0A98A298731F6BE51591401BBF095A5797/,principal,telecharge,bug1,,non,oui, +http://cloud-3.steamusercontent.com/ugc/2058763770177201933/E0DBF0D812FFF4F7F3A77CF1E4EAB84F78B8C49E/,principal,cache,bug2,,non,oui, +http://cloud-3.steamusercontent.com/ugc/2058763770177202012/76CB0371503304D5AAF562E5E2F04961CD206090/,principal,telecharge,bug3,,non,oui, +http://cloud-3.steamusercontent.com/ugc/2058763770177202081/37F68E146C49B315AA46E15BE88DDB56AE97646C/,principal,telecharge,bugleader,,non,oui, +http://cloud-3.steamusercontent.com/ugc/2174736446809184624/F2826DD52329584D1C3B3795B0E55948EA96B467/,principal,telecharge,cloneengineer,BucketheadBits/Units/Color Replacer,oui,oui, +http://cloud-3.steamusercontent.com/ugc/2174736446809184711/BC2EE95F62E043F83A352F825B6A041AC6D59959/,principal,telecharge,clonemedic,BucketheadBits/Units/Color Replacer,oui,oui, +http://cloud-3.steamusercontent.com/ugc/2174736446809184812/3A020CF4B5983E1AF55F65A3F8F7BDCBAAEAAACC/,principal,telecharge,clonetechnician,BucketheadBits/Units/Color Replacer,oui,oui, +http://cloud-3.steamusercontent.com/ugc/2174736446809185328/4A6DA42CDB70EF979D5B8B675CEFA5459FA60D4E/,principal,telecharge,p2_mortar,BucketheadBits/Units/Color Replacer,oui,oui, +http://cloud-3.steamusercontent.com/ugc/2174736446809185513/A794F69FD4F7FF6093A8E4564633AF49C95DE79D/,principal,telecharge,drksithprobe,BucketheadBits/Units/Color Replacer,oui,oui, +http://cloud-3.steamusercontent.com/ugc/2174736446809185590/81774E94925CD5B15B7CE0DC52DEC465D9774024/,principal,telecharge,maul,BucketheadBits/Units/Color Replacer | BucketheadBits/Units/Glow Geometry,oui,oui, +http://cloud-3.steamusercontent.com/ugc/2174736446809185654/E58BE2AB7BC859E1A896FF9B9909B6976E69CF4B/,principal,telecharge,pkworker,BucketheadBits/Units/Color Replacer,oui,oui, +http://cloud-3.steamusercontent.com/ugc/2174736446809185719/FF120BC2FA5DC8258021E2849C2B81591CCA36B9/,principal,telecharge,tseries,BucketheadBits/Units/Color Replacer,oui,oui, +http://cloud-3.steamusercontent.com/ugc/2174736446809185784/C7B137C19E24986DBE1E9A2712676AB320E4B2A9/,principal,telecharge,viper,BucketheadBits/Units/Color Replacer,oui,oui, +http://cloud-3.steamusercontent.com/ugc/2174736446809185852/7940F0BEFCFE905039054DA1CA3BBF3C0CB2C7A9/,principal,telecharge,clanwrenchump,BucketheadBits/Units/Color Replacer,oui,oui, +http://cloud-3.steamusercontent.com/ugc/2174736446809185988/83F7A4664576B192905C6393A6D9A5DAA776E01A/,principal,telecharge,tristanwren,BucketheadBits/Units/Color Replacer,oui,oui, +http://cloud-3.steamusercontent.com/ugc/2174736446809186071/A6DB57CF6BA2EEDAB6EB8A719DB8D0702708C759/,principal,telecharge,ursawren,BucketheadBits/Units/Color Replacer,oui,oui, +http://cloud-3.steamusercontent.com/ugc/2174736446809186179/35024924D8BC8A727F508557AF7B714D2E3D22FF/,principal,telecharge,mandoresistance_2,BucketheadBits/Units/Color Replacer,oui,oui, +http://cloud-3.steamusercontent.com/ugc/2174736446809186272/7872209AB5CBE104129F9AFC58267EB8F6CF80D1/,principal,telecharge,mandoresistance_1,BucketheadBits/Units/Color Replacer,oui,oui, +http://cloud-3.steamusercontent.com/ugc/2174736446809186354/387C36C2BB545E6CC882A05C0D81F5BE164166B7/,principal,telecharge,clonecommander,BucketheadBits/Units/Color Replacer,oui,oui, +http://cloud-3.steamusercontent.com/ugc/2174736446809186437/C255A6920C6B62ADD6B948311053BAAE4803BE29/,principal,telecharge,mandoresistance_leader,BucketheadBits/Units/Color Replacer,oui,oui, +http://cloud-3.steamusercontent.com/ugc/2174736446809186518/DCA8031C62A867134FAA814D4976978058C01369/,principal,telecharge,lando,BucketheadBits/Units/Color Replacer,oui,oui, +http://cloud-3.steamusercontent.com/ugc/2174736446809186599/4B154E18EF2C0ADE6C347FC4B15AD856D00546DF/,principal,telecharge,sabine,BucketheadBits/Units/Color Replacer,oui,oui, +http://cloud-3.steamusercontent.com/ugc/2174736446809252570/7F009B812ED06B7E45CFCE48142293A4B9C77991/,principal,telecharge,mandoduelist,BucketheadBits/Units/Color Replacer,oui,oui, +http://cloud-3.steamusercontent.com/ugc/2174736446813135349/81275DD398B659088A018A09394B7FD6E5C3B279/,principal,telecharge,waxer,BucketheadBits/Units/Color Replacer,oui,oui, +http://cloud-3.steamusercontent.com/ugc/2174736446813135454/32F343B3295B563DF3041AF5F433E151F88C66B6/,principal,telecharge,boil,BucketheadBits/Units/Color Replacer,oui,oui, +http://cloud-3.steamusercontent.com/ugc/2174736446813135529/6A6C874DBCA77E800A77C20FD36C2F223661CD10/,principal,telecharge,cody,BucketheadBits/Units/Color Replacer,oui,oui, +http://cloud-3.steamusercontent.com/ugc/2202884666993392985/D48A26F5F9D3498814911131BA08B0BAF92F8B65/,principal,telecharge,atrt_gar,BucketheadBits/Units/Color Replacer,oui,oui, +http://cloud-3.steamusercontent.com/ugc/2474241114696859319/2846289D99E3CA2DC68F2BB8FC69ECF1ABE2072E/,principal,telecharge,delta_07,,non,oui, +http://cloud-3.steamusercontent.com/ugc/2474241114696859485/0340EC3130B99413F05F2CB2544E9FDE79A3871D/,principal,telecharge,delta_40,,non,oui, +http://cloud-3.steamusercontent.com/ugc/2474241114696859554/12CFFC76B71288B5426C2E57CC8A91F515B075F2/,principal,telecharge,delta_62,,non,oui, +http://cloud-3.steamusercontent.com/ugc/2474241114696859651/A77E973493F46183AC97F68C1A191EC0E74F6A65/,principal,telecharge,delta_leader,,non,oui, +http://cloud-3.steamusercontent.com/ugc/2474241114696882381/265198067C41DF8333A609EDCE831A547A68F28F/,secondaire,telecharge,delta_38mat 1,BucketheadBits/Units/Color Replacer,oui,oui, +http://cloud-3.steamusercontent.com/ugc/2474241114696882497/A846281F67580B208A2BBBDADE7C601230486E20/,secondaire,telecharge,delta_40mat 1,BucketheadBits/Units/Color Replacer,oui,oui, +http://cloud-3.steamusercontent.com/ugc/2474241114696882580/BE0E56B70A5D6B576BA4AAB83FDB1DB2BD835887/,secondaire,telecharge,delta_62mat 1,BucketheadBits/Units/Color Replacer,oui,oui, +http://cloud-3.steamusercontent.com/ugc/2474241114696882664/1B6168DA14AFA3A40CC823399CC4072FD1B7E958/,secondaire,telecharge,delta_07mat 1,BucketheadBits/Units/Color Replacer,oui,oui, +http://cloud-3.steamusercontent.com/ugc/2475370743175243825/0B07462AB1D02ACB64262C1E875E9DC5E3719850/,principal,telecharge,echo_model,BucketheadBits/Units/Color Replacer,oui,oui, +http://cloud-3.steamusercontent.com/ugc/2475370743175243916/EFBD0137414E802232F64B02C78A9D9275C9C1CB/,principal,cache,hunter_model,BucketheadBits/Units/Color Replacer,oui,oui, +http://cloud-3.steamusercontent.com/ugc/2475370743175243961/93E8549BC0F1F88228D651FAE226459945DC6651/,principal,telecharge,omega_model,BucketheadBits/Units/Color Replacer,oui,oui, +http://cloud-3.steamusercontent.com/ugc/2475370743175244098/67CBDAB9CA48B24940FC743CEB778A526C990993/,principal,telecharge,tech_model,BucketheadBits/Units/Color Replacer,oui,oui, +http://cloud-3.steamusercontent.com/ugc/2475370743175244156/4986205CB2289E6CF72269D9A17E6B2D405968DA/,principal,telecharge,wrecker_model,BucketheadBits/Units/Color Replacer,oui,oui, +http://cloud-3.steamusercontent.com/ugc/2475370743175244300/863B36B154CA2A32E4C36B9CFBC47984846ECE3C/,principal,telecharge,crosshair_model,BucketheadBits/Units/Color Replacer,oui,oui, +http://cloud-3.steamusercontent.com/ugc/2495630600682582649/F03C73249983DDC1178314FD61C7D53DA27840EE/,secondaire,telecharge,range_trooper_mat,BucketheadBits/Units/Color Replacer,oui,oui, +http://cloud-3.steamusercontent.com/ugc/2495630600682582714/3AFE8876506FE4B261417033A0E804BA9146FECE/,secondaire,telecharge,rep_commandomat,BucketheadBits/Units/Color Replacer,oui,oui, +http://cloud-3.steamusercontent.com/ugc/2495630600682669442/778C5CDC3ED0EF8036784484685D9C1E283AE229/,principal,telecharge,commando_1,,non,oui, +http://cloud-3.steamusercontent.com/ugc/2495630600682669514/964CC0732F05CF777C4F226E4A66B82C9B8F17F1/,principal,telecharge,commando_2,,non,oui, +http://cloud-3.steamusercontent.com/ugc/2495630600682669589/FE6E365D8DFE4186F7AE93CBEF854B84881DFA18/,principal,telecharge,commando_3,,non,oui, +http://cloud-3.steamusercontent.com/ugc/2495630600682669631/743A3F4EE203D22A0C7A8324994F8DD6D15337C0/,principal,telecharge,commando_leader,,non,oui, +http://cloud-3.steamusercontent.com/ugc/2495630600682669687/1A75297DAE22B6DFE46AF5B69EDC87652B23957F/,principal,telecharge,range_trooper_leader_model,,non,oui, +http://cloud-3.steamusercontent.com/ugc/2495630600682669758/7E6C79BDA776AD0618FF66FCD961C59DD6B0F4F1/,principal,telecharge,range_trooper_model,,non,oui, +http://cloud-3.steamusercontent.com/ugc/2495630600682669844/3306C99E1B2A23502CA35EEB63FC842EA7FB4E3A/,principal,telecharge,range_trooper_dlt-20a_model,,non,oui, +http://cloud-3.steamusercontent.com/ugc/2495630600682669896/C2F5892D64B3B5CE33A83A3F874C1A66594F6412/,principal,telecharge,range_trooper_t-21a_model,,non,oui, +http://cloud-3.steamusercontent.com/ugc/773995200348530664/5E248091F8CC37B1023257338D4947E4ADFE48AB/,secondaire,telecharge,arc_materials,,non,oui, +http://cloud-3.steamusercontent.com/ugc/773995528924546789/8774CBBDC3C4F18B11A444CC96EA5FE7F00DB48F/,secondaire,telecharge,bx_droid_materials,,non,oui, +https://steamusercontent-a.akamaihd.net/ugc/14648332786386280089/CFF5EDB1D4A6A8136BEC1997DEBF668DB0166B48/,principal,telecharge,ahsoka commander,,non,non, +https://steamusercontent-a.akamaihd.net/ugc/15416532958990284151/F41C3DBAFCDCA9717ED5F6A53E6E46F1BFABA467/,principal,cache,ahsoka padawn,,non,non, +https://steamusercontent-a.akamaihd.net/ugc/16432158164944196/4594ADE002844CEEB6FB9A75E17AA802FCAE89FF/,principal,telecharge,crab 1 variant,,non,non, +https://steamusercontent-a.akamaihd.net/ugc/2446089105226763008/9B5002BC5C049F340FF7CDBC875F5053A5DB2574/,principal,telecharge,djin djarin 10k,,non,non, +https://steamusercontent-a.akamaihd.net/ugc/2446089105227025807/2E7D8F479762060CAF447A2E5A6C27891C314EA2/,principal,telecharge,moff gideon 10k,,non,non, +https://steamusercontent-a.akamaihd.net/ugc/2446089105227059084/0EB4EE32683338BC754DA5EC1F613ABA71048E90/,principal,telecharge,kallus 10k,,non,non, +https://steamusercontent-a.akamaihd.net/ugc/2446090001278329724/E8E229E0E3FB6230D9F5A1823C71032A0FC9F2D0/,principal,telecharge,7th sister,,non,non, +https://steamusercontent-a.akamaihd.net/ugc/2456221571853672166/B86F663B609267644D837B4F18C59614C6785229/,principal,telecharge,5th test,,non,non, +https://steamusercontent-a.akamaihd.net/ugc/2478747809407737751/27A207BFDA271D2EA267D400CBDF551B11EE093C/,principal,telecharge,legion stormtrooper,,non,non, +https://steamusercontent-a.akamaihd.net/ugc/2478747809413608082/BD8A164AAD4C70AE2F8CB8165F3D2DC9FD94C778/,principal,telecharge,legion storm trooper leader,,non,non, +https://steamusercontent-a.akamaihd.net/ugc/2482129948495931625/A14C0E047A0C7C8D12B96B34A16D2DAAA3A5E9E3/,principal,cache,poi_token,,non,oui, +https://steamusercontent-a.akamaihd.net/ugc/2491137781649821412/A274C8B3E646E0EBFB81D282570C5A1C6D263F2B/,principal,telecharge,riot_2,,non,oui, +https://steamusercontent-a.akamaihd.net/ugc/2491137781649821497/585AF58548561265B23B01A56577DE0732464636/,principal,telecharge,riot_3,,non,oui, +https://steamusercontent-a.akamaihd.net/ugc/2491137781649821557/0B4EFC2CDDBC7BB72768141562946583278CAAD6/,principal,telecharge,riot_4,,non,oui, +https://steamusercontent-a.akamaihd.net/ugc/2491137781649821645/5FF305DCBED87DDE0DC92AB430557E501D5CDFC2/,principal,telecharge,riot_leader,,non,oui, +https://steamusercontent-a.akamaihd.net/ugc/2491137781649821736/A6557A52AB579A320023B7028C55A38815DC566E/,secondaire,telecharge,riot_stormtrooper_mat,BucketheadBits/Units/Color Replacer,oui,oui, +https://steamusercontent-a.akamaihd.net/ugc/2491137781649838294/7197479F9D7ADF9DB1287E740A469A0E5C28F2ED/,principal,telecharge,stormtroopermarksman,,non,oui, diff --git a/mac-patcher/tools/inventory_mod_bundles.py b/mac-patcher/tools/inventory_mod_bundles.py new file mode 100644 index 000000000..460750ede --- /dev/null +++ b/mac-patcher/tools/inventory_mod_bundles.py @@ -0,0 +1,166 @@ +#!/usr/bin/env python3 +"""Inventorie les bundles reellement references par le mod et dit lesquels ont besoin du fix Metal. + +Le mod ne liste pas ses assets dans sa save : les figurines sont spawnees +dynamiquement depuis mod/src/includes/generated/cards.ttslua, ou chaque mini +porte un `bundle` (maillage) et parfois un `secondary` (materiaux partages, donc +la teinte et le shader Color Replacer). Cf memoire registre-valide-invalide V17. + +Pour chaque URL : on prend le fichier dans le cache TTS local s'il y est, sinon +on le telecharge. On lit ensuite son nom d'AssetBundle interne, ses shaders +embarques, et on regarde si un rebuild du meme nom existe. + +Sortie : un CSV inventaire-bundles.csv exploitable pour la suite. +""" + +import csv +import glob +import hashlib +import os +import re +import sys +import time +import urllib.request + +import UnityPy + +REPO = "swlegion-tts/mod/src/includes/generated/cards.ttslua" +CACHE = os.path.expanduser("~/Library/Tabletop Simulator/Mods/Assetbundles") +DOWNLOADS = "tts-assets/published-bundles" +REBUILD_WIN = "UnityProject-U6/AssetBundles-win" +OUT = "inventaire-bundles.csv" + + +def urls_from_mod(): + """Renvoie {url: role} ou role vaut 'principal' ou 'secondaire'.""" + raw = open(REPO, encoding="utf-8").read() + out = {} + for u in re.findall(r'bundle\s*=\s*"([^"]+)"', raw): + out.setdefault(u, "principal") + for u in re.findall(r'secondary\s*=\s*"([^"]+)"', raw): + out[u] = "secondaire" # prime sur principal : c'est le role qui porte les materiaux + return out + + +def cache_index(): + """{identifiant ugc: chemin} du cache TTS local. + + On n'apparie PAS sur l'URL aplatie : le mod reference `cloud-3.steamusercontent.com` + alors que TTS met en cache sous le nom de l'URL Akamai. Seul l'identifiant + numerique `ugc/` est commun aux deux. + """ + index = {} + for path in glob.glob(CACHE + "/*.unity3d"): + for ugc_id in re.findall(r"ugc(\d{6,})", os.path.basename(path)): + index[ugc_id] = path + return index + + +def downloadable(url): + """`cloud-3.steamusercontent.com` repond 403 : l'hote Akamai en https sert le meme contenu.""" + url = re.sub(r"^https?://[^/]+", "https://steamusercontent-a.akamaihd.net", url) + return url + + +def local_copy(url, index): + """Chemin local du bundle : cache TTS si present, sinon telechargement. Renvoie (chemin, origine).""" + match = re.search(r"/ugc/(\d+)", url) + if match and match.group(1) in index: + return index[match.group(1)], "cache" + + dest = os.path.join(DOWNLOADS, hashlib.sha1(url.encode()).hexdigest()[:16] + ".unity3d") + if os.path.exists(dest): + return dest, "telecharge" + + os.makedirs(DOWNLOADS, exist_ok=True) + req = urllib.request.Request(downloadable(url), headers={"User-Agent": "Mozilla/5.0"}) + with urllib.request.urlopen(req, timeout=180) as resp: + data = resp.read() + if not data.startswith(b"UnityFS"): + raise ValueError(f"reponse non-bundle ({len(data)} o)") + with open(dest, "wb") as fh: + fh.write(data) + return dest, "telecharge" + + +def inspect(path): + """(nom_du_bundle, [shaders embarques])""" + env = UnityPy.load(path) + name, shaders = None, [] + for obj in env.objects: + if obj.type.name == "AssetBundle" and name is None: + try: + name = obj.read_typetree().get("m_Name") + except Exception: + pass + elif obj.type.name == "Shader": + try: + shaders.append(obj.read_typetree()["m_ParsedForm"]["m_Name"]) + except Exception: + shaders.append("?") + return name, shaders + + +def main(): + urls = urls_from_mod() + rebuilt = { + os.path.basename(f) + for f in glob.glob(REBUILD_WIN + "/*") + if not f.endswith(".manifest") and os.path.basename(f) != "AssetBundles" + } + print(f"{len(urls)} URL de bundles referencees par le mod, {len(rebuilt)} bundles rebuildes disponibles") + + index = cache_index() + print(f"{len(index)} bundles dans le cache TTS local, indexes par identifiant ugc") + + rows = [] + started = time.time() + for i, (url, role) in enumerate(sorted(urls.items()), 1): + try: + path, origin = local_copy(url, index) + except Exception as exc: + rows.append({"url": url, "role": role, "origine": "ECHEC", "bundle": "", + "shaders": "", "besoin_fix": "", "rebuild_dispo": "", "note": str(exc)[:80]}) + print(f" ✗ telechargement {url} — {exc}") + continue + + try: + name, shaders = inspect(path) + except Exception as exc: + rows.append({"url": url, "role": role, "origine": origin, "bundle": "", + "shaders": "", "besoin_fix": "", "rebuild_dispo": "", "note": f"illisible: {exc}"[:80]}) + continue + + rows.append({ + "url": url, + "role": role, + "origine": origin, + "bundle": name or "", + "shaders": " | ".join(sorted(set(shaders))), + "besoin_fix": "oui" if shaders else "non", + "rebuild_dispo": "oui" if name in rebuilt else "non", + "note": "", + }) + + if i % 20 == 0 or i == len(urls): + print(f" {i}/{len(urls)} ({time.time() - started:.0f} s)") + + with open(OUT, "w", newline="", encoding="utf-8") as fh: + writer = csv.DictWriter(fh, fieldnames=list(rows[0].keys())) + writer.writeheader() + writer.writerows(rows) + + besoin = [r for r in rows if r["besoin_fix"] == "oui"] + pret = [r for r in besoin if r["rebuild_dispo"] == "oui"] + print(f"\n{len(rows)} bundles inventories") + print(f" ont besoin du fix (shader embarque) : {len(besoin)}") + print(f" dont un rebuild existe deja : {len(pret)}") + print(f" SANS rebuild (absents du projet) : {len(besoin) - len(pret)}") + for r in besoin: + if r["rebuild_dispo"] == "non": + print(f" ⚠ {r['bundle'] or ''} ({r['role']}) — {r['shaders'][:60]}") + print(f" ecrit {OUT}") + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/mac-patcher/tools/merge_subshader_platforms.py b/mac-patcher/tools/merge_subshader_platforms.py new file mode 100644 index 000000000..f12204ef1 --- /dev/null +++ b/mac-patcher/tools/merge_subshader_platforms.py @@ -0,0 +1,102 @@ +#!/usr/bin/env python3 +"""Fusionne deux bundles en donnant a chaque plateforme SON PROPRE SubShader. + +Pourquoi pas merge_shader_platforms.py : les tables de liaison de parametres +(m_NameIndices, m_CommonParameters, m_ConstantBufferBindings) sont stockees UNE +FOIS PAR PASSE et partagees par toutes les plateformes. DirectX et OpenGLCore +peuvent cohabiter parce qu'ils partagent cette disposition ($Globals, memes +offsets) — c'est ce que font les bundles publies du mod. Metal, lui, eclate les +globals en VGlobals/FGlobals et remet les offsets a zero : greffer un programme +Metal dans une passe DirectX lui donne les mauvaises liaisons, et il rend faux +sans aucun message d'erreur (verifie le 12/08/2026). + +Un shader peut en revanche declarer plusieurs SubShaders, et chacun porte ses +propres passes donc ses propres tables. On empile donc le SubShader du bundle +macOS derriere celui du bundle Windows, en esperant qu'Unity descende au suivant +quand le premier n'a pas de variante pour l'API courante. + +Usage: + merge_subshader_platforms.py +""" + +import sys + +import UnityPy + +GPU = {4: "d3d11", 9: "gles3", 14: "metal", 15: "glcore", 18: "vulkan"} + + +def shaders_by_name(env): + out = {} + for obj in env.objects: + if obj.type.name != "Shader": + continue + tree = obj.read_typetree() + out[tree["m_ParsedForm"]["m_Name"]] = tree + return out + + +def merge(base_tree, donor_tree): + """Concatene les blobs, puis ajoute les SubShaders du donneur. Renvoie le nb de plateformes ajoutees.""" + added = 0 + blob = bytes(base_tree["compressedBlob"]) + + for i, platform in enumerate(donor_tree["platforms"]): + if platform in base_tree["platforms"]: + continue + shift = len(blob) + base_tree["platforms"].append(platform) + base_tree["offsets"].append([o + shift for o in donor_tree["offsets"][i]]) + base_tree["compressedLengths"].append(list(donor_tree["compressedLengths"][i])) + base_tree["decompressedLengths"].append(list(donor_tree["decompressedLengths"][i])) + base_tree["stageCounts"].append(donor_tree["stageCounts"][i]) + blob += bytes(donor_tree["compressedBlob"]) + added += 1 + + if added: + base_tree["compressedBlob"] = list(blob) + # Le SubShader du donneur arrive AVEC ses tables de parametres : c'est + # tout l'interet de la manoeuvre. + base_tree["m_ParsedForm"]["m_SubShaders"].extend(donor_tree["m_ParsedForm"]["m_SubShaders"]) + + return added + + +def main(base_path, donor_path, out_path): + base_env = UnityPy.load(base_path) + donors = shaders_by_name(UnityPy.load(donor_path)) + total = 0 + + for obj in base_env.objects: + if obj.type.name != "Shader": + continue + tree = obj.read_typetree() + name = tree["m_ParsedForm"]["m_Name"] + if name not in donors: + print(f" {name}: absent du bundle d'apport, laisse tel quel") + continue + + before = [GPU.get(p, p) for p in tree["platforms"]] + nsub_before = len(tree["m_ParsedForm"]["m_SubShaders"]) + added = merge(tree, donors[name]) + after = [GPU.get(p, p) for p in tree["platforms"]] + nsub = len(tree["m_ParsedForm"]["m_SubShaders"]) + + if added: + obj.save_typetree(tree) + total += added + print(f" {name}: {before} -> {after}, SubShaders {nsub_before} -> {nsub}") + + if not total: + print(" rien a fusionner") + + with open(out_path, "wb") as fh: + fh.write(base_env.file.save(packer="lzma")) + print(f" ecrit {out_path}") + + +if __name__ == "__main__": + if len(sys.argv) != 4: + print(__doc__) + sys.exit(1) + main(sys.argv[1], sys.argv[2], sys.argv[3]) diff --git a/mac-patcher/tools/patch_shader_vertexcolor.py b/mac-patcher/tools/patch_shader_vertexcolor.py new file mode 100644 index 000000000..32c6c8aab --- /dev/null +++ b/mac-patcher/tools/patch_shader_vertexcolor.py @@ -0,0 +1,115 @@ +#!/usr/bin/env python3 +"""Neutralise la lecture de la couleur de sommet, le temps d'un build macOS. + +Pourquoi : les shaders d'effets lumineux lisent `v.color`, un canal de sommet +que AUCUN mesh du mod ne possede. Quand le canal manque, DirectX et OpenGL +fournissent du blanc (1,1,1,1) et l'effet s'allume ; Metal fournit du noir +(0,0,0,0). Les passes concernees sont en `Blend One One`, donc multipliees par +zero elles n'ajoutent rien : la lame de Yoda rend, mais ne brille pas. Constate +en jeu le 12/08/2026, puis demontre. + +Dans GlowGeometry.shader l'extinction est double : + + o.v.x = min(1.0f, viewSat * v.color.a); // le fonduanguleux -> 0 + float4 lerpColor = _FarColor * pow(...) * i.col.r * _Contrast; // l'intensite -> 0 + +On remplace donc `v.color` par du blanc, ce qui reproduit exactement ce que +Windows recoit. C'est sur : sur les 408 meshes des 248 bundles publies, UN SEUL +porte un canal Color (`del_meeko`), et il n'utilise aucun shader custom — il +fait partie des bundles qu'on ne touche jamais. + +Comme on ne greffe QUE le SubShader macOS, le rendu Windows n'est pas altere. + +⚠ Se combine avec patch_shader_precision.py : les deux scripts sauvegardent en +`.orig` sans jamais ecraser une sauvegarde existante, donc appliquer les deux a +la suite conserve le vrai original, et le `--restore` de l'un remet tout en +place. + +Usage : + patch_shader_vertexcolor.py --apply # patche les .shader (sauvegarde en .orig) + patch_shader_vertexcolor.py --restore # remet les sources d'origine +""" + +import argparse +import os +import re +import shutil +import sys + +ROOT = "UnityProject-U6/Assets" + +# Liste explicite plutot qu'un balayage : le remplacement n'est legitime que +# pour NOS shaders, sur des meshes dont on a verifie l'absence du canal. Les +# shaders tiers (SineVFX) travaillent sur leurs propres geometries. +TARGETS = [ + "Units/_Shaders/GlowGeometry.shader", + "Units/_Shaders/RimGlowGeometry.shader", + "Units/_Shaders/RimGlowGeometry_Shield.shader", + "Units/_Shaders/BlasterBolt_1Pass.shader", + "Shaders/BB_Sprite_BillboardY.shader", +] + +VERTEX_COLOR = re.compile(r"\bv\.color\b") +WHITE = "float4(1,1,1,1)" + + +def apply(): + touched = 0 + for rel in TARGETS: + path = os.path.join(ROOT, rel) + if not os.path.exists(path): + print(f" ⚠ absent, ignore : {rel}") + continue + + # Certains shaders sont en latin-1 (le "© Allen White" de l'en-tete) : + # lire en binaire et ne pas reencoder, pour ne rien alterer d'autre. + with open(path, "rb") as fh: + raw = fh.read() + encoding = "utf-8-sig" + try: + src = raw.decode(encoding) + except UnicodeDecodeError: + encoding = "latin-1" + src = raw.decode(encoding) + + out, n = VERTEX_COLOR.subn(WHITE, src) + if not n: + print(f" ⚠ aucune occurrence de v.color dans {rel}") + continue + + backup = path + ".orig" + if not os.path.exists(backup): # ne jamais ecraser une sauvegarde par du deja patche + shutil.copy2(path, backup) + with open(path, "w", encoding=encoding) as fh: + fh.write(out) + touched += 1 + print(f" patche {rel} ({n} occurrence{'s' if n > 1 else ''})") + + print(f"{touched} shaders sur {len(TARGETS)} neutralises") + return 0 if touched == len(TARGETS) else 1 + + +def restore(): + count = 0 + for base, dirs, files in os.walk(ROOT): + for name in files: + if not name.endswith(".orig"): + continue + backup = os.path.join(base, name) + shutil.move(backup, backup[:-5]) + count += 1 + print(f"{count} shaders restaures") + return 0 + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + group = parser.add_mutually_exclusive_group(required=True) + group.add_argument("--apply", action="store_true") + group.add_argument("--restore", action="store_true") + args = parser.parse_args() + return apply() if args.apply else restore() + + +if __name__ == "__main__": + sys.exit(main()) From c445ca69509eb4b9f1d2a2aa9f54e8da681abfe5 Mon Sep 17 00:00:00 2001 From: Martin Pourrat Date: Thu, 13 Aug 2026 23:38:38 +0200 Subject: [PATCH 26/42] mac-patcher: stop dropping forceFigMode on the way to gToggleRange The hover hotkey sets forceFigMode so a hovered token shows the fig-leader bands rather than its own single ring, and macResolveBundle reads it -- but gRangeTrigger rebuilt the params table with figGUID alone, so the flag never arrived and the branch was dead code. showRangeOnHoveredModel already forwarded it, so the same gesture gave two different results depending on which path it took. Found by harness_projectors.py, which drives the Lua the patcher really writes, outside TTS. 24 checks, all green now. Also records an open arbitration in the spec: bases with no cohesion bundle (huge, long, laat, epic, snail) draw nothing, like vanilla, where the old decal engine fell back to the small radius. Co-Authored-By: Claude Opus 5 (1M context) --- mac-patcher/cahier-des-charges-overlays.md | 9 +++++++++ mac-patcher/patch_save_for_mac.py | 10 ++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/mac-patcher/cahier-des-charges-overlays.md b/mac-patcher/cahier-des-charges-overlays.md index 6b242438e..5eef08389 100644 --- a/mac-patcher/cahier-des-charges-overlays.md +++ b/mac-patcher/cahier-des-charges-overlays.md @@ -146,6 +146,15 @@ Projector, verrouillé, sans gravité, nommé « Cohesion Ruler ». | mode vanilla : toggle et non respawn | `spawnCohesionRuler` d'origine **respawne** au lieu de basculer. Sans interception, un deuxième clic la redessinait et elle ne s'éteignait jamais. On lit `fig.getVar("cohesionRuler")` pour connaître l'état réel | | garde | l'objet survolé peut ne pas être une figurine et n'avoir aucune de ces fonctions. Le `pcall` retombe alors sur notre moteur | +**❓ Arbitrage ouvert, constaté au banc le 13/08 : les socles sans bundle de cohésion.** +`getCohesionLinks()` ne connaît que `small`, `medium` et `large`. Pour `huge`, `long`, +`laat`, `epic` et `snail`, le vanilla **ne dessine rien** et le moteur Projectors fait +pareil, donc on est à parité. Mais l'ancien moteur à décals retombait sur le rayon +`small` et dessinait quelque chose. Le trou compte surtout pour les **socles oblongs**, +dont les unités ont plusieurs figurines et donc une vraie cohésion à mesurer. Trois +issues : rester au vanilla, réétirer un bundle existant, ou refabriquer un anneau +oblong. **Non tranché.** + ## 4. Les tokens à `rangeKey`, et le Bomb Cart **Objets concernés**, 19 fichiers plus le Bomb Cart, tous via `!/TokenWithRangeRuler` ou diff --git a/mac-patcher/patch_save_for_mac.py b/mac-patcher/patch_save_for_mac.py index 240b9abe1..4720c1f7b 100644 --- a/mac-patcher/patch_save_for_mac.py +++ b/mac-patcher/patch_save_for_mac.py @@ -421,7 +421,13 @@ local fig = getObjectFromGUID(params.figGUID) if not fig then return end if overlayMode ~= "windows" then - gToggleRange({figGUID = params.figGUID}) + -- Forward the WHOLE params table. Rebuilding it with figGUID alone + -- dropped forceFigMode, which the hover hotkey sets and + -- macResolveBundle reads: the fig-leader bands documented for a + -- hovered token never rendered, its own single ring did instead. + -- showRangeOnHoveredModel already forwards it, so the same gesture + -- gave two different results depending on which path it took. + gToggleRange(params) return end -- The vanilla bundle Range lives in the GLOBAL scope: !/RangeRulers is @@ -438,7 +444,7 @@ if pcall(function() spawnRangeRulerOriginalGlobal(fig) end) then macWinRangeGUID = params.figGUID else - gToggleRange({figGUID = params.figGUID}) + gToggleRange(params) end end end From bcf616a59be1a73ac99b001182d40ec203677f07 Mon Sep 17 00:00:00 2001 From: Martin Pourrat Date: Fri, 14 Aug 2026 00:30:37 +0200 Subject: [PATCH 27/42] Add the range 0.5 band to the Iron Squadron rulers Eight new bi-platform Projector bundles, built from the mod's own range prefabs, with one thing added: a white band from the base edge out to 3in, and range 1's orange starting at 3in instead of at the base. Where the band lands, without a single hand-tuned value: grad is linear in distance, so 3in sits exactly half way between the base edge (grad == uvShadow) and the range 1 edge. On the 27mm base that midpoint is 0.884295 where the exact analytic threshold is 0.884334 -- a thousandth of an inch. It also works on the oblong materials, whose thresholds Allen tuned by hand against an orthographic size that follows no formula (33.4, not 30.93): they inherit that tuning for free. Separate bundles on purpose. The repaired bundles are served from the TTS cache under the mod's own Steam URLs, so anything added to them would show in the mod's original mode too and the toggle would stop meaning anything for Range. These are new assets with no UGC entry, served from the fork. The band itself sits behind a _HALFBAND_ON keyword the mod's own materials do not carry, so their rebuilds stay identical. Only the hover hotkey reaches them; a token's own R button keeps the mod's single-ring bundle. Co-Authored-By: Claude Opus 5 (1M context) --- mac-patcher/patch_save_for_mac.py | 40 +++++++++++++++++- .../projector_100mm_isq.unity3d | Bin 0 -> 17076 bytes .../projector_100mm_oblong_isq.unity3d | Bin 0 -> 17655 bytes .../projector_120mm_isq.unity3d | Bin 0 -> 16989 bytes .../projector_150mm_isq.unity3d | Bin 0 -> 16913 bytes .../projector_200mm_oblong_isq.unity3d | Bin 0 -> 17763 bytes .../projector_27mm_isq.unity3d | Bin 0 -> 16922 bytes .../projector_50mm_isq.unity3d | Bin 0 -> 16782 bytes .../projector_70mm_isq.unity3d | Bin 0 -> 16962 bytes 9 files changed, 38 insertions(+), 2 deletions(-) create mode 100644 mod/data/mac-fallback-assets/projector_100mm_isq.unity3d create mode 100644 mod/data/mac-fallback-assets/projector_100mm_oblong_isq.unity3d create mode 100644 mod/data/mac-fallback-assets/projector_120mm_isq.unity3d create mode 100644 mod/data/mac-fallback-assets/projector_150mm_isq.unity3d create mode 100644 mod/data/mac-fallback-assets/projector_200mm_oblong_isq.unity3d create mode 100644 mod/data/mac-fallback-assets/projector_27mm_isq.unity3d create mode 100644 mod/data/mac-fallback-assets/projector_50mm_isq.unity3d create mode 100644 mod/data/mac-fallback-assets/projector_70mm_isq.unity3d diff --git a/mac-patcher/patch_save_for_mac.py b/mac-patcher/patch_save_for_mac.py index 4720c1f7b..5624e92ca 100644 --- a/mac-patcher/patch_save_for_mac.py +++ b/mac-patcher/patch_save_for_mac.py @@ -83,6 +83,32 @@ bombCart = "medium", } +-- The Iron Squadron range rulers. Same Projector, same geometry, same colours +-- as the mod's, with one thing added: the range 0.5 band, white, from the base +-- edge out to 3in, with range 1's orange starting at 3in instead of at the +-- base. Built from the mod's own prefabs (see make_isq_range_prefabs.py), so +-- they are bi-platform like everything else we rebuild. +-- +-- These are NEW assets: they have no Steam UGC entry, so they cannot be served +-- from the TTS cache like the 143 repaired bundles. They are served from the +-- fork instead. That separation is the point: the repaired bundles sit under +-- the mod's own URLs, so anything added to them would show in the mod's +-- original mode too, and the toggle would stop meaning anything for Range. +-- +-- Only the hover hotkey reaches this table (forceFigMode). A token's own R +-- button keeps the mod's single-ring bundle, deliberately. +local ISQ_ASSETS = "__ISQ_ASSETS_BASE__" +local ISQ_RANGE_BUNDLES = { + small = ISQ_ASSETS .. "projector_27mm_isq.unity3d", + medium = ISQ_ASSETS .. "projector_50mm_isq.unity3d", + large = ISQ_ASSETS .. "projector_70mm_isq.unity3d", + huge = ISQ_ASSETS .. "projector_100mm_isq.unity3d", + laat = ISQ_ASSETS .. "projector_120mm_isq.unity3d", + epic = ISQ_ASSETS .. "projector_150mm_isq.unity3d", + long = ISQ_ASSETS .. "projector_100mm_oblong_isq.unity3d", + snail = ISQ_ASSETS .. "projector_200mm_oblong_isq.unity3d", +} + -- Per family: the name TTS gives the spawned object, whether it tracks its -- figure, and the pitch the vanilla spawn uses. -- @@ -146,7 +172,11 @@ return links[key] end local bs = macGetBaseSize(fig) or (key and TOKEN_TO_BASESIZE[key]) - return bs and links[bs] or nil + if not bs then return nil end + -- Iron Squadron rulers first: same geometry as the mod's, plus the + -- white range 0.5 band. Fall back to the mod's own bundle if a base + -- size ever appears that we have no ruler for. + return ISQ_RANGE_BUNDLES[bs] or links[bs] end return nil @@ -1351,7 +1381,13 @@ def main(): original_global_len = len(data.get("LuaScript", "")) existing = data.get("LuaScript", "") cleaned, n_removed = GLOBAL_PATCH_MARKER_RE.subn("", existing) - data["LuaScript"] = cleaned + GLOBAL_PATCH_LUA + # One source of truth for where our own assets live: the Lua block carries + # a placeholder, filled here from ASSETS_BASE_URL. Flipping to upstream + # before merge is then a one-line change. + global_block = GLOBAL_PATCH_LUA.replace("__ISQ_ASSETS_BASE__", ASSETS_BASE_URL) + if "__ISQ_ASSETS_BASE__" in global_block: + sys.exit("ASSETS_BASE placeholder left unfilled in the Global block") + data["LuaScript"] = cleaned + global_block new_global_len = len(data["LuaScript"]) note = " (replaced existing patch)" if n_removed else "" print(f"Global LuaScript: {original_global_len} -> {new_global_len} bytes{note}") diff --git a/mod/data/mac-fallback-assets/projector_100mm_isq.unity3d b/mod/data/mac-fallback-assets/projector_100mm_isq.unity3d new file mode 100644 index 0000000000000000000000000000000000000000..c4ce924cda2f5659556903c17966dd078681ba60 GIT binary patch literal 17076 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

-gw}5~*n%1lCXgd^Bc|qt3Bu$(d^=lGI}wa2 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 literal 0 HcmV?d00001 diff --git a/mod/data/mac-fallback-assets/projector_100mm_oblong_isq.unity3d b/mod/data/mac-fallback-assets/projector_100mm_oblong_isq.unity3d new file mode 100644 index 0000000000000000000000000000000000000000..3a52da312ffbd96a442308d8fecc6b6202146b76 GIT binary patch literal 17655 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 literal 0 HcmV?d00001 diff --git a/mod/data/mac-fallback-assets/projector_200mm_oblong_isq.unity3d b/mod/data/mac-fallback-assets/projector_200mm_oblong_isq.unity3d new file mode 100644 index 0000000000000000000000000000000000000000..504b29f69aea023a4814dc49ae266de2e2c3f08b GIT binary patch literal 17763 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 literal 0 HcmV?d00001 diff --git a/mod/data/mac-fallback-assets/projector_50mm_isq.unity3d b/mod/data/mac-fallback-assets/projector_50mm_isq.unity3d new file mode 100644 index 0000000000000000000000000000000000000000..9c221da85902d578a198b7c2d9bceff387066c0b GIT binary patch literal 16782 zcmV)0K+eBaZfSIRMpFO)000OzE_g0@05&i%FfK4IHZo>0000000000%jsO4vMgRZ+ zTL1t6K>z>%000000000000018004jh003s%XOJFb;06h6!AIn@L~DzU!0jk}3|o>k z{tNZFl=ZY$qFICIXcO)e)c(%^r>sf?358Esg*PTMB zvE2i(w%)1Ba8sn;pF*w)5RNCK@+=c7hnM`0ul=Qxo-d;Kx2!MOBaZCM?_iQ2+xSdNCM zO&6OwL8oB<$+uf7-T>R{T`_G+@7YK2)&8z|;cS{|g`ChSa76$vS8-^Xw;lptk9Ly7@M*QkMVro5L0E;Y)8QXD9s9!-#;p|e3~ z19!!F3;3oN+~RBnAxLj^JSTe}CKQBTmB@E@d@sc+65i-qoAcTM%QS}~I7+5mI+<@y zvrZs@gx#pw-HcL0$lS=p5u-g4ruxk8bP0}=QpM9x1Qki4Pty_J$62Y#sKdO!$K*50 zN!mEt5X#|uEx^cB9LW^e`q_P7M#RlN`%Jn~RB!W(5@@8LBWaCLfcvmTlqz>!kYsy+ zPmSJ&cip7qy;QLvu;~86hA&q|8$k8>Eo_HWhY&yZ5Wi|Mo93 z2l#uOAanCFdHdyKeg{h`%c5sa!)z=WL2%_fIdchJO>F6>z}Nj+r{e(NWi1$A)aX=5 zA`sQ^WaBmu0QAsnE|M4VEO?-vW*>zQzGHyFh+QGq%oX{;%uB_-S;qX%g#X=zEU@LP z&Uk-&AQeO<_m!kmDD{Eg{vQqWyN%C12owfgUxF#wu1#${>ZXP^l+Jd@z~v%T6T6_% zHjIsm0-qbXIBehA9~`(w4v~T6`)(N~(XX3U&|ID65rcl$*8HV#pKT&q#2dz?9ZFSa zf}(k|nqcn$hwmGdI3#$}?^dN*>T@S$%^jIP(=*ya-lj7K;31af7}OGTeC83(!=?Mq zYfqzX`3+lH%?XjrfRtL2I+E$la7MZUiEt=Za+#cnw%qnXG5?q!#eb^#;v}}j;#KEm z>Gg2|kSMdK0P5Kt*91bl5lk(67~s)`vxq>zO{Y{xpvKq7nhkechf zdg5*n;!77~dwcAUSh-|Cp*UV4`kW;(_>RcxsZN@OVv)l&0+JQ3q{#Q1qAQIKZPxh@ z_MguAl}KE%&(efrq4k0yN5s}okney=?BYu*-O!%t+qwznOX-X8Af>K9Fe1S9**47) zEDWPdd>Px(;7SE7XhpbUhIVwb_6yl%X_)cHds$G)5EJRo@sR!ofmjIVJz>Ocf1INq zYfsf8&2spog(D3Rs9%F|9Zq>lT^CLBkyHlAqWcl3=? zRD<{sP$G^G0^=i%FDD$l2>@x-SXe%S>)3^Qj^zQ?Ee}b88SOve(6bUQm|73cMj+_# z8(LQNIzTeOkI=D>nwje9g>>j~{l+s^$FWl{7xAk$i8@0?vp8f9Z>pR1tARMmodXNg zP$JXyL0!peF|NH>ujzi7@L0&)frPISM)L6dQpppU+oy36W>U!gy2XMEE?**?iTL1nBH65Vp1-io#5HdQ2)phv*66{B$SwH|&fb;eb z%`~p;hAbD+AxwuIj*WAW0uWP}U^OO9N2Vi?ZtoQh!1IPs2yBuxN>Ey+%arapRoAc& z-4gBj<*9lp=MwW=Ad^k^%Viz3(rNQf$Xk{{!4ylK6SIxBbZu(J{|vcYVnNl|E!sKw z8uIPHnE0LlLp*LitF9+02Vf~1)>1P9~`kE%sx3R;zUv3wmGQA*2Qq)qu=7%f9I>)bQrzR7EcJb~z zQGBb9-rt~*yVXbMK_~P?Y1S)PiKm9Je}cLGm*8uw zS@@svjOrOAYR~r60y@a5Ri7h@;^+Xm<$ahcM&HX(h$W(ygft^U=yaA9e8y3!W?Goi z=GP^qEeyR$hG@jk*XCr|#}mHV)-QN==36{WHWq5D zs`eL)um!o&tOZgNKW{n%-7=GJRi}#$k5i0fe+YH&PI)bI=k|jt;(GeA^~TxpW;AsX zjOLysD;z+XI01d1^KYs{VI2$u$t=T~$#IbtiwCaIG3}H!(JMFe+Wz$k?<0YqkdR(P zrJ9zFYwBrca731Tmt<+%)byKeZ^XJTN2O_wldcTT>CN&QUgDc|QqWyPdtadaZx<8U~AP2i26m zmp7e2eA=su8qPE`5^`H(TKPhp&=<-!N{{3vrA#s6Wg)?cM7Ka5Px3-O;P2_{>NU!t z{MPigPdRtQ%y3LHJx@;hfxDg!5vHc9#$KP|z$xY@&s`~}@g$B*NGf=_W+C1LDXIWf z_0bdh%VfW*Le?Mzx#m_>U6k*{OF%{q=Mu{HgrO?ZwgZ6-EYL-#f$S~%`iwLjCVPe~ z&x;|BQYBYnNG31plYG$NuFl7@aO&(Di?ru)nl}E83&D5@O_WT#Ru%HB|VDn^|+@BNA?d`!8pDLZT4s3o<*s10%Q*>^;rg0O=%Har`C zTPK0LRV)OTg8v+zUPSfH2_8}C#1s;MRx|d=>|i6rZ!n;em*oi(@(x)Q9nbuVy7D2r zGYy-wI(#f@FA5|uPQ=#QwP(eyZ2jRYs!3pUMvX4P3~y{h!bHIbz*H6cN>;n3r;3y8 zMcjhHVSPzTNU3}Xp<_S*d)cZPw(anfJ9OvPYkQ`M0GBuw6=MS(1_~Ecw82xgh`z|n z@R}w2YoQCCy1qy59q{{|49u{y%?=kl-}rUg-FzR9!IO;|zIj9GK7n?GY=XlEAf+p| z-p2?TgbKBg;L&*nHm$KJ(D(DEJ5O}k2~cD_8x->PTV7>dNaNPF%nj1PVbgG~scKBa zVnlZ@v%;+w@$d6dq(*rAap-x=NscdubLTK~s84t)Bp5{J3E#p_cBy|{b{2cn7r`Jg z&;nj5>MzbqCyxp2iFy6M_*#4WGm4ZYZBx@?&b5TqEQP9Lz3J z8tpJPLHS(uI27Pr`y$AfCau)E(?Uv5EY*D3I3xj#C_hU~t*x+1XZ`LZpk^Mw!?z#c znUYu>@Gnfxd0PCV_cpTG(7W3P(SmE(xp83ug02UG2u6U$2kiDC9|-rZhT2`jrMkqO z{YPFbe~ZT#f8bZfKE$8w8dI8aIMa#{#U5@%l{KGd_;b68DRlK*qA4j}(>bL+V z)p*cBTfqnEAe>+l9~$j=yH#0LLof(WZKb#C+LL^s4FPbC+53VomP zj##fk%`K)c;6xcyYLL1`8571t%ii|h-#HGBFkFg@C8+6q7Aq7yP;4z^IxH7VgsR{B34=MUYWQpJjKy`AJCp_|M4~3wbs}Zcr z&v*W`t1fvIJMg;r9nMw_uC0%4AdhEttx@ac>rSrRS*e0UP%l48`83 z4a2%kr_30MJI&&Tsb1E)f6)=Fi9s>Tegx+U-(CrFAx|=cZKVa!OSY-bOb$xB_K2HO znqwTqf_){lx@wR+_K3}W&XJ2_(Ltw#;#_p6gDLxVM<*{K9!dLfCVwT?qbz908-&zZ z1vHjdv)l*I>#^=Lfnlgqbq&G7u7j1$z$S&9#QhtoKue+6?Z}7qujheeU}*a(SU*aO zm@&dw>XB>>giZjoQk|>Gy3reiKW_S`H=zV(fa^--s+xyBW53DG|h{Q;)IbSmn%nX{{rghT!X}*wDVvj;Ni;k4v;3OxCw71HCuwzh=!^Jq6t81TRFc z*!0>J1O%Rho5~)-oM=cHvx__GxSxFMN@Dj~EQnK?#TK$E;|8~OA^|uwqh*gCzA6QzV4$c2$Uiw7S~GU=K!L@8JE z5FTkzABhuM%s#OFCynG`z$77uy%}fb`Tc)tPjYRCZT;Rprl-iaGjDFmob}? zOrfBJOgaX&%X+iw)j|N$kR5m(mW*43)B%T!s!vK@5XyLQAz_YzIh%=i3a3eO<~Pua z0sYkxnP>nks+@6yt2~@SJ!;ZMPiU2Mz8!~M5P)%PX^y^l$_&>#CD-l9tUmg$3=l7s z+%S4VGuEZwXV6CW4eNN-reFmw?GVA6@90im^_ZXc=7759fy(>EDd`cNNhK>UAx5r= zLkhA7sfKsPktKU<>~M^bR;?!TxXX8Z6N^9Zxyw9+X4QB_%(!~NEKkP zWnWDY*o}nn*HcBdMR=V()BVO(cUblenf|wgV|?K4vpG`TzSeViduz$v-#sOQ#BzZ7 zEJ+2G3qR#NXSNNn_|Ck z2cdXjgsv_1!9IhqI?Bo>8lro;QTcT>n>eLTO7b(sFSOsxwr56T9fcvYFy+0(^40a~ zl8dWSg$dts@L_IZ&&RU|ueLy>Le~;i$u7_f!k`?8l>UH3Bv1Z^nKS>>s!{Q|soT@_ zz_-CF;cG}$wnTz>yw2_E+S&6zTZDTDwOw3$KbunE7;KG6I9rAK&gdyY#n|@;usa*1 zn}SLa%S_D(5dt)ot*hAz)4;&#i>c$+%5gY0s@0)yLi((B&sJKQ5t}$$#FQ$j3PktRuQ})oX0eyl1zE2DMm@gncs)9IZ4`-1AM4H-Ka( zzP3XXvETTW*#!0ZhE*Q^0Wie!xE!aiN+WGz9KSTd|w`F(+G~e85dcJQ(wTMH* z1Y>D{a)M+%ZxT%zrEOvGPN4vH*ZdqT6IZ9b1|2kRzdg{8x;1q9QyFKeMySu%pA5-^^%fni|8IU}`Ka5u}SWP`%<}fCO?9J{zYAUWhic(O`D@4Dl57? z7|+&^g6|M(?-5>w1yn@oMvcb63VYbFZv4$WF0*Lv1Scyg60wL_TPuaw2=n~1JA(OL zM`|3keL_0~3>LmF$BSTODSXtk3~(!RV?g6$|Ld@Zb2gd9k!Po;vO9xljds2mts|SL9ar{Xr)Ax84Wj@}3g|L%!yegPb0M>KYsB z%tlhf^MZ;qUkOJpzc|`hr{6DNoVVygkby9Z2r-xgvc4~wqs)#J!-j{M!73|QrD3h4 zwp0tmv5!NnY^J$;E?J8Ox&kT*?AmhwjrJm6vA5`l&#)|Qd@l79$c0Z-aw!iLt$NXaCVG{3M%$)~A}Qq& z{=%r-16>0#wD~3{@a+ZCUjus5G-iNbKPu=Me#YGwGabhg{q?4!tV=bsq=hv zxm%1tSnO4{EM)q4c(osu^2b){NuJGRM{y%t?UQ>un}gusVcl<#;_0SFve-4da3^(e zs+5kPJguIo?Iz%19Yqz`zN2e;Eb7Uw(JOf*5^@a3uU(ZcHUM@!-ZP}!HZi?=Gp73C zDXX@m_7j+xPgcy?6Y(?_ZLHIL8 znsDQ)G|@tMYX$#bQMD%kUDjJ)bd43$F3|0S$@m-0`r+~?jeEuCA99aZt}y%Bbi2QF zJY2CAFYP|@P(l4q8j=$&>q98IrInE7_&FHSDc$v2XUp&?kxGnKNj_{&f2|7(ig1D6 z<(5K)ibJ!+6fIJlZ0090dORnzQ%+F$zz?(?V_7v3@7Vv{U7t?}O+S|jj?CyD)UGkx zXYR{QcR!6D?(Fu{^}gbc31HV0Ia@U*L6fKiXZK+ew3f{2G%!QP!3vV;t5|4l$Wn?M z6R%$!Y~tf&Nc$Jo!gNzNEV&3?yS^tfZ>7A*HGF_0m6J%VQcjO}jv%!PWfy7@^>>lEjOHMY^nt{m;<@%)!vGm#m(AH@#VsJTJ{zb5e0QjR6Ds@RC44RX9$ znM+CuP~^~j`eKlwWC5EN1<9R?^pN_fpUT=VVKmdW` z4o`7Y0$P`pcG4(A3*u)8M%`LGXGLjHIH0vYkA@v-MCV6vx+P$nALmJ5toC;SMXPUX z5i2KVY!EGb+z6MR+}GiYwnPOuG$Fd z8lYrAwbgaf{>^p2jf%EdA%wz&0G$tHxC1bEd$4fd>D<)2=LB6ctl>^boArjC&@JU% z7e22*fm%`69+8c$S-@RH=B2Fx0-0~@=J54zq&1HS&UypdD#LG2yHwsjL}9BD&J8o= zCs@k(uEw)7OLPdxRa}+#9Pf($x<2}dqX{#%^@Cx6kKzev{mmt7hd<)W9LEAiRs>Y) zM71`+<~3zZ<1?BR?ax^?U^L&Sr?FSLmzxq?w&NB0!O&vwY*cRb1W55A2QawaovZK- zq&L!1j6iLj;N@tU@??7j>(^7B^x7d7Q2hHTE2EUoP{GXFxWQmdFKx|r65FKT0Fz)$>rk z$c(5wh|JuvqZ@oD6pjfi1qBY-Dk< zLE3%gSi2k!*Jk&?xI>MY(FjtV)HRoUGgknQYWO{ALeg53Td>=lh}nsDemr#?Whd+K zacK|*wjN+WIT#P=EVBbLy`QMed28K>$cMAu1D5n)ar@ObLK6Ee*$g`c zGtEdmwfM60;)_nuncz|#JL-XgZN(cg>Q-*hc{NN18lD+N?^OLVG!q^WB3;=_>KB^H zLIIvDa#&&P4Dyc-EBNH&g?cro<4h(|3Xw28sWpW;u0}t4B%jri1OPzxh9?8n1DZHj zs>-St6ul74x$g8R+~!{xK`-<(fCXr5`;brX-z8Y&i>s z`l8%3XJz>%4vOo(%{Isu4^Z;iQYzI8?%{$_R0DQgY?gGt4S&sGTJH?;HM@_L#}}Z2@qcA-rOuDx`2!g3=Opj;&LMSdYg{ zDeqIJg2bSTut)E61w~@r+_XGVZ*Yu(diT`qD_LdvSc1C9tDKJ$FKtSpJBhSITDLk!M+P z5i=%+%*(?j?CHt|$8qg^p_&nGN>C&3&KNV z$09Qm9QFm|K=qj_XJjXOb1T^ws@BaG>(g%pam8c|N@xN!u%~e`&yol)gw5ya>gp8& zp6nUg)<{Z!&3ea&m#*gFt~7oi-@a#)v0WUT9q@A;$lEti45zU+A%<%GhDoCDcNrig zPln=+_Y+dSO{72+;R`3BrE-&CYhD~q_zyKnEMaSFBSNyiY*%C+rK;kZ0z6CV(VCpo ze9AH+NQ9$rH|)|evTpv|b#xN6>13o?(PdrFfRqQe|DEDF_;%f?( zui>a&FNM-ef04Vif> zNl4wP?Mc0nJ4-ay#_-869W;#I5Lw~osG>jm(aG#K&$8C)=N>BqQR}; zr)J^GbAe~0_o68rRhI;CqPCY)UB+#WI9$}q-AIQ_ie3Ph(w<*8y7aig6|Eku5?23wNgu&sgTM;Q5#AyuLUdw@b0_x5D{3P&a`vCnPj@Mz$qOs98 z^MleJ^=U_s1y7$;g#tA1ZZO>NAEZnoxL(vNG+>(hLFO$3Ix@T&$IrB@FjSzE*hn((Wtgj* zYOkSvt)e#=+i;5_Mn+;K$E3^%3S|Y~Dr+9K_1a&}Xo?0;Tb0mk<~=ur306Cfg&aWc zM9_1IzyrTIzLxSjeEUFn*aa|-V3;jnX-kBiCFHMyhf{hLD>7mPn&9gcCtvIgQs`xl zFE4k=y>5x_FOF0s4;QY-l>yTXTFao+fLCy8uYbu=*%9K*FN*lqM7$U~X}&i7?e>hZZw$We^Y){}1*EUQ3%?Ps}O3#YOdj85W4JC_3F&`7_?rawcU! zl)Z9N@%oAdI+n z78f%rL(bIFz8KJ~w^H2k(Vvmj*?(KFCM@);HHx+OT{(FY4ZI@MW*sZIhNczQA729p z6HN|~p0#c5_~dqK+rHJ{Sg;)6ukeJ(K%6T((jNNw$1Z@B@}c^hj%h|!KAGK?;^kuH z(qL|s8#KUCPQg0;l?aX7I)>yuNsYdRu5TI@7j2Z>(mi;K$JDwVy=-D3-W)8$VPX+? zf7)Ox0q@!k7Jl_mgAwif!5G~hIcn&jA2H*QQgJ1BbP2-Lm3%3tskz0H{%|$1Y(Ywy z{$>Lnyw)9_4&0FlJP+1e`8Y&{--qfDU+!|Z1=xN{OD>ELJVq1LxJsdK$;xo5T*?`T zK?XFVYgWaTkNBRvIoe~28+gVqxr^oph$C2X!T;z(y5mf+Tn0_~0T3(t3sQ;9g%y88 zj0HY*Pf$+pO|@HPCz;E|aX)UMQgd?YU1e#Bbs1vuIP9zHxE*o6Nbz&)w@6{tqIZx%+@y3SC&JLg%bn?dbqM`~xfqz5NO)sl8(JrX?U}0qi4A z{CLCc%ntErjMx4T*#KBYA6}&H9(%=~RA?H`E^ig*?fx_zs=(v=V+7vuQl#3Jpfd)* zrIqy{M$5=W_biPuh)0uMp&9BPShN33efM+<(NW(7b&Wn9t024odIYFgdh6$zKT?vF z`VCPKLpK^WGKDXY}R&$3G5E*r_jFtHDM zX=SQ*em#KMSzWID33*SF21D!IU?8)`^gzuqSPgyN#Mgf^X~P=b;gZf|0&7HBTVw_& zzQY4cTSi>;QLN2;5(5jOA^n| z#LHAg&p3+`btL+?FQx>=s`CpxetCGfL%(j;UF;I}bcwR>)S&49Un~L$PNMf}rib z+pa|f4yl*3i-h%sW%XO}_O9?C+ZtAbJ<}`*Fg5<)Wh%F=o1N)MeHFj$p+6&4+eZ`{ zFN#$GL|iUG2V6L4lHlisoSWE7rU*8wg4)%5$?!&RiXc)+sy8=vlC>IWbYw}?H155W zc+|#2h6n+BBIONGOVhodev(61@``G<{W5aew{2DAkhQ!|x!?V8hwQWA`$`!dzNvY~ zIip=rYx>8}k@ZRaS%O@`QJ6NsP{g(^yIYlaVh~E;2sq-{P1Kgs~<8tdlkH_NWO_^PUX{{i&(U60J>6zlIR*UDqeqCeTi5HKC0gn?p&+Z89F z0sm=`ABo(#bZHc?RF$0v7PRpO0t(KwHQt}WXY!?ypG|qI6ckN&Xg-^TUa-yta`_=` zgCxZJkfc+J9T7{a(-}+V!$6!C@#Go&yXYv*z29z^#>5wUBnu?81QJo_`^dQvn+dN| zggYfN<^4qHQb8ub2h2R#3&x*SGhXWEALQdVY20FcVE9t+h=%Vf+(65U4JtVmFJ$hhrP{>yI20%>RSyHH1 z{I<|V)SR+IAj586{$b03vP)d(%+mW(Q+fOov;J}D1U;t8q@5 zo*hUrm}+%CvtNWHOBi%-7e}*x23bebm@iJ<;BworSt0XB^R;Klr+nsH*0ZbAI}OqW z%GX#9Blqy>@WXi+n`L!!*mEW6?1vG#=*PgzuZ7fI1}YqpS6UKR5!Icjl^&Y!ake6c z8V|!GEek{4r#yZLfySFOI_9Tv(IJXSorsG@@A|jS3}_ipX?V%Y|ADWBgeuck1<`%0 zB}6greYxT!yh*m1$M%W$I?WZvOU5J>2oKgjk?DnqZJM}0Bc9Z$qD8h*l-n?*hc@qp zw%zEhNb8PjKSVXa(=Fz*U4Gp9&cg);f&7=sD5uuyp~hQReQ1(y&cc%L$9KWDvH2zZ z-quS1yp}REwHWU0)5-NY)}uNzTinDq*7g2KOf6$Q>P8uw<=_!utKu~hbXD(UvY1rT zO$eL)G_X?S?3HdIt!b2vOcK@gd?9jz(&>~@GrSeY0AIjU)}Ly*p!tN(ia?yC9ecLh zep$yrB<_{f1NaQbDz2Q|S;*vQmH?O;0x?7tp*U$7%#GwR*(Sd2_u>0adxG}BT(=o- zQV%StofcegaqR`$yl*@X&TDCT(Y<&#jeAF5 zk=8PK1-Pz-YDNp-aDv_bGVNEPp&u^&4|(20?Nd8}*ve;^A^O8AE@w;BwSc1~7RXy zg#s!TINUukAsFp%!o|NM?t#=1oKXO@Mfp+DrH28)$SAu>*KjwCIIrZj3uhVemSl+j zAeVgpdXs(^s|CsMJDO;HQiJcCQTju~Dsh%NZrCM9he|Vmp*&_Itp->jFqMf_}3r`!_>(JZUd+(!#_r2!8or^H6AWv1$VE-7RX7;pJOH-w-~EHCf(#lgs_{=g<% z1@nsf;w4%kF&-ycm=g$~ax~IFn-U5&{-qh(7^P(NRFL&_gWf_q4CR3Bvfi1Yjla^K z<*FunyngFP*7yO@U1lyG4K&bS!v95Y#A8dU3&((pz}=%x{LzAUu#3iN9`m`q#R;&N z+ok@vU#Z=Rnc(_|ulLeuLhc7^Y5>&0wu)#NmTBZg?$Aygv)5_-l{7U2TPy>V5XiNGt1*suf2@{K9)8}Txoy%DY5(sRk0n+2m zj=O4XqQ)>(QJ5Em;|52@rAaj^FRhN5O3zbujk#*~*eGWe0!(*fNZPd>x`= zQvvML3#LjtlQ9(+wN9))_p~&Q_vdrQ`OL1Pt=RkxJ$< zHSTeqrOzjKvnPZuIls!w52TqVKg9J=+cNRPD|4`XzTkQ(j}Gq=Mz05!)`4!0ty@Q= z>@A$26H+;Z!SW5Kg{+NfQ5>IZC=l@mXuFR=E!>0vU~Z_k?a&6SyHJPbiosDZ2czcE z8N!2lXF4?G8sC~QDg1~Zi<*Rl za3+L2jL1j#rhsflYZ?r0ktH6!Dcd?j*PYJI8AcIv}% zETo04Z_?Tg1M_LK{ylh-si%xzE_vtxSW!x#eW~Ub_R}x6c2~l-X)IJci-fyYxq@ju zp3ggU*g=BlEpf_0Oe~Q9F{}gxd&pqm?jJS-h?ex6DLIiM5Yf0*6b-9qMUl}M#PdgC zY>U(m^ka znD)?;Pg!kno{9{lNjLhE3t|3T(tcJm3y`ML!iK~kOF)}x{s2l3P#&e`q{%L%UUs%X z8`_luY`=Nz>HjvrSV!*2#H&o{mNO^%koY|k4@ruDEtFIfN{jR z?3q~O&I32@cH6=Fm~LyI?D5LA$%;XI!5_oB#*QnKe^R>qLX5sGT2j3lM|A{0niWpY zj-vBZELiwi5U~CWc+F8Vnj=Y^Rq8~=B&RL0jiHIYlO>Y%b5(*JcI3)5&vVS?&tV@jw4VgbhC8XO8?scGN1&F(c9+j`;Ks z#9juVvyYKKSS<@C9<@EKFE~y<)Rw#Rm;8s{Y1#4%1VlHSmA-lSZDZ1Pqtwuc2)%8} z{*9wUD^x*4S;H&qONI-R)bdrXz7DSx;=`QBrieE-!FX;n??W8x@G4y%T~=mk@yp2U zmvsP{GM_@aY0nIh4_x~6`1s~pG^chc6!KSMYr%n(X6cJvB6QYyfq!FH1k|JlDYrUf z6TD^Y&5>J3oBzPKkl-dE7-4uDOsx zguRt?DWja0&n@LlaFB5Z( zD~RSgK@iTEejZC0LK))U5qCwhrtk4F1Fw4J47rM_$~2o}g_n59$ySLvNsK<&9-Twz zmK^>Q^sq0A2Ey-O&;z;a*63v$+_FnzJE)?0vUrI9`K!~QK!yyk-ksuoSuyVU6BxD{{psSQ7t-}L$7J;IOHnmv>1!eQ>BDuy0NfZ|zK{kl-^uH;gm`!q7v z{HeyRy;|$jjuyckj;4BmicFn4Dhz9lLosYCaa9xdqT`Mmj1Lw)dxV;HJzy8LV7_yG z4s_$xHqJD|bHxIin9E2gmCDbeYQ^EC3myed{E-xdlm(0_k<<@>>_S9%NR73azYxZ0 z=lJKXI~sa7aG;@P8U{Xxx+K~EO5gpUHxLo9xNb1!o&&~TWh13aP7wZ~5|TjYvLlhV z|CAG9#cb6z`;)!X*=Cn%(d#1)r$7?-mH>F5o7$-jO4v8OT0>smfRIgF!YJkO$bR?2 z_$Hgii3+u8-M*1yymxCn_xaCFYn@y_rcw8c+#0Y70j~7|2n?Db259LaATw@H0y}|KP(>GFfEl z{hVh0X7LddNJ3^-L-tSS7HEgQ?i@SCp(N;+h6N-wk!`Ey5gF-sGdcnYoRIUDDF#WX%_gPXR4rh@&Kj+m0JjqxODosDUOO!e!(~D7K0|`XB;xMKK=inHD_^ zc4;SN@d#sKZWpe4P#rPR7$Yb-T>mJ@*znbMHX)>U&jaOAs~vSRu= zD7VoZLxt_u)^HPl&=okHziv0myW6{|5BiL`lfs2H_DFxeE z7Ln(UAQ*>&0bK#2{v~NP|K>>@e#`H37K?I})^dEgxCIaE-enzIoUl`#T-$zUMPRbE zC0eMI{R9+1(|ctF2$E-)#IAD2Cyx8H`Yj#+DD&qa#3qX8$GNSDTBgF6Y6XFl@(dwK zX%dPtZIm~wu}L~Q-Z7h=Wu5MhZwJh^z!wA73aB~pK)wPNp#3Y9nCftyVy$X=R)LJz zCz`02#eRhv7VYCgML)YXX>oibO|Qh%yOFHUqpjTPz?^$$Ev}eq1v!DA_P`?acvnVE zz24M%nAWLam%M%@#}lwym9*8M-;zw%xK(_siFclgNp6B4I)uPyp_e$}KFs6KF(MZ- zYeilucT6(pXKi4i+h^Z%VriO<;x1G=K2OXglvXVuQ1x?duJNJ*T#^6HcJ&0q2rFqR zx}k0a8GfOaMsCu5I0000000000&LI3~&NdN!< zTL1t6K>z>%000000000000018004jh003s%XOJFbCJ7070m~xp(4=-2TCK{2na-wd z;D*QKlHpv#5i<_f0%+Wp{GgS7P|<08Pc(p<1@VLvLO6f_?;5ZGT>t=p0001N0V9F3 zCc)}YBLX_hk$Y55c$rT3Lj$OBGAgk6bkN6s;z748dq8$P2)S#0Oe_OVjVNVsYuwgG z27DQHGVadP@JlxPzBkvy!N)7-XT zxVv+(uY^bp|?Nl;f;%@c2=(= zzA_sZ4WZ_iFa(E0sTRlXu=N|HL5`LuPN1qkDMo8pWq`#PBQCrd*_F(z{i_ zLO{EDc~oe%mkb_!mDoTgWfG#hDD^5;r6P^`c*e>mqpPjM(GapJLA8z1o4&^~1L)Sj z1~TG!Op7JEX^MOPDGNFdInu0l_WLN2Zdfu>%IzV|e&aqj9hh?I)5-Z5<;kRoJkJ&FYhd*=Fw^qwLSlAX8M3C}F1!uw| z4ATM7pyR&0=aZiAR?K&F6KWjNLTB%e4%UIwaHj0F)R9OJsZQe%J)dKCOh!-?xTcUQ zqc)DyRq$988Rl9YO{0?pPXx)tWyq(4!CD~Upvk33X#|eX-DOc0#8r}Y>N%9`lr(w* zw~7hTE%z)d7)RLxPf7D(S&sNy1gv(2WC{bI*8juF3Vt4ToaRK;asY_@i6Z~=(|Qvu zSH;qWqSWe#IyjNhI%Wu~0mVSr+F_xiQ2g$cFdtZ@t{7Ng9ceWVSf;6m;Z}0ADB+!*7tNRiJtDi)vkM zm)%`NUr&H#sqvjtX}Pr%2Q4I)(O06a?8t~FyE7Bs8;cd-&9r^@a2l&MaZ5bJm?sOq zg4P1`OuHLHs(!H|Uv?}Wsi#|Ssi&Nh1}N*@4_O^(rV&Z`h%-s~lPe4eETQ7XIo+lA zQt3LyteOtdY~E{ZoP)>`4Oo8Z!z~O-$Mz}fU+WeNnA1e(23OE|+}U2FIhR{@ba@G5 zwM`KIh*pk3H=fWCO#;H_H(O~e8WNyY*JAjJ75tg6vfNHPNN2)0X#-7jJyHNY-6x{U z(YgB9sSz(v+l0xi*h48$y`vvW?`k8753U#Id>3nNpDb*U)|dPLu73tK?)0#c(F z{f^?^bYF_P$@`MzLAF3!){I(Vy;Z)GG-CW|YI-v)2|2TB8G#102`@caj-J-qgyiBm zZ^NSWgO1nRcvKrD1($AQ5lPC*$IAlBQl|LftBJP zIad!7J3|O8|7>HiIL1XJN74m`&o>t4&)Q~Z5T{;E;~}dCj{^%9$I_;uABxl0%(pjW zRTtpu>4{gmf@_@K;|y~rDF+ywF#YJ$7WQ>DE4c;nJ}GpSH#(D8?4ULwx(c0xA8JN8Z;#++cm=;d`3FBHw=I}yA4UVv)1eKseGA@`lVrnKJO2{hXAx@4WDYoIK*SsnNtvW)vT4Wlw3 zNjigWj@x(0*R~ICgWkiR)^`X)RjRovcr9z-0FY8l6x)U}X;7BG{UH2j+|wu5+Z(U@ zQ<$h6hH;hB3>~c#(Ji2*}rOyG@(3((gE9>HGA3t-8nSz-<=eSw_z z_1(-~3srElH5MW&Ei%!)=joCqU`lU0Kb~_T@9@v9UP=LQf%dCm9d)+N|&cT;OvovCr@Rxyk=)XeDE zjg+Olprj4;ukiFxD`i@OsPNSzj##!x*zfb{l)*N4Oyh#-3`^guw8t1~!cUA7K9Q4D z;_)N_+p`V{44*FYkwmJ-!DnbYT?jpH(~K|}7`$Xt!(X#-s%9}NTC(exarM_?V9Q=N zH3TDdZ?fO=MLEIngg+rSBQIe$B%dmT0K{;nDUa&hpbhs}az|_*@?;Rc*I)MX%xiL7 zcrNuDma#FllDN>dc3MQQe+hwRB!Zj&mIlJ?4n8Ml2?9Dcy5O=c%(i4nr?o6&a9xRR zQ9ipHLP3>v))e3vTgad~-!Okh_B0c$flN_ax_)Tmm*rx!PlJl0D{*8EU=M55w-&F^ z=2{1#QZ=@G@aL^#=HmX8gZMW#-A;;|sEn0|U&ulRn20O>yEDLw1m%dq_SSE0*!(9P zs~kc6&XFsHqP7#s+Si2ol&ll^jvJKhfdm&5%Bc2PaT>F9h;{G_;JpnK7(m2_%Cslc ztu@M`Tw?_|LWa$XSK;h(rw+TyMXL;(*AdKo}}S(SU39;v<)r@vJ?OaPDlv-b3+wb4&`3yRRwB)r&l>SM?4%s7EPD8J}6*y69;aE4(Y z`W&=VVME~l9P7NDfdt(&1r?-D|BXa6A^J$@+)vIttgxvZ#*YTk!Qd@OheP8SS58<{ z5^8do7X-&S;UR2-F^242P0(t*BMQCc=gG4E2b#0s*v0O&Xzl4rlQ)gSM z;{@Y(E}dXHohb6Ve^vbX-Z<~v=GR6c6-)NL^k2EK?`#(XoOs!D6C?%)IXJkR{x8?t zwXXGfoqr<)U#55N%yr}@W!-&#>FO@6;QwW>4HjF}1kjoEoC|Xf1Ig3fy@GCTxJs?8 z-1$LsVDK?WVO4b5rTc34f`(NUAe2m+9x71V&e$c3jaqeUbXzaaAziZ2i?&vm`hwju zHUJ#@uyRHB7@m7ex*^Tv=%RsO!#W@)JCJ11W1Ws$nAd0SM1q zq(y75-CA?%8&BN=_G=-QJ|9iqehEoUn<(aAEeHNb+U(_+P`A8T%Dfz=qLGmT>~2;D z$H@pM!_yJWWo#}7B19qL`jc&*u)!mNM{<-YVP~#V8mcrH+Q9#k@;<+MzV;4rGgBdX z9d4z{WXQ5HRD?vtL$0Zgt!_tmg|mY~wcdJ@Tb36*Bnk!?%mkvPj)KSJXMAOFdf(f_ zLyS00w-cTU$0o0gUMPVpEDb+4A%H?GG9>g)G-p*tcZAji8=N_f3&!XhwDX4GBFjz)M77MN zGFH;s9iFi_C2vRnb2MX;0P

    2J77gr^$PSX}&S!*LvhO`~xuD$Aor05qAnyEFmP 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 Date: Fri, 14 Aug 2026 01:31:48 +0200 Subject: [PATCH 28/42] Stop the oblong arcs leaking over the base, and see it without TTS Martin reported broken arc fragments crossing the middle of a snail base, and only a snail base. Reproduced outside the game and fixed. The cause: the BACK arcs are drawn on UVs displaced by _ArcOffset, but cut by a base mask computed on the undisplaced ones, so they overhang the base by roughly that displacement. It is -0.029 on long and -0.039 on snail, so on long the overhang stays under the base edge and on snail it does not. Same bug on both, visible on one. The fix widens the cut for the arcs alone, through a new _ArcCut that defaults to 0 -- `base` keeps serving the range bands, which must not move by a thousandth. The mod's own materials carry no _ArcCut, so their rebuilds are unchanged. The bundles are renamed _v2 because TTS caches by URL: republishing under the same name downloads nothing. Also adds RenderProjectorTest, which is what made this findable. The existing bench frames on the prefab's Renderers and a Projector has none, so projectors could only ever be judged in game. This one builds the scene a Projector needs -- a ground plane, the projector 20 units above it at 90 degrees, an orthographic camera overhead -- and writes a PNG. It also reports shader support, which caught a Windows-only bundle being loaded on a Metal editor. And BuildNamed, which builds only the bundles it is given: the full pass rebuilds all 360 twice, ~4.5 min, where iterating on one visual now costs 30 seconds end to end. Co-Authored-By: Claude Opus 5 (1M context) --- mac-patcher/patch_save_for_mac.py | 16 ++++++++-------- ...q.unity3d => projector_100mm_isq_v2.unity3d} | Bin .../projector_100mm_oblong_isq.unity3d | Bin 17655 -> 0 bytes .../projector_100mm_oblong_isq_v2.unity3d | Bin 0 -> 17803 bytes ...q.unity3d => projector_120mm_isq_v2.unity3d} | Bin ...q.unity3d => projector_150mm_isq_v2.unity3d} | Bin .../projector_200mm_oblong_isq.unity3d | Bin 17763 -> 0 bytes .../projector_200mm_oblong_isq_v2.unity3d | Bin 0 -> 17922 bytes ...sq.unity3d => projector_27mm_isq_v2.unity3d} | Bin ...sq.unity3d => projector_50mm_isq_v2.unity3d} | Bin ...sq.unity3d => projector_70mm_isq_v2.unity3d} | Bin 11 files changed, 8 insertions(+), 8 deletions(-) rename mod/data/mac-fallback-assets/{projector_100mm_isq.unity3d => projector_100mm_isq_v2.unity3d} (100%) delete mode 100644 mod/data/mac-fallback-assets/projector_100mm_oblong_isq.unity3d create mode 100644 mod/data/mac-fallback-assets/projector_100mm_oblong_isq_v2.unity3d rename mod/data/mac-fallback-assets/{projector_120mm_isq.unity3d => projector_120mm_isq_v2.unity3d} (100%) rename mod/data/mac-fallback-assets/{projector_150mm_isq.unity3d => projector_150mm_isq_v2.unity3d} (100%) delete mode 100644 mod/data/mac-fallback-assets/projector_200mm_oblong_isq.unity3d create mode 100644 mod/data/mac-fallback-assets/projector_200mm_oblong_isq_v2.unity3d rename mod/data/mac-fallback-assets/{projector_27mm_isq.unity3d => projector_27mm_isq_v2.unity3d} (100%) rename mod/data/mac-fallback-assets/{projector_50mm_isq.unity3d => projector_50mm_isq_v2.unity3d} (100%) rename mod/data/mac-fallback-assets/{projector_70mm_isq.unity3d => projector_70mm_isq_v2.unity3d} (100%) diff --git a/mac-patcher/patch_save_for_mac.py b/mac-patcher/patch_save_for_mac.py index 5624e92ca..9463e2466 100644 --- a/mac-patcher/patch_save_for_mac.py +++ b/mac-patcher/patch_save_for_mac.py @@ -99,14 +99,14 @@ -- button keeps the mod's single-ring bundle, deliberately. local ISQ_ASSETS = "__ISQ_ASSETS_BASE__" local ISQ_RANGE_BUNDLES = { - small = ISQ_ASSETS .. "projector_27mm_isq.unity3d", - medium = ISQ_ASSETS .. "projector_50mm_isq.unity3d", - large = ISQ_ASSETS .. "projector_70mm_isq.unity3d", - huge = ISQ_ASSETS .. "projector_100mm_isq.unity3d", - laat = ISQ_ASSETS .. "projector_120mm_isq.unity3d", - epic = ISQ_ASSETS .. "projector_150mm_isq.unity3d", - long = ISQ_ASSETS .. "projector_100mm_oblong_isq.unity3d", - snail = ISQ_ASSETS .. "projector_200mm_oblong_isq.unity3d", + small = ISQ_ASSETS .. "projector_27mm_isq_v2.unity3d", + medium = ISQ_ASSETS .. "projector_50mm_isq_v2.unity3d", + large = ISQ_ASSETS .. "projector_70mm_isq_v2.unity3d", + huge = ISQ_ASSETS .. "projector_100mm_isq_v2.unity3d", + laat = ISQ_ASSETS .. "projector_120mm_isq_v2.unity3d", + epic = ISQ_ASSETS .. "projector_150mm_isq_v2.unity3d", + long = ISQ_ASSETS .. "projector_100mm_oblong_isq_v2.unity3d", + snail = ISQ_ASSETS .. "projector_200mm_oblong_isq_v2.unity3d", } -- Per family: the name TTS gives the spawned object, whether it tracks its diff --git a/mod/data/mac-fallback-assets/projector_100mm_isq.unity3d b/mod/data/mac-fallback-assets/projector_100mm_isq_v2.unity3d similarity index 100% rename from mod/data/mac-fallback-assets/projector_100mm_isq.unity3d rename to mod/data/mac-fallback-assets/projector_100mm_isq_v2.unity3d diff --git a/mod/data/mac-fallback-assets/projector_100mm_oblong_isq.unity3d b/mod/data/mac-fallback-assets/projector_100mm_oblong_isq.unity3d deleted file mode 100644 index 3a52da312ffbd96a442308d8fecc6b6202146b76..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17655 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 literal 0 HcmV?d00001 diff --git a/mod/data/mac-fallback-assets/projector_120mm_isq.unity3d b/mod/data/mac-fallback-assets/projector_120mm_isq_v2.unity3d similarity index 100% rename from mod/data/mac-fallback-assets/projector_120mm_isq.unity3d rename to mod/data/mac-fallback-assets/projector_120mm_isq_v2.unity3d diff --git a/mod/data/mac-fallback-assets/projector_150mm_isq.unity3d b/mod/data/mac-fallback-assets/projector_150mm_isq_v2.unity3d similarity index 100% rename from mod/data/mac-fallback-assets/projector_150mm_isq.unity3d rename to mod/data/mac-fallback-assets/projector_150mm_isq_v2.unity3d diff --git a/mod/data/mac-fallback-assets/projector_200mm_oblong_isq.unity3d b/mod/data/mac-fallback-assets/projector_200mm_oblong_isq.unity3d deleted file mode 100644 index 504b29f69aea023a4814dc49ae266de2e2c3f08b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17763 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 Date: Fri, 14 Aug 2026 01:50:00 +0200 Subject: [PATCH 29/42] Make the oblong arcs start at the base edge again The previous cut was too blunt: widening it for everyone erased the stray fragments but opened a gap between the base and where the arcs start. Zooming the render bench on the base settled it. The vanilla long ruler is clean -- its four arcs stop symmetrically at the base edge. The vanilla snail ruler carries two short fragments floating inside the base, detached from anything, which is exactly what was reported. So the defect is snail only, and long needs no correction at all. The cut is now per material, and bisected against the render rather than guessed: 0.008 still left two specks, 0.014 clears them without opening a gap, 0.022 started to open one. long keeps 0, which is the vanilla cut exactly. The whole thing now sits behind _HALFBAND_ON, so the mod's own materials compile the untouched branch. That was not true of the previous commit, which changed their arcs too. An attempt in between, kept out: cutting the back arcs in their own frame, displaced by sqrt(2) * _ArcOffset along the base's long axis. It reads right and the render disagreed -- it let the far pair run deep into the base on long, which vanilla does not. Bundles renamed _v3, TTS caches by URL. Co-Authored-By: Claude Opus 5 (1M context) --- mac-patcher/patch_save_for_mac.py | 16 ++++++++-------- ...2.unity3d => projector_100mm_isq_v3.unity3d} | Bin .../projector_100mm_oblong_isq_v2.unity3d | Bin 17803 -> 0 bytes .../projector_100mm_oblong_isq_v3.unity3d | Bin 0 -> 18064 bytes ...2.unity3d => projector_120mm_isq_v3.unity3d} | Bin ...2.unity3d => projector_150mm_isq_v3.unity3d} | Bin .../projector_200mm_oblong_isq_v2.unity3d | Bin 17922 -> 0 bytes .../projector_200mm_oblong_isq_v3.unity3d | Bin 0 -> 18138 bytes ...v2.unity3d => projector_27mm_isq_v3.unity3d} | Bin ...v2.unity3d => projector_50mm_isq_v3.unity3d} | Bin ...v2.unity3d => projector_70mm_isq_v3.unity3d} | Bin 11 files changed, 8 insertions(+), 8 deletions(-) rename mod/data/mac-fallback-assets/{projector_100mm_isq_v2.unity3d => projector_100mm_isq_v3.unity3d} (100%) delete mode 100644 mod/data/mac-fallback-assets/projector_100mm_oblong_isq_v2.unity3d create mode 100644 mod/data/mac-fallback-assets/projector_100mm_oblong_isq_v3.unity3d rename mod/data/mac-fallback-assets/{projector_120mm_isq_v2.unity3d => projector_120mm_isq_v3.unity3d} (100%) rename mod/data/mac-fallback-assets/{projector_150mm_isq_v2.unity3d => projector_150mm_isq_v3.unity3d} (100%) delete mode 100644 mod/data/mac-fallback-assets/projector_200mm_oblong_isq_v2.unity3d create mode 100644 mod/data/mac-fallback-assets/projector_200mm_oblong_isq_v3.unity3d rename mod/data/mac-fallback-assets/{projector_27mm_isq_v2.unity3d => projector_27mm_isq_v3.unity3d} (100%) rename mod/data/mac-fallback-assets/{projector_50mm_isq_v2.unity3d => projector_50mm_isq_v3.unity3d} (100%) rename mod/data/mac-fallback-assets/{projector_70mm_isq_v2.unity3d => projector_70mm_isq_v3.unity3d} (100%) diff --git a/mac-patcher/patch_save_for_mac.py b/mac-patcher/patch_save_for_mac.py index 9463e2466..9c3f25bce 100644 --- a/mac-patcher/patch_save_for_mac.py +++ b/mac-patcher/patch_save_for_mac.py @@ -99,14 +99,14 @@ -- button keeps the mod's single-ring bundle, deliberately. local ISQ_ASSETS = "__ISQ_ASSETS_BASE__" local ISQ_RANGE_BUNDLES = { - small = ISQ_ASSETS .. "projector_27mm_isq_v2.unity3d", - medium = ISQ_ASSETS .. "projector_50mm_isq_v2.unity3d", - large = ISQ_ASSETS .. "projector_70mm_isq_v2.unity3d", - huge = ISQ_ASSETS .. "projector_100mm_isq_v2.unity3d", - laat = ISQ_ASSETS .. "projector_120mm_isq_v2.unity3d", - epic = ISQ_ASSETS .. "projector_150mm_isq_v2.unity3d", - long = ISQ_ASSETS .. "projector_100mm_oblong_isq_v2.unity3d", - snail = ISQ_ASSETS .. "projector_200mm_oblong_isq_v2.unity3d", + small = ISQ_ASSETS .. "projector_27mm_isq_v3.unity3d", + medium = ISQ_ASSETS .. "projector_50mm_isq_v3.unity3d", + large = ISQ_ASSETS .. "projector_70mm_isq_v3.unity3d", + huge = ISQ_ASSETS .. "projector_100mm_isq_v3.unity3d", + laat = ISQ_ASSETS .. "projector_120mm_isq_v3.unity3d", + epic = ISQ_ASSETS .. "projector_150mm_isq_v3.unity3d", + long = ISQ_ASSETS .. "projector_100mm_oblong_isq_v3.unity3d", + snail = ISQ_ASSETS .. "projector_200mm_oblong_isq_v3.unity3d", } -- Per family: the name TTS gives the spawned object, whether it tracks its diff --git a/mod/data/mac-fallback-assets/projector_100mm_isq_v2.unity3d b/mod/data/mac-fallback-assets/projector_100mm_isq_v3.unity3d similarity index 100% rename from mod/data/mac-fallback-assets/projector_100mm_isq_v2.unity3d rename to mod/data/mac-fallback-assets/projector_100mm_isq_v3.unity3d diff --git a/mod/data/mac-fallback-assets/projector_100mm_oblong_isq_v2.unity3d b/mod/data/mac-fallback-assets/projector_100mm_oblong_isq_v2.unity3d deleted file mode 100644 index 6dce8f02381b060c60982ed2324a0941901cd32c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17803 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 diff --git a/mod/data/mac-fallback-assets/projector_100mm_oblong_isq_v3.unity3d b/mod/data/mac-fallback-assets/projector_100mm_oblong_isq_v3.unity3d new file mode 100644 index 0000000000000000000000000000000000000000..b8e46570c2d594abcb9d6d31c4db68a1828375ca GIT binary patch literal 18064 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 FT2Ac`45k18 literal 0 HcmV?d00001 diff --git a/mod/data/mac-fallback-assets/projector_27mm_isq_v2.unity3d b/mod/data/mac-fallback-assets/projector_27mm_isq_v3.unity3d similarity index 100% rename from mod/data/mac-fallback-assets/projector_27mm_isq_v2.unity3d rename to mod/data/mac-fallback-assets/projector_27mm_isq_v3.unity3d diff --git a/mod/data/mac-fallback-assets/projector_50mm_isq_v2.unity3d b/mod/data/mac-fallback-assets/projector_50mm_isq_v3.unity3d similarity index 100% rename from mod/data/mac-fallback-assets/projector_50mm_isq_v2.unity3d rename to mod/data/mac-fallback-assets/projector_50mm_isq_v3.unity3d diff --git a/mod/data/mac-fallback-assets/projector_70mm_isq_v2.unity3d b/mod/data/mac-fallback-assets/projector_70mm_isq_v3.unity3d similarity index 100% rename from mod/data/mac-fallback-assets/projector_70mm_isq_v2.unity3d rename to mod/data/mac-fallback-assets/projector_70mm_isq_v3.unity3d From 865b33ced8228fcc0d960892403ac12bbf235ce2 Mon Sep 17 00:00:00 2001 From: Martin Pourrat Date: Fri, 14 Aug 2026 02:00:03 +0200 Subject: [PATCH 30/42] Put the oblong arcs back against the base edge Martin, in game: still a gap. The widened cut is what makes it -- it is a monotone trade-off, measured on snail: 0 puts the arcs against the base and brings the two stray fragments back, 0.008 shrinks them to specks with a visible gap, 0.014 clears them with a clear gap. His instruction is that the arcs start at the base, so the cut goes back to 0 on both oblongs, which is the mod's own cut exactly. The snail fragments come back with it, as in the mod today. Clearing them without opening a gap means reworking the shader's front/rear arc split, not pushing this value further. The property stays, defaulting to 0, so the lever is documented and there if the rework needs it. Bundles renamed _v4, TTS caches by URL. Co-Authored-By: Claude Opus 5 (1M context) --- mac-patcher/patch_save_for_mac.py | 16 ++++++++-------- ...3.unity3d => projector_100mm_isq_v4.unity3d} | Bin ...3d => projector_100mm_oblong_isq_v4.unity3d} | Bin ...3.unity3d => projector_120mm_isq_v4.unity3d} | Bin ...3.unity3d => projector_150mm_isq_v4.unity3d} | Bin .../projector_200mm_oblong_isq_v3.unity3d | Bin 18138 -> 0 bytes .../projector_200mm_oblong_isq_v4.unity3d | Bin 0 -> 18148 bytes ...v3.unity3d => projector_27mm_isq_v4.unity3d} | Bin ...v3.unity3d => projector_50mm_isq_v4.unity3d} | Bin ...v3.unity3d => projector_70mm_isq_v4.unity3d} | Bin 10 files changed, 8 insertions(+), 8 deletions(-) rename mod/data/mac-fallback-assets/{projector_100mm_isq_v3.unity3d => projector_100mm_isq_v4.unity3d} (100%) rename mod/data/mac-fallback-assets/{projector_100mm_oblong_isq_v3.unity3d => projector_100mm_oblong_isq_v4.unity3d} (100%) rename mod/data/mac-fallback-assets/{projector_120mm_isq_v3.unity3d => projector_120mm_isq_v4.unity3d} (100%) rename mod/data/mac-fallback-assets/{projector_150mm_isq_v3.unity3d => projector_150mm_isq_v4.unity3d} (100%) delete mode 100644 mod/data/mac-fallback-assets/projector_200mm_oblong_isq_v3.unity3d create mode 100644 mod/data/mac-fallback-assets/projector_200mm_oblong_isq_v4.unity3d rename mod/data/mac-fallback-assets/{projector_27mm_isq_v3.unity3d => projector_27mm_isq_v4.unity3d} (100%) rename mod/data/mac-fallback-assets/{projector_50mm_isq_v3.unity3d => projector_50mm_isq_v4.unity3d} (100%) rename mod/data/mac-fallback-assets/{projector_70mm_isq_v3.unity3d => projector_70mm_isq_v4.unity3d} (100%) diff --git a/mac-patcher/patch_save_for_mac.py b/mac-patcher/patch_save_for_mac.py index 9c3f25bce..933439b07 100644 --- a/mac-patcher/patch_save_for_mac.py +++ b/mac-patcher/patch_save_for_mac.py @@ -99,14 +99,14 @@ -- button keeps the mod's single-ring bundle, deliberately. local ISQ_ASSETS = "__ISQ_ASSETS_BASE__" local ISQ_RANGE_BUNDLES = { - small = ISQ_ASSETS .. "projector_27mm_isq_v3.unity3d", - medium = ISQ_ASSETS .. "projector_50mm_isq_v3.unity3d", - large = ISQ_ASSETS .. "projector_70mm_isq_v3.unity3d", - huge = ISQ_ASSETS .. "projector_100mm_isq_v3.unity3d", - laat = ISQ_ASSETS .. "projector_120mm_isq_v3.unity3d", - epic = ISQ_ASSETS .. "projector_150mm_isq_v3.unity3d", - long = ISQ_ASSETS .. "projector_100mm_oblong_isq_v3.unity3d", - snail = ISQ_ASSETS .. "projector_200mm_oblong_isq_v3.unity3d", + small = ISQ_ASSETS .. "projector_27mm_isq_v4.unity3d", + medium = ISQ_ASSETS .. "projector_50mm_isq_v4.unity3d", + large = ISQ_ASSETS .. "projector_70mm_isq_v4.unity3d", + huge = ISQ_ASSETS .. "projector_100mm_isq_v4.unity3d", + laat = ISQ_ASSETS .. "projector_120mm_isq_v4.unity3d", + epic = ISQ_ASSETS .. "projector_150mm_isq_v4.unity3d", + long = ISQ_ASSETS .. "projector_100mm_oblong_isq_v4.unity3d", + snail = ISQ_ASSETS .. "projector_200mm_oblong_isq_v4.unity3d", } -- Per family: the name TTS gives the spawned object, whether it tracks its diff --git a/mod/data/mac-fallback-assets/projector_100mm_isq_v3.unity3d b/mod/data/mac-fallback-assets/projector_100mm_isq_v4.unity3d similarity index 100% rename from mod/data/mac-fallback-assets/projector_100mm_isq_v3.unity3d rename to mod/data/mac-fallback-assets/projector_100mm_isq_v4.unity3d diff --git a/mod/data/mac-fallback-assets/projector_100mm_oblong_isq_v3.unity3d b/mod/data/mac-fallback-assets/projector_100mm_oblong_isq_v4.unity3d similarity index 100% rename from mod/data/mac-fallback-assets/projector_100mm_oblong_isq_v3.unity3d rename to mod/data/mac-fallback-assets/projector_100mm_oblong_isq_v4.unity3d diff --git a/mod/data/mac-fallback-assets/projector_120mm_isq_v3.unity3d b/mod/data/mac-fallback-assets/projector_120mm_isq_v4.unity3d similarity index 100% rename from mod/data/mac-fallback-assets/projector_120mm_isq_v3.unity3d rename to mod/data/mac-fallback-assets/projector_120mm_isq_v4.unity3d diff --git a/mod/data/mac-fallback-assets/projector_150mm_isq_v3.unity3d b/mod/data/mac-fallback-assets/projector_150mm_isq_v4.unity3d similarity index 100% rename from mod/data/mac-fallback-assets/projector_150mm_isq_v3.unity3d rename to mod/data/mac-fallback-assets/projector_150mm_isq_v4.unity3d diff --git a/mod/data/mac-fallback-assets/projector_200mm_oblong_isq_v3.unity3d b/mod/data/mac-fallback-assets/projector_200mm_oblong_isq_v3.unity3d deleted file mode 100644 index 9111b2c7abbcf2d38336f7c3c1a81188045a9fde..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18138 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 FT2Ac`45k18 diff --git a/mod/data/mac-fallback-assets/projector_200mm_oblong_isq_v4.unity3d b/mod/data/mac-fallback-assets/projector_200mm_oblong_isq_v4.unity3d new file mode 100644 index 0000000000000000000000000000000000000000..881782e7d714f0fd2932d8453ed56a76a49fdcf9 GIT binary patch literal 18148 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 PM9g>%W)oBY{uB Date: Fri, 14 Aug 2026 02:09:09 +0200 Subject: [PATCH 31/42] Find what actually made the snail arcs break, and set it Not the cut. _ArcOffset. It splits the arcs into two families, one anchored toward the front of the base and one toward the rear, so they radiate from both ends of a long base instead of a single point. The wider the offset, the further apart the two anchors -- and past a threshold the INNER TIP of the rear family emerges from the side of the base. Those tips are the two fragments. Measured on snail, changing that one value and nothing else: 0 arcs converge at the centre, clean -0.029 clean (this is the long material's own value) -0.033 two pixels -0.037 fragments visible -0.039 the reported defect (snail's shipped value) So snail goes to -0.029. The anchors move 26% closer, which does not read in play, and the defect goes without cutting anything: the arcs still meet the base edge with no gap. _ArcCut stays at 0 everywhere -- it treated the symptom. Bundles renamed _v5, TTS caches by URL. Co-Authored-By: Claude Opus 5 (1M context) --- mac-patcher/patch_save_for_mac.py | 16 ++++++++-------- ...4.unity3d => projector_100mm_isq_v5.unity3d} | Bin ...3d => projector_100mm_oblong_isq_v5.unity3d} | Bin ...4.unity3d => projector_120mm_isq_v5.unity3d} | Bin ...4.unity3d => projector_150mm_isq_v5.unity3d} | Bin .../projector_200mm_oblong_isq_v4.unity3d | Bin 18148 -> 0 bytes .../projector_200mm_oblong_isq_v5.unity3d | Bin 0 -> 18147 bytes ...v4.unity3d => projector_27mm_isq_v5.unity3d} | Bin ...v4.unity3d => projector_50mm_isq_v5.unity3d} | Bin ...v4.unity3d => projector_70mm_isq_v5.unity3d} | Bin 10 files changed, 8 insertions(+), 8 deletions(-) rename mod/data/mac-fallback-assets/{projector_100mm_isq_v4.unity3d => projector_100mm_isq_v5.unity3d} (100%) rename mod/data/mac-fallback-assets/{projector_100mm_oblong_isq_v4.unity3d => projector_100mm_oblong_isq_v5.unity3d} (100%) rename mod/data/mac-fallback-assets/{projector_120mm_isq_v4.unity3d => projector_120mm_isq_v5.unity3d} (100%) rename mod/data/mac-fallback-assets/{projector_150mm_isq_v4.unity3d => projector_150mm_isq_v5.unity3d} (100%) delete mode 100644 mod/data/mac-fallback-assets/projector_200mm_oblong_isq_v4.unity3d create mode 100644 mod/data/mac-fallback-assets/projector_200mm_oblong_isq_v5.unity3d rename mod/data/mac-fallback-assets/{projector_27mm_isq_v4.unity3d => projector_27mm_isq_v5.unity3d} (100%) rename mod/data/mac-fallback-assets/{projector_50mm_isq_v4.unity3d => projector_50mm_isq_v5.unity3d} (100%) rename mod/data/mac-fallback-assets/{projector_70mm_isq_v4.unity3d => projector_70mm_isq_v5.unity3d} (100%) diff --git a/mac-patcher/patch_save_for_mac.py b/mac-patcher/patch_save_for_mac.py index 933439b07..e24ac3ece 100644 --- a/mac-patcher/patch_save_for_mac.py +++ b/mac-patcher/patch_save_for_mac.py @@ -99,14 +99,14 @@ -- button keeps the mod's single-ring bundle, deliberately. local ISQ_ASSETS = "__ISQ_ASSETS_BASE__" local ISQ_RANGE_BUNDLES = { - small = ISQ_ASSETS .. "projector_27mm_isq_v4.unity3d", - medium = ISQ_ASSETS .. "projector_50mm_isq_v4.unity3d", - large = ISQ_ASSETS .. "projector_70mm_isq_v4.unity3d", - huge = ISQ_ASSETS .. "projector_100mm_isq_v4.unity3d", - laat = ISQ_ASSETS .. "projector_120mm_isq_v4.unity3d", - epic = ISQ_ASSETS .. "projector_150mm_isq_v4.unity3d", - long = ISQ_ASSETS .. "projector_100mm_oblong_isq_v4.unity3d", - snail = ISQ_ASSETS .. "projector_200mm_oblong_isq_v4.unity3d", + small = ISQ_ASSETS .. "projector_27mm_isq_v5.unity3d", + medium = ISQ_ASSETS .. "projector_50mm_isq_v5.unity3d", + large = ISQ_ASSETS .. "projector_70mm_isq_v5.unity3d", + huge = ISQ_ASSETS .. "projector_100mm_isq_v5.unity3d", + laat = ISQ_ASSETS .. "projector_120mm_isq_v5.unity3d", + epic = ISQ_ASSETS .. "projector_150mm_isq_v5.unity3d", + long = ISQ_ASSETS .. "projector_100mm_oblong_isq_v5.unity3d", + snail = ISQ_ASSETS .. "projector_200mm_oblong_isq_v5.unity3d", } -- Per family: the name TTS gives the spawned object, whether it tracks its diff --git a/mod/data/mac-fallback-assets/projector_100mm_isq_v4.unity3d b/mod/data/mac-fallback-assets/projector_100mm_isq_v5.unity3d similarity index 100% rename from mod/data/mac-fallback-assets/projector_100mm_isq_v4.unity3d rename to mod/data/mac-fallback-assets/projector_100mm_isq_v5.unity3d diff --git a/mod/data/mac-fallback-assets/projector_100mm_oblong_isq_v4.unity3d b/mod/data/mac-fallback-assets/projector_100mm_oblong_isq_v5.unity3d similarity index 100% rename from mod/data/mac-fallback-assets/projector_100mm_oblong_isq_v4.unity3d rename to mod/data/mac-fallback-assets/projector_100mm_oblong_isq_v5.unity3d diff --git a/mod/data/mac-fallback-assets/projector_120mm_isq_v4.unity3d b/mod/data/mac-fallback-assets/projector_120mm_isq_v5.unity3d similarity index 100% rename from mod/data/mac-fallback-assets/projector_120mm_isq_v4.unity3d rename to mod/data/mac-fallback-assets/projector_120mm_isq_v5.unity3d diff --git a/mod/data/mac-fallback-assets/projector_150mm_isq_v4.unity3d b/mod/data/mac-fallback-assets/projector_150mm_isq_v5.unity3d similarity index 100% rename from mod/data/mac-fallback-assets/projector_150mm_isq_v4.unity3d rename to mod/data/mac-fallback-assets/projector_150mm_isq_v5.unity3d diff --git a/mod/data/mac-fallback-assets/projector_200mm_oblong_isq_v4.unity3d b/mod/data/mac-fallback-assets/projector_200mm_oblong_isq_v4.unity3d deleted file mode 100644 index 881782e7d714f0fd2932d8453ed56a76a49fdcf9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18148 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 PM9g>%W)oBY{uB0000000000+;{X5vNdN!< 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 Date: Fri, 14 Aug 2026 02:19:38 +0200 Subject: [PATCH 32/42] Cut the rear arcs at their own apex, and leave _ArcOffset alone Martin was right twice: moving _ArcOffset on snail is not allowed, the anchor spread is a property of that base size; and a translation of the rear centre should not, on its own, make fragments appear. It does not. The split does. _ArcOffset moves the rear X along the base's long axis, but the plane separating the front family from the rear one is placed at |_ArcOffset|, not at where that X is actually centred. So the rear branches get cut across rather than at their apex, and the two stumps remain. They stay hidden while they fall under the base; widening the anchor moves them further from the axis without widening the base, which is why they surface past a threshold. The FRONT family never had the problem: its plane, x = 0, is exactly its own centre. The true displacement is sqrt(2) * _ArcOffset in UV, so 2*sqrt(2) once in centred coordinates. Hence _BackSplit = 2.8284271, which is a geometric constant and not a tuned value. The check that confirms the reading: at that value the rear apex lands exactly at the end of the base -- 0.110 against a half-length of 0.111 on snail, 0.082 against 0.0895 on long. Which is where Allen meant to anchor the rear arcs all along. _ArcOffset is back to its shipped values on both oblongs, _ArcCut stays 0, and both render clean: four arcs meeting the base, no stumps, no gap. Bundles renamed _v6, TTS caches by URL. Co-Authored-By: Claude Opus 5 (1M context) --- mac-patcher/patch_save_for_mac.py | 16 ++++++++-------- ...5.unity3d => projector_100mm_isq_v6.unity3d} | Bin .../projector_100mm_oblong_isq_v5.unity3d | Bin 18064 -> 0 bytes .../projector_100mm_oblong_isq_v6.unity3d | Bin 0 -> 18196 bytes ...5.unity3d => projector_120mm_isq_v6.unity3d} | Bin ...5.unity3d => projector_150mm_isq_v6.unity3d} | Bin .../projector_200mm_oblong_isq_v5.unity3d | Bin 18147 -> 0 bytes .../projector_200mm_oblong_isq_v6.unity3d | Bin 0 -> 18307 bytes ...v5.unity3d => projector_27mm_isq_v6.unity3d} | Bin ...v5.unity3d => projector_50mm_isq_v6.unity3d} | Bin ...v5.unity3d => projector_70mm_isq_v6.unity3d} | Bin 11 files changed, 8 insertions(+), 8 deletions(-) rename mod/data/mac-fallback-assets/{projector_100mm_isq_v5.unity3d => projector_100mm_isq_v6.unity3d} (100%) delete mode 100644 mod/data/mac-fallback-assets/projector_100mm_oblong_isq_v5.unity3d create mode 100644 mod/data/mac-fallback-assets/projector_100mm_oblong_isq_v6.unity3d rename mod/data/mac-fallback-assets/{projector_120mm_isq_v5.unity3d => projector_120mm_isq_v6.unity3d} (100%) rename mod/data/mac-fallback-assets/{projector_150mm_isq_v5.unity3d => projector_150mm_isq_v6.unity3d} (100%) delete mode 100644 mod/data/mac-fallback-assets/projector_200mm_oblong_isq_v5.unity3d create mode 100644 mod/data/mac-fallback-assets/projector_200mm_oblong_isq_v6.unity3d rename mod/data/mac-fallback-assets/{projector_27mm_isq_v5.unity3d => projector_27mm_isq_v6.unity3d} (100%) rename mod/data/mac-fallback-assets/{projector_50mm_isq_v5.unity3d => projector_50mm_isq_v6.unity3d} (100%) rename mod/data/mac-fallback-assets/{projector_70mm_isq_v5.unity3d => projector_70mm_isq_v6.unity3d} (100%) diff --git a/mac-patcher/patch_save_for_mac.py b/mac-patcher/patch_save_for_mac.py index e24ac3ece..21336d048 100644 --- a/mac-patcher/patch_save_for_mac.py +++ b/mac-patcher/patch_save_for_mac.py @@ -99,14 +99,14 @@ -- button keeps the mod's single-ring bundle, deliberately. local ISQ_ASSETS = "__ISQ_ASSETS_BASE__" local ISQ_RANGE_BUNDLES = { - small = ISQ_ASSETS .. "projector_27mm_isq_v5.unity3d", - medium = ISQ_ASSETS .. "projector_50mm_isq_v5.unity3d", - large = ISQ_ASSETS .. "projector_70mm_isq_v5.unity3d", - huge = ISQ_ASSETS .. "projector_100mm_isq_v5.unity3d", - laat = ISQ_ASSETS .. "projector_120mm_isq_v5.unity3d", - epic = ISQ_ASSETS .. "projector_150mm_isq_v5.unity3d", - long = ISQ_ASSETS .. "projector_100mm_oblong_isq_v5.unity3d", - snail = ISQ_ASSETS .. "projector_200mm_oblong_isq_v5.unity3d", + small = ISQ_ASSETS .. "projector_27mm_isq_v6.unity3d", + medium = ISQ_ASSETS .. "projector_50mm_isq_v6.unity3d", + large = ISQ_ASSETS .. "projector_70mm_isq_v6.unity3d", + huge = ISQ_ASSETS .. "projector_100mm_isq_v6.unity3d", + laat = ISQ_ASSETS .. "projector_120mm_isq_v6.unity3d", + epic = ISQ_ASSETS .. "projector_150mm_isq_v6.unity3d", + long = ISQ_ASSETS .. "projector_100mm_oblong_isq_v6.unity3d", + snail = ISQ_ASSETS .. "projector_200mm_oblong_isq_v6.unity3d", } -- Per family: the name TTS gives the spawned object, whether it tracks its diff --git a/mod/data/mac-fallback-assets/projector_100mm_isq_v5.unity3d b/mod/data/mac-fallback-assets/projector_100mm_isq_v6.unity3d similarity index 100% rename from mod/data/mac-fallback-assets/projector_100mm_isq_v5.unity3d rename to mod/data/mac-fallback-assets/projector_100mm_isq_v6.unity3d diff --git a/mod/data/mac-fallback-assets/projector_100mm_oblong_isq_v5.unity3d b/mod/data/mac-fallback-assets/projector_100mm_oblong_isq_v5.unity3d deleted file mode 100644 index b8e46570c2d594abcb9d6d31c4db68a1828375ca..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18064 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 LVXRyK`4KT?oq|kl literal 0 HcmV?d00001 diff --git a/mod/data/mac-fallback-assets/projector_120mm_isq_v5.unity3d b/mod/data/mac-fallback-assets/projector_120mm_isq_v6.unity3d similarity index 100% rename from mod/data/mac-fallback-assets/projector_120mm_isq_v5.unity3d rename to mod/data/mac-fallback-assets/projector_120mm_isq_v6.unity3d diff --git a/mod/data/mac-fallback-assets/projector_150mm_isq_v5.unity3d b/mod/data/mac-fallback-assets/projector_150mm_isq_v6.unity3d similarity index 100% rename from mod/data/mac-fallback-assets/projector_150mm_isq_v5.unity3d rename to mod/data/mac-fallback-assets/projector_150mm_isq_v6.unity3d diff --git a/mod/data/mac-fallback-assets/projector_200mm_oblong_isq_v5.unity3d b/mod/data/mac-fallback-assets/projector_200mm_oblong_isq_v5.unity3d deleted file mode 100644 index a4f64d29b84391443f73b7b20bea91f5a0a512da..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18147 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 Sa_63U65ob;8~^{8qsmT!28vz) literal 0 HcmV?d00001 diff --git a/mod/data/mac-fallback-assets/projector_27mm_isq_v5.unity3d b/mod/data/mac-fallback-assets/projector_27mm_isq_v6.unity3d similarity index 100% rename from mod/data/mac-fallback-assets/projector_27mm_isq_v5.unity3d rename to mod/data/mac-fallback-assets/projector_27mm_isq_v6.unity3d diff --git a/mod/data/mac-fallback-assets/projector_50mm_isq_v5.unity3d b/mod/data/mac-fallback-assets/projector_50mm_isq_v6.unity3d similarity index 100% rename from mod/data/mac-fallback-assets/projector_50mm_isq_v5.unity3d rename to mod/data/mac-fallback-assets/projector_50mm_isq_v6.unity3d diff --git a/mod/data/mac-fallback-assets/projector_70mm_isq_v5.unity3d b/mod/data/mac-fallback-assets/projector_70mm_isq_v6.unity3d similarity index 100% rename from mod/data/mac-fallback-assets/projector_70mm_isq_v5.unity3d rename to mod/data/mac-fallback-assets/projector_70mm_isq_v6.unity3d From d381748d7e98e3a07dd1cc02b825110e105c72ad Mon Sep 17 00:00:00 2001 From: Martin Pourrat Date: Fri, 14 Aug 2026 02:27:27 +0200 Subject: [PATCH 33/42] Give cohesion a ring on the base sizes the mod has none for getCohesionLinks() only knows small, medium and large. On anything else vanilla spawnCohesionRuler returns without drawing, so huge, laat and epic units simply had no cohesion ring. They have one now. Nothing was invented. BB_CohesionProjector draws its ring at the projector's outer edge and reads nothing else, so the whole geometry is a single number: ortho = half the base + 3in. That is exactly what the mod's own three carry (27mm -> 3.531496 = 0.53150 + 3, 50mm -> 3.984252, 70mm -> 4.377953). 3in is range 1/2, the distance cohesion is measured at, and the same one the white band marks on the rulers. long and snail are left out on purpose: the cohesion shader only knows Circle(), it cannot draw a stadium. They need an oblong variant built the way BB_OblongRangeProjector is, with oblongVert and Capsule. Co-Authored-By: Claude Opus 5 (1M context) --- mac-patcher/patch_save_for_mac.py | 26 ++++++++++++++++-- .../halfcohesion_100mm_isq_v1.unity3d | Bin 0 -> 9739 bytes .../halfcohesion_120mm_isq_v1.unity3d | Bin 0 -> 9595 bytes .../halfcohesion_150mm_isq_v1.unity3d | Bin 0 -> 10051 bytes 4 files changed, 24 insertions(+), 2 deletions(-) create mode 100644 mod/data/mac-fallback-assets/halfcohesion_100mm_isq_v1.unity3d create mode 100644 mod/data/mac-fallback-assets/halfcohesion_120mm_isq_v1.unity3d create mode 100644 mod/data/mac-fallback-assets/halfcohesion_150mm_isq_v1.unity3d diff --git a/mac-patcher/patch_save_for_mac.py b/mac-patcher/patch_save_for_mac.py index 21336d048..c1b976fa3 100644 --- a/mac-patcher/patch_save_for_mac.py +++ b/mac-patcher/patch_save_for_mac.py @@ -109,6 +109,25 @@ snail = ISQ_ASSETS .. "projector_200mm_oblong_isq_v6.unity3d", } +-- Cohesion rings for the base sizes the mod has none for. getCohesionLinks() +-- only knows small (27mm), medium (50mm) and large (70mm); on anything else +-- vanilla spawnCohesionRuler returns without drawing. These fill the gap. +-- +-- Nothing was invented: BB_CohesionProjector draws its ring at the projector's +-- outer edge and reads nothing else, so the whole geometry is one number, +-- ortho = half the base + 3in, which is what the mod's own three carry +-- (27mm -> 3.531496 = 0.53150 + 3, and so on). 3in is range 1/2, the distance +-- cohesion is measured at -- the same one the white band marks on the rulers. +-- +-- long and snail are missing on purpose: the cohesion shader only knows +-- Circle(), it cannot draw a stadium. They need an oblong variant, built the +-- way BB_OblongRangeProjector is (oblongVert + Capsule). +local ISQ_COHESION_BUNDLES = { + huge = ISQ_ASSETS .. "halfcohesion_100mm_isq_v1.unity3d", + laat = ISQ_ASSETS .. "halfcohesion_120mm_isq_v1.unity3d", + epic = ISQ_ASSETS .. "halfcohesion_150mm_isq_v1.unity3d", +} + -- Per family: the name TTS gives the spawned object, whether it tracks its -- figure, and the pitch the vanilla spawn uses. -- @@ -150,10 +169,13 @@ if params.bundle then return params.bundle end if kind == "cohesion" then + local bs = macGetBaseSize(fig) + if not bs then return nil end + -- Ours first, for the base sizes the mod has no ring for at all. + if ISQ_COHESION_BUNDLES[bs] then return ISQ_COHESION_BUNDLES[bs] end if not getCohesionLinks then return nil end local links = getCohesionLinks() - local bs = macGetBaseSize(fig) - return (links and bs) and links[bs] or nil + return links and links[bs] or nil end if kind == "range" then diff --git a/mod/data/mac-fallback-assets/halfcohesion_100mm_isq_v1.unity3d b/mod/data/mac-fallback-assets/halfcohesion_100mm_isq_v1.unity3d new file mode 100644 index 0000000000000000000000000000000000000000..a0b5ed53862ab6c9628b46786a36976666fabd49 GIT binary patch literal 9739 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 literal 0 HcmV?d00001 diff --git a/mod/data/mac-fallback-assets/halfcohesion_150mm_isq_v1.unity3d b/mod/data/mac-fallback-assets/halfcohesion_150mm_isq_v1.unity3d new file mode 100644 index 0000000000000000000000000000000000000000..f9b7a4cdeca26b32794a094445cda70e46038005 GIT binary patch literal 10051 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 Zg_8V>D|lL2AOq-5j@HHL5*+*_gxX0?hUowR literal 0 HcmV?d00001 From 9fc473cbcf54a7e3117a9aaa6eabc98b0443ed5c Mon Sep 17 00:00:00 2001 From: Martin Pourrat Date: Fri, 14 Aug 2026 02:47:20 +0200 Subject: [PATCH 34/42] Give the oblong bases a cohesion ring too long and snail had none, and they could not: the mod's cohesion shader computes its gradient with Circle(), so it can only draw a disc, and a disc on an elongated base would be wrong. BB_OblongCohesionProjector is written for them. The round one places its ring at the projector's edge, which works because the edge of a square projector is a circle of known radius; for a capsule the distance to the base is not the distance to the centre, so this one measures it and compares against _RingDistance. Same profile otherwise: dark at the base, bright at range 1/2. The base geometry is not invented. It is read back out of the oblong RANGE materials, the only place in the project where those dimensions are written: radius 1.00748in for both, segment 2.99029in on long and 3.70231in on snail. Two things the render bench caught that reading could not: The oblong range prefabs have TWO levels -- a root at 90 degrees about X like every other projector, and a CHILD named `projector` rolled 90 degrees about Z that carries the component. That child roll is what aligns the capsule's long axis with the base. A flat, single-level prefab renders the stadium across the model instead of along it. It has to be on the child precisely because TTS imposes its own rotation on the root. And the bench must impose the pose rather than compose with the prefab's: composing broke the long range ruler's render, while imposing matches what the game shows. Co-Authored-By: Claude Opus 5 (1M context) --- mac-patcher/patch_save_for_mac.py | 16 ++++++++++------ ...nity3d => halfcohesion_100mm_isq_v2.unity3d} | Bin ...nity3d => halfcohesion_120mm_isq_v2.unity3d} | Bin ...nity3d => halfcohesion_150mm_isq_v2.unity3d} | Bin .../halfcohesion_long_isq_v2.unity3d | Bin 0 -> 9622 bytes .../halfcohesion_snail_isq_v2.unity3d | Bin 0 -> 9576 bytes 6 files changed, 10 insertions(+), 6 deletions(-) rename mod/data/mac-fallback-assets/{halfcohesion_100mm_isq_v1.unity3d => halfcohesion_100mm_isq_v2.unity3d} (100%) rename mod/data/mac-fallback-assets/{halfcohesion_120mm_isq_v1.unity3d => halfcohesion_120mm_isq_v2.unity3d} (100%) rename mod/data/mac-fallback-assets/{halfcohesion_150mm_isq_v1.unity3d => halfcohesion_150mm_isq_v2.unity3d} (100%) create mode 100644 mod/data/mac-fallback-assets/halfcohesion_long_isq_v2.unity3d create mode 100644 mod/data/mac-fallback-assets/halfcohesion_snail_isq_v2.unity3d diff --git a/mac-patcher/patch_save_for_mac.py b/mac-patcher/patch_save_for_mac.py index c1b976fa3..886aa224e 100644 --- a/mac-patcher/patch_save_for_mac.py +++ b/mac-patcher/patch_save_for_mac.py @@ -119,13 +119,17 @@ -- (27mm -> 3.531496 = 0.53150 + 3, and so on). 3in is range 1/2, the distance -- cohesion is measured at -- the same one the white band marks on the rulers. -- --- long and snail are missing on purpose: the cohesion shader only knows --- Circle(), it cannot draw a stadium. They need an oblong variant, built the --- way BB_OblongRangeProjector is (oblongVert + Capsule). +-- long and snail go through BB_OblongCohesionProjector, written for them: the +-- mod's cohesion shader computes its gradient with Circle() and can only draw +-- a disc. Their base geometry is not invented either -- it is read back out of +-- the oblong RANGE materials, the only place in the project where those +-- dimensions are written down. local ISQ_COHESION_BUNDLES = { - huge = ISQ_ASSETS .. "halfcohesion_100mm_isq_v1.unity3d", - laat = ISQ_ASSETS .. "halfcohesion_120mm_isq_v1.unity3d", - epic = ISQ_ASSETS .. "halfcohesion_150mm_isq_v1.unity3d", + huge = ISQ_ASSETS .. "halfcohesion_100mm_isq_v2.unity3d", + laat = ISQ_ASSETS .. "halfcohesion_120mm_isq_v2.unity3d", + epic = ISQ_ASSETS .. "halfcohesion_150mm_isq_v2.unity3d", + long = ISQ_ASSETS .. "halfcohesion_long_isq_v2.unity3d", + snail = ISQ_ASSETS .. "halfcohesion_snail_isq_v2.unity3d", } -- Per family: the name TTS gives the spawned object, whether it tracks its diff --git a/mod/data/mac-fallback-assets/halfcohesion_100mm_isq_v1.unity3d b/mod/data/mac-fallback-assets/halfcohesion_100mm_isq_v2.unity3d similarity index 100% rename from mod/data/mac-fallback-assets/halfcohesion_100mm_isq_v1.unity3d rename to mod/data/mac-fallback-assets/halfcohesion_100mm_isq_v2.unity3d diff --git a/mod/data/mac-fallback-assets/halfcohesion_120mm_isq_v1.unity3d b/mod/data/mac-fallback-assets/halfcohesion_120mm_isq_v2.unity3d similarity index 100% rename from mod/data/mac-fallback-assets/halfcohesion_120mm_isq_v1.unity3d rename to mod/data/mac-fallback-assets/halfcohesion_120mm_isq_v2.unity3d diff --git a/mod/data/mac-fallback-assets/halfcohesion_150mm_isq_v1.unity3d b/mod/data/mac-fallback-assets/halfcohesion_150mm_isq_v2.unity3d similarity index 100% rename from mod/data/mac-fallback-assets/halfcohesion_150mm_isq_v1.unity3d rename to mod/data/mac-fallback-assets/halfcohesion_150mm_isq_v2.unity3d diff --git a/mod/data/mac-fallback-assets/halfcohesion_long_isq_v2.unity3d b/mod/data/mac-fallback-assets/halfcohesion_long_isq_v2.unity3d new file mode 100644 index 0000000000000000000000000000000000000000..7e2fbd9ffa47ee61aec607c17b758a4901e72a64 GIT binary patch literal 9622 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 MR&oMA|Ii*Y%4xuxQ2+n{ literal 0 HcmV?d00001 diff --git a/mod/data/mac-fallback-assets/halfcohesion_snail_isq_v2.unity3d b/mod/data/mac-fallback-assets/halfcohesion_snail_isq_v2.unity3d new file mode 100644 index 0000000000000000000000000000000000000000..f358225c0b7610431b4072a463f63f06307a8954 GIT binary patch literal 9576 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 ShN+M Date: Fri, 14 Aug 2026 02:54:46 +0200 Subject: [PATCH 35/42] Fix the oblong cohesion size: the base is two radii wide, not one Martin, in game: it works, but it is not range 1/2. My reading of the oblong base was half its real width. The mod's oblong shader masks the base with Step(grad, smoothness, uvShadow), which is Capsule(...) < 1 - uvShadow -- and 1 - uvShadow IS the normalised radius. So its base reaches TWO radii from the segment, not one. Measured against the render to be sure: the long base is 2.02in half-width, where the naive reading gives 1.007in. The cohesion stadium was therefore built around a base half as wide, and its ring fell short. The radius is now passed to the shader explicitly, in inches, rather than derived from _BaseSize, so the mistake cannot be replayed there. Checked with the camera locked to the same extent for both bundles, which is what -fov on the bench is for: the ring now measures 5.06in half-width and 6.53in half-length against 5.015 and 6.51 expected, and lands on the outer edge of the white range 1/2 band of the same base. The round sizes were already right -- huge measures 4.93in against 4.97 expected, on the band. Bundles renamed _v3, TTS caches by URL. Co-Authored-By: Claude Opus 5 (1M context) --- mac-patcher/patch_save_for_mac.py | 4 ++-- .../halfcohesion_long_isq_v2.unity3d | Bin 9622 -> 0 bytes .../halfcohesion_long_isq_v3.unity3d | Bin 0 -> 9596 bytes .../halfcohesion_snail_isq_v2.unity3d | Bin 9576 -> 0 bytes .../halfcohesion_snail_isq_v3.unity3d | Bin 0 -> 9555 bytes 5 files changed, 2 insertions(+), 2 deletions(-) delete mode 100644 mod/data/mac-fallback-assets/halfcohesion_long_isq_v2.unity3d create mode 100644 mod/data/mac-fallback-assets/halfcohesion_long_isq_v3.unity3d delete mode 100644 mod/data/mac-fallback-assets/halfcohesion_snail_isq_v2.unity3d create mode 100644 mod/data/mac-fallback-assets/halfcohesion_snail_isq_v3.unity3d diff --git a/mac-patcher/patch_save_for_mac.py b/mac-patcher/patch_save_for_mac.py index 886aa224e..b04c13e90 100644 --- a/mac-patcher/patch_save_for_mac.py +++ b/mac-patcher/patch_save_for_mac.py @@ -128,8 +128,8 @@ huge = ISQ_ASSETS .. "halfcohesion_100mm_isq_v2.unity3d", laat = ISQ_ASSETS .. "halfcohesion_120mm_isq_v2.unity3d", epic = ISQ_ASSETS .. "halfcohesion_150mm_isq_v2.unity3d", - long = ISQ_ASSETS .. "halfcohesion_long_isq_v2.unity3d", - snail = ISQ_ASSETS .. "halfcohesion_snail_isq_v2.unity3d", + long = ISQ_ASSETS .. "halfcohesion_long_isq_v3.unity3d", + snail = ISQ_ASSETS .. "halfcohesion_snail_isq_v3.unity3d", } -- Per family: the name TTS gives the spawned object, whether it tracks its diff --git a/mod/data/mac-fallback-assets/halfcohesion_long_isq_v2.unity3d b/mod/data/mac-fallback-assets/halfcohesion_long_isq_v2.unity3d deleted file mode 100644 index 7e2fbd9ffa47ee61aec607c17b758a4901e72a64..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9622 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 MR&oMA|Ii*Y%4xuxQ2+n{ diff --git a/mod/data/mac-fallback-assets/halfcohesion_long_isq_v3.unity3d b/mod/data/mac-fallback-assets/halfcohesion_long_isq_v3.unity3d new file mode 100644 index 0000000000000000000000000000000000000000..53b43c1c59200a08c2e4ce1ad92c35cbe9aff3c6 GIT binary patch literal 9596 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 m0EiK`z!+%5M0000000000bXaE2JNB{r; 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 ShN+M0000000000bQvd(}NB{r; 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 Date: Fri, 14 Aug 2026 03:04:46 +0200 Subject: [PATCH 36/42] Give the Objective token's R button a range 1/2 ring It showed range 1. Martin wants range 1/2 on it. The mod already had exactly this object, and it is not a range ruler: the POI's 3in ring is BB_CohesionProjector with its orthographic size at 4, one inch of base radius plus three. Ours is the same build at the token's own base -- 27mm, so 0.53150 + 3 = 3.53150 -- and it keeps the ring's current amber, so only the SIZE changes. Measured on the bench at 3.54in. Routed by the object's NAME, not by rangeKey: "token" is shared by Objective, Condition, Cad Bane, Proton Charge and Complete the Mission, and only Objective should change. The bench now checks both halves of that -- Objective gets ours, Condition still gets the mod's. The hover hotkey is untouched, it still draws the fig-leader bands. Nothing here covers an Advantage token: the mod has none, under that name or any other. Asked. Co-Authored-By: Claude Opus 5 (1M context) --- mac-patcher/patch_save_for_mac.py | 21 ++++++++++++++++-- .../token05_objective_isq_v1.unity3d | Bin 0 -> 9675 bytes 2 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 mod/data/mac-fallback-assets/token05_objective_isq_v1.unity3d diff --git a/mac-patcher/patch_save_for_mac.py b/mac-patcher/patch_save_for_mac.py index b04c13e90..41b0ae99c 100644 --- a/mac-patcher/patch_save_for_mac.py +++ b/mac-patcher/patch_save_for_mac.py @@ -132,6 +132,21 @@ snail = ISQ_ASSETS .. "halfcohesion_snail_isq_v3.unity3d", } +-- Range 1/2 rings for the tokens whose own R button should show range 1/2 +-- rather than the range 1 the mod gives them. Keyed by the object's name, +-- because rangeKey cannot separate them: "token" is shared by Objective, +-- Condition, Cad Bane, Proton Charge and Complete the Mission alike. +-- +-- The mod already had exactly this object, and it is not a range ruler: the +-- POI's 3in ring is BB_CohesionProjector with its orthographic size at 4, +-- one inch of base radius plus three. Ours is the same build at the token's +-- own base, and it keeps the ring's current amber so only the SIZE changes. +-- +-- The hover hotkey is untouched: it still draws the fig-leader bands. +local ISQ_TOKEN_RINGS = { + ["Objective Token"] = ISQ_ASSETS .. "token05_objective_isq_v1.unity3d", +} + -- Per family: the name TTS gives the spawned object, whether it tracks its -- figure, and the pitch the vanilla spawn uses. -- @@ -194,8 +209,10 @@ end -- Token R button: its own single-ring bundle. Hover hotkey -- (forceFigMode): the full fig-leader bands instead. - if key and not params.forceFigMode and links[key] then - return links[key] + if key and not params.forceFigMode then + local ok, nm = pcall(function() return fig.getName() end) + if ok and nm and ISQ_TOKEN_RINGS[nm] then return ISQ_TOKEN_RINGS[nm] end + if links[key] then return links[key] end end local bs = macGetBaseSize(fig) or (key and TOKEN_TO_BASESIZE[key]) if not bs then return nil end diff --git a/mod/data/mac-fallback-assets/token05_objective_isq_v1.unity3d b/mod/data/mac-fallback-assets/token05_objective_isq_v1.unity3d new file mode 100644 index 0000000000000000000000000000000000000000..e113633cf934eadf065c75e7c02f2f45e2a3d0d2 GIT binary patch literal 9675 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 NX9|eYBmX0-;Q+F;$dUj6 literal 0 HcmV?d00001 From 41f692a52a118ae7588219443053f97016d99ac2 Mon Sep 17 00:00:00 2001 From: Martin Pourrat Date: Fri, 14 Aug 2026 03:07:32 +0200 Subject: [PATCH 37/42] Range 1/2 on the Condition token too, and one ring for both The Advantage token the game means is the mod's Condition token (Martin, 14 Aug). It shares the Objective's base and colour, so the ring is now named for what it is -- token05_27mm_isq -- and serves both. Bane, Proton Charge and Complete the Mission carry the same rangeKey and keep the mod's range 1 ring. That is the point of routing by name, and the bench pins both sides of it. Co-Authored-By: Claude Opus 5 (1M context) --- mac-patcher/patch_save_for_mac.py | 5 ++++- .../token05_27mm_isq_v1.unity3d | Bin 0 -> 9708 bytes .../token05_objective_isq_v1.unity3d | Bin 9675 -> 0 bytes 3 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 mod/data/mac-fallback-assets/token05_27mm_isq_v1.unity3d delete mode 100644 mod/data/mac-fallback-assets/token05_objective_isq_v1.unity3d diff --git a/mac-patcher/patch_save_for_mac.py b/mac-patcher/patch_save_for_mac.py index 41b0ae99c..721dd7ec6 100644 --- a/mac-patcher/patch_save_for_mac.py +++ b/mac-patcher/patch_save_for_mac.py @@ -143,8 +143,11 @@ -- own base, and it keeps the ring's current amber so only the SIZE changes. -- -- The hover hotkey is untouched: it still draws the fig-leader bands. +-- Objective and Condition share the base and the colour, so one ring serves +-- both. Condition is what the game calls the Advantage token (Martin, 14 Aug). local ISQ_TOKEN_RINGS = { - ["Objective Token"] = ISQ_ASSETS .. "token05_objective_isq_v1.unity3d", + ["Objective Token"] = ISQ_ASSETS .. "token05_27mm_isq_v1.unity3d", + ["Condition Token"] = ISQ_ASSETS .. "token05_27mm_isq_v1.unity3d", } -- Per family: the name TTS gives the spawned object, whether it tracks its diff --git a/mod/data/mac-fallback-assets/token05_27mm_isq_v1.unity3d b/mod/data/mac-fallback-assets/token05_27mm_isq_v1.unity3d new file mode 100644 index 0000000000000000000000000000000000000000..427f272655f0283f4e003cf0e3b91dd8f9f1659b GIT binary patch literal 9708 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 literal 0 HcmV?d00001 diff --git a/mod/data/mac-fallback-assets/token05_objective_isq_v1.unity3d b/mod/data/mac-fallback-assets/token05_objective_isq_v1.unity3d deleted file mode 100644 index e113633cf934eadf065c75e7c02f2f45e2a3d0d2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9675 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 NX9|eYBmX0-;Q+F;$dUj6 From 84e82e0cca26f4fb2d47f442cbd4d19a41894456 Mon Sep 17 00:00:00 2001 From: Martin Pourrat Date: Fri, 14 Aug 2026 03:15:21 +0200 Subject: [PATCH 38/42] Mark the attack chain out of scope rather than broken Its range routing was never wired, and the five clears on that path only ever touch the mod's ruler, so RANGE then ATTACK leaves two rulers on screen. That was going to be the next fix. It is not a fix. Martin, 14 Aug: the feature dates from V1 of the game, three years ago, and is no longer accurate under V2. So the spec now says so plainly -- known, accepted, do not wire it. If it is ever revisited it will be to bring attack mode up to V2 or drop it, which belongs to the V2 tuning batch, not here. Written down because the finding reads exactly like a bug, and the next person through will otherwise spend an evening fixing something that should not exist. Co-Authored-By: Claude Opus 5 (1M context) --- mac-patcher/cahier-des-charges-overlays.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/mac-patcher/cahier-des-charges-overlays.md b/mac-patcher/cahier-des-charges-overlays.md index 5eef08389..8620510e7 100644 --- a/mac-patcher/cahier-des-charges-overlays.md +++ b/mac-patcher/cahier-des-charges-overlays.md @@ -107,6 +107,26 @@ L'objet le plus chargé : il porte trois des quatre familles. | extinction | `gClearRange` **puis** `exitTargetingMode` | | pourquoi le clear à l'extinction | `exitTargetingMode` et `clearRangeRulers` n'atteignent que la règle vanilla. Sans ce clear, nos anneaux restaient affichés en position OFF | +### Chaîne d'attaque, `attackMode` — HORS PÉRIMÈTRE + +⚠ **Ne pas router, ne pas « réparer ». Arbitrage Martin, 14/08 : la fonctionnalité +date de la V1 du jeu, elle a trois ans et elle n'est plus juste en V2.** + +Constat, pour que personne ne le redécouvre comme un bug : `ATTACK` mène à +`attack()` puis `attackMode()`, qui appelle le `spawnRangeRuler` **vanilla** du +scope de l'Order Token. En mode Iron Squadron, l'attaque pose donc quand même la +règle d'origine. Et les cinq sorties de ce chemin — `exitTargetingMode`, +`exitAttackMode`, `clearTemplates`, `attackMenu`, `stopAttack` — n'effacent que +le vanilla, jamais `activeOverlays` : allumer RANGE puis attaquer laisse les deux +règles à l'écran. + +C'est **connu et accepté**. Le seul déclencheur de range réellement routé côté +Order Token est le bouton RANGE (`targetingMode`). + +Si un jour on y revient, ce sera pour **mettre le mode attaque à la V2 ou le +retirer**, pas pour brancher l'existant — donc dans le lot « fine tuning V2 », +pas ici. + ### Boutons de mouvement, famille MaxMove Chaînes : `MOVE` vers `initMove` vers `moveUnit(false)`, `DEPLOY` vers `initDeploy` vers From f0223dd83024c8eb8276d52b0e97e484542a6f2c Mon Sep 17 00:00:00 2001 From: Martin Pourrat Date: Fri, 14 Aug 2026 03:27:16 +0200 Subject: [PATCH 39/42] Route the attack chain after all, as a stopgap Martin: fix the hole while we wait for a V2 tool to replace the feature. attackMode() now goes through gClearRange + gRangeTrigger like the RANGE button, and exitTargetingMode, exitAttackMode and clearTemplates each clear our overlay alongside their existing pcalls. RANGE then ATTACK no longer leaves two rulers on screen. Defined in ORDER_TOKEN_BUTTON_OVERRIDES rather than the Cohesion block, because that one is appended last and therefore wins. The May ban still holds: spawnRangeRuler and clearRangeRulers are not overridden on the Order Token -- only their callers are redefined. The bench grew an Order Token scope to prove it. The patcher's block is loaded into a stubbed environment whose vanilla spawnRangeRuler raises, so a regression fails the run instead of passing quietly. Seven checks, 36 in total. The spec says plainly that this is a holding fix on a feature that dates from V1 and is not accurate under V2. Co-Authored-By: Claude Opus 5 (1M context) --- mac-patcher/cahier-des-charges-overlays.md | 38 ++++++++------ mac-patcher/patch_save_for_mac.py | 59 ++++++++++++++++++++++ 2 files changed, 81 insertions(+), 16 deletions(-) diff --git a/mac-patcher/cahier-des-charges-overlays.md b/mac-patcher/cahier-des-charges-overlays.md index 8620510e7..ed386a64e 100644 --- a/mac-patcher/cahier-des-charges-overlays.md +++ b/mac-patcher/cahier-des-charges-overlays.md @@ -107,25 +107,31 @@ L'objet le plus chargé : il porte trois des quatre familles. | extinction | `gClearRange` **puis** `exitTargetingMode` | | pourquoi le clear à l'extinction | `exitTargetingMode` et `clearRangeRulers` n'atteignent que la règle vanilla. Sans ce clear, nos anneaux restaient affichés en position OFF | -### Chaîne d'attaque, `attackMode` — HORS PÉRIMÈTRE +### Chaîne d'attaque, `attackMode` — ROUTÉE, mais en attente de remplacement -⚠ **Ne pas router, ne pas « réparer ». Arbitrage Martin, 14/08 : la fonctionnalité -date de la V1 du jeu, elle a trois ans et elle n'est plus juste en V2.** +⚠ **La fonctionnalité elle-même est périmée.** Arbitrage Martin, 14/08 : elle date +de la V1 du jeu, elle a trois ans et elle n'est plus juste en V2. Ce qui suit est +un **bouchon** posé le temps qu'un outil V2 la remplace, pas une conception. Si on +y revient, ce sera pour la mettre à la V2 ou la retirer — lot « fine tuning V2 ». -Constat, pour que personne ne le redécouvre comme un bug : `ATTACK` mène à -`attack()` puis `attackMode()`, qui appelle le `spawnRangeRuler` **vanilla** du -scope de l'Order Token. En mode Iron Squadron, l'attaque pose donc quand même la -règle d'origine. Et les cinq sorties de ce chemin — `exitTargetingMode`, -`exitAttackMode`, `clearTemplates`, `attackMenu`, `stopAttack` — n'effacent que -le vanilla, jamais `activeOverlays` : allumer RANGE puis attaquer laisse les deux -règles à l'écran. +**Ce qui n'allait pas** : `ATTACK` mène à `attack()` puis `attackMode()`, qui +appelait le `spawnRangeRuler` **vanilla** du scope de l'Order Token. En mode Iron +Squadron l'attaque posait donc quand même la règle du mod. Et les sorties de ce +chemin — `exitTargetingMode`, `exitAttackMode`, `clearTemplates` — n'effaçaient +que le vanilla, jamais `activeOverlays` : allumer RANGE puis attaquer laissait +**deux règles** à l'écran. -C'est **connu et accepté**. Le seul déclencheur de range réellement routé côté -Order Token est le bouton RANGE (`targetingMode`). - -Si un jour on y revient, ce sera pour **mettre le mode attaque à la V2 ou le -retirer**, pas pour brancher l'existant — donc dans le lot « fine tuning V2 », -pas ici. +| | comportement attendu | +|---|---| +| allumage | `exitTargetingMode`, `highlightEnemies`, puis `gClearRange` et `gRangeTrigger` sur `selectedUnitObj` — même schéma que le bouton RANGE | +| extinction | `exitTargetingMode`, qui efface les deux moteurs | +| les trois effaceurs | `exitTargetingMode`, `exitAttackMode` et `clearTemplates` appellent `gClearRange` en plus de leurs `pcall` d'origine | +| où c'est défini | dans `ORDER_TOKEN_BUTTON_OVERRIDES`, **pas** dans le bloc Cohésion : celui-là est ajouté en dernier, donc c'est lui qui gagne | +| ⚠ interdit maintenu | **on ne surcharge toujours pas** `spawnRangeRuler` / `clearRangeRulers` sur l'Order Token. On redéfinit les appelants, jamais l'API de portée | + +**Couverture** : scénario 5d du banc `harness_projectors.py`, qui charge le bloc +du patcher dans un environnement bouchonné où `spawnRangeRuler` vanilla lève une +erreur — si le routage régresse, le banc tombe au lieu de passer. ### Boutons de mouvement, famille MaxMove diff --git a/mac-patcher/patch_save_for_mac.py b/mac-patcher/patch_save_for_mac.py index 721dd7ec6..0a943a429 100644 --- a/mac-patcher/patch_save_for_mac.py +++ b/mac-patcher/patch_save_for_mac.py @@ -1000,6 +1000,65 @@ end end +-- ⏳ CORRECTIF D'ATTENTE, 14 aout. La chaine d'attaque n'a jamais ete routee : +-- attackMode() appelle le spawnRangeRuler vanilla du scope de l'Order Token, +-- donc le mode Iron Squadron recevait quand meme la regle du mod, et aucune des +-- sorties de ce chemin ne touchait activeOverlays -- RANGE puis ATTACK laissait +-- deux regles a l'ecran. +-- +-- Arbitrage Martin : la fonctionnalite date de la V1 du jeu et n'est plus juste +-- en V2. Ceci la branche en attendant qu'un outil V2 la remplace ; ce n'est pas +-- une conception, c'est un bouchon. Le garder ennuyeux. +-- Spec : section "Chaine d'attaque" de cahier-des-charges-overlays.md. +-- +-- Defini ici et pas dans le bloc Cohesion parce que ce bloc-ci est ajoute EN +-- DERNIER, donc c'est lui qui gagne. Le local vient avant les fonctions qui le +-- capturent. +local function macClearSelectedRange() + if selectedUnitObj then + Global.call("gClearRange", { figGUID = selectedUnitObj.getGUID() }) + end +end + +function attackMode() + if not attackModeOn then + exitTargetingMode() + highlightEnemies() + if selectedUnitObj then + Global.call("gClearRange", { figGUID = selectedUnitObj.getGUID() }) + Global.call("gRangeTrigger", { figGUID = selectedUnitObj.getGUID() }) + end + attackModeOn = true + resetTargetingButtons() + else + exitTargetingMode() + end +end + +function exitTargetingMode() + enemyHighlighted = false + attackModeOn = false + macClearSelectedRange() + pcall(clearRangeRulers) + pcall(unhighlightEnemies) + pcall(clearAttackLine) +end + +function exitAttackMode() + enemyHighlighted = false + attackModeOn = false + macClearSelectedRange() + pcall(clearRangeRulers) + pcall(unhighlightEnemies) +end + +function clearTemplates() + pcall(clearMovementTemplates) + macClearSelectedRange() + pcall(clearRangeRulers) + pcall(clearCohesionRulers) +end + function targetingMode(_, playerColor) if not selectedUnitObj then return end if not enemyHighlighted then From 8269cc56d33fa4ea745f7637ea4a700bc3d04a4e Mon Sep 17 00:00:00 2001 From: Martin Pourrat Date: Fri, 14 Aug 2026 12:17:54 +0200 Subject: [PATCH 40/42] Return mod/src to upstream, and drop the dead per-seat remnants The 1011-line divergence in mod/src was the decal-era overlay engine: the 873-line Overlays.ttslua, its require, the RangeRulers router, the Cohesion wrapper, the Order_Token overrides and the isqLogo UI asset. All of it was superseded on 12 August when the patcher moved to real Projectors, and Martin cancelled the backport on the 14th: the engine lives in the patcher, the PR's mergeable content is the asset fix. mod/src now matches origin/main exactly, which also retires the two source-vs-patcher divergences the spec tracked (including the latent SIGSEGV one). In the patcher, two dead pieces found by auditing every injected block: macRemoveAll was defined and never called, and macActivePlayerForMove was written by all nine movement buttons to feed a gGetMode argument that the table-wide mode has ignored since per-seat was dropped. Removed, with the comment that documented the capture. Bench: 36 checks, green before and after. Co-Authored-By: Claude Opus 5 (1M context) --- mac-patcher/patch_save_for_mac.py | 21 +- mod/src/StarWarsLegion.json | 4 - mod/src/StarWarsLegion.lua | 1 - mod/src/StarWarsLegion/Order_Token.a57c41.lua | 107 +-- mod/src/includes/Cohesion.ttslua | 28 +- mod/src/includes/Overlays.ttslua | 873 ------------------ mod/src/includes/RangeRulers.ttslua | 30 - 7 files changed, 33 insertions(+), 1031 deletions(-) delete mode 100644 mod/src/includes/Overlays.ttslua diff --git a/mac-patcher/patch_save_for_mac.py b/mac-patcher/patch_save_for_mac.py index 0a943a429..743b1c135 100644 --- a/mac-patcher/patch_save_for_mac.py +++ b/mac-patcher/patch_save_for_mac.py @@ -288,12 +288,6 @@ for _, key in ipairs(keys) do macRemove(key) end end -function macRemoveAll() - local keys = {} - for key in pairs(activeOverlays) do keys[#keys + 1] = key end - for _, key in ipairs(keys) do macRemove(key) end -end - -- Reconcile the scene with the registry: give a Projector to every entry that -- has never had one, and drop entries that lost theirs. function macRedrawNow() @@ -789,7 +783,7 @@ -- also fires when changeSpeed2/3 calls moveUnit() with no isDeploy arg. if isDeploy ~= true then if maxMoveTemplateBundleToSpawn ~= nil then - local _macMode = Global.call("gGetMode", {color = macActivePlayerForMove}) + local _macMode = Global.call("gGetMode", {}) if _macMode == "windows" then -- WINDOWS ORIGINAL: spawn Custom_AssetBundle Projector maxMoveTemplate = spawnObject({ @@ -1081,10 +1075,6 @@ end end --- Capture playerColor for Maximum Move per-seat routing. moveUnit() doesn't --- receive the click color, so each entry-point button stashes it in a --- script-global var that the spawn block reads. Defaults to nil -> Mac mode. - -- initMove / initDeploy: redefine the body INLINE rather than wrap, because -- wrapping (capturing the original via a local + calling it) reproducibly -- broke every Order Token button click in testing (root cause unknown; @@ -1093,7 +1083,6 @@ -- capture so the MAXMOVE_SPAWN block can route to Mac/Windows per seat. function initMove(obj, playerColor) if not selectedUnitObj then return end - macActivePlayerForMove = playerColor initPos = selectedUnitObj.getPosition() initRot = selectedUnitObj.getRotation() selectedUnitObj.call("setStartPos") @@ -1101,7 +1090,6 @@ end function initDeploy(obj, playerColor) if not selectedUnitObj then return end - macActivePlayerForMove = playerColor initPos = selectedUnitObj.getPosition() initRot = selectedUnitObj.getRotation() selectedUnitObj.call("setStartPos") @@ -1117,28 +1105,24 @@ -- Tokens (helper fns setTemplateVariables/clearTemplates/moveUnit exist -- on both because they're part of the include set the List Builder emits). function changeSpeed1(_, playerColor) - macActivePlayerForMove = playerColor unitData.selectedSpeed = 1 setTemplateVariables() clearTemplates() moveUnit() end function changeSpeed2(_, playerColor) - macActivePlayerForMove = playerColor unitData.selectedSpeed = 2 setTemplateVariables() clearTemplates() moveUnit() end function changeSpeed3(_, playerColor) - macActivePlayerForMove = playerColor unitData.selectedSpeed = 3 setTemplateVariables() clearTemplates() moveUnit() end function moveForward(_, playerColor) - macActivePlayerForMove = playerColor self.editButton({ index = 11, click_function = "moveBackwards", label = "B", tooltip = "Move Backwards" @@ -1147,7 +1131,6 @@ moveUnit() end function moveBackwards(_, playerColor) - macActivePlayerForMove = playerColor self.editButton({ index = 11, click_function = "moveForward", label = "F", tooltip = "Move Forward" @@ -1156,12 +1139,10 @@ moveUnit() end function moveLeft(_, playerColor) - macActivePlayerForMove = playerColor moveDirection = "left" moveUnit() end function moveRight(_, playerColor) - macActivePlayerForMove = playerColor moveDirection = "right" moveUnit() end diff --git a/mod/src/StarWarsLegion.json b/mod/src/StarWarsLegion.json index f4f71c161..1b7f385c5 100644 --- a/mod/src/StarWarsLegion.json +++ b/mod/src/StarWarsLegion.json @@ -317,10 +317,6 @@ { "Name": "rangeRuler", "URL": "http://cloud-3.steamusercontent.com/ugc/966480765118137238/1157F7217EB80F31A92427567B377F857576DAE9/" - }, - { - "Name": "isqLogo", - "URL": "https://raw.githubusercontent.com/ironsquadronfr-hub/tts/mac-projector-fallback/mod/data/mac-fallback-assets/iron_squadron_logo_v2.png" } ], "ObjectStates": [] diff --git a/mod/src/StarWarsLegion.lua b/mod/src/StarWarsLegion.lua index 989babcf6..2ddaa6966 100644 --- a/mod/src/StarWarsLegion.lua +++ b/mod/src/StarWarsLegion.lua @@ -4,7 +4,6 @@ require('!/common/SHA256') require('!/data/ListBuilder') require('!/generated/cards') require('!/UI') -require('!/Overlays') require('!/RangeRulers') require('!/Cohesion') diff --git a/mod/src/StarWarsLegion/Order_Token.a57c41.lua b/mod/src/StarWarsLegion/Order_Token.a57c41.lua index a0ffab22c..fbf2ff744 100644 --- a/mod/src/StarWarsLegion/Order_Token.a57c41.lua +++ b/mod/src/StarWarsLegion/Order_Token.a57c41.lua @@ -366,23 +366,15 @@ function resetButtons() end end -function toggleCohesionRuler(_, playerColor) - -- Mac fallback: capture playerColor (TTS passes it as 2nd arg on click) - -- and route through gCohesionTrigger (the mode router). - if not selectedUnitObj then return end +function toggleCohesionRuler() if not rulerOn then - -- Deterministic ON: gCohesionTrigger toggles by GUID, so clear any - -- stale Mac overlay first (e.g., drawn via the hover hotkey). - Global.call("gClearCohesion", { figGUID = selectedUnitObj.getGUID() }) - Global.call("gCohesionTrigger", { - figGUID = selectedUnitObj.getGUID(), - playerColor = playerColor, - }) + selectedUnitObj.call("spawnCohesionRuler", selectedUnitObj) rulerOn = true else selectedUnitObj.call("clearCohesionRuler") rulerOn = false end + end ------------------------------------------------- NEXTUNIT ------------------------------------------------------------ @@ -559,37 +551,26 @@ function moveUnit(isDeploy) local maxMoveBundles = getMovementLinks() local baseSizeMoveBundles = maxMoveBundles[unitData.baseSize] - local maxMoveTemplateBundleToSpawn = baseSizeMoveBundles and baseSizeMoveBundles[unitData.selectedSpeed] + local maxMoveTemplateBundleToSpawn = baseSizeMoveBundles[unitData.selectedSpeed] - -- Mac fallback: permissive condition (covers nil + false) so the overlay - -- also fires when changeSpeed2/3 calls moveUnit() with no isDeploy arg. - if isDeploy ~= true then + if isDeploy == false then + --max movement ring projector if maxMoveTemplateBundleToSpawn ~= nil then - local _macMode = Global.call("gGetMode", {color = macActivePlayerForMove}) - if _macMode == "windows" then - -- WINDOWS ORIGINAL: spawn Custom_AssetBundle Projector - maxMoveTemplate = spawnObject({ - type = "Custom_AssetBundle", - position = {basePos.x, basePos.y + 20, basePos.z}, - rotation = {0, basePos.y, 0}, - scale = {0,0,0} - }) - maxMoveTemplate.setCustomObject({ - type = 0, - assetbundle = maxMoveTemplateBundleToSpawn - }) - maxMoveTemplate.setLock(true) - maxMoveTemplate.use_gravity = false - maxMoveTemplate.setName("Maximum Move") - else - -- MAC FALLBACK: route through the Global Overlays manager - Global.call("gSpawnMaxMove", { - figGUID = selectedUnitObj.getGUID(), - baseSize = unitData.baseSize, - speed = unitData.selectedSpeed, - }) - maxMoveTemplate = nil - end + maxMoveTemplate = spawnObject({ + type = "Custom_AssetBundle", + position = {basePos.x, basePos.y + 20, basePos.z}, + rotation = {0, basePos.y, 0}, + scale = {0,0,0} -- 0 scale will hide TTS default box and won't impact projector + }) + + maxMoveTemplate.setCustomObject({ + type = 0, + assetbundle = maxMoveTemplateBundleToSpawn + }) + + maxMoveTemplate.setLock(true) + maxMoveTemplate.use_gravity = false + maxMoveTemplate.setName("Maximum Move") end end ------------------------------------------- SPAWN BUTTON ------------------------------------------- @@ -741,8 +722,7 @@ function moveStart() end) end -function moveBackwards(_, playerColor) - macActivePlayerForMove = playerColor -- Mac fallback per-seat capture +function moveBackwards() self.editButton({ index = 11, click_function = "moveForward", @@ -753,8 +733,7 @@ function moveBackwards(_, playerColor) moveUnit() end -function moveForward(_, playerColor) - macActivePlayerForMove = playerColor -- Mac fallback per-seat capture +function moveForward() self.editButton({ index = 11, click_function = "moveBackwards", @@ -765,14 +744,12 @@ function moveForward(_, playerColor) moveUnit() end -function moveLeft(_, playerColor) - macActivePlayerForMove = playerColor -- Mac fallback per-seat capture +function moveLeft() moveDirection = "left" moveUnit() end -function moveRight(_, playerColor) - macActivePlayerForMove = playerColor -- Mac fallback per-seat capture +function moveRight() moveDirection = "right" moveUnit() end @@ -803,14 +780,9 @@ function clearMovementTemplates() if templateB ~= nil then destroyObject(templateB) end - -- Mac fallback dual-path: destroy bundle if Windows-mode spawn produced - -- one, AND clear the Global Overlays manager entry (Mac fallback). Either - -- may be set depending on the active player's mode at spawn time. if maxMoveTemplate ~= nil then - pcall(destroyObject, maxMoveTemplate) + destroyObject(maxMoveTemplate) end - Global.call("gClearAllMaxMove", {}) - maxMoveTemplate = nil end function clearCohesionRulers() @@ -831,27 +803,21 @@ end ------------------------------------------------- CHANGESPEED------------------------------------------------------------ --- Mac fallback per-seat capture: each speed button stashes the clicking --- player's color so the dual-path branch in moveUnit() can pick the right --- renderer for the Maximum Move overlay. -function changeSpeed1(_, playerColor) - macActivePlayerForMove = playerColor +function changeSpeed1() unitData.selectedSpeed = 1 setTemplateVariables() clearTemplates() moveUnit() end -function changeSpeed2(_, playerColor) - macActivePlayerForMove = playerColor +function changeSpeed2() unitData.selectedSpeed = 2 setTemplateVariables() clearTemplates() moveUnit() end -function changeSpeed3(_, playerColor) - macActivePlayerForMove = playerColor +function changeSpeed3() unitData.selectedSpeed = 3 setTemplateVariables() clearTemplates() @@ -953,25 +919,14 @@ function attack() attackMode() end -function targetingMode(_, playerColor) - -- Mac fallback: capture playerColor and route through gRangeTrigger. - if not selectedUnitObj then return end +function targetingMode() if not enemyHighlighted then exitAttackMode() highlightEnemies() - -- Deterministic ON: gRangeTrigger toggles by GUID, so clear any - -- stale Mac overlay first to guarantee this click draws. - Global.call("gClearRange", { figGUID = selectedUnitObj.getGUID() }) - Global.call("gRangeTrigger", { - figGUID = selectedUnitObj.getGUID(), - playerColor = playerColor, - }) + spawnRangeRuler(selectedUnitObj) enemyHighlighted = true resetRangeButtons() else - -- exitTargetingMode/clearRangeRulers only clears the vanilla bundle - -- ruler; clear the Mac overlay too so OFF really hides the rings. - Global.call("gClearRange", { figGUID = selectedUnitObj.getGUID() }) exitTargetingMode() end end diff --git a/mod/src/includes/Cohesion.ttslua b/mod/src/includes/Cohesion.ttslua index 38fadbe33..1a28778af 100644 --- a/mod/src/includes/Cohesion.ttslua +++ b/mod/src/includes/Cohesion.ttslua @@ -58,30 +58,4 @@ function clearCohesionRuler() cohesionRuler.destruct() cohesionRuler = nil end -end --- ============================================ --- Mac fallback per-seat router (appended). --- Alias the original spawn/clear so Windows-mode players still get their --- bundle Projector, while routing default calls through Global Overlays. --- See !/Overlays for the manager. The `*Original` aliases are called by --- gCohesionTrigger when the active player has chosen "windows" mode. --- ============================================ -spawnCohesionRulerOriginal = spawnCohesionRuler -clearCohesionRulerOriginal = clearCohesionRuler - -function spawnCohesionRuler(cohesionSourceObject) - if not cohesionSourceObject then return end - Global.call("gCohesionTrigger", { - figGUID = cohesionSourceObject.getGUID(), - playerColor = nil, - }) -end - -function clearCohesionRuler() - if self and self.getGUID and self.getGUID() ~= "-1" then - Global.call("gClearCohesion", { figGUID = self.getGUID() }) - end - if cohesionRuler ~= nil then - pcall(clearCohesionRulerOriginal) - end -end +end \ No newline at end of file diff --git a/mod/src/includes/Overlays.ttslua b/mod/src/includes/Overlays.ttslua deleted file mode 100644 index aa0ebaada..000000000 --- a/mod/src/includes/Overlays.ttslua +++ /dev/null @@ -1,873 +0,0 @@ --- MacFallback.ttslua - Mac fallback for the TTS Unity 6 Projector magenta bug. --- Replaces every Custom_AssetBundle Projector overlay (Cohesion / Range / --- Maximum Move / Deployment Boundary) with a vector-lines + decal hybrid --- rendered via Global.setVectorLines / Global.setDecals. Per-seat toggle so --- Windows players keep the original Projectors. - --- Manager Global + event handlers + vector-lines rendering. --- Called by Unit_Leader / Order_Token via Global.call from their patched --- Cohesion functions. --- ============================================ - -activeOverlays = activeOverlays or {} -hiddenWhilePickedUp = hiddenWhilePickedUp or {} - --- Public hosting for the PNG assets used by the Mac fallback overlays. --- TTS loads decals from HTTP(S) URLs (Steam Workshop UGC, GitHub raw, or any --- static host). After merge, this points to the repo's mac-fallback-assets/ --- folder; before merge, replace with the PR branch URL for testing. -local ASSETS_BASE = "https://raw.githubusercontent.com/ironsquadronfr-hub/tts/mac-projector-fallback/mod/data/mac-fallback-assets/" -local COHESION_HALO_URL = ASSETS_BASE .. "cohesion_halo.png" -local MAX_MOVE_CYAN_URL = ASSETS_BASE .. "max_move_cyan.png" -local DEPLOYMENT_RED_URL = ASSETS_BASE .. "deployment_red.png" -local DEPLOYMENT_BLUE_URL = ASSETS_BASE .. "deployment_blue.png" -local RANGE_DECAL_URLS = { - smokeToken = ASSETS_BASE .. "range_smokeToken.png", - token = ASSETS_BASE .. "range_token.png", - tokenRangeTwo = ASSETS_BASE .. "range_tokenRangeTwo.png", - poi = ASSETS_BASE .. "range_poi.png", - bombCart = ASSETS_BASE .. "range_bombCart.png", - -- Fig leaders: per-base-size PNGs (bands pre-offset by the base radius so - -- the decal bands line up with the vector-line rings). - fig_leader = { - small = ASSETS_BASE .. "range_fig_leader_small.png", - medium = ASSETS_BASE .. "range_fig_leader_medium.png", - large = ASSETS_BASE .. "range_fig_leader_large.png", - huge = ASSETS_BASE .. "range_fig_leader_huge.png", - laat = ASSETS_BASE .. "range_fig_leader_laat.png", - epic = ASSETS_BASE .. "range_fig_leader_epic.png", - long = ASSETS_BASE .. "range_fig_leader_long_stadium.png", - snail = ASSETS_BASE .. "range_fig_leader_snail_stadium.png", - }, -} -local RANGE_MAX_RADIUS = { - fig_leader = 30, -- R5 max - smokeToken = 1, - token = 1, - tokenRangeTwo = 2, - poi = 3, - bombCart = 2, -} - --- Range band colors (RGBA) extracted from BB_RangeProjector material defaults --- + demi-portee blanche pour SWL Range 0.5 (3 inches) -local RANGE_COLORS = { - half = {1.0, 1.0, 1.0, 0.6}, -- 0.5 = 3" white - one = {1.0, 0.764, 0.0, 0.7}, -- R1 yellow - two = {1.0, 0.459, 0.0, 0.7}, -- R2 orange - three = {1.0, 0.079, 0.0, 0.7}, -- R3 red - four = {0.764, 0.0, 0.259, 0.7}, -- R4 magenta - five = {0.528, 0.0, 0.443, 0.7}, -- R5 violet -} - --- Per-rangeKey configurations: list of {radius_inches, color_name} -local RANGE_CONFIGS = { - -- Fig leaders: half + 4 bands at SWL standard ranges 3/6/12/18/24" - small = {{r=3,c="half"},{r=6,c="one"},{r=12,c="two"},{r=18,c="three"},{r=24,c="four"},{r=30,c="five"}}, - medium = {{r=3,c="half"},{r=6,c="one"},{r=12,c="two"},{r=18,c="three"},{r=24,c="four"},{r=30,c="five"}}, - large = {{r=3,c="half"},{r=6,c="one"},{r=12,c="two"},{r=18,c="three"},{r=24,c="four"},{r=30,c="five"}}, - huge = {{r=3,c="half"},{r=6,c="one"},{r=12,c="two"},{r=18,c="three"},{r=24,c="four"},{r=30,c="five"}}, - laat = {{r=3,c="half"},{r=6,c="one"},{r=12,c="two"},{r=18,c="three"},{r=24,c="four"},{r=30,c="five"}}, - epic = {{r=3,c="half"},{r=6,c="one"},{r=12,c="two"},{r=18,c="three"},{r=24,c="four"},{r=30,c="five"}}, - long = {{r=3,c="half"},{r=6,c="one"},{r=12,c="two"},{r=18,c="three"},{r=24,c="four"},{r=30,c="five"}}, - snail = {{r=3,c="half"},{r=6,c="one"},{r=12,c="two"},{r=18,c="three"},{r=24,c="four"},{r=30,c="five"}}, - -- Token rangeKeys (1 to 2 bands depending on use) - smokeToken = {{r=1,c="one"}}, - token = {{r=1,c="one"}}, - tokenRangeTwo = {{r=1,c="one"},{r=2,c="two"}}, - poi = {{r=3,c="one"}}, - bombCart = {{r=1,c="one"},{r=2,c="two"}}, -} - -local COHESION_RADIUS_IN_MAC = { - small = 3.531496, -- 27mm (halfCohesion_27mm OrthographicSize) - medium = 3.984252, -- 50mm - large = 4.377953, -- 70mm -} - --- Base radius (inches) from base diameter in mm. -local FIG_BASE_RADIUS_IN = { - small = 27 / 2 / 25.4, -- 0.5315" - medium = 50 / 2 / 25.4, -- 0.9842" - large = 70 / 2 / 25.4, -- 1.3779" - huge = 100 / 2 / 25.4, -- 1.9685" - laat = 120 / 2 / 25.4, -- 2.3622" - epic = 150 / 2 / 25.4, -- 2.9527" - long = 50 / 2 / 25.4, -- approx for oblong - snail = 50 / 2 / 25.4, -- ditto -} - -local function macFigBaseRadius(fig) - if not fig then return 0.5315 end - local data = fig.getTable("unitData") - if not data or not data.baseSize then return 0.5315 end - return FIG_BASE_RADIUS_IN[data.baseSize] or 0.5315 -end - --- Token base radii (inches) - measured from token edge for range bands -local TOKEN_BASE_RADIUS = { - smokeToken = 18.8 / 2 / 25.4, -- 0.370" - token = 25.1 / 2 / 25.4, -- 0.494" - tokenRangeTwo = 25.1 / 2 / 25.4, -- 0.494" - poi = 50.8 / 2 / 25.4, -- 1.000" - bombCart = 50.0 / 2 / 25.4, -- 0.984" -} - --- Maximum Move radii (inches), indexed by baseSize then speed 1..3 --- Source: ProjectorRadius from BB_MovementProjector materials (single variants) -local MAX_MOVE_RADIUS = { - small = { 4.547244, 6.515748, 8.484252}, -- 27mm - medium = { 5.669292, 7.637795, 9.606299}, -- 50mm - large = { 6.850394, 8.818897, 10.787401}, -- 70mm - huge = { 8.622047, 10.590551, 12.559055}, -- 100mm - laat = { 9.803149, 11.771653, 13.740157}, -- 120mm - epic = {11.574803, 13.543307, 15.511811}, -- 150mm - long = {13.051181, 15.019685, 16.988190}, -- oblong - snail = {14.527559, 16.496063, 18.464567}, -- snail -} - --- Deployment cell dimensions (width X, depth Z, inches). --- All cells live on a 6"x6" grid; sub-cells are halves/quarters of that cell. -local DEPLOYMENT_CELL_SIZES = { - r = {6, 6}, b = {6, 6}, -- full cell - rl = {6, 6}, bl = {6, 6}, -- large variant (also full cell) - rh = {6, 3}, bh = {6, 3}, -- horizontal half (3" deep) - rs = {3, 6}, bs = {3, 6}, -- vertical half (3" wide), x-offset +1.5 - rss = {3, 6}, bss = {3, 6}, -- vertical half (3" wide), x-offset -1.5 - rc = {3, 3}, bc = {3, 3}, -- corner quarter - rcc = {3, 3}, bcc = {3, 3}, -- opposite corner quarter -} - --- A ray hit counts as "ground" only if it is not the ignored object and not --- a transient object: anything still in motion (e.g. a movement template --- falling into place the frame the overlay spawns) or the hovering --- "Maximum Move" Windows bundle would otherwise catch the center ray and --- float the fill decal above its border ring. -local function macHitIsGround(h, ignoreObj) - local obj = h.hit_object - if obj == nil then return true end - if obj == ignoreObj then return false end - if obj.getName and obj.getName() == "Maximum Move" then return false end - local ok, v = pcall(function() return obj.getVelocity() end) - if ok and v and (math.abs(v.x) + math.abs(v.y) + math.abs(v.z)) > 0.05 then - return false - end - return true -end - -local function macRayGroundY(x, z, offset, ignoreObj) - local hits = Physics.cast({ - origin = {x, 30, z}, - direction = {0, -1, 0}, - type = 1, - max_distance = 50, - }) - for _, h in ipairs(hits) do - if macHitIsGround(h, ignoreObj) then - return h.point.y + (offset or 0.05) - end - end - return offset or 0.05 -end - -local function macBuildRect(cx, cz, hw, hd, color, thickness) - local segPerSide = 8 - local pts = {} - local corners = { - {cx - hw, cz + hd}, {cx + hw, cz + hd}, - {cx + hw, cz - hd}, {cx - hw, cz - hd}, - } - for i = 1, 4 do - local a = corners[i] - local b = corners[i % 4 + 1] - for s = 0, segPerSide - 1 do - local t = s / segPerSide - local x = a[1] + (b[1] - a[1]) * t - local z = a[2] + (b[2] - a[2]) * t - table.insert(pts, {x, macRayGroundY(x, z), z}) - end - end - local c1 = corners[1] - table.insert(pts, {c1[1], macRayGroundY(c1[1], c1[2]), c1[2]}) - return {points = pts, color = color, thickness = thickness or 0.06} -end - -local function macBuildRing(centerPos, radius, color, thickness, ignoreObj) - local nSeg = 64 - local pts = {} - for i = 0, nSeg do - local a = (i / nSeg) * 2 * math.pi - local x = centerPos.x + radius * math.cos(a) - local z = centerPos.z + radius * math.sin(a) - local hits = Physics.cast({ - origin = {x, centerPos.y + 10, z}, - direction = {0, -1, 0}, - type = 1, - max_distance = 20, - }) - local y = centerPos.y + 0.05 - for _, h in ipairs(hits) do - if macHitIsGround(h, ignoreObj) then - y = h.point.y + 0.05 - break - end - end - table.insert(pts, {x, y, z}) - end - return {points = pts, color = color, thickness = thickness or 0.05} -end - -local macBuilders = {} - -macBuilders.range = function(fig, params) - local pos = fig.getPosition() - -- Try to resolve rangeKey from params, then from the figure's script var - local rangeKey = (params and params.rangeKey) or fig.getVar("rangeKey") - local config, decalURL, maxR, br - if rangeKey and RANGE_CONFIGS[rangeKey] then - config = RANGE_CONFIGS[rangeKey] - decalURL = RANGE_DECAL_URLS[rangeKey] - maxR = RANGE_MAX_RADIUS[rangeKey] - br = TOKEN_BASE_RADIUS[rangeKey] or 0 - else - local data = fig.getTable("unitData") - local baseSize = (data and data.baseSize) or "small" - config = RANGE_CONFIGS[baseSize] or RANGE_CONFIGS.small - decalURL = RANGE_DECAL_URLS.fig_leader[baseSize] - or RANGE_DECAL_URLS.fig_leader.small - maxR = RANGE_MAX_RADIUS.fig_leader - br = macFigBaseRadius(fig) - end - - -- SWL convention: all distances are measured from the base/token edge. - - -- Vector lines (contour) - local lines = {} - for _, band in ipairs(config) do - table.insert(lines, macBuildRing(pos, band.r + br, RANGE_COLORS[band.c], 0.1, fig)) - end - - -- Decal halo (filled bands) - flat on the ground under the fig - local hits = Physics.cast({ - origin = {pos.x, pos.y + 10, pos.z}, - direction = {0, -1, 0}, - type = 1, - max_distance = 20, - }) - local groundY = pos.y - for _, h in ipairs(hits) do - if macHitIsGround(h, fig) then groundY = h.point.y; break end - end - - local effectiveMaxR = maxR + br - return { - lines = lines, - decals = { - { - name = "range_decal_" .. fig.getGUID(), - url = decalURL, - position = {pos.x, groundY + 0.02, pos.z}, -- below cohesion halo - rotation = {90, 0, 0}, - scale = {effectiveMaxR * 2, effectiveMaxR * 2, effectiveMaxR * 2}, - } - }, - } -end - -macBuilders.maxmove = function(fig, params) - local pos = fig.getPosition() - local baseSize = (params and params.baseSize) or "small" - local speed = (params and params.speed) or 1 - local radii = MAX_MOVE_RADIUS[baseSize] or MAX_MOVE_RADIUS.small - local r = radii[speed] or radii[1] - local color = {0.333, 0.800, 1.000, 0.7} - -- Base ring: small white outline matching the figure's base - -- (BB_MovementProjector renders a base ring on top of the cyan max-move). - local br = FIG_BASE_RADIUS_IN[baseSize] or FIG_BASE_RADIUS_IN.small - local baseColor = {1, 1, 1, 0.8} - - -- Ground raycast for decal position - local hits = Physics.cast({ - origin = {pos.x, pos.y + 10, pos.z}, - direction = {0, -1, 0}, - type = 1, - max_distance = 20, - }) - local groundY = pos.y - for _, h in ipairs(hits) do - if macHitIsGround(h, fig) then groundY = h.point.y; break end - end - - return { - lines = { - macBuildRing(pos, r, color, 0.1, fig), -- outer cyan max-move - macBuildRing(pos, br, baseColor, 0.06, fig), -- inner white base ring - }, - decals = { - { - name = "maxmove_decal_" .. fig.getGUID(), - url = MAX_MOVE_CYAN_URL, - position = {pos.x, groundY + 0.025, pos.z}, - rotation = {90, 0, 0}, - scale = {r * 2, r * 2, r * 2}, - } - }, - } -end - -macBuilders.deployment = function(_, params) - local pos = params.pos -- {x, y, z} cell center (after offset) - local cell = params.cell -- "r"/"b"/"rh"/... key - local size = DEPLOYMENT_CELL_SIZES[cell] or {6, 6} - local w, d = size[1], size[2] - local cx, cz = pos[1], pos[3] - local hw, hd = w / 2, d / 2 - - local isRed = cell:sub(1, 1) == "r" - local lineColor = isRed and {1, 0.15, 0.15, 0.9} or {0.15, 0.4, 1, 0.9} - local url = isRed and DEPLOYMENT_RED_URL or DEPLOYMENT_BLUE_URL - - local groundY = macRayGroundY(cx, cz, 0) - - return { - lines = { macBuildRect(cx, cz, hw, hd, lineColor, 0.08) }, - decals = { - { - name = "deployment_decal_" .. cell .. "_" .. tostring(cx) .. "_" .. tostring(cz), - url = url, - position = {cx, groundY + 0.03, cz}, - rotation = {90, 0, 0}, - scale = {w, d, 1}, - } - }, - } -end - -macBuilders.cohesion = function(fig, params) - local pos = fig.getPosition() - local data = fig.getTable("unitData") - local baseSize = (data and data.baseSize) or "small" - local r = COHESION_RADIUS_IN_MAC[baseSize] or COHESION_RADIUS_IN_MAC.small - if params and params.radius then r = params.radius end - - -- Find ground level under the fig so the flat decal sits on the table, - -- not at the fig pivot (which is above the base). - local hits = Physics.cast({ - origin = {pos.x, pos.y + 10, pos.z}, - direction = {0, -1, 0}, - type = 1, - max_distance = 20, - }) - local groundY = pos.y - for _, h in ipairs(hits) do - if h.hit_object ~= fig then - groundY = h.point.y - break - end - end - - return { - lines = { macBuildRing(pos, r, {1, 1, 1, 0.8}, 0.06, fig) }, - decals = { - { - name = "cohesion_halo_" .. fig.getGUID(), - url = COHESION_HALO_URL, - position = {pos.x, groundY + 0.04, pos.z}, - rotation = {90, 0, 0}, - scale = {r * 2, r * 2, r * 2}, - } - }, - } -end - -function macRedrawAll() - local lines, decals = {}, {} - -- Preload all texture URLs (invisible decals far below the table) so TTS - -- keeps them cached and we never get the white-square flash on respawn. - local preloadURLs = { - COHESION_HALO_URL, - RANGE_DECAL_URLS.smokeToken, - RANGE_DECAL_URLS.token, RANGE_DECAL_URLS.tokenRangeTwo, - RANGE_DECAL_URLS.poi, RANGE_DECAL_URLS.bombCart, - RANGE_DECAL_URLS.fig_leader.small, RANGE_DECAL_URLS.fig_leader.medium, - RANGE_DECAL_URLS.fig_leader.large, RANGE_DECAL_URLS.fig_leader.huge, - RANGE_DECAL_URLS.fig_leader.laat, RANGE_DECAL_URLS.fig_leader.epic, - RANGE_DECAL_URLS.fig_leader.long, RANGE_DECAL_URLS.fig_leader.snail, - MAX_MOVE_CYAN_URL, - DEPLOYMENT_RED_URL, DEPLOYMENT_BLUE_URL, - } - for i, url in ipairs(preloadURLs) do - table.insert(decals, { - name = "preload_" .. i, - url = url, - position = {0, -200 - i * 0.01, 0}, - rotation = {90, 0, 0}, - scale = {0.01, 0.01, 0.01}, - }) - end - local stale = {} - for key, entry in pairs(activeOverlays) do - local b = macBuilders[entry.type] - if b then - -- Deployment entries have no fig (params-driven). Others need a - -- live Object - drop them silently if destroyed/invalid. - local needsFig = (entry.type ~= "deployment") - if needsFig and (not entry.fig - or type(entry.fig.getPosition) ~= "function") then - stale[#stale + 1] = key - else - local ok, out = pcall(b, entry.fig, entry.params) - if ok and out then - for _, l in ipairs(out.lines or {}) do - table.insert(lines, l) - end - for _, d in ipairs(out.decals or {}) do - table.insert(decals, d) - end - else - stale[#stale + 1] = key - end - end - end - end - for _, k in ipairs(stale) do activeOverlays[k] = nil end - Global.setVectorLines(lines) - Global.setDecals(decals) -end - -function gSpawnCohesion(params) - local fig = getObjectFromGUID(params.figGUID) - if not fig then return end - activeOverlays[fig.getGUID() .. ":cohesion"] = { - type = "cohesion", fig = fig, params = params or {} - } - macRedrawAll() -end - -function gClearCohesion(params) - local fig = getObjectFromGUID(params.figGUID) - if not fig then return end - activeOverlays[fig.getGUID() .. ":cohesion"] = nil - macRedrawAll() -end - -function gToggleCohesion(params) - local fig = getObjectFromGUID(params.figGUID) - if not fig then return end - local key = fig.getGUID() .. ":cohesion" - if activeOverlays[key] then - gClearCohesion(params) - else - gSpawnCohesion(params) - end -end - --- Range polling: a slow timer (5 frames = ~12 fps) that re-draws active --- range rulers so they follow figures in real-time. Stops automatically when --- no range overlay is active anymore - avoids the overnight memory leak. -macRangePollingActive = macRangePollingActive or false - -function macRangePoll() - local hasRange = false - for _, e in pairs(activeOverlays) do - if e.type == "range" then hasRange = true; break end - end - if hasRange then - macRedrawAll() - Wait.frames(macRangePoll, 5) - else - macRangePollingActive = false - end -end - -function gSpawnRange(params) - local fig = getObjectFromGUID(params.figGUID) - if not fig then return end - activeOverlays[fig.getGUID() .. ":range"] = { - type = "range", fig = fig, params = params or {} - } - macRedrawAll() - if not macRangePollingActive then - macRangePollingActive = true - Wait.frames(macRangePoll, 5) - end -end - -function gClearRange(params) - local fig = getObjectFromGUID(params.figGUID) - if not fig then return end - activeOverlays[fig.getGUID() .. ":range"] = nil - -- Windows mode: also destroy the vanilla bundle this fig owns. It was - -- spawned in the Global scope by gRangeTrigger, so the token's own - -- exitTargetingMode/clearRangeRulers cannot reach it. - if macWinRangeGUID == params.figGUID then - pcall(clearRangeRulersOriginal) - macWinRangeGUID = nil - end - macRedrawAll() -end - -function gToggleRange(params) - local fig = getObjectFromGUID(params.figGUID) - if not fig then return end - local key = fig.getGUID() .. ":range" - if activeOverlays[key] then - gClearRange(params) - else - gSpawnRange(params) - end -end - -function gClearAllRange() - for k, e in pairs(activeOverlays) do - if e.type == "range" then activeOverlays[k] = nil end - end - macRedrawAll() -end - -function gSpawnDeployment(params) - -- params: { cell = "r" | "b" | ..., pos = {x, y, z} } - if not params or not params.cell or not params.pos then return end - local key = "deploy:" .. params.cell .. ":" - .. tostring(params.pos[1]) .. ":" .. tostring(params.pos[3]) - activeOverlays[key] = {type = "deployment", fig = nil, params = params} - macRedrawAll() -end - -function gClearAllDeployment() - for k, e in pairs(activeOverlays) do - if e.type == "deployment" then activeOverlays[k] = nil end - end - macRedrawAll() -end - -function gSpawnMaxMove(params) - local fig = getObjectFromGUID(params.figGUID) - if not fig then return end - activeOverlays[fig.getGUID() .. ":maxmove"] = { - type = "maxmove", fig = fig, params = params or {} - } - macRedrawAll() -end - -function gClearMaxMove(params) - local fig = getObjectFromGUID(params.figGUID) - if not fig then return end - activeOverlays[fig.getGUID() .. ":maxmove"] = nil - macRedrawAll() -end - -function gClearAllMaxMove() - for k, e in pairs(activeOverlays) do - if e.type == "maxmove" then activeOverlays[k] = nil end - end - macRedrawAll() -end - -function onObjectPickUp(player_color, obj) - if not obj or not obj.getGUID then return end - local guid = obj.getGUID() - local prefix = guid .. ":" - local plen = #prefix - local changed = false - for key, entry in pairs(activeOverlays) do - if key:sub(1, plen) == prefix then - -- Cohesion: static, hide during pickup, restore on drop. - -- Range: keep visible; the polling timer redraws each tick so - -- the ruler follows the figure in real-time during the drag. - if entry.type == "cohesion" then - hiddenWhilePickedUp[key] = entry - activeOverlays[key] = nil - changed = true - end - end - end - if changed then macRedrawAll() end -end - -function onObjectDrop(player_color, obj) - if not obj or not obj.getGUID then return end - local guid = obj.getGUID() - local prefix = guid .. ":" - local plen = #prefix - local changed = false - for key, entry in pairs(hiddenWhilePickedUp) do - if key:sub(1, plen) == prefix then - activeOverlays[key] = entry - hiddenWhilePickedUp[key] = nil - changed = true - end - end - if changed then macRedrawAll() end -end - -function onObjectDestroy(obj) - if not obj or not obj.getGUID then return end - local guid = obj.getGUID() - local prefix = guid .. ":" - local plen = #prefix - local changed = false - for key in pairs(activeOverlays) do - if key:sub(1, plen) == prefix then - activeOverlays[key] = nil - changed = true - end - end - for key in pairs(hiddenWhilePickedUp) do - if key:sub(1, plen) == prefix then - hiddenWhilePickedUp[key] = nil - end - end - if changed then macRedrawAll() end -end - --- Texture preload is handled by macRedrawAll which always includes all PNG --- URLs as invisible decals far below the table. No separate preload needed. - --- ============================================ --- TABLE-WIDE OVERLAY TOGGLE (Cohesion + Range + Deployment) --- One switch for the whole table: "windows" (the mod's original Projectors) --- or "mac" (the Iron Squadron overlays). Per-seat modes were dropped on --- purpose: any rendered overlay is visible to every player (TTS engine --- limitation), so one player triggering an original Projector shows it to --- the whole table anyway. The switch is the Iron Squadron button in the --- bottom-right menu: default grey = off (originals, untouched), green = on. --- ============================================ - -overlayMode = overlayMode or "windows" -- "windows" | "mac", table-wide - -function gGetMode(_) return overlayMode end -function gGetDeploymentMode() return overlayMode end - -function gCohesionTrigger(params) - if not params or not params.figGUID then return end - local fig = getObjectFromGUID(params.figGUID) - if not fig then return end - if overlayMode ~= "windows" then - gToggleCohesion({figGUID = params.figGUID}) - return - end - -- Windows mode: the vanilla Projector lives in the FIG scope (every fig - -- requires !/Cohesion), so read and clear it there. Vanilla - -- spawnCohesionRuler RESPAWNS instead of toggling, so without this a - -- second click just redrew the ruler and it could never be turned off. - -- pcall guards objects that carry no such function (e.g. a hovered - -- non-fig object), which fall back to the Mac renderer. - local ok, isOn = pcall(function() return fig.getVar("cohesionRuler") ~= nil end) - if not ok then - gToggleCohesion({figGUID = params.figGUID}) - return - end - if isOn then - pcall(function() fig.call("clearCohesionRulerOriginal", fig) end) - elseif not pcall(function() fig.call("spawnCohesionRulerOriginal", fig) end) then - gToggleCohesion({figGUID = params.figGUID}) - end -end - --- Which fig currently owns the vanilla (Windows-mode) Range bundle, so a --- second trigger on the same fig turns it off like vanilla --- showRangeOnHoveredModel does. -macWinRangeGUID = macWinRangeGUID or nil - -function gRangeTrigger(params) - if not params or not params.figGUID then return end - local fig = getObjectFromGUID(params.figGUID) - if not fig then return end - if overlayMode ~= "windows" then - gToggleRange({figGUID = params.figGUID}) - return - end - -- The vanilla bundle Range lives in the GLOBAL scope: !/RangeRulers is - -- required by Global, while figs only require !/Cohesion. Calling - -- fig.call("spawnRangeRulerOriginal", fig) therefore ALWAYS raised - -- "no such function"; the pcall swallowed it and we fell through to the - -- Mac renderer, so Windows mode silently drew Mac overlays instead of - -- the original Projector. spawnRangeRulerOriginal is the Global alias - -- set by !/RangeRulers, resolved at call time (it loads after us). - local wasOn = (macWinRangeGUID == params.figGUID) - pcall(clearRangeRulersOriginal) - macWinRangeGUID = nil - if not wasOn then - if pcall(function() spawnRangeRulerOriginal(fig) end) then - macWinRangeGUID = params.figGUID - else - gToggleRange({figGUID = params.figGUID}) - end - end -end - -function macModeToggle(_, _, _) - overlayMode = (overlayMode == "mac") and "windows" or "mac" - -- Wipe both renderers' overlays so stale visuals don't linger after the - -- toggle; each player just re-triggers their hotkey. Deployment is - -- deliberately spared: those zones are laid out once at setup and only - -- SETUP_CONTROLLER can put them back, so wiping them on a toggle click - -- would cost the table its board for a cosmetic reason. - for k, e in pairs(activeOverlays) do - if e.type == "cohesion" or e.type == "range" or e.type == "maxmove" then - activeOverlays[k] = nil - end - end - macRedrawAll() - for _, obj in ipairs(getAllObjects()) do - if obj.getVar and obj.getVar("cohesionRuler") then - pcall(function() obj.call("clearCohesionRulerOriginal", obj) end) - end - if obj.getVar and obj.getVar("rangeRuler") then - pcall(function() obj.call("clearRangeRulersOriginal", obj) end) - end - end - -- The Windows-mode Range bundle is spawned from the Global scope, which - -- getAllObjects() above does not cover. - pcall(clearRangeRulersOriginal) - macWinRangeGUID = nil - broadcastToAll( - (overlayMode == "mac") and "Iron Squadron overlays ON for the whole table." - or "Iron Squadron overlays OFF: the mod's original overlays are back.", - (overlayMode == "mac") and {0.55, 0.9, 0.6} or {0.9, 0.75, 0.55}) - macDeferRefresh() -end - -local function macFindNodeById(tree, id) - for _, node in ipairs(tree) do - if node.attributes and node.attributes.id == id then return node, tree end - if node.children then - local found, parent = macFindNodeById(node.children, id) - if found then return found, parent end - end - end - return nil, nil -end - --- UI: single Iron Squadron toggle button in the bottom-right --- legionFloatingMenu. -function macRefreshModeUI() - local tree = UI.getXmlTable() or {} - -- Drop the legacy mode-picker panel if this save still carries one. - for i = #tree, 1, -1 do - if tree[i].attributes and tree[i].attributes.id == "macModePanel" then - table.remove(tree, i) - end - end - local menu = macFindNodeById(tree, "legionFloatingMenu") - if menu and menu.children then - local isMac = (overlayMode == "mac") - local attrs = { - id = "macModeMenuButton", - onClick = "macModeToggle", - tooltip = isMac - and "Iron Squadron overlays: ON for the whole table. Click to go back to the mod's original overlays." - or "Iron Squadron overlays: OFF, the mod's original overlays are in use. Click to turn them on for the whole table.", - } - -- OFF keeps the sibling buttons' default light-grey look (Welcome, - -- Chess Clocks); ON switches to green. - if isMac then attrs.color = "#1e7a3a" end - local button = { - tag = "Button", - attributes = attrs, - children = {{ - -- White PNG sprite (CustomUIAssets "isqLogo"), tinted per - -- state: dark on the grey button, white on green. The shape - -- lives in the alpha channel, which is what makes the tint - -- work. - tag = "Image", - attributes = { - image = "isqLogo", - color = isMac and "#FFFFFF" or "#2b2b2b", - preserveAspect = "true", - raycastTarget = "false", - }, - }}, - } - local placed = false - for i, c in ipairs(menu.children) do - if c.attributes and c.attributes.id == "macModeMenuButton" then - menu.children[i] = button - placed = true - break - end - end - if not placed then - for i, c in ipairs(menu.children) do - if c.attributes and c.attributes.interactable == "false" then - menu.children[i] = button - placed = true - break - end - end - end - end - UI.setXmlTable(tree) -end - --- Defer one frame: TTS throws a UTF-8 byte-buffer encoding error if we --- rebuild the UI XML synchronously inside a click handler. pcall guards --- against any residual race. -function macDeferRefresh() - Wait.frames(function() pcall(macRefreshModeUI) end, 1) -end - --- Initial UI build, deferred + pcalled like the rest. -Wait.time(function() pcall(macRefreshModeUI) end, 2) - --- Override hotkey init functions to capture playerColor and route through --- the mode router. Defining initCohesionHotkeys/initRangebandHotkeys --- here SHADOWS the originals - when the original onLoad runs init*(), our --- versions register the hotkey instead. - -function initCohesionHotkeys() - addHotkey("Show Cohesion On Hovered Model", - function(playerColor, hoverObject, _) - if not hoverObject or not hoverObject.interactable then return end - gCohesionTrigger({ - figGUID = hoverObject.getGUID(), - playerColor = playerColor, - }) - end) -end - -function initRangebandHotkeys() - addHotkey("Show Range On Hovered Model", - function(playerColor, hoverObject, _) - if not hoverObject or not hoverObject.interactable then return end - gRangeTrigger({ - figGUID = hoverObject.getGUID(), - playerColor = playerColor, - }) - end) -end - --- Legacy global-scope wrappers (for any code that still calls these directly). --- Default to mac mode when no color context is available. -function showCohesionOnHoveredModel(hoverObject) - if not hoverObject or not hoverObject.interactable then return end - gToggleCohesion({ figGUID = hoverObject.getGUID() }) -end - -function spawnCohesionRuler(cohesionSourceObject) - if not cohesionSourceObject then return end - gSpawnCohesion({ figGUID = cohesionSourceObject.getGUID() }) -end - -function clearCohesionRuler() - for key, entry in pairs(activeOverlays) do - if entry.type == "cohesion" then activeOverlays[key] = nil end - end - macRedrawAll() -end - -function showRangeOnHoveredModel(hoverObject) - if not hoverObject or not hoverObject.interactable then return end - gToggleRange({ figGUID = hoverObject.getGUID() }) -end - -function spawnRangeRuler(rangeSourceObject, _) - if not rangeSourceObject then return end - gSpawnRange({ figGUID = rangeSourceObject.getGUID() }) -end - -function clearRangeRulers() - gClearAllRange() -end - diff --git a/mod/src/includes/RangeRulers.ttslua b/mod/src/includes/RangeRulers.ttslua index c51676e09..6df6e15a7 100644 --- a/mod/src/includes/RangeRulers.ttslua +++ b/mod/src/includes/RangeRulers.ttslua @@ -80,33 +80,3 @@ function spawnRangeRuler(rangeSourceObject, projectorBundleOverride) noRulers = false end - --- ============================================ --- Mac fallback per-seat router (appended). --- Mirrors the Cohesion pattern. See !/Overlays for the manager. --- ============================================ -spawnRangeRulerOriginal = spawnRangeRuler -clearRangeRulersOriginal = clearRangeRulers - -function spawnRangeRuler(rangeSourceObject, _) - if not rangeSourceObject then return end - Global.call("gRangeTrigger", { - figGUID = rangeSourceObject.getGUID(), - playerColor = nil, - }) -end - -function clearRangeRulers() - Global.call("gClearAllRange", {}) - -- Also run the original (destroys the bundle Object spawned in Windows - -- mode). Skip if rangeRuler was never set (pure-Mac session). - if rangeRuler ~= nil then - pcall(clearRangeRulersOriginal) - end -end - -function clearRangeRuler() - if self and self.getGUID and self.getGUID() ~= "-1" then - Global.call("gClearRange", { figGUID = self.getGUID() }) - end -end From 13bcd12cb448905b970c6194e5c31408a7132d42 Mon Sep 17 00:00:00 2001 From: Martin Pourrat Date: Fri, 14 Aug 2026 14:58:23 +0200 Subject: [PATCH 41/42] Drop what the PR no longer needs to carry The branch had accumulated three kinds of ballast that a reviewer would have to wade through before reaching the fix. Dead assets: mod/data/mac-fallback-assets held 47 files, of which the patcher references 15 (eight Projectors, five half-cohesion bundles, the logo, the 0.5 token ring). The other 32 are the decal era and the silhouette experiments: the range_fig_leader PNGs, the deployment and max-move decals, the cohesion halo, four generations of stadium and silhouette meshes, and both silhouette_mac_fallback bundles. Nothing in the chain has loaded any of them since the move to Projectors on 12 August. They remain reachable at the overlays-decals-v1 tag. Investigation notes and one-shot scripts: the retro-*.md retrospectives, design-refactor.md, SHADER_INVENTORY.md and materials-reference.md are our French working notes, and inspect_*.py, scan_bundles.py, extract_projector_specs.py, patch_cohesion_rename.py and generate_overlay_assets.py were written to answer questions that are now answered. They are archived on our side; the repair chain that stays useful lives on in tools/. Stale README: it still advertised the mirror-into-a-save-slot behaviour, removed on 11 August, and indexed the files above. Bench: 36 checks, green. Co-Authored-By: Claude Opus 5 (1M context) --- mac-patcher/.gitignore | 1 - mac-patcher/README.md | 18 +- mac-patcher/SHADER_INVENTORY.md | 59 --- mac-patcher/cahier-des-charges-overlays.md | 324 ------------- mac-patcher/design-refactor.md | 330 ------------- mac-patcher/extract_projector_specs.py | 198 -------- mac-patcher/generate_overlay_assets.py | 282 ----------- mac-patcher/inspect_cohesion.py | 83 ---- mac-patcher/inspect_externals.py | 51 -- mac-patcher/materials-reference.md | 170 ------- mac-patcher/patch_cohesion_rename.py | 81 ---- mac-patcher/patch_save_for_mac.py | 4 +- mac-patcher/retro-cohesion.md | 170 ------- mac-patcher/retro-deployment.md | 76 --- mac-patcher/retro-movement.md | 122 ----- mac-patcher/retro-range.md | 86 ---- mac-patcher/scan_bundles.py | 166 ------- .../mac-fallback-assets/cohesion_halo.png | Bin 22585 -> 0 bytes .../mac-fallback-assets/collider_null.obj | 4 - .../mac-fallback-assets/deployment_blue.png | Bin 856 -> 0 bytes .../mac-fallback-assets/deployment_red.png | Bin 856 -> 0 bytes .../mac-fallback-assets/max_move_cyan.png | Bin 4124 -> 0 bytes .../mac-fallback-assets/range_bombCart.png | Bin 12426 -> 0 bytes .../range_fig_leader_epic.png | Bin 19173 -> 0 bytes .../range_fig_leader_huge.png | Bin 18811 -> 0 bytes .../range_fig_leader_laat.png | Bin 19058 -> 0 bytes .../range_fig_leader_large.png | Bin 18753 -> 0 bytes .../range_fig_leader_long_stadium.png | Bin 19025 -> 0 bytes .../range_fig_leader_medium.png | Bin 18599 -> 0 bytes .../range_fig_leader_small.png | Bin 18475 -> 0 bytes .../range_fig_leader_snail_stadium.png | Bin 19127 -> 0 bytes mod/data/mac-fallback-assets/range_poi.png | Bin 10364 -> 0 bytes .../mac-fallback-assets/range_smokeToken.png | Bin 10364 -> 0 bytes mod/data/mac-fallback-assets/range_token.png | Bin 10364 -> 0 bytes .../range_tokenRangeTwo.png | Bin 12344 -> 0 bytes .../mac-fallback-assets/silh_exact_long_1.obj | 369 -------------- .../silh_exact_snail_1.obj | 369 -------------- .../silh_shaped_long_1.obj | 374 -------------- .../silh_shaped_snail_1.obj | 374 -------------- .../silh_vanilla_long_1.obj | 190 -------- .../silh_vanilla_long_2.obj | 190 -------- .../silh_vanilla_snail_1.obj | 190 -------- .../silh_vanilla_snail_2.obj | 190 -------- .../silhouette_mac_fallback.unity3d | Bin 10922 -> 0 bytes .../silhouette_mac_fallback_v2.unity3d | Bin 106057 -> 0 bytes .../mac-fallback-assets/stadium_long_2.obj | 456 ------------------ .../mac-fallback-assets/stadium_long_3.obj | 374 -------------- .../mac-fallback-assets/stadium_snail_2.obj | 456 ------------------ .../mac-fallback-assets/stadium_snail_3.obj | 374 -------------- 49 files changed, 9 insertions(+), 6122 deletions(-) delete mode 100644 mac-patcher/SHADER_INVENTORY.md delete mode 100644 mac-patcher/cahier-des-charges-overlays.md delete mode 100644 mac-patcher/design-refactor.md delete mode 100644 mac-patcher/extract_projector_specs.py delete mode 100644 mac-patcher/generate_overlay_assets.py delete mode 100644 mac-patcher/inspect_cohesion.py delete mode 100644 mac-patcher/inspect_externals.py delete mode 100644 mac-patcher/materials-reference.md delete mode 100644 mac-patcher/patch_cohesion_rename.py delete mode 100644 mac-patcher/retro-cohesion.md delete mode 100644 mac-patcher/retro-deployment.md delete mode 100644 mac-patcher/retro-movement.md delete mode 100644 mac-patcher/retro-range.md delete mode 100644 mac-patcher/scan_bundles.py delete mode 100644 mod/data/mac-fallback-assets/cohesion_halo.png delete mode 100644 mod/data/mac-fallback-assets/collider_null.obj delete mode 100644 mod/data/mac-fallback-assets/deployment_blue.png delete mode 100644 mod/data/mac-fallback-assets/deployment_red.png delete mode 100644 mod/data/mac-fallback-assets/max_move_cyan.png delete mode 100644 mod/data/mac-fallback-assets/range_bombCart.png delete mode 100644 mod/data/mac-fallback-assets/range_fig_leader_epic.png delete mode 100644 mod/data/mac-fallback-assets/range_fig_leader_huge.png delete mode 100644 mod/data/mac-fallback-assets/range_fig_leader_laat.png delete mode 100644 mod/data/mac-fallback-assets/range_fig_leader_large.png delete mode 100644 mod/data/mac-fallback-assets/range_fig_leader_long_stadium.png delete mode 100644 mod/data/mac-fallback-assets/range_fig_leader_medium.png delete mode 100644 mod/data/mac-fallback-assets/range_fig_leader_small.png delete mode 100644 mod/data/mac-fallback-assets/range_fig_leader_snail_stadium.png delete mode 100644 mod/data/mac-fallback-assets/range_poi.png delete mode 100644 mod/data/mac-fallback-assets/range_smokeToken.png delete mode 100644 mod/data/mac-fallback-assets/range_token.png delete mode 100644 mod/data/mac-fallback-assets/range_tokenRangeTwo.png delete mode 100644 mod/data/mac-fallback-assets/silh_exact_long_1.obj delete mode 100644 mod/data/mac-fallback-assets/silh_exact_snail_1.obj delete mode 100644 mod/data/mac-fallback-assets/silh_shaped_long_1.obj delete mode 100644 mod/data/mac-fallback-assets/silh_shaped_snail_1.obj delete mode 100644 mod/data/mac-fallback-assets/silh_vanilla_long_1.obj delete mode 100644 mod/data/mac-fallback-assets/silh_vanilla_long_2.obj delete mode 100644 mod/data/mac-fallback-assets/silh_vanilla_snail_1.obj delete mode 100644 mod/data/mac-fallback-assets/silh_vanilla_snail_2.obj delete mode 100644 mod/data/mac-fallback-assets/silhouette_mac_fallback.unity3d delete mode 100644 mod/data/mac-fallback-assets/silhouette_mac_fallback_v2.unity3d delete mode 100644 mod/data/mac-fallback-assets/stadium_long_2.obj delete mode 100644 mod/data/mac-fallback-assets/stadium_long_3.obj delete mode 100644 mod/data/mac-fallback-assets/stadium_snail_2.obj delete mode 100644 mod/data/mac-fallback-assets/stadium_snail_3.obj diff --git a/mac-patcher/.gitignore b/mac-patcher/.gitignore index 34bac69b0..ed156d277 100644 --- a/mac-patcher/.gitignore +++ b/mac-patcher/.gitignore @@ -3,4 +3,3 @@ __pycache__/ *.pyc *.bak *.bak-* -scan_bundles_*.out diff --git a/mac-patcher/README.md b/mac-patcher/README.md index 420bd3889..22166ff25 100644 --- a/mac-patcher/README.md +++ b/mac-patcher/README.md @@ -47,9 +47,8 @@ pip install -r requirements.txt python3 patch_save_for_mac.py [--reload] ``` -The patcher also mirrors the patched save into -`~/Library/Tabletop Simulator/Saves/TS_Save_N.json` (next free slot, or the -existing `SWL BETA - MAC PATCH` slot if present) so TTS picks it up in +The patcher writes only to ``. Point that at a slot under +`~/Library/Tabletop Simulator/Saves/` if you want TTS to pick it up in Games -> Save & Load. `--reload` hot-pushes the patched scripts to a running TTS instance via the @@ -64,11 +63,8 @@ fresh. Per-object wrappers are also stripped before re-injection. ## Files - `patch_save_for_mac.py` - main patcher -- `scan_bundles.py` - UnityPy scanner for the local TTS bundle cache -- `extract_projector_specs.py` - dump Projector material properties from a - bundle (used to discover the `_Arc` shader keyword for firing arc lines) -- `generate_overlay_assets.py` - regenerate the range/cohesion/etc. PNG - decals from authoritative SWL geometry -- `inspect_*.py` - debug helpers -- `retro-*.md` - retrospective notes on each subsystem rewrite -- `SHADER_INVENTORY.md` - list of custom shaders in the vanilla bundles +- `proposals-upstream.md` - the work we offered to do, for the maintainers +- `tools/` - the bundle repair chain, documented in `tools/README.md`: + build, merge the per-platform SubShaders, graft a Metal SubShader into a + 2019.1 bundle, inventory the mod's bundles, install the result into the + local TTS cache diff --git a/mac-patcher/SHADER_INVENTORY.md b/mac-patcher/SHADER_INVENTORY.md deleted file mode 100644 index 926e86db4..000000000 --- a/mac-patcher/SHADER_INVENTORY.md +++ /dev/null @@ -1,59 +0,0 @@ -# SW Legion TTS Mod — Shader Inventory - -Scan effectué le 2026-05-07 sur `~/Library/Tabletop Simulator/Mods/Assetbundles/` (40 bundles `.unity3d`). -Outil : UnityPy 1.25.0, script `scan_bundles.py`. Output brut : `scan_bundles_2026-05-07.out`. - -## TL;DR -**9 shaders custom distincts**, **tous embarqués dans le `.unity3d` qui les utilise**. Donc : -- L'astuce "Always Included Shaders" du player TTS est **non-applicable** : ces shaders ne sont pas chargés depuis le pool du player, ils vivent dans les bundles. -- Le bug magenta vient du fait que le bytecode/code source de ces shaders custom ne fonctionne plus correctement sous Unity 6 + Metal sur Mac. -- Les overlays magenta listés par Martin (cohésion, range, deployment, movement) correspondent **exactement** aux 4 shaders `BucketheadBits/Projector/*`. - -## Inventaire complet (par catégorie) - -### Shaders Projector (overlays affectés par le bug magenta) -| Shader | Materials | Bundles | -|---|---|---| -| `BucketheadBits/Projector/Movement` | `ProjectorMaterial_27mm_speed1_single`, `ProjectorMaterial_27mm_speed2_single`, `ProjectorMaterial_50mm_speed2_single` | 3 | -| `BucketheadBits/Projector/Deployment` | `Projector_Deployment_Blue` (×2), `Projector_Deployment_Red` (×2) | 4 | -| `BucketheadBits/Projector/Range` | `ProjectorMaterial_25mm_token`, `ProjectorMaterial_27mm`, `ProjectorMaterial_50mm` | 3 | -| `BucketheadBits/Projector/Cohesion` | `Cohesion_27mm` | 1 | - -→ 11 materials projector au total, 4 shaders distincts à porter en priorité. - -### Outils / autres custom -| Shader | Materials | Bundles | -|---|---|---| -| `BucketheadBits/MoveTool` | `Speed1`, `Speed2` | 2 | -| `BucketheadBits/Tokens/Lambert Channel Mask` | `unitIDtoken_1` à `unitIDtoken_10` | 10 | -| `BucketheadBits/Silhouette` | `BucketheadBits_Silhouette` | 1 | -| `BucketheadBits/Units/Color Replacer` | `Ewok_SharedMat` | 1 | -| `DWD/LightenSkybox` | `Skybox` | 1 | - -→ Le shader `Tokens/Lambert Channel Mask` correspond aux 10 unitIDtokens loggés en console par TTS lors du bug : "Shader didn't load correctly for AssetBundle material unitIDtoken_X". Donc ce shader est **explicitement confirmé cassé**. - -## Auteurs -- Préfixe **`BucketheadBits/`** sur 8/9 shaders → ancien contributeur "Buckethead". Aucun repo GitHub public trouvé sous ce handle. Possible que ce soit un handle alternatif de Tieren (crédité ailleurs comme "original mod creator"). -- Préfixe **`DWD/`** sur 1 shader (LightenSkybox) → autre auteur, juste un tint skybox. - -## Implications pour la conversation avec Ben - -1. **L'angle "Always Included Shaders" n'est pas la bonne piste** pour ce bug, parce que les shaders custom sont embarqués dans les bundles. Si Ben a essayé cette piste, c'est cohérent que ça n'ait rien donné. - -2. **Le scope minimum réaliste** : porter / remplacer ces 9 shaders sous Unity 6 (compilation Metal-compatible). Soit en partant des sources s'il les a, soit en réécrivant des équivalents stock. - -3. **Materials = 11 projectors + 10 tokens + 4 outils + 1 skybox = 26 materials affectés au total** dans 27 bundles différents. Volumétrie raisonnable si les shaders sont swappable d'un coup. - -4. **Type technique des shaders** : - - Les `Projector/*` sont des shaders Unity Projector (transparent, projection avec bandes alternées) — historiquement tricky à porter Metal. - - Le `Tokens/Lambert Channel Mask` est un shader de coloration par canaux (R/G/B/A) — utilisé pour appliquer la couleur du joueur sur un mesh à canaux. Classique mais codé custom. - - Les autres (MoveTool, Silhouette, Color Replacer, LightenSkybox) sont des shaders d'effets simples. - -## Sources non-trouvées -- Aucun repo public sous `swlegion`, `swlegion-dev`, `matanlurey`, `halestom15`, `Buckethead` ne contient les sources Unity de ces shaders. -- Le projet Unity vit donc en privé sur la machine d'un contributeur (probablement Decaf ou Ben). - -## Prochaine étape -Attendre Ben pour confirmer si les sources sont disponibles. Cet inventaire répond déjà partiellement à ses questions 1 et 2 : -- Q1 ("custom shaders updated or just retargeted ?") : on sait maintenant exactement ce qu'il faut updater. -- Q2 ("which shaders are referenced ?") : liste complète ci-dessus. diff --git a/mac-patcher/cahier-des-charges-overlays.md b/mac-patcher/cahier-des-charges-overlays.md deleted file mode 100644 index ed386a64e..000000000 --- a/mac-patcher/cahier-des-charges-overlays.md +++ /dev/null @@ -1,324 +0,0 @@ -# Cahier des charges fonctionnel, overlays Iron Squadron - -Écrit le 12 août 2026, après la validation en jeu des projectors bi-plateforme. -À ce moment-là plus rien du fix de rendu ne passe par le Lua : notre couche devient un -module de confort, et on veut la reposer sur de vrais Projectors au lieu de décals plats. -Ce document décrit **ce que chaque objet doit faire**, pour que le changement de rendu ne -perde rien en silence, et pour servir de liste de recette en jeu après. - -**Périmètre** : les **trois** familles qui passent par le toggle, à savoir **Range**, -**Cohésion** et **MaxMove**. Les silhouettes, les tokens de numéro d'unité et **les -zones de déploiement** en sont **sortis** (arbitrage Martin, 12/08) : leurs bundles sont -réparés, donc le vanilla suffit et le contournement Lua n'a plus lieu d'être. Le code -correspondant a été retiré du patcher et de `mod/src` le soir même. **La section 5 -ci-dessous est donc caduque**, elle est conservée pour mémoire du comportement retiré. - -**Source** : lecture du code, pas de la mémoire. Branche `mac-projector-fallback` pour -`mod/src`, et `mac-patcher/patch_save_for_mac.py` pour le moteur à jour. Les deux ne -disent pas la même chose partout, voir la section 9. - -## 0. Vocabulaire et architecture - -**Mode** : `overlayMode`, une seule valeur pour toute la table, `"windows"` (rendu -d'origine) ou `"mac"` (le nôtre). Lu par `gGetMode` et `gGetDeploymentMode`. Le per-seat -a été abandonné pour une raison structurelle : le Lua TTS ne tourne que chez l'hôte, et -tout overlay rendu est visible de tous les joueurs. - -**Registre** : `activeOverlays`, une entrée par overlay actif, clé -`":"` pour range, cohesion et maxmove, et -`"deploy:::"` pour le déploiement, qui n'a pas de figurine. - -**Les quatre familles** : - -| famille | porte sur | suit la figurine | déclenché par | -|---|---|---|---| -| range | figurine ou token | oui, en continu | bouton RANGE, raccourci de survol, bouton R d'un token | -| cohesion | figurine meneuse d'unité | oui, y compris pendant le drag | bouton COHESION, raccourci de survol | -| maxmove | figurine meneuse d'unité | **non**, ancré au départ | boutons MOVE, DEPLOY, 1, 2, 3, F, B, L, R | -| deployment | cellules de la table | sans objet | SETUP_CONTROLLER | - -## 1. Global, le gestionnaire (`StarWarsLegion.lua` + `!/Overlays`) - -**Rôle** : détient le registre, le mode, la boucle de suivi, et l'unique point de rendu. - -**API appelée par les objets** - -| fonction | effet attendu | -|---|---| -| `gRangeTrigger{figGUID}` | allume ou éteint la range de cette figurine, en respectant le mode | -| `gSpawnRange` / `gClearRange` / `gToggleRange` | manipulation directe d'une entrée range | -| `gCohesionTrigger{figGUID}` | idem pour la cohésion | -| `gSpawnCohesion` / `gClearCohesion` / `gToggleCohesion` | idem | -| `gSpawnMaxMove{figGUID, baseSize, speed}` | pose le gabarit de mouvement maximal | -| `gClearMaxMove{figGUID}` | retire celui de cette unité **seulement** | -| `gSpawnDeployment{cell, pos}` / `gClearAllDeployment` | zones de déploiement | -| `gGetMode` / `gGetDeploymentMode` | lisent `overlayMode` | - -**Raccourcis clavier** (`StarWarsLegion.lua`, lignes 603 et 614) - -1. « Show Range On Hovered Model » : `showRangeOnHoveredModel(hoverObject)`. Sémantique - vanilla conservée : survoler à nouveau le **même** objet éteint, via la comparaison - avec `selectedUnitObj`. -2. « Show Cohesion On Hovered Model » : `showCohesionOnHoveredModel(hoverObject)`, même - sémantique. -3. Le raccourci de range force le rendu « figurine meneuse » à toutes ses bandes, via - `params.forceFigMode`, même si l'objet survolé porte un `rangeKey`. - -**Boucle de suivi** `macRangePoll`, toutes les 5 images - -- Ne reconstruit **que** si une figurine suivie a réellement bougé, seuil 0,01 en - position et 0,5 degré en lacet. Sans ce test, le suivi faisait chuter la fréquence - d'affichage sur les figurines immobiles. -- S'arrête toute seule quand plus rien n'est suivi, pas de fuite. -- Ne suit que `range` et `cohesion`. **`maxmove` ne doit jamais être suivi.** - -**Nettoyage automatique** - -- `onObjectDestroy` purge toutes les entrées préfixées par le GUID de l'objet détruit. -- Une entrée dont la figurine n'est plus valide est éliminée au redessin suivant. - -**Basculement de mode** `macModeToggle` - -- Inverse `overlayMode`, efface les overlays des **deux** moteurs, puis rafraîchit le - bouton. La range vanilla vit dans le scope Global et n'est pas couverte par - `getAllObjects()`, elle doit être effacée explicitement. -- Le bouton vit dans `legionFloatingMenu`, gris par défaut comme ses voisins Welcome et - Chess Clock, vert à l'état actif. - -## 2. Order Token (`a57c41`) - -L'objet le plus chargé : il porte trois des quatre familles. - -### Bouton COHESION, `toggleCohesionRuler(_, playerColor)` - -| | comportement attendu | -|---|---| -| garde | ne fait rien si `selectedUnitObj` est nil | -| allumage | `gClearCohesion` **d'abord**, puis `gCohesionTrigger` | -| pourquoi le clear d'abord | `gCohesionTrigger` bascule par GUID. Un overlay laissé par le raccourci de survol faisait que le premier clic du bouton **éteignait** au lieu d'allumer | -| extinction | passe par le même déclencheur | - -### Bouton RANGE, `targetingMode(_, playerColor)` - -| | comportement attendu | -|---|---| -| garde | ne fait rien si `selectedUnitObj` est nil | -| allumage | `exitAttackMode`, `highlightEnemies`, puis `gClearRange` et `gRangeTrigger` | -| extinction | `gClearRange` **puis** `exitTargetingMode` | -| pourquoi le clear à l'extinction | `exitTargetingMode` et `clearRangeRulers` n'atteignent que la règle vanilla. Sans ce clear, nos anneaux restaient affichés en position OFF | - -### Chaîne d'attaque, `attackMode` — ROUTÉE, mais en attente de remplacement - -⚠ **La fonctionnalité elle-même est périmée.** Arbitrage Martin, 14/08 : elle date -de la V1 du jeu, elle a trois ans et elle n'est plus juste en V2. Ce qui suit est -un **bouchon** posé le temps qu'un outil V2 la remplace, pas une conception. Si on -y revient, ce sera pour la mettre à la V2 ou la retirer — lot « fine tuning V2 ». - -**Ce qui n'allait pas** : `ATTACK` mène à `attack()` puis `attackMode()`, qui -appelait le `spawnRangeRuler` **vanilla** du scope de l'Order Token. En mode Iron -Squadron l'attaque posait donc quand même la règle du mod. Et les sorties de ce -chemin — `exitTargetingMode`, `exitAttackMode`, `clearTemplates` — n'effaçaient -que le vanilla, jamais `activeOverlays` : allumer RANGE puis attaquer laissait -**deux règles** à l'écran. - -| | comportement attendu | -|---|---| -| allumage | `exitTargetingMode`, `highlightEnemies`, puis `gClearRange` et `gRangeTrigger` sur `selectedUnitObj` — même schéma que le bouton RANGE | -| extinction | `exitTargetingMode`, qui efface les deux moteurs | -| les trois effaceurs | `exitTargetingMode`, `exitAttackMode` et `clearTemplates` appellent `gClearRange` en plus de leurs `pcall` d'origine | -| où c'est défini | dans `ORDER_TOKEN_BUTTON_OVERRIDES`, **pas** dans le bloc Cohésion : celui-là est ajouté en dernier, donc c'est lui qui gagne | -| ⚠ interdit maintenu | **on ne surcharge toujours pas** `spawnRangeRuler` / `clearRangeRulers` sur l'Order Token. On redéfinit les appelants, jamais l'API de portée | - -**Couverture** : scénario 5d du banc `harness_projectors.py`, qui charge le bloc -du patcher dans un environnement bouchonné où `spawnRangeRuler` vanilla lève une -erreur — si le routage régresse, le banc tombe au lieu de passer. - -### Boutons de mouvement, famille MaxMove - -Chaînes : `MOVE` vers `initMove` vers `moveUnit(false)`, `DEPLOY` vers `initDeploy` vers -`moveUnit(true)`, et `1` / `2` / `3` vers `changeSpeed1..3` qui appellent `clearTemplates` -puis `moveUnit()` **sans argument**. - -| | comportement attendu | -|---|---| -| condition de pose | `isDeploy ~= true`, condition permissive qui couvre nil **et** false. Une condition `isDeploy == false` raterait les appels des boutons de vitesse, qui n'ont pas d'argument. C'est le bug du « fill décalé au premier spawn » | -| ancrage | position **et** lacet capturés au moment de la pose. Le gabarit **ne suit pas** la figurine qui glisse vers sa destination. Le lacet compte pour les socles oblongs, dont l'anneau de base doit garder son orientation pendant que la figurine pivote | -| capture du joueur | chaque bouton stocke `playerColor` dans `macActivePlayerForMove`, hérité du per-seat. Sans objet depuis que le mode est global, à retirer un jour | -| nettoyage | `clearMovementTemplates` détruit `templateA`, `templateB`, l'objet `maxMoveTemplate` du mode vanilla, **et** appelle `gClearMaxMove` pour **cette unité seulement** | -| ⚠ portée du nettoyage | ne **jamais** revenir à un effacement global : `gClearAllMaxMove` supprimait les anneaux des autres tokens quand deux joueurs avaient MOVE ouvert en même temps | - -### Filtre de sol partagé, `macHitIsGround` - -Utilisé sur les six sites de lancer de rayon. Ignore les figurines, les objets en -mouvement, et le bundle nommé « Maximum Move » qui plane à +20 en mode vanilla. -Ce filtre **disparaît** avec les décals, voir section 8. - -## 3. Unit Leader (`99f1c8`) et l'include `!/Cohesion` - -**Rôle** : la figurine meneuse d'unité porte la cohésion. L'Order Token et le raccourci -de survol l'appellent tous les deux. - -**Vanilla** : `spawnCohesionRuler` choisit le bundle selon `unitData.baseSize` parmi -`small` (27 mm), `medium` (50 mm) et `large` (70 mm), pose un `Custom_AssetBundle` 20 -unités au-dessus de la figurine, à l'échelle 0 pour cacher la boîte TTS sans gêner le -Projector, verrouillé, sans gravité, nommé « Cohesion Ruler ». - -**Iron Squadron** - -| | comportement attendu | -|---|---| -| ⚡ suivi pendant le drag | la cohésion **reste visible et suit la figurine pendant qu'on la déplace**, comme la range. Arbitrage du 11/08, contraire au vanilla qui l'efface au ramassage | -| mise en œuvre | `gClearCohesion` **ignore** la demande tant que `fig.held_by_color` est vrai. Le seul appelant dans cet état est le `onPickedUp` vanilla | -| mode vanilla : toggle et non respawn | `spawnCohesionRuler` d'origine **respawne** au lieu de basculer. Sans interception, un deuxième clic la redessinait et elle ne s'éteignait jamais. On lit `fig.getVar("cohesionRuler")` pour connaître l'état réel | -| garde | l'objet survolé peut ne pas être une figurine et n'avoir aucune de ces fonctions. Le `pcall` retombe alors sur notre moteur | - -**❓ Arbitrage ouvert, constaté au banc le 13/08 : les socles sans bundle de cohésion.** -`getCohesionLinks()` ne connaît que `small`, `medium` et `large`. Pour `huge`, `long`, -`laat`, `epic` et `snail`, le vanilla **ne dessine rien** et le moteur Projectors fait -pareil, donc on est à parité. Mais l'ancien moteur à décals retombait sur le rayon -`small` et dessinait quelque chose. Le trou compte surtout pour les **socles oblongs**, -dont les unités ont plusieurs figurines et donc une vraie cohésion à mesurer. Trois -issues : rester au vanilla, réétirer un bundle existant, ou refabriquer un anneau -oblong. **Non tranché.** - -## 4. Les tokens à `rangeKey`, et le Bomb Cart - -**Objets concernés**, 19 fichiers plus le Bomb Cart, tous via `!/TokenWithRangeRuler` ou -un `require('!/RangeRulers')` direct : - -| `rangeKey` | objets | rendu attendu | -|---|---|---| -| `token` | Objectif et ses 4 états, Condition et ses 5 états, Cad Bane (3), Charge à protons, Complete the Mission | 1 anneau, portée 1, socle 25,1 mm | -| `smokeToken` | Fumée | 1 anneau, portée 1, socle 18,8 mm | -| `tokenRangeTwo` | Graffiti | 2 anneaux, portées 1 et 2 | -| `poi` | POI | 1 anneau à 3 pouces, portée 0,5, socle 50,8 mm soit un rayon de 1,000 pouce | -| `bombCart` | Bomb Cart | 2 anneaux, portées 1 et 2, socle 50 mm | - -**Deux rendus différents selon le déclencheur.** Le bouton R d'un token rend **son** -anneau, celui de sa fiche ci-dessus. Le **raccourci de survol**, lui, force le rendu -« figurine meneuse » à toutes ses bandes via `forceFigMode`, et le dimensionne avec le -socle équivalent le plus proche, pour que le joueur voie ce que verrait une unité de -cette empreinte : - -| token | socle équivalent au survol | -|---|---| -| Fumée, Objectif, Condition, Graffiti, Cad Bane, Charge à protons | `small` (27 mm) | -| **POI**, Bomb Cart | `medium` (50 mm) | - -**Interface** : deux boutons « R » identiques, l'un à la rotation 0 et l'autre à 180, -pour que le token soit utilisable sur ses deux faces. État booléen local `rangeOn`. -`onDestroy` efface la règle. - -**Comportement attendu** - -| | | -|---|---| -| mode vanilla | délègue à la fonction d'origine **aliasée avant surcharge**, pour que le token garde **son** bundle. Sans cet alias le token recevrait le bundle de figurine meneuse, ou rien du tout | -| mode Iron Squadron | bascule via `gClearRange` et `gRangeTrigger`, et tient `rangeOn` à jour | -| dimensionnement | la famille vient de `rangeKey`, lu sur la variable de l'objet | - -**⚠ Interdit, à ne jamais réintroduire** : surcharger `spawnRangeRuler`, -`clearRangeRulers` ou `clearRangeRuler` **sur les scripts de tokens**. Ça produisait un -plantage TTS reproductible sur Mac, dans le ramasse-miettes Mono, quand le raccourci -d'une figurine posait la règle vanilla. Le routage de la range passe par Global, pas par -les tokens. Le seul alias autorisé sur ces objets est `clearRangeRulersOriginal`, dont le -basculement de mode a besoin. - -## 5. SETUP_CONTROLLER (`1cb552`), zones de déploiement — CADUQUE - -⚠ **Sorti du toggle le 12/08 au soir.** `spawnBoundaryCell` et `clearDeploymentBoundary` -sont revenus au vanilla exact dans `mod/src`, et le patcher n'injecte plus rien ici : les -zones se posent comme dans le mod d'origine, sur les deux plateformes, leur bundle étant -réparé. La section reste pour mémoire de ce que faisait le double chemin. - -**Rôle** : pose les cellules de la zone de déploiement d'une mission. - -| | comportement attendu | -|---|---| -| point de branchement | `spawnBoundaryCell(cell, x, z)`, après le calcul de position, sur `gGetDeploymentMode` | -| mode vanilla | pose un `Custom_AssetBundle` nommé « Deployment Boundary », verrouillé, échelle 0, orienté par `deployRotations[cell]` | -| mode Iron Squadron | `gSpawnDeployment{cell, pos}` | -| nettoyage | `clearDeploymentBoundary` appelle `gClearAllDeployment` **d'abord**, puis détruit les objets nommés « Deployment Boundary » de la zone de bataille | -| couverture | les missions d'après mars (Cauldron, Contact Contact!, Outflank, Payload) sont **déjà couvertes**, matrices en cellules `r` et `b` plus inversion bleue, spawner unique routé. Rien à convertir | - -## 6. Les projectors qui ne passent PAS par le toggle - -Deux entrées du menu du GAME_CONTROLLER (`623b03`) posent des Projectors sans jamais -consulter `gGetMode`. Ils sont hors périmètre, mais il faut savoir qu'ils existent, sinon -on croit que le toggle couvre tous les projectors du mod. - -| entrée de menu | fonction | objet posé | bundle | état sur Mac | -|---|---|---|---|---| -| « Toggle Poi Guide » | `togglePoiGuide` | « Poi Guide », posé en `{8, 30, 0}` | `projector_poiguide` | **n'a jamais été cassé** : pas de shader custom | -| « Toggle Masks : Mid » et ses variantes gauche et droite | `toggleMaskMid` / `Right` / `Left` puis `placeMask(x, z)` | « Masking Boundary », 4 par appel, posés en y = 75 | `projector_masking_3x3` | **était magenta, réparé par le bundle bi-plateforme** | - -Ces deux familles servent à la **création de cartes**, pas au jeu. Elles tiennent leur -propre état, `existingPoiGuide` et la table `existingMasks`, et leur propre nettoyage, -`clearMasks`. Elles ne sont balayées par aucune des deux fonctions de la section suivante. - -**C'est la démonstration en miniature de la direction générale** : le masking était cassé -sur Mac, personne n'a jamais écrit une ligne de Lua pour lui, et il est réparé par le seul -remplacement de son bundle. - -## 7. Les balayeuses par nom, et pourquoi elles comptent - -Deux fonctions détruisent des objets **par leur nom** : - -- `standbyTokens` (`StarWarsLegion.lua`) : « Cohesion Ruler », « Movement Template », - « Range Ruler », « Deployment Boundary » ; -- `removeLockedRulers` (`GAME_CONTROLLER.623b03`) : « Cohesion Ruler » et « Range Ruler ». - -**⚠ Conséquence directe du passage aux Projectors.** Aujourd'hui nos overlays sont des -lignes et des décals, sans objet dans la scène : les deux balayeuses ne les voient pas, -et tout notre nettoyage passe par les `gClear*`. Dès qu'on posera de vrais objets -Projector, ils deviendront balayables par nom. C'est à décider explicitement, pas à -subir : soit on les nomme comme le vanilla et on hérite du nettoyage gratuitement, soit -on les nomme autrement et on garde la main. Le piège est de les nommer par accident. - -## 8. Ce qui disparaît avec les décals - -Tout ceci n'existe que parce qu'un décal est plat et ne sait pas épouser le relief. Un -Projector drape et suit tout seul, donc le changement **supprime** du code : - -- `macRayGroundY` et les lancers de rayon au sol, 64 par anneau, 32 par calotte de stade ; -- `macBuildRect`, `macBuildRing`, `macBuildStadium`, toute la géométrie à la main ; -- le cache de géométrie par entrée, qui n'existait que pour ne pas refaire 65 lancers de - rayon par image sur les overlays immobiles ; -- la coalescence du redessin, report d'une image plus signature triée, qui évitait de - reprojeter les décals et faisait sautiller les ombres ; -- le préchargement des PNG en décals invisibles sous la table, contre le flash de carré - blanc au respawn ; -- le filtre `macHitIsGround` ; -- la boucle `macRangePoll`, puisque le Projector vanilla suit déjà nativement. - -**⚠ Deux dépendances cachées à traiter avant de supprimer** - -1. Le **MaxMove ancré** (section 2) dépend du fait que rien ne le fasse suivre. Un - Projector suit son parent par nature : il faudra le poser **détaché**, à la position et - au lacet capturés. -2. Les **socles oblongs** sont aujourd'hui rendus en stade, rectangle plus deux calottes, - avec le lacet de la figurine. Le vanilla a ses propres bundles oblongs, désormais - réparés. À vérifier en jeu : est-ce qu'ils suffisent, ou est-ce qu'on garde notre - géométrie. - -## 9. Les deux divergences source contre patcher, à trancher - -Le moteur du patcher et la source de la branche ne disent pas la même chose. Le patcher -est celui qui a été validé en jeu. - -**Divergence 1, la plus grave.** `mod/src/includes/RangeRulers.ttslua` surcharge -`spawnRangeRuler`, `clearRangeRulers` et `clearRangeRuler` sur tous les objets qui -incluent le fichier, donc sur les 20 tokens. C'est **exactement le motif que le patcher -interdit** dans un commentaire « HISTORY, do not re-introduce », pour cause de plantage -TTS Mac reproductible. Le patcher, lui, n'y pose qu'un alias. La source de la branche -porte donc un plantage latent, et un backport naïf le ferait remonter. - -**Divergence 2.** La source appelle `gClearAllRange` et `gClearAllMaxMove`, qui existent -dans `Overlays.ttslua` mais **pas** dans le moteur du patcher, où l'effacement global de -MaxMove a été délibérément remplacé par un effacement ciblé sur l'unité, parce qu'il -supprimait les anneaux des autres joueurs. Ces appels sont donc soit sans effet, soit -porteurs du bug déjà corrigé. - -**Conséquence pratique** : le backport ne doit pas se faire dans le sens qu'on croyait. -Ce n'est pas « compléter la source avec ce que le patcher a en plus », c'est **aligner la -source sur le patcher**, y compris en retirant des surcharges qu'elle porte en trop. diff --git a/mac-patcher/design-refactor.md b/mac-patcher/design-refactor.md deleted file mode 100644 index a94b2d03a..000000000 --- a/mac-patcher/design-refactor.md +++ /dev/null @@ -1,330 +0,0 @@ -# Design refactor — Overlays Projector SWL TTS (Mac/Unity 6) - -**Status** : draft 15 mai 2026. Spec pour le patch event-driven hybride (decals plats + vector lines drapants). Base : 4 retro-*.md + materials-reference.md + shaders Allen White lus. - -## 1. Contexte (résumé exécutif) - -Le passage du player TTS à Unity 6 a strippé les variants Standard receiver des Projectors legacy. Sur Mac, **tous les overlays Projector du mod SWL s'affichent en magenta** : Cohesion Ruler, Range Ruler, Maximum Move, Deployment Boundary. Validation empirique session 14-15 mai : aucun fix côté bundle/shader ne marche (le strip est player-side TTS U6). Fix Berserk = ticket à ouvrir mais sans garantie de calendrier. - -**Solution mod-side validée** : remplacer le pattern Custom_AssetBundle (Projector) par un combo **Decal plat (PNG hébergé) + Vector lines (drapant via raycast)** orchestré par un manager Global event-driven. - -## 1bis. Fallback per-seat avec auto-test au boot - -Le refactor ne **remplace pas** le Projector legacy, il l'**augmente** d'un fallback per-seat. Chaque joueur a un compat flag détecté au boot, et le rendu s'adapte : - -- **Seats non-Mac** (TTS U6 OK) → voient le **Projector legacy** (rendu original préservé) -- **Seats Mac** (bug magenta) → voient le **patch hybride** (decal + vector lines) - -Quand Berserk corrigera le bug, l'auto-test au boot suivant désactivera le compat pour les seats Mac → retour automatique au comportement legacy, zéro action utilisateur. - -### 1bis.1 État par-seat (Global script) - -```lua -compatBySeat = {} -- {Red=true|false, Blue=true|false, ...} true = Mac/needs patch - -function onLoad(script_state) - if script_state ~= "" then - compatBySeat = JSON.decode(script_state) or {} - end - testCompatForAllSeated() -end - -function onSave() - return JSON.encode(compatBySeat) -end - -function getMacSeats() - local out = {} - for color, isMac in pairs(compatBySeat) do - if isMac then table.insert(out, color) end - end - return out -end - -function getNonMacSeats() - local out = {} - for color, isMac in pairs(compatBySeat) do - if not isMac then table.insert(out, color) end - end - return out -end -``` - -### 1bis.2 Test compat au boot - -```lua -function testCompatForAllSeated() - for _, player in pairs(Player.getPlayers()) do - if player.seated then - offerCompatTest(player) - end - end -end - -function offerCompatTest(player) - -- Spawn un canary Projector en zone hors-jeu (sous la table) - local canary = spawnObject({ - type="Custom_AssetBundle", - position={-50, -10, -50}, - scale={0,0,0} - }) - canary.setCustomObject({assetbundle = COHESION_27MM_URL}) - - -- Wait quelques secondes le temps que le bundle charge - Wait.time(function() - -- UI popup pour ce joueur uniquement - player.broadcast("Test rendu : cliquez sur ce que vous voyez sur le canary (Y=-10)") - -- Buttons "Couleurs OK" et "Magenta/rose" - -- onClick stocke compatBySeat[player.color] = true|false - -- destruct canary - end, 3) -end -``` - -### 1bis.3 Spawn d'un overlay (pattern unifié) - -```lua -function spawnOverlay(type, fig, params) - local macSeats = getMacSeats() - local nonMacSeats = getNonMacSeats() - local entry = {type=type, fig=fig, params=params, objects={}} - - -- 1. Projector legacy pour les seats non-Mac - if #nonMacSeats > 0 then - local projector = spawnObject({type="Custom_AssetBundle", ...}) - projector.setCustomObject({assetbundle = bundleURLs[type][fig.baseSize]}) - projector.setLock(true) - projector.setName(type .. "_legacy") - if #macSeats > 0 then projector.setInvisibleTo(macSeats) end - entry.objects.projector = projector - end - - -- 2. Custom_Tile (PNG plat) pour les seats Mac - if #macSeats > 0 then - local tile = spawnObject({type="Custom_Tile", position=fig.pos+Y0.1, scale=...}) - tile.setCustomObject({image = pngURLs[type][fig.baseSize]}) - tile.setLock(true) - tile.setName(type .. "_patch") - if #nonMacSeats > 0 then tile.setInvisibleTo(nonMacSeats) end - entry.objects.tile = tile - end - - -- 3. Vector lines (drape relief) pour les seats Mac - if #macSeats > 0 then - entry.lines = buildVectorLines(type, fig, params, macSeats) - -- ajoutées au batch global - end - - activeOverlays[fig.getGUID() .. ":" .. type] = entry - redrawAll() -end -``` - -### 1bis.4 Bug Berserk fix → reset auto - -Quand Berserk corrigera les variants Standard receiver dans le player TTS U6 : -- Au prochain boot de partie, `testCompatForAllSeated` re-run pour chaque seat -- Les Mac users verront maintenant le canary correctement → cliquent "Couleurs OK" → `compatBySeat[color] = false` -- Le patch ne s'active plus pour eux, comportement legacy restauré -- Aucun changement de code requis côté mod - -**Re-test manuel** : un bouton "Re-test compatibility" dans l'UI Notes du mod permet de forcer un nouveau test à tout moment (utile si le user veut vérifier après une mise à jour TTS). - -### 1bis.5 Incertitudes à valider empiriquement au POC - -| Incertitude | Plan B si KO | -|---|---| -| `Object.setInvisibleTo` cache-t-il le **rendu de la projection** d'un Projector ou seulement le GameObject parent ? | Si KO : si au moins 1 Mac seat présent, on ne spawn PAS le Projector du tout (tout le monde voit le patch — compromis : 1 Mac dans la partie = tout le monde adopte le rendu patch) | -| `Global.setDecals()` supporte-t-il un filtre `players` per entry ? | Si KO : utiliser `Custom_Tile` Objects (déjà ce qu'on a au-dessus, avec `setInvisibleTo`). Plus propre et déjà compatible per-seat | - -À tester en début de phase d'implémentation, avant de pousser tout le code. - -## 2. Architecture event-driven (manager Global) - -### 2.1 État global unique - -```lua --- mod/src/includes/Overlays.ttslua (nouveau) -local activeOverlays = {} -- clé = "{guid}:{type}" → {type, fig, params} -local hiddenWhilePickedUp = {} -- buffer pour les overlays cachés temporairement -``` - -### 2.2 API publique unifiée - -```lua --- Spawn / clear par type, scopé à une fig -function spawnOverlay(type, fig, params) -function clearOverlayForFig(type, fig) -function clearAllOverlays() -- reset complet - --- Adapters pour conserver l'API existante des callers -function spawnCohesionRuler(fig) -- → spawnOverlay("cohesion", fig, {}) -function clearCohesionRuler() -- → clearOverlayForFig("cohesion", self) -function spawnRangeRuler(fig, override) -- → spawnOverlay("range", fig, {override=override}) -function clearRangeRulers() -- → clearOverlayForFig("range", selectedUnitObj) --- etc. -``` - -### 2.3 Event handlers (Global) - -```lua -function onObjectPickUp(player_color, obj) - -- buffer tous les overlays attachés à obj puis les retirer du draw - hidePickedUp(obj) - redrawAll() -end - -function onObjectDrop(player_color, obj) - -- restaurer les overlays de obj depuis le buffer - restorePickedUp(obj) - redrawAll() -end - -function onObjectDestroy(obj) - -- nettoyage définitif - purgeForFig(obj) - redrawAll() -end -``` - -### 2.4 Rendu unique par tick d'event - -```lua -function redrawAll() - local lines, decals = {}, {} - for _, entry in pairs(activeOverlays) do - local l, d = builders[entry.type](entry.fig, entry.params) - for _, line in ipairs(l) do table.insert(lines, line) end - for _, decal in ipairs(d) do table.insert(decals, decal) end - end - Global.setVectorLines(lines) - Global.setDecals(decals) -end -``` - -**Important** : `setVectorLines` et `setDecals` sont des **singletons** côté TTS — chaque appel remplace toute la collection. D'où le manager global qui agrège. - -## 3. Spec par overlay - -### 3.1 Cohesion - -| Composant | Détail | -|---|---| -| Trigger spawn | Hotkey "Show Cohesion On Hovered Model" / bouton COHESION Order Token / dropCoroutine post-mouvement (`moveState=true`) | -| Trigger clear | Mêmes triggers (toggle) + onPickedUp (auto) + standby/reload globaux | -| Decal PNG | `cohesion_halo.png` — gradient radial blanc fade depuis le centre, fond transparent, 512×512px | -| Decal params | `position = fig.pos + Y0.1`, `rotation = (90, 0, 0)` (face vers le haut), `scale = (baseRadius+1, baseRadius+1, baseRadius+1) × 2` | -| Vector line | 1 cercle filaire blanc à `r = base_radius + 0.5"` du centre, drapé par raycast 32 segments | -| Couleur | #FFFFFF α=0.6 | - -API conservée : `showCohesionOnHoveredModel`, `spawnCohesionRuler`, `clearCohesionRuler`. Compatible avec les 3 sites de require existants (Global, Unit_Leader, Order_Token) car redirigés vers le manager global. - -### 3.2 Range Ruler - -| Composant | Détail | -|---|---| -| Trigger spawn | Hotkey "Show Range On Hovered Model" / bouton RANGE Order Token (targetingMode/attackMode) / bouton R sur POI/tokens | -| Trigger clear | Mêmes triggers (toggle) + clearTemplates (post-drop mouvement) + exit modes | -| Decal PNG | `range_bands.png` (universel) — 4 anneaux concentriques à 6/12/18/24 inches relatifs, couleurs jaune/orange/rouge/magenta foncé, fond transparent, 1024×1024px | -| Decal params | `position = fig.pos + Y0.1`, `scale = (60, 60, 60)` (couvre 24" de rayon + marge) | -| Vector lines | 4 cercles filaires aux rayons absolus **6", 12", 18", 24"** du centre, mêmes couleurs que les bandes du PNG | -| Couleur (par anneau) | R1 #FFC300, R2 #FF7500, R3 #FF1400, R4 #C20042 (alpha 0.6 sur les lignes) | -| Variantes | Tokens (smokeToken/token/tokenRangeTwo/bombCart/POI) → moins d'anneaux (1 ou 2), PNG distincts ou même PNG avec scale ajusté | - -API conservée : `showRangeOnHoveredModel`, `spawnRangeRuler(fig, override)`, `clearRangeRuler/clearRangeRulers`. - -Pour les variantes, le `override` permet de passer un type explicite (`"smokeToken"`, `"poi"`, etc.) au lieu du baseSize de la fig. - -### 3.3 Maximum Move - -| Composant | Détail | -|---|---| -| Trigger spawn | Lors du clic sur bouton speed (1/2/3) sur Order Token (flow mouvement) | -| Trigger clear | clearMovementTemplates (drop final) | -| Decal PNG | `max_move_disk.png` — disque plein bleu ciel #55CCFF α=0.48, fond transparent, 512×512px | -| Decal params | `position = fig.pos + Y0.1`, `scale = ProjectorRadius × 2` selon (baseSize, speed) | -| Vector line | 1 cercle filaire bleu ciel au rayon = ProjectorRadius (drape relief) + 1 anneau base blanc fin à r = baseRadius + 0.5" | -| Couleur | Cercle principal #55CCFF α=0.6, anneau base #FFFFFF α=0.5 | -| Rayons | Lookup table `maxMoveRadius[baseSize][speed]` (ex: `27mm.speed1=4.55", speed2=6.52", speed3=8.48"`) — extraits de `_ProjectorRadius` dans les materials Movement | - -API conservée : flow existant dans `Order_Token.a57c41.lua:552-574`, remplacement du `spawnObject Custom_AssetBundle` par `spawnOverlay("maxmove", fig, {speed=selectedSpeed, baseSize=unitData.baseSize})`. - -### 3.4 Deployment Boundary - -| Composant | Détail | -|---|---| -| Trigger spawn | `spawnDeploymentBoundary(matrix)` au setup (depuis menu UI Deployment) | -| Trigger clear | `clearDeploymentBoundary()` (menu UI Remove Overlay) + standby global | -| Decal PNG | `deployment_red.png` + `deployment_blue.png` — rectangle plein uniforme α=0.5, 256×256px | -| Decal params | Par cellule de la matrix, `position = grid pos + offset`, `scale = (6, 6, 6)` (taille standard d'une cellule SWL), rotation selon `deployRotations[cell]` | -| Vector lines | Contour rectangle drapant (4 côtés × N segments via raycast) par cellule, couleur match decal | -| Couleur | Rouge #FF0000 / Bleu #0000FF α=0.5 | -| Variantes | Half/L/Corner/Round → combinaisons de cellules dans la matrix, le manager gère chaque cellule individuellement (1 decal + 1 contour par cellule) | - -API conservée : `spawnDeploymentBoundary(matrix)`, `clearDeploymentBoundary()`. Internement, chaque cellule est enregistrée comme un overlay distinct avec un GUID synthétique (ex `"deployment:bs:5:3"`). - -## 4. Assets PNG à générer - -| Fichier | Dimensions | Description | Hosting | -|---|---|---|---| -| `cohesion_halo.png` | 512×512 | Gradient radial blanc centre → transparent bord, RGBA | iron-squadron.fr/tts-assets/ | -| `range_bands.png` | 1024×1024 | 4 anneaux concentriques aux rayons relatifs 0.25/0.5/0.75/1.0, gradient discret (pas blend), couleurs jaune/orange/rouge/magenta, alpha 0.6 | iron-squadron.fr/tts-assets/ | -| `range_smoke.png` | 256×256 | 1 anneau à rayon relatif 1.0, blanc opaque | idem | -| `range_token.png` | 256×256 | 1 anneau à rayon relatif 1.0, jaune | idem | -| `range_tokenRangeTwo.png` | 256×256 | 2 anneaux, jaune + orange | idem | -| `range_poi.png` | 256×256 | 1 anneau pour POI (range 0.5 / 3") | idem | -| `range_bombCart.png` | 256×256 | 2 anneaux | idem | -| `max_move_disk.png` | 512×512 | Disque plein bleu ciel #55CCFF α=0.48, RGBA | idem | -| `deployment_red.png` | 256×256 | Carré rouge plein #FF0000 α=0.5 | idem | -| `deployment_blue.png` | 256×256 | Carré bleu plein #0000FF α=0.5 | idem | - -**Génération** : script Python Pillow `generate_overlay_assets.py` qui produit tous les PNG d'un coup. Reproductible, versionnable dans `swlegion-tts/tool/`. - -**Upload** : `rsync` vers le VPS Iron Squadron, dossier `/var/www/iron-squadron/tts-assets/` (ou similaire). URL stable indépendante de Steam. - -## 5. Edge cases et invariants - -| Cas | Gestion | -|---|---| -| Multi-overlays simultanés (plusieurs figs avec cohesion + range) | Cohabitent dans la table `activeOverlays`, un `redrawAll()` au moindre changement | -| Fig détruite (mort en combat) | `onObjectDestroy` → `purgeForFig` → redraw | -| Pickup pendant overlay actif | `onObjectPickUp` → buffer dans `hiddenWhilePickedUp`, retire du rendu | -| Drop après pickup | `onObjectDrop` → restore depuis buffer, redraw (positions recalculées par les builders) | -| Pickup d'un objet sans overlay | Handler skip silencieux (test sur présence dans la table) | -| Reload de partie | `activeOverlays` se reset au boot (variable Lua locale du Global), OK | -| Filtres `standbyTokens` / `removeLockedRulers` (scans `getAllObjects()` par nom) | Deviennent caducs (plus d'Object physique). À supprimer ou laisser comme no-op | -| Test multi-joueurs réseau | Le manager Global est synchronisé par TTS (Lua sync), donc tous les joueurs voient les mêmes overlays | -| Drape impossible sur certains terrains custom | Limitation acceptable (déjà flag par Ben). Le decal plat sert de fallback visuel | - -## 6. Chemin de migration (séquentiel, testable étape par étape) - -1. **Setup Manager Global** : créer `mod/src/includes/Overlays.ttslua`. Aucun caller encore branché. Test : `npm run compile && load mod`, no-op confirmé -2. **Cohesion** (60 lignes, le plus simple) : réécrire `mod/src/includes/Cohesion.ttslua` pour rediriger vers le manager. Test : spawn via hotkey + bouton + dropCoroutine sur Mac -3. **Range Ruler** : réécrire `mod/src/includes/RangeRulers.ttslua` + adapter `POI_Token.lua` + `TokenWithRangeRuler.ttslua`. Test : 4 anneaux + tokens -4. **Maximum Move** : adapter `Order_Token.a57c41.lua:552-574` (spawn inline → call manager) + `clearMovementTemplates`. Test : flow mouvement complet sur Mac -5. **Deployment** : réécrire `SETUP_CONTROLLER.1cb552.lua:243-323`. Test : sélection scenario + spawn de la zone -6. **Cleanup** : supprimer les filtres `standbyTokens` / `removeLockedRulers` pour les types qui ne sont plus des Objects. Garder le filtre pour Movement Template (mesh, toujours Object) -7. **PR sur swlegion/tts** : branche `mac-overlays-refactor`, description du bug + solution + diff. Test communauté - -## 7. Compatibilité conservée - -- **Tous les sites de require existants** continuent à fonctionner sans modif (`require('!/Cohesion')`, `require('!/RangeRulers')`) -- **Toutes les fonctions globales conservent leur signature** (`spawnCohesionRuler(fig)`, `clearRangeRulers()`, etc.) -- **Pas de change d'API publique** → callers (Unit_Leader, Order_Token, POI_Token, etc.) inchangés -- **Variables d'état globales** comme `selectedUnitObj` conservées pour compat avec les filtres et la logique de toggle - -## 8. Risques connus à surveiller - -| Risque | Mitigation | -|---|---| -| Performance multi-overlays (N décals + N×64 vectors) | Tester empiriquement sur table chargée. Si lag, sparse raycast (32 segments) ou skip raycast si table plate détectée | -| Synchronisation decal/vector lines pas pixel-perfect | Vector lines au-dessus du decal (Y légèrement supérieur), tolérance visuelle | -| URL Iron Squadron offline | Hosting sur 2 destinations (VPS + GitHub Pages backup) ou inclure le CDN dans le repo si TTS supporte les data URIs | -| Bug U6 sur les decals aussi (improbable, POC validé le 14 mai) | Garder Path B = ticket Berserk en parallèle | -| Refactor casse un caller obscur | Test exhaustif des 5 sites de spawn + tous les triggers connus | - -## 9. Annexes - -- `materials-reference.md` : tous les params visuels extraits -- `retro-cohesion.md`, `retro-range.md`, `retro-deployment.md`, `retro-movement.md` : déclencheurs et call graphs -- `swlegion-tts/mod/src/includes/` : code source des modules à patcher diff --git a/mac-patcher/extract_projector_specs.py b/mac-patcher/extract_projector_specs.py deleted file mode 100644 index e699f8f16..000000000 --- a/mac-patcher/extract_projector_specs.py +++ /dev/null @@ -1,198 +0,0 @@ -#!/usr/bin/env python3 -""" -Scan Unity .mat and .prefab YAML files in UnityProject-U6/Assets/Projectors/ -and extract critical parameters for the SWL TTS mod refactor. - -Output: materials-reference.md with structured tables per overlay. -""" -import os -import re -from pathlib import Path -from collections import defaultdict - -ROOT = Path("/Users/martinpourrat/MARTIN/Star Wars Legion/Mod TTS SWL/UnityProject-U6/Assets/Projectors") -OUT = Path("/Users/martinpourrat/MARTIN/Star Wars Legion/Mod TTS SWL/materials-reference.md") - -OVERLAYS = ["Cohesion", "Range", "Deployment", "Movement"] - - -def read(p: Path) -> str: - return p.read_text(encoding="utf-8", errors="replace") - - -def parse_material(path: Path) -> dict: - """Extract critical fields from a Unity .mat YAML file.""" - text = read(path) - out = {"path": str(path.relative_to(ROOT)), "name": path.stem} - - m = re.search(r"m_ShaderKeywords:\s*(.*)", text) - out["keywords"] = m.group(1).strip() if m else "" - - m = re.search(r"m_Shader:\s*\{fileID:\s*\d+,\s*guid:\s*([0-9a-f]+)", text) - out["shader_guid"] = m.group(1) if m else "" - - # Floats — capture key params - floats = {} - for fname in ["_BaseSize", "_ProjectorRadius", "_BandSize", "_BandContrast", - "_MaxRange", "_Arc", "_RangeSize", "_GradScaler", - "_OneTuner", "_TwoTuner", "_ThreeTuner", "_FourTuner", - "_FiveTuner", "_InfinityTuner"]: - m = re.search(rf"-\s*{re.escape(fname)}:\s*(-?[\d.]+)", text) - if m: - floats[fname] = m.group(1) - out["floats"] = floats - - # Colors — capture all _Color* / _Range* - colors = {} - for m in re.finditer(r"-\s*(_\w+):\s*\{r:\s*([\d.]+),\s*g:\s*([\d.]+),\s*b:\s*([\d.]+),\s*a:\s*([\d.]+)\}", text): - name, r, g, b, a = m.groups() - if name in ("_BumpScale",): # not a color - continue - colors[name] = (float(r), float(g), float(b), float(a)) - out["colors"] = colors - - return out - - -def parse_prefab(path: Path) -> dict: - """Extract critical fields from a Unity .prefab YAML file (Projector components).""" - text = read(path) - out = {"path": str(path.relative_to(ROOT)), "name": path.stem} - - # Count Projector components (Unity type id 119) - projectors = re.findall(r"---\s*!u!119\s*&\d+\s*\nProjector:(.*?)(?=\n---|\Z)", text, re.DOTALL) - out["n_projectors"] = len(projectors) - - proj_data = [] - for body in projectors: - d = {} - for fname in ["m_OrthographicSize", "m_FarClipPlane", "m_NearClipPlane", - "m_FieldOfView", "m_AspectRatio", "m_Orthographic"]: - m = re.search(rf"{fname}:\s*(-?[\d.]+)", body) - if m: - d[fname] = m.group(1) - m = re.search(r"m_Material:\s*\{fileID:\s*\d+,\s*guid:\s*([0-9a-f]+)", body) - if m: - d["material_guid"] = m.group(1) - proj_data.append(d) - out["projectors"] = proj_data - - # Transforms (LocalPosition Y, rotation) - transforms = [] - for body in re.findall(r"---\s*!u!4\s*&\d+\s*\nTransform:(.*?)(?=\n---|\Z)", text, re.DOTALL): - d = {} - m = re.search(r"m_LocalPosition:\s*\{x:\s*(-?[\d.]+),\s*y:\s*(-?[\d.]+),\s*z:\s*(-?[\d.]+)\}", body) - if m: - d["pos"] = (float(m.group(1)), float(m.group(2)), float(m.group(3))) - m = re.search(r"m_LocalEulerAnglesHint:\s*\{x:\s*(-?[\d.]+),\s*y:\s*(-?[\d.]+),\s*z:\s*(-?[\d.]+)\}", body) - if m: - d["rot"] = (float(m.group(1)), float(m.group(2)), float(m.group(3))) - transforms.append(d) - out["transforms"] = transforms - - return out - - -def rgba_to_hex(r, g, b, a): - """Convert 0-1 RGBA to hex + alpha note.""" - rh, gh, bh = int(r * 255), int(g * 255), int(b * 255) - return f"#{rh:02X}{gh:02X}{bh:02X} (α={a:.2f})" - - -def fmt_colors(colors): - """Format dict of colors as compact markdown.""" - if not colors: - return "—" - parts = [] - for name, (r, g, b, a) in colors.items(): - if a == 0 and r == 0 and g == 0 and b == 0: - parts.append(f"`{name}` transparent") - else: - parts.append(f"`{name}` {rgba_to_hex(r, g, b, a)}") - return "
    ".join(parts) - - -def fmt_floats(floats): - """Format dict of floats.""" - if not floats: - return "—" - return ", ".join(f"`{k}`={v}" for k, v in floats.items()) - - -def main(): - materials_by_overlay = defaultdict(list) - prefabs_by_overlay = defaultdict(list) - - for overlay in OVERLAYS: - for p in sorted((ROOT / overlay).rglob("*.mat")): - if p.suffix == ".meta": - continue - materials_by_overlay[overlay].append(parse_material(p)) - for p in sorted((ROOT / overlay).rglob("*.prefab")): - if p.suffix == ".meta": - continue - prefabs_by_overlay[overlay].append(parse_prefab(p)) - - # Build the master doc - lines = [] - lines.append("# Materials & Prefabs Reference — SWL TTS Projector Overlays") - lines.append("") - lines.append("Extraction directe des `.mat` et `.prefab` Unity (YAML) dans `UnityProject-U6/Assets/Projectors/`. Source de vérité pour reproduire le rendu en vector lines.") - lines.append("") - lines.append("Notation : couleurs en hex + alpha. Champs `Floats` clés du shader projector (paramètres procéduraux des anneaux).") - lines.append("") - - for overlay in OVERLAYS: - lines.append(f"## {overlay}") - lines.append("") - - # Materials table - lines.append("### Materials") - lines.append("") - lines.append("| Material | Shader keywords | Floats clés | Couleurs |") - lines.append("|---|---|---|---|") - for m in materials_by_overlay[overlay]: - kw = m["keywords"] or "—" - lines.append(f"| `{m['name']}` | `{kw}` | {fmt_floats(m['floats'])} | {fmt_colors(m['colors'])} |") - lines.append("") - - # Prefabs table - lines.append("### Prefabs") - lines.append("") - lines.append("| Prefab | Nb Projectors | OrthographicSize / FarClip | Transform pos/rot | Material guid |") - lines.append("|---|---|---|---|---|") - for p in prefabs_by_overlay[overlay]: - n = p["n_projectors"] - proj_sizes = [pr.get("m_OrthographicSize", "?") for pr in p["projectors"]] - proj_far = [pr.get("m_FarClipPlane", "?") for pr in p["projectors"]] - proj_summary = "
    ".join(f"size={s}, far={f}" for s, f in zip(proj_sizes, proj_far)) if proj_sizes else "—" - - tr_summary = "
    ".join( - f"pos=({t.get('pos', ('?',)*3)[0]}, {t.get('pos', ('?',)*3)[1]}, {t.get('pos', ('?',)*3)[2]}) rot=({t.get('rot', ('?',)*3)[0]}, {t.get('rot', ('?',)*3)[1]}, {t.get('rot', ('?',)*3)[2]})" - for t in p["transforms"] - ) if p["transforms"] else "—" - - mat_guids = [pr.get("material_guid", "?") for pr in p["projectors"]] - mat_summary = "
    ".join(g[:12] + "…" for g in mat_guids) if mat_guids else "—" - - lines.append(f"| `{p['name']}` | {n} | {proj_summary} | {tr_summary} | {mat_summary} |") - lines.append("") - - # Final notes - lines.append("## Notes globales") - lines.append("") - lines.append("- Cohesion : double set `Materials/cohesion_*` et `_Revamp/halfCohesion_*`. Probable : `_Revamp/` est la version actuellement utilisée (le bundle live s'appelle `halfcohesion_27mm.unity3d` cf shader-inventory).") - lines.append("- Range : shader procédural avec jusqu'à 5 bandes (`_RangeOne` à `_RangeFive`) + `_RangeInfinity`. Le keyword `_MAXRANGE_RANGEFIVE` ou `_MAXRANGE_RANGEFOUR` détermine la dernière bande visible.") - lines.append("- Movement : un seul Projector par prefab, paramétré par `_BaseSize` + speed. Le `_Arc` doit contrôler la portion d'arc visible.") - lines.append("- Deployment : 6 materials uniques réutilisés par 12 prefabs (rotations différentes pour matérialiser corner/half/L/round/score).") - - OUT.write_text("\n".join(lines), encoding="utf-8") - print(f"Wrote {OUT}") - # Stats - total_mats = sum(len(v) for v in materials_by_overlay.values()) - total_prefabs = sum(len(v) for v in prefabs_by_overlay.values()) - print(f"Scanned {total_mats} materials and {total_prefabs} prefabs across {len(OVERLAYS)} overlays.") - - -if __name__ == "__main__": - main() diff --git a/mac-patcher/generate_overlay_assets.py b/mac-patcher/generate_overlay_assets.py deleted file mode 100644 index d11b19321..000000000 --- a/mac-patcher/generate_overlay_assets.py +++ /dev/null @@ -1,282 +0,0 @@ -#!/usr/bin/env python3 -""" -Generate PNG assets for the Mac Cohesion + Range overlay fallback. -""" -from pathlib import Path -from PIL import Image, ImageDraw -import math - -OUT_DIR = Path(__file__).parent / "tts-assets" -OUT_DIR.mkdir(exist_ok=True) - - -# Range band colors (R, G, B in 0..255) — from BB_RangeProjector defaults -RANGE_COLORS = { - "half": (255, 255, 255), # 0.5 / 3" — white - "one": (255, 195, 0), # R1 / 6" — yellow - "two": (255, 117, 0), # R2 / 12" — orange - "three": (255, 20, 0), # R3 / 18" — red - "four": (195, 0, 66), # R4 / 24" — magenta - "five": (134, 0, 112), # R5 / 30" — violet -} - -# Configurations per overlay type (bands = list of (radius_inches, color_key)) -# Edge-based convention: each band's effective world radius is band_r + base_r. -RANGE_BAND_CONFIGS = { - "fig_leader": { - "bands": [(3, "half"), (6, "one"), (12, "two"), - (18, "three"), (24, "four"), (30, "five")], - "max_radius": 30, - }, - # SWL ranges in inches: Range 1 = 6", Range 2 = 12", Range 0.5 (poi) = 3". - "smokeToken": {"bands": [(6, "one")], "max_radius": 6}, - "token": {"bands": [(6, "one")], "max_radius": 6}, - "tokenRangeTwo": {"bands": [(6, "one"), (12, "two")], "max_radius": 12}, - "poi": {"bands": [(3, "one")], "max_radius": 3}, - "bombCart": {"bands": [(6, "one"), (12, "two")], "max_radius": 12}, -} - -# Base radii (inches, half-diameter) per ROUND fig base size. Oblong bases -# (long, snail) live in OBLONG_DIMENSIONS_MM below — they don't use a single -# radius and don't generate round PNGs. -FIG_BASE_RADIUS_IN = { - "small": 27 / 2 / 25.4, - "medium": 50 / 2 / 25.4, - "large": 70 / 2 / 25.4, - "huge": 100 / 2 / 25.4, - "laat": 120 / 2 / 25.4, - "epic": 150 / 2 / 25.4, -} - -# Token base radii (inches), only needed for multi-band tokens. -TOKEN_BASE_RADIUS_IN = { - "tokenRangeTwo": 25.1 / 2 / 25.4, - "bombCart": 50.0 / 2 / 25.4, -} - - -def _with_base_offset(config: dict, base_r: float) -> dict: - """Shift band radii outward by base_r and grow max_radius accordingly so - the PNG band proportions match the world positions of the vector-line - rings (which are drawn at band_r + base_r).""" - return { - "bands": [(r + base_r, c) for r, c in config["bands"]], - "max_radius": config["max_radius"] + base_r, - } - - -def generate_cohesion_halo(size: int = 512) -> Path: - """Halo radial blanc fade transparent — reproduit le rendu Cohesion bundle. - - Le shader BB_CohesionProjector fait `rangeOne = (1 - grad)` puis multiplie - par alpha global. On reproduit ce fade : opaque au centre, transparent au - bord. - """ - img = Image.new("RGBA", (size, size), (0, 0, 0, 0)) - pixels = img.load() - cx, cy = size / 2, size / 2 - max_r = size / 2 - - # Alpha global du material Cohesion 27mm = 0.37 ; on multiplie par le fade - base_alpha = 0.37 - - for y in range(size): - for x in range(size): - dx, dy = x - cx, y - cy - dist = math.sqrt(dx * dx + dy * dy) - r_norm = dist / max_r # [0, 1+] depuis le centre - if r_norm > 1.0: - continue # transparent au-delà du rayon - - # Fade radial : (1 - r) avec courbe douce - # Le shader fait (1 - grad) linéaire, on garde la même chose - fade = max(0.0, 1.0 - r_norm) - alpha = int(base_alpha * fade * 255) - pixels[x, y] = (255, 255, 255, alpha) - - out = OUT_DIR / "cohesion_halo.png" - img.save(out) - return out - - -def generate_range_band_png(name: str, config: dict, size: int = 1024, - alpha: float = 0.2) -> Path: - """Generate a circular range overlay with concentric bands. - - Drawing from outer-to-inner: each filled ellipse overlays the previous, - producing clean rings. - """ - img = Image.new("RGBA", (size, size), (0, 0, 0, 0)) - draw = ImageDraw.Draw(img) - cx = cy = size / 2 - max_r_pix = size / 2 - a = int(alpha * 255) - - for band_r, color_key in reversed(config["bands"]): - r_pix = (band_r / config["max_radius"]) * max_r_pix - r, g, b = RANGE_COLORS[color_key] - draw.ellipse( - [(cx - r_pix, cy - r_pix), (cx + r_pix, cy + r_pix)], - fill=(r, g, b, a), - ) - - out = OUT_DIR / f"range_{name}.png" - img.save(out) - return out - - -# Oblong base dimensions (mm). Used to render stadium-shape range overlays -# whose 6 bands stay concentric to a rectangular footprint with rounded caps. -OBLONG_DIMENSIONS_MM = { - "long": {"width": 100, "length": 175}, - "snail": {"width": 100, "length": 200}, -} - - -def generate_range_band_stadium_png(base_size: str, dims_mm: dict, - config: dict, alpha: float = 0.2, - pixels_per_inch: int = 16) -> Path: - """Generate a stadium-shape PNG with 6 concentric range bands. - - The PNG dimensions encode the *outermost* band's bounding box (so the - decal can be stretched in TTS using scale = {shortSpan, longSpan, 1} and - the bands stay aligned with the matching vector stadium outlines). - - A stadium = rounded rectangle whose corner radius equals half the - short dimension, producing a pill shape with semicircular caps on the - long-axis ends. Each band is one rounded_rectangle of width - 2*(halfWid + band_r) and length 2*(halfLen + band_r), corner radius - halfWid + band_r. Drawn outer-to-inner so each band overpaints the next. - """ - halfWid_in = (dims_mm["width"] / 2) / 25.4 - halfLen_in = (dims_mm["length"] / 2) / 25.4 - max_dist = config["max_radius"] - - shortSpan_in = 2 * (halfWid_in + max_dist) - longSpan_in = 2 * (halfLen_in + max_dist) - - W = int(round(shortSpan_in * pixels_per_inch)) - H = int(round(longSpan_in * pixels_per_inch)) - cx, cy = W / 2, H / 2 - - img = Image.new("RGBA", (W, H), (0, 0, 0, 0)) - draw = ImageDraw.Draw(img) - a = int(alpha * 255) - - for band_r, color_key in reversed(config["bands"]): - half_w_px = (halfWid_in + band_r) * pixels_per_inch - half_h_px = (halfLen_in + band_r) * pixels_per_inch - r, g, b = RANGE_COLORS[color_key] - draw.rounded_rectangle( - [(cx - half_w_px, cy - half_h_px), - (cx + half_w_px, cy + half_h_px)], - radius=half_w_px, # = half of the short side → semicircle caps - fill=(r, g, b, a), - ) - - out = OUT_DIR / f"range_fig_leader_{base_size}_stadium.png" - img.save(out) - return out - - -def generate_filled_disk(name: str, color_rgb: tuple, size: int = 512, - alpha: float = 0.2) -> Path: - """Generate a simple filled disk PNG (used for Maximum Move overlay).""" - img = Image.new("RGBA", (size, size), (0, 0, 0, 0)) - draw = ImageDraw.Draw(img) - cx = cy = size / 2 - r = size / 2 - a = int(alpha * 255) - draw.ellipse([(cx - r, cy - r), (cx + r, cy + r)], - fill=(color_rgb[0], color_rgb[1], color_rgb[2], a)) - out = OUT_DIR / f"{name}.png" - img.save(out) - return out - - -def generate_filled_square(name: str, color_rgb: tuple, size: int = 256, - alpha: float = 0.3) -> Path: - """Generate a filled square PNG (used for Deployment Boundary cells).""" - img = Image.new("RGBA", (size, size), - (color_rgb[0], color_rgb[1], color_rgb[2], int(alpha * 255))) - out = OUT_DIR / f"{name}.png" - img.save(out) - return out - - -def generate_silhouette_top_disc(size: int = 512) -> Path: - """Hologram-style top cap for the Mac silhouette cylinder. - - Radial gradient: bright green-cyan center fades to transparent at the - rim. Combined with the vector wireframe cylinder this gives the - Star Wars hologram briefing look (Leia "Help me Obi-Wan" projection). - """ - img = Image.new("RGBA", (size, size), (0, 0, 0, 0)) - pixels = img.load() - cx, cy = size / 2, size / 2 - max_r = size / 2 - - r_center, g_center, b_center = 102, 255, 178 # bright hologram cyan-green - a_center = 0.85 - - for y in range(size): - for x in range(size): - dx, dy = x - cx, y - cy - dist = math.sqrt(dx * dx + dy * dy) - r_norm = dist / max_r - if r_norm > 1.0: - continue - # Smooth radial falloff (1-r squared) for a soft hologram glow - fade = (1.0 - r_norm) ** 1.5 - alpha = int(a_center * fade * 255) - pixels[x, y] = (r_center, g_center, b_center, alpha) - - out = OUT_DIR / "silhouette_top.png" - img.save(out) - return out - - -def main(): - p = generate_cohesion_halo() - print(f"Generated {p} ({p.stat().st_size} bytes)") - - # Fig leaders (round bases): one PNG per base size, bands shifted by base radius. - fig_cfg = RANGE_BAND_CONFIGS["fig_leader"] - for base_size, br in FIG_BASE_RADIUS_IN.items(): - out = generate_range_band_png(f"fig_leader_{base_size}", - _with_base_offset(fig_cfg, br)) - print(f"Generated {out} ({out.stat().st_size} bytes)") - - # Oblong bases: stadium-shape PNGs (rectangular footprint + rounded caps). - for base_size, dims in OBLONG_DIMENSIONS_MM.items(): - out = generate_range_band_stadium_png(base_size, dims, fig_cfg) - print(f"Generated {out} ({out.stat().st_size} bytes)") - - # Multi-band tokens: bake in their base radius for alignment. - for name, br in TOKEN_BASE_RADIUS_IN.items(): - cfg = RANGE_BAND_CONFIGS[name] - out = generate_range_band_png(name, _with_base_offset(cfg, br)) - print(f"Generated {out} ({out.stat().st_size} bytes)") - - # Single-band tokens: no offset adjustment needed (band sits at outer edge). - for name in ("smokeToken", "token", "poi"): - out = generate_range_band_png(name, RANGE_BAND_CONFIGS[name]) - print(f"Generated {out} ({out.stat().st_size} bytes)") - - # Maximum Move: cyan filled disk (#55CCFF) - p = generate_filled_disk("max_move_cyan", (85, 204, 255), alpha=0.2) - print(f"Generated {p} ({p.stat().st_size} bytes)") - - # Deployment Boundary: red and blue filled squares (alpha 0.5 = match bundle) - p = generate_filled_square("deployment_red", (255, 0, 0), alpha=0.3) - print(f"Generated {p} ({p.stat().st_size} bytes)") - p = generate_filled_square("deployment_blue", (0, 0, 255), alpha=0.3) - print(f"Generated {p} ({p.stat().st_size} bytes)") - - # Silhouette top cap: hologram-style green/cyan radial gradient. - p = generate_silhouette_top_disc() - print(f"Generated {p} ({p.stat().st_size} bytes)") - - -if __name__ == "__main__": - main() diff --git a/mac-patcher/inspect_cohesion.py b/mac-patcher/inspect_cohesion.py deleted file mode 100644 index e26becbed..000000000 --- a/mac-patcher/inspect_cohesion.py +++ /dev/null @@ -1,83 +0,0 @@ -#!/usr/bin/env python3 -"""Inspect Cohesion bundle structure: list objects, materials, shaders, and the m_Shader PPtr.""" -import os -import sys -import UnityPy - -BUNDLE = os.path.expanduser( - "~/Library/Tabletop Simulator/Mods/Assetbundles/" - "httpssteamusercontentaakamaihdnetugc2482129948496305632EBBE2560D4336E6C96317EDDA787E225CF0E5B48.unity3d" -) - -env = UnityPy.load(BUNDLE) - -print("=" * 80) -print("BUNDLE METADATA") -print("=" * 80) -for f in env.files.values(): - print(f" file: {type(f).__name__}") - if hasattr(f, "unity_version"): - print(f" unity_version: {f.unity_version}") - if hasattr(f, "target_platform"): - print(f" target_platform: {f.target_platform}") - if hasattr(f, "externals"): - print(f" externals (cross-bundle refs):") - for ext in getattr(f, "externals", []): - print(f" - {ext}") - -print() -print("=" * 80) -print("ALL OBJECTS") -print("=" * 80) -for obj in env.objects: - path_id = getattr(obj, "path_id", "?") - type_name = obj.type.name - try: - data = obj.read() - name = getattr(data, "m_Name", "") or "" - except Exception as e: - name = f"" - print(f" PathID={path_id:<6} type={type_name:<15} name={name!r}") - -print() -print("=" * 80) -print("MATERIAL DETAILS (looking for Cohesion_27mm)") -print("=" * 80) -for obj in env.objects: - if obj.type.name != "Material": - continue - data = obj.read() - print(f"\nMaterial PathID={obj.path_id} name={data.m_Name!r}") - sref = data.m_Shader - print(f" m_Shader PPtr:") - print(f" file_id = {getattr(sref, 'file_id', '?')} " - f"(0 = internal to this bundle, !=0 = external file)") - print(f" path_id = {getattr(sref, 'path_id', '?')}") - # Try to resolve - try: - sobj = sref.deref() - if sobj: - sd = sobj.read() - sname = ( - getattr(getattr(sd, "m_ParsedForm", None), "m_Name", None) - or getattr(sd, "m_Name", None) - ) - print(f" resolved -> Shader name = {sname!r}") - else: - print(f" resolved -> None (external or missing)") - except Exception as e: - print(f" resolve error: {e!r}") - -print() -print("=" * 80) -print("SHADER DETAILS") -print("=" * 80) -for obj in env.objects: - if obj.type.name != "Shader": - continue - data = obj.read() - sname = ( - getattr(getattr(data, "m_ParsedForm", None), "m_Name", None) - or getattr(data, "m_Name", None) - ) - print(f" PathID={obj.path_id} Shader name={sname!r}") diff --git a/mac-patcher/inspect_externals.py b/mac-patcher/inspect_externals.py deleted file mode 100644 index c9307a210..000000000 --- a/mac-patcher/inspect_externals.py +++ /dev/null @@ -1,51 +0,0 @@ -#!/usr/bin/env python3 -"""For each bundle: dump its externals (referenced external files) and list materials with external m_Shader PPtr.""" -import os -import sys -import UnityPy - -BUNDLE_DIR = os.path.expanduser("~/Library/Tabletop Simulator/Mods/Assetbundles/") - -bundles = sorted(f for f in os.listdir(BUNDLE_DIR) if f.endswith(".unity3d")) - -# We are most interested in bundles whose materials use external shaders (file_id != 0) -print("=" * 90) -print("BUNDLES WITH EXTERNAL m_Shader REFERENCES") -print("=" * 90) - -for fname in bundles: - path = os.path.join(BUNDLE_DIR, fname) - short_id = fname.replace("httpssteamusercontentaakamaihdnetugc", "")[:20] - env = UnityPy.load(path) - - external_mats = [] - for obj in env.objects: - if obj.type.name != "Material": - continue - try: - data = obj.read() - sref = data.m_Shader - fid = getattr(sref, "file_id", None) - pid = getattr(sref, "path_id", None) - if fid and fid != 0: - external_mats.append((data.m_Name, fid, pid)) - except Exception: - pass - - if not external_mats: - continue - - print(f"\n{short_id}:") - # Dump externals table - for f in env.files.values(): - if hasattr(f, "externals"): - print(f" externals table:") - for i, ext in enumerate(getattr(f, "externals", [])): - # The externals entry usually has a 'path' and 'guid' - ext_path = getattr(ext, "path", "?") - ext_guid = getattr(ext, "guid", "?") - # index i+1 because file_id is 1-based for externals (file_id=0 means self) - print(f" file_id={i+1} path={ext_path!r} guid={ext_guid}") - print(f" materials with external m_Shader:") - for name, fid, pid in external_mats: - print(f" material={name!r} m_Shader=(file_id={fid}, path_id={pid})") diff --git a/mac-patcher/materials-reference.md b/mac-patcher/materials-reference.md deleted file mode 100644 index eabaae364..000000000 --- a/mac-patcher/materials-reference.md +++ /dev/null @@ -1,170 +0,0 @@ -# Materials & Prefabs Reference — SWL TTS Projector Overlays - -Extraction directe des `.mat` et `.prefab` Unity (YAML) dans `UnityProject-U6/Assets/Projectors/`. Source de vérité pour reproduire le rendu en vector lines. - -Notation : couleurs en hex + alpha. Champs `Floats` clés du shader projector (paramètres procéduraux des anneaux). - -## Cohesion - -### Materials - -| Material | Shader keywords | Floats clés | Couleurs | -|---|---|---|---| -| `Cohesion_27mm` | `_ARC_OFF _MAXRANGE_RANGEONE _MOVES_SINGLE` | `_BaseSize`=27, `_ProjectorRadius`=4.479488, `_MaxRange`=0, `_Arc`=0, `_RangeSize`=-76.5 | `_Base` #FFFFFF (α=1.00)
    `_Color` #FFFFFF (α=0.37)
    `_EmissionColor` #000000 (α=1.00)
    `_MoveOne` #FFFFFF (α=0.30)
    `_MoveTwo` #FF0000 (α=1.00)
    `_RangeFive` #FFFF00 (α=1.00)
    `_RangeFour` #00FF00 (α=1.00)
    `_RangeInfinity` #000000 (α=1.00)
    `_RangeOne` #FFFFFF (α=1.00)
    `_RangeThree` #FF6C00 (α=1.00)
    `_RangeTwo` #0000FF (α=1.00) | -| `Cohesion_50mm` | `_MAXRANGE_RANGEONE _MOVES_SINGLE` | `_BaseSize`=50, `_ProjectorRadius`=5.470629, `_MaxRange`=0, `_Arc`=0, `_RangeSize`=-76.5 | `_Base` #FFFFFF (α=1.00)
    `_Color` #FFFFFF (α=0.67)
    `_EmissionColor` #000000 (α=1.00)
    `_MoveOne` #FFFFFF (α=0.30)
    `_MoveTwo` #FF0000 (α=1.00)
    `_RangeFive` #FFFF00 (α=1.00)
    `_RangeFour` #00FF00 (α=1.00)
    `_RangeInfinity` #7F7F7F (α=1.00)
    `_RangeOne` #FFFFFF (α=1.00)
    `_RangeThree` #FF6C00 (α=1.00)
    `_RangeTwo` #0000FF (α=1.00) | -| `Cohesion_70mm` | `_MAXRANGE_RANGEONE _MOVES_SINGLE` | `_BaseSize`=70, `_ProjectorRadius`=6.850394, `_MaxRange`=0, `_Arc`=0, `_RangeSize`=-76.5 | `_Base` #FFFFFF (α=1.00)
    `_Color` #FFFFFF (α=0.67)
    `_EmissionColor` #000000 (α=1.00)
    `_MoveOne` #FFFFFF (α=0.30)
    `_MoveTwo` #FF0000 (α=1.00)
    `_RangeFive` #FFFF00 (α=1.00)
    `_RangeFour` #00FF00 (α=1.00)
    `_RangeInfinity` #7F7F7F (α=1.00)
    `_RangeOne` #FFFFFF (α=1.00)
    `_RangeThree` #FF6C00 (α=1.00)
    `_RangeTwo` #0000FF (α=1.00) | -| `Cohesion_27mm` | `_ARC_OFF _MAXRANGE_RANGEONE _MOVES_SINGLE` | `_BaseSize`=27, `_ProjectorRadius`=3.531496, `_MaxRange`=0, `_Arc`=0, `_RangeSize`=-76.5 | `_Base` #FFFFFF (α=1.00)
    `_Color` #FFFFFF (α=0.37)
    `_EmissionColor` #000000 (α=1.00)
    `_MoveOne` #FFFFFF (α=0.30)
    `_MoveTwo` #FF0000 (α=1.00)
    `_RangeFive` #FFFF00 (α=1.00)
    `_RangeFour` #00FF00 (α=1.00)
    `_RangeInfinity` #000000 (α=1.00)
    `_RangeOne` #FFFFFF (α=1.00)
    `_RangeThree` #FF6C00 (α=1.00)
    `_RangeTwo` #0000FF (α=1.00) | -| `Cohesion_50mm` | `_MAXRANGE_RANGEONE _MOVES_SINGLE` | `_BaseSize`=50, `_ProjectorRadius`=3.984252, `_MaxRange`=0, `_Arc`=0, `_RangeSize`=-76.5 | `_Base` #FFFFFF (α=1.00)
    `_Color` #FFFFFF (α=0.67)
    `_EmissionColor` #000000 (α=1.00)
    `_MoveOne` #FFFFFF (α=0.30)
    `_MoveTwo` #FF0000 (α=1.00)
    `_RangeFive` #FFFF00 (α=1.00)
    `_RangeFour` #00FF00 (α=1.00)
    `_RangeInfinity` #7F7F7F (α=1.00)
    `_RangeOne` #FFFFFF (α=1.00)
    `_RangeThree` #FF6C00 (α=1.00)
    `_RangeTwo` #0000FF (α=1.00) | -| `Cohesion_70mm` | `_MAXRANGE_RANGEONE _MOVES_SINGLE` | `_BaseSize`=70, `_ProjectorRadius`=4.3779526, `_MaxRange`=0, `_Arc`=0, `_RangeSize`=-76.5 | `_Base` #FFFFFF (α=1.00)
    `_Color` #FFFFFF (α=0.67)
    `_EmissionColor` #000000 (α=1.00)
    `_MoveOne` #FFFFFF (α=0.30)
    `_MoveTwo` #FF0000 (α=1.00)
    `_RangeFive` #FFFF00 (α=1.00)
    `_RangeFour` #00FF00 (α=1.00)
    `_RangeInfinity` #7F7F7F (α=1.00)
    `_RangeOne` #FFFFFF (α=1.00)
    `_RangeThree` #FF6C00 (α=1.00)
    `_RangeTwo` #0000FF (α=1.00) | - -### Prefabs - -| Prefab | Nb Projectors | OrthographicSize / FarClip | Transform pos/rot | Material guid | -|---|---|---|---|---| -| `cohesion_27mm` | 1 | size=4.547244, far=45 | pos=(0.0, 20.0, 0.0) rot=(90.0, 0.0, 0.0) | ebe2e870a59f… | -| `cohesion_50mm` | 1 | size=5.669291, far=45 | pos=(0.0, 20.0, 0.0) rot=(90.0, 0.0, 0.0) | 406845c49cf4… | -| `cohesion_70mm` | 1 | size=6.850394, far=45 | pos=(0.0, 20.0, 0.0) rot=(90.0, 0.0, 0.0) | 3a57b0b27e32… | -| `halfCohesion_27mm` | 1 | size=3.531496, far=45 | pos=(0.0, 20.0, 0.0) rot=(90.0, 0.0, 0.0) | 0e1c90ce1ef6… | -| `halfCohesion_50mm` | 1 | size=3.984252, far=45 | pos=(0.0, 20.0, 0.0) rot=(90.0, 0.0, 0.0) | 2e05a24ab516… | -| `halfCohesion_70mm` | 1 | size=4.3779526, far=45 | pos=(0.0, 20.0, 0.0) rot=(90.0, 0.0, 0.0) | 7cee44cc736f… | - -## Range - -### Materials - -| Material | Shader keywords | Floats clés | Couleurs | -|---|---|---|---| -| `ProjectorMaterial_100mm` | `_ARC_ON _MAXRANGE_RANGEFIVE _RANGE_FIVE` | `_BaseSize`=100, `_ProjectorRadius`=30, `_BandSize`=0.278, `_BandContrast`=3, `_MaxRange`=4, `_Arc`=1, `_RangeSize`=-76.5, `_OneTuner`=0.0183, `_TwoTuner`=0.0062, `_ThreeTuner`=0.0245, `_FourTuner`=0.0123, `_FiveTuner`=0, `_InfinityTuner`=0 | `_Color` #FFFFFF (α=0.60)
    `_EmissionColor` #000000 (α=1.00)
    `_RangeFive` #860070 (α=1.00)
    `_RangeFour` #C20042 (α=1.00)
    `_RangeInfinity` transparent
    `_RangeOne` #FFC300 (α=1.00)
    `_RangeThree` #FF1400 (α=1.00)
    `_RangeTwo` #FF7500 (α=1.00) | -| `ProjectorMaterial_100mm_oblong` | `_ARC_ON _MAXRANGE_RANGEFIVE` | `_BaseSize`=47.4, `_ProjectorRadius`=30, `_BandSize`=0.34, `_BandContrast`=3, `_MaxRange`=4, `_Arc`=1, `_RangeSize`=-76.5, `_OneTuner`=-0.022, `_TwoTuner`=-0.0421, `_ThreeTuner`=-0.0324, `_FourTuner`=-0.0525, `_FiveTuner`=0.073, `_InfinityTuner`=0 | `_Color` #FFFFFF (α=0.60)
    `_EmissionColor` #000000 (α=1.00)
    `_RangeFive` #860070 (α=1.00)
    `_RangeFour` #C20042 (α=1.00)
    `_RangeInfinity` transparent
    `_RangeOne` #FFC300 (α=1.00)
    `_RangeThree` #FF1400 (α=1.00)
    `_RangeTwo` #FF7500 (α=1.00) | -| `ProjectorMaterial_100mm_snail` | `_ARC_ON _MAXRANGE_RANGEFIVE` | `_BaseSize`=47.4, `_ProjectorRadius`=30, `_BandSize`=0.34, `_BandContrast`=3, `_MaxRange`=4, `_Arc`=1, `_RangeSize`=-76.5, `_OneTuner`=-0.0216, `_TwoTuner`=-0.0421, `_ThreeTuner`=-0.0324, `_FourTuner`=-0.0525, `_FiveTuner`=0.073, `_InfinityTuner`=0 | `_Color` #FFFFFF (α=0.60)
    `_EmissionColor` #000000 (α=1.00)
    `_RangeFive` #860070 (α=1.00)
    `_RangeFour` #C20042 (α=1.00)
    `_RangeInfinity` transparent
    `_RangeOne` #FFC300 (α=1.00)
    `_RangeThree` #FF1400 (α=1.00)
    `_RangeTwo` #FF7500 (α=1.00) | -| `ProjectorMaterial_120mm` | `_ARC_ON _MAXRANGE_RANGEFIVE` | `_BaseSize`=120, `_ProjectorRadius`=30, `_BandSize`=0.278, `_BandContrast`=3, `_MaxRange`=4, `_Arc`=1, `_RangeSize`=-76.5, `_OneTuner`=0.022, `_TwoTuner`=0.0074, `_ThreeTuner`=0.0292, `_FourTuner`=0.0146, `_FiveTuner`=0, `_InfinityTuner`=0 | `_Color` #FFFFFF (α=0.60)
    `_EmissionColor` #000000 (α=1.00)
    `_RangeFive` #860070 (α=1.00)
    `_RangeFour` #C20042 (α=1.00)
    `_RangeInfinity` transparent
    `_RangeOne` #FFC300 (α=1.00)
    `_RangeThree` #FF1400 (α=1.00)
    `_RangeTwo` #FF7500 (α=1.00) | -| `ProjectorMaterial_150mm` | `_ARC_ON _MAXRANGE_RANGEFIVE` | `_BaseSize`=150, `_ProjectorRadius`=30, `_BandSize`=0.278, `_BandContrast`=3, `_MaxRange`=4, `_Arc`=1, `_RangeSize`=-76.5, `_OneTuner`=0.027, `_TwoTuner`=0.009, `_ThreeTuner`=0.0358, `_FourTuner`=0.018, `_FiveTuner`=0, `_InfinityTuner`=0 | `_Color` #FFFFFF (α=0.60)
    `_EmissionColor` #000000 (α=1.00)
    `_RangeFive` #860070 (α=1.00)
    `_RangeFour` #C20042 (α=1.00)
    `_RangeInfinity` transparent
    `_RangeOne` #FFC300 (α=1.00)
    `_RangeThree` #FF1400 (α=1.00)
    `_RangeTwo` #FF7500 (α=1.00) | -| `ProjectorMaterial_18mm_smokeToken` | `_ARC_OFF _MAXRANGE_RANGEONE` | `_BaseSize`=18.8, `_ProjectorRadius`=6, `_BandSize`=-0.11, `_BandContrast`=0.46, `_MaxRange`=0, `_Arc`=0, `_RangeSize`=-76.5, `_OneTuner`=0, `_TwoTuner`=0.0034, `_ThreeTuner`=0.0034, `_FourTuner`=0.0034, `_FiveTuner`=0, `_InfinityTuner`=0 | `_Color` #3A3145 (α=0.59)
    `_EmissionColor` #000000 (α=1.00)
    `_RangeFive` #860070 (α=1.00)
    `_RangeFour` #C20042 (α=1.00)
    `_RangeInfinity` transparent
    `_RangeOne` #FFFFFF (α=1.00)
    `_RangeThree` #FF1400 (α=1.00)
    `_RangeTwo` #FF7500 (α=1.00) | -| `ProjectorMaterial_25mm_token` | `_ARC_OFF _MAXRANGE_RANGEONE` | `_BaseSize`=27, `_ProjectorRadius`=2.97, `_BandSize`=-0.45, `_BandContrast`=3, `_MaxRange`=0, `_Arc`=0, `_RangeSize`=-76.5, `_OneTuner`=0, `_TwoTuner`=0.0034, `_ThreeTuner`=0.0034, `_FourTuner`=0.0034, `_FiveTuner`=0, `_InfinityTuner`=0 | `_Color` #FFFFFF (α=0.60)
    `_EmissionColor` #000000 (α=1.00)
    `_RangeFive` #860070 (α=1.00)
    `_RangeFour` #C20042 (α=1.00)
    `_RangeInfinity` transparent
    `_RangeOne` #FFC300 (α=1.00)
    `_RangeThree` #FF1400 (α=1.00)
    `_RangeTwo` #FF7500 (α=1.00) | -| `ProjectorMaterial_25mm_tokenRangeTwo` | `_ARC_OFF _MAXRANGE_RANGETWO` | `_BaseSize`=28.12, `_ProjectorRadius`=14.9, `_BandSize`=0.04, `_BandContrast`=3, `_MaxRange`=1, `_Arc`=0, `_RangeSize`=-76.5, `_OneTuner`=0, `_TwoTuner`=0.0062, `_ThreeTuner`=0.0034, `_FourTuner`=0.0034, `_FiveTuner`=0, `_InfinityTuner`=0 | `_Color` #FFFFFF (α=0.60)
    `_EmissionColor` #000000 (α=1.00)
    `_RangeFive` #860070 (α=1.00)
    `_RangeFour` #C20042 (α=1.00)
    `_RangeInfinity` transparent
    `_RangeOne` #FFC300 (α=1.00)
    `_RangeThree` #FF1400 (α=1.00)
    `_RangeTwo` #FF7500 (α=1.00) | -| `ProjectorMaterial_27mm` | `_ARC_OFF _MAXRANGE_RANGEFIVE` | `_BaseSize`=27, `_ProjectorRadius`=30, `_BandSize`=0.278, `_BandContrast`=3, `_MaxRange`=4, `_Arc`=0, `_RangeSize`=-76.5, `_GradScaler`=0.0034, `_OneTuner`=0.0053, `_TwoTuner`=0.0019, `_ThreeTuner`=0.0072, `_FourTuner`=0.0037, `_FiveTuner`=0, `_InfinityTuner`=0.0034 | `_Color` #FFFFFF (α=0.60)
    `_EmissionColor` #000000 (α=1.00)
    `_RangeFive` #860070 (α=1.00)
    `_RangeFour` #C20042 (α=1.00)
    `_RangeInfinity` transparent
    `_RangeOne` #FFC300 (α=1.00)
    `_RangeThree` #FF1400 (α=1.00)
    `_RangeTwo` #FF7500 (α=1.00) | -| `ProjectorMaterial_50mm` | `_ARC_ON _MAXRANGE_RANGEFIVE` | `_BaseSize`=50, `_ProjectorRadius`=30, `_BandSize`=0.278, `_BandContrast`=3, `_MaxRange`=4, `_Arc`=1, `_RangeSize`=-76.5, `_GradScaler`=0, `_OneTuner`=0.0098, `_TwoTuner`=0.0034, `_ThreeTuner`=0.0127, `_FourTuner`=0.0063, `_FiveTuner`=0, `_InfinityTuner`=0 | `_Color` #FFFFFF (α=0.60)
    `_EmissionColor` #000000 (α=1.00)
    `_RangeFive` #860070 (α=1.00)
    `_RangeFour` #C20042 (α=1.00)
    `_RangeInfinity` transparent
    `_RangeOne` #FFC300 (α=1.00)
    `_RangeThree` #FF1400 (α=1.00)
    `_RangeTwo` #FF7500 (α=1.00) | -| `ProjectorMaterial_50mm_bombCart` | `_ARC_OFF _MAXRANGE_RANGETWO` | `_BaseSize`=50, `_ProjectorRadius`=12, `_BandSize`=0.01, `_BandContrast`=3, `_MaxRange`=1, `_Arc`=0, `_RangeSize`=-76.5, `_OneTuner`=0, `_TwoTuner`=0.0034, `_ThreeTuner`=0.0034, `_FourTuner`=0.0034, `_FiveTuner`=0, `_InfinityTuner`=0 | `_Color` #FFFFFF (α=0.60)
    `_EmissionColor` #000000 (α=1.00)
    `_RangeFive` #860070 (α=1.00)
    `_RangeFour` #C20042 (α=1.00)
    `_RangeInfinity` transparent
    `_RangeOne` #FFC300 (α=1.00)
    `_RangeThree` #FF1400 (α=1.00)
    `_RangeTwo` #FF7500 (α=1.00) | -| `ProjectorMaterial_70mm` | `_ARC_ON _MAXRANGE_RANGEFIVE` | `_BaseSize`=70, `_ProjectorRadius`=30, `_BandSize`=0.278, `_BandContrast`=2.87, `_MaxRange`=4, `_Arc`=1, `_RangeSize`=-76.5, `_OneTuner`=0.0132, `_TwoTuner`=0.0045, `_ThreeTuner`=0.0175, `_FourTuner`=0.009, `_FiveTuner`=0, `_InfinityTuner`=0 | `_Color` #FFFFFF (α=0.35)
    `_EmissionColor` #000000 (α=1.00)
    `_RangeFive` #860070 (α=1.00)
    `_RangeFour` #C20042 (α=1.00)
    `_RangeInfinity` transparent
    `_RangeOne` #FFC300 (α=1.00)
    `_RangeThree` #FF1400 (α=1.00)
    `_RangeTwo` #FF7500 (α=1.00) | -| `Projector_BoardGuide` | `m_LightmapFlags: 4` | — | `_CameraFadeParams` transparent
    `_Color` #FFFFFF (α=1.00)
    `_ColorAddSubDiff` transparent
    `_EmissionColor` #000000 (α=1.00)
    `_SoftParticleFadeParams` transparent
    `_TintColor` #7F7F7F (α=0.50) | - -### Prefabs - -| Prefab | Nb Projectors | OrthographicSize / FarClip | Transform pos/rot | Material guid | -|---|---|---|---|---| -| `projector_100mm` | 1 | size=31.9685, far=45 | pos=(0.0, 20.0, 0.0) rot=(90.0, 0.0, 0.0) | 4b37ff3d68c5… | -| `projector_100mm_oblong` | 1 | size=33.4, far=45 | pos=(0.0, -1.5, 0.0) rot=(0.0, 0.0, 90.0)
    pos=(0.0, 20.0, 0.0) rot=(90.0, 0.0, 0.0) | 6c0556b105e8… | -| `projector_120mm` | 1 | size=32.3622, far=45 | pos=(0.0, 20.0, 0.0) rot=(90.0, 0.0, 0.0) | ab767c454926… | -| `projector_150mm` | 1 | size=32.95276, far=45 | pos=(0.0, 20.0, 0.0) rot=(90.0, 0.0, 0.0) | 3a33cb678c17… | -| `projector_200mm_oblong` | 1 | size=33.4, far=45 | pos=(0.0, 20.0, 0.0) rot=(90.0, 0.0, 0.0)
    pos=(-0.0, -0.26, -0.0) rot=(0.0, 0.0, 90.0) | cccc683b4b18… | -| `projector_27mm` | 1 | size=30.5314, far=45 | pos=(0.0, 20.0, 0.0) rot=(90.0, 0.0, 0.0) | b1c5ef617632… | -| `projector_50mm` | 1 | size=30.984253, far=45 | pos=(0.0, 20.0, 0.0) rot=(90.0, 0.0, 0.0) | 20ce39a8e0e1… | -| `projector_70mm` | 1 | size=31.37795, far=45 | pos=(0.0, 20.0, 0.0) rot=(90.0, 0.0, 0.0) | 977480df799a… | -| `projector_POIGuide` | 1 | size=36, far=45 | pos=(0.0, 20.0, 0.0) rot=(90.0, 0.0, 0.0) | a0fb1f64d52e… | -| `projector_bomb_cart` | 1 | size=12.98425, far=45 | pos=(0.0, 20.0, 0.0) rot=(90.0, 0.0, 0.0) | 417ae88dafb1… | -| `projector_smokeToken` | 1 | size=6.3700786, far=45 | pos=(0.0, 20.0, 0.0) rot=(90.0, 0.0, 0.0) | 3ef1e0f12697… | -| `projector_token` | 1 | size=7.06299, far=45 | pos=(0.0, 20.0, 0.0) rot=(90.0, 0.0, 0.0) | 94ad9a7a030f… | -| `projector_tokenRangeTwo` | 1 | size=12.6, far=45 | pos=(0.0, 20.0, 0.0) rot=(90.0, 0.0, 0.0) | 0905fd93d0b7… | - -## Deployment - -### Materials - -| Material | Shader keywords | Floats clés | Couleurs | -|---|---|---|---| -| `Projector_Deployment_Blue` | `m_LightmapFlags: 4` | — | `_Color` #0000FF (α=0.50)
    `_EmissionColor` #000000 (α=1.00) | -| `Projector_Deployment_Blue_Round` | `m_LightmapFlags: 4` | — | `_Color` #0000FF (α=0.50)
    `_EmissionColor` #000000 (α=1.00) | -| `Projector_Deployment_Red` | `m_LightmapFlags: 4` | — | `_Color` #FF0000 (α=0.50)
    `_EmissionColor` #000000 (α=1.00) | -| `Projector_Deployment_Red_Round` | `m_LightmapFlags: 4` | — | `_Color` #FF0000 (α=0.50)
    `_EmissionColor` #000000 (α=1.00) | -| `Projector_Score_Blue` | `m_LightmapFlags: 4` | — | `_Color` #0000FF (α=0.50)
    `_EmissionColor` #000000 (α=1.00) | -| `Projector_Score_Red` | `m_LightmapFlags: 4` | — | `_Color` #FF0000 (α=0.50)
    `_EmissionColor` #000000 (α=1.00) | - -### Prefabs - -| Prefab | Nb Projectors | OrthographicSize / FarClip | Transform pos/rot | Material guid | -|---|---|---|---|---| -| `projector_blue_score` | 1 | size=6, far=25 | pos=(0.08, 10.71, -19.42) rot=(90.0, 0.0, 0.0) | fe66dad2ac93… | -| `projector_blue_spawn` | 1 | size=3, far=25 | pos=(0.08, 10.71, -19.42) rot=(90.0, 0.0, 0.0) | 23c778da5a02… | -| `projector_blue_spawn_L` | 2 | size=1.5, far=25
    size=3, far=25 | pos=(10.65, 10.71, -19.76) rot=(90.0, 0.0, 0.0)
    pos=(1.5, 1.5, 0.0) rot=(0.0, 0.0, 90.0)
    pos=(0.0, -1.5000002, 0.0) rot=(0.0, 0.0, 90.0) | 23c778da5a02…
    23c778da5a02… | -| `projector_blue_spawn_corner` | 1 | size=1.5, far=25 | pos=(10.65, 10.71, -19.76) rot=(90.0, 0.0, 0.0)
    pos=(-1.5, -1.5, 0.0) rot=(0.0, 0.0, 90.0) | 23c778da5a02… | -| `projector_blue_spawn_half` | 1 | size=3, far=25 | pos=(0.0, -1.5, 0.0) rot=(0.0, 0.0, 90.0)
    pos=(10.65, 10.71, -19.76) rot=(90.0, 0.0, 0.0) | 23c778da5a02… | -| `projector_blue_spawn_round2` | 1 | size=12, far=25 | pos=(0.08, 10.71, -19.42) rot=(90.0, 0.0, 0.0) | 34786d447192… | -| `projector_red_score` | 1 | size=6, far=25 | pos=(0.08, 10.71, -19.42) rot=(90.0, 0.0, 0.0) | 90fdc53ff83c… | -| `projector_red_spawn` | 1 | size=3, far=25 | pos=(0.08, 10.71, -19.42) rot=(90.0, 0.0, 0.0) | 93e068805588… | -| `projector_red_spawn_L` | 2 | size=3, far=25
    size=1.5, far=25 | pos=(0.08, 10.71, -19.42) rot=(90.0, 0.0, 0.0)
    pos=(0.0, 1.5, 0.0) rot=(0.0, 0.0, 90.0)
    pos=(-1.5, -1.5, -0.0) rot=(0.0, 0.0, 90.0) | 93e068805588…
    93e068805588… | -| `projector_red_spawn_corner` | 1 | size=1.5, far=25 | pos=(0.08, 10.71, -19.42) rot=(90.0, 0.0, 0.0)
    pos=(1.5, 1.5, -0.0) rot=(0.0, 0.0, 90.0) | 93e068805588… | -| `projector_red_spawn_half` | 1 | size=3, far=25 | pos=(0.0, 1.5, -0.0) rot=(0.0, 0.0, 90.0)
    pos=(0.08, 10.71, -19.42) rot=(90.0, 0.0, 0.0) | 93e068805588… | -| `projector_red_spawn_round2` | 1 | size=12, far=25 | pos=(0.08, 10.71, -19.42) rot=(90.0, 0.0, 0.0) | 54824e17d05f… | - -## Movement - -### Materials - -| Material | Shader keywords | Floats clés | Couleurs | -|---|---|---|---| -| `ProjectorMaterial_100mm_speed1_single` | `_MAXRANGE_RANGEINFINITY _MOVES_SINGLE` | `_BaseSize`=70, `_ProjectorRadius`=8.622047, `_MaxRange`=5, `_RangeSize`=-76.5 | `_Base` #FFFFFF (α=1.00)
    `_Color` #FFFFFF (α=0.48)
    `_EmissionColor` #000000 (α=1.00)
    `_MoveOne` #55CCFF (α=1.00)
    `_MoveTwo` #357A97 (α=1.00)
    `_RangeFive` #FFFF6D (α=1.00)
    `_RangeFour` #FFD600 (α=1.00)
    `_RangeInfinity` #FFFFFF (α=0.47)
    `_RangeOne` #6C0000 (α=1.00)
    `_RangeThree` #FF7B00 (α=1.00)
    `_RangeTwo` #DA0000 (α=1.00) | -| `ProjectorMaterial_100mm_speed2_single` | `_MAXRANGE_RANGEINFINITY _MOVES_SINGLE` | `_BaseSize`=70, `_ProjectorRadius`=10.590551, `_MaxRange`=5, `_RangeSize`=-76.5 | `_Base` #FFFFFF (α=1.00)
    `_Color` #FFFFFF (α=0.48)
    `_EmissionColor` #000000 (α=1.00)
    `_MoveOne` #55CCFF (α=1.00)
    `_MoveTwo` #357A97 (α=1.00)
    `_RangeFive` #FFFF6D (α=1.00)
    `_RangeFour` #FFD600 (α=1.00)
    `_RangeInfinity` #FFFFFF (α=0.47)
    `_RangeOne` #6C0000 (α=1.00)
    `_RangeThree` #FF7B00 (α=1.00)
    `_RangeTwo` #DA0000 (α=1.00) | -| `ProjectorMaterial_100mm_speed3_single` | `_MAXRANGE_RANGEINFINITY _MOVES_SINGLE` | `_BaseSize`=70, `_ProjectorRadius`=12.559055, `_MaxRange`=5, `_RangeSize`=-76.5 | `_Base` #FFFFFF (α=1.00)
    `_Color` #FFFFFF (α=0.48)
    `_EmissionColor` #000000 (α=1.00)
    `_MoveOne` #55CCFF (α=1.00)
    `_MoveTwo` #357A97 (α=1.00)
    `_RangeFive` #FFFF6D (α=1.00)
    `_RangeFour` #FFD600 (α=1.00)
    `_RangeInfinity` #FFFFFF (α=0.47)
    `_RangeOne` #6C0000 (α=1.00)
    `_RangeThree` #FF7B00 (α=1.00)
    `_RangeTwo` #DA0000 (α=1.00) | -| `ProjectorMaterial_120mm_speed1_single` | `_MAXRANGE_RANGEINFINITY _MOVES_SINGLE` | `_BaseSize`=70, `_ProjectorRadius`=9.803149, `_MaxRange`=5, `_RangeSize`=-76.5 | `_Base` #FFFFFF (α=1.00)
    `_Color` #FFFFFF (α=0.48)
    `_EmissionColor` #000000 (α=1.00)
    `_MoveOne` #55CCFF (α=1.00)
    `_MoveTwo` #357A97 (α=1.00)
    `_RangeFive` #FFFF6D (α=1.00)
    `_RangeFour` #FFD600 (α=1.00)
    `_RangeInfinity` #FFFFFF (α=0.47)
    `_RangeOne` #6C0000 (α=1.00)
    `_RangeThree` #FF7B00 (α=1.00)
    `_RangeTwo` #DA0000 (α=1.00) | -| `ProjectorMaterial_120mm_speed2_single` | `_MAXRANGE_RANGEINFINITY _MOVES_SINGLE` | `_BaseSize`=70, `_ProjectorRadius`=11.771653, `_MaxRange`=5, `_RangeSize`=-76.5 | `_Base` #FFFFFF (α=1.00)
    `_Color` #FFFFFF (α=0.48)
    `_EmissionColor` #000000 (α=1.00)
    `_MoveOne` #55CCFF (α=1.00)
    `_MoveTwo` #357A97 (α=1.00)
    `_RangeFive` #FFFF6D (α=1.00)
    `_RangeFour` #FFD600 (α=1.00)
    `_RangeInfinity` #FFFFFF (α=0.47)
    `_RangeOne` #6C0000 (α=1.00)
    `_RangeThree` #FF7B00 (α=1.00)
    `_RangeTwo` #DA0000 (α=1.00) | -| `ProjectorMaterial_120mm_speed3_single` | `_MAXRANGE_RANGEINFINITY _MOVES_SINGLE` | `_BaseSize`=70, `_ProjectorRadius`=13.740157, `_MaxRange`=5, `_RangeSize`=-76.5 | `_Base` #FFFFFF (α=1.00)
    `_Color` #FFFFFF (α=0.48)
    `_EmissionColor` #000000 (α=1.00)
    `_MoveOne` #55CCFF (α=1.00)
    `_MoveTwo` #357A97 (α=1.00)
    `_RangeFive` #FFFF6D (α=1.00)
    `_RangeFour` #FFD600 (α=1.00)
    `_RangeInfinity` #FFFFFF (α=0.47)
    `_RangeOne` #6C0000 (α=1.00)
    `_RangeThree` #FF7B00 (α=1.00)
    `_RangeTwo` #DA0000 (α=1.00) | -| `ProjectorMaterial_150mm_speed1_single` | `_MAXRANGE_RANGEINFINITY _MOVES_SINGLE` | `_BaseSize`=70, `_ProjectorRadius`=11.574803, `_MaxRange`=5, `_RangeSize`=-76.5 | `_Base` #FFFFFF (α=1.00)
    `_Color` #FFFFFF (α=0.48)
    `_EmissionColor` #000000 (α=1.00)
    `_MoveOne` #55CCFF (α=1.00)
    `_MoveTwo` #357A97 (α=1.00)
    `_RangeFive` #FFFF6D (α=1.00)
    `_RangeFour` #FFD600 (α=1.00)
    `_RangeInfinity` #FFFFFF (α=0.47)
    `_RangeOne` #6C0000 (α=1.00)
    `_RangeThree` #FF7B00 (α=1.00)
    `_RangeTwo` #DA0000 (α=1.00) | -| `ProjectorMaterial_150mm_speed2_single` | `_MAXRANGE_RANGEINFINITY _MOVES_SINGLE` | `_BaseSize`=70, `_ProjectorRadius`=13.543307, `_MaxRange`=5, `_RangeSize`=-76.5 | `_Base` #FFFFFF (α=1.00)
    `_Color` #FFFFFF (α=0.48)
    `_EmissionColor` #000000 (α=1.00)
    `_MoveOne` #55CCFF (α=1.00)
    `_MoveTwo` #357A97 (α=1.00)
    `_RangeFive` #FFFF6D (α=1.00)
    `_RangeFour` #FFD600 (α=1.00)
    `_RangeInfinity` #FFFFFF (α=0.47)
    `_RangeOne` #6C0000 (α=1.00)
    `_RangeThree` #FF7B00 (α=1.00)
    `_RangeTwo` #DA0000 (α=1.00) | -| `ProjectorMaterial_150mm_speed3_single` | `_MAXRANGE_RANGEINFINITY _MOVES_SINGLE` | `_BaseSize`=70, `_ProjectorRadius`=15.511811, `_MaxRange`=5, `_RangeSize`=-76.5 | `_Base` #FFFFFF (α=1.00)
    `_Color` #FFFFFF (α=0.48)
    `_EmissionColor` #000000 (α=1.00)
    `_MoveOne` #55CCFF (α=1.00)
    `_MoveTwo` #357A97 (α=1.00)
    `_RangeFive` #FFFF6D (α=1.00)
    `_RangeFour` #FFD600 (α=1.00)
    `_RangeInfinity` #FFFFFF (α=0.47)
    `_RangeOne` #6C0000 (α=1.00)
    `_RangeThree` #FF7B00 (α=1.00)
    `_RangeTwo` #DA0000 (α=1.00) | -| `ProjectorMaterial_27mm_speed1_double` | `_MAXRANGE_RANGEINFINITY _MOVES_DOUBLE` | `_BaseSize`=27, `_ProjectorRadius`=8.45, `_MaxRange`=5, `_RangeSize`=-76.5 | `_Color` #FFFFFF (α=0.48)
    `_EmissionColor` #000000 (α=1.00)
    `_MoveOne` #55CCFF (α=1.00)
    `_MoveTwo` #357A97 (α=1.00)
    `_RangeFive` #FFFF6D (α=1.00)
    `_RangeFour` #FFD600 (α=1.00)
    `_RangeInfinity` #FFFFFF (α=0.47)
    `_RangeOne` #6C0000 (α=1.00)
    `_RangeThree` #FF7B00 (α=1.00)
    `_RangeTwo` #DA0000 (α=1.00) | -| `ProjectorMaterial_27mm_speed1_single` | `_MAXRANGE_RANGEINFINITY _MOVES_SINGLE` | `_BaseSize`=27, `_ProjectorRadius`=4.547244, `_MaxRange`=5, `_RangeSize`=-76.5 | `_Base` #FFFFFF (α=1.00)
    `_Color` #FFFFFF (α=0.48)
    `_EmissionColor` #000000 (α=1.00)
    `_MoveOne` #55CCFF (α=1.00)
    `_MoveTwo` #357A97 (α=1.00)
    `_RangeFive` #FFFF6D (α=1.00)
    `_RangeFour` #FFD600 (α=1.00)
    `_RangeInfinity` #FFFFFF (α=0.47)
    `_RangeOne` #6C0000 (α=1.00)
    `_RangeThree` #FF7B00 (α=1.00)
    `_RangeTwo` #DA0000 (α=1.00) | -| `ProjectorMaterial_27mm_speed2_double` | `_MAXRANGE_RANGEINFINITY _MOVES_DOUBLE` | `_BaseSize`=27, `_ProjectorRadius`=12.42748, `_MaxRange`=5, `_RangeSize`=-76.5 | `_Color` #FFFFFF (α=0.48)
    `_EmissionColor` #000000 (α=1.00)
    `_MoveOne` #55CCFF (α=1.00)
    `_MoveTwo` #357A97 (α=1.00)
    `_RangeFive` #FFFF6D (α=1.00)
    `_RangeFour` #FFD600 (α=1.00)
    `_RangeInfinity` #FFFFFF (α=0.47)
    `_RangeOne` #6C0000 (α=1.00)
    `_RangeThree` #FF7B00 (α=1.00)
    `_RangeTwo` #DA0000 (α=1.00) | -| `ProjectorMaterial_27mm_speed2_single` | `_MAXRANGE_RANGEINFINITY _MOVES_SINGLE` | `_BaseSize`=27, `_ProjectorRadius`=6.515748, `_MaxRange`=5, `_RangeSize`=-76.5 | `_Base` #FFFFFF (α=1.00)
    `_Color` #FFFFFF (α=0.48)
    `_EmissionColor` #000000 (α=1.00)
    `_MoveOne` #55CCFF (α=1.00)
    `_MoveTwo` #357A97 (α=1.00)
    `_RangeFive` #FFFF6D (α=1.00)
    `_RangeFour` #FFD600 (α=1.00)
    `_RangeInfinity` #FFFFFF (α=0.47)
    `_RangeOne` #6C0000 (α=1.00)
    `_RangeThree` #FF7B00 (α=1.00)
    `_RangeTwo` #DA0000 (α=1.00) | -| `ProjectorMaterial_27mm_speed3_double` | `_MAXRANGE_RANGEINFINITY _MOVES_DOUBLE` | `_BaseSize`=27, `_ProjectorRadius`=16.42748, `_MaxRange`=5, `_RangeSize`=-76.5 | `_Color` #FFFFFF (α=0.48)
    `_EmissionColor` #000000 (α=1.00)
    `_MoveOne` #55CCFF (α=1.00)
    `_MoveTwo` #357A97 (α=1.00)
    `_RangeFive` #FFFF6D (α=1.00)
    `_RangeFour` #FFD600 (α=1.00)
    `_RangeInfinity` #FFFFFF (α=0.47)
    `_RangeOne` #6C0000 (α=1.00)
    `_RangeThree` #FF7B00 (α=1.00)
    `_RangeTwo` #DA0000 (α=1.00) | -| `ProjectorMaterial_27mm_speed3_single` | `_MAXRANGE_RANGEINFINITY _MOVES_SINGLE` | `_BaseSize`=27, `_ProjectorRadius`=8.484252, `_MaxRange`=5, `_RangeSize`=-76.5 | `_Base` #FFFFFF (α=1.00)
    `_Color` #FFFFFF (α=0.48)
    `_EmissionColor` #000000 (α=1.00)
    `_MoveOne` #55CCFF (α=1.00)
    `_MoveTwo` #357A97 (α=1.00)
    `_RangeFive` #FFFF6D (α=1.00)
    `_RangeFour` #FFD600 (α=1.00)
    `_RangeInfinity` #FFFFFF (α=0.47)
    `_RangeOne` #6C0000 (α=1.00)
    `_RangeThree` #FF7B00 (α=1.00)
    `_RangeTwo` #DA0000 (α=1.00) | -| `ProjectorMaterial_50mm_speed1_single` | `_MAXRANGE_RANGEINFINITY _MOVES_SINGLE` | `_BaseSize`=50, `_ProjectorRadius`=5.6692915, `_MaxRange`=5, `_RangeSize`=-76.5 | `_Base` #FFFFFF (α=1.00)
    `_Color` #FFFFFF (α=0.48)
    `_EmissionColor` #000000 (α=1.00)
    `_MoveOne` #55CCFF (α=1.00)
    `_MoveTwo` #357A97 (α=1.00)
    `_RangeFive` #FFFF6D (α=1.00)
    `_RangeFour` #FFD600 (α=1.00)
    `_RangeInfinity` #FFFFFF (α=0.47)
    `_RangeOne` #6C0000 (α=1.00)
    `_RangeThree` #FF7B00 (α=1.00)
    `_RangeTwo` #DA0000 (α=1.00) | -| `ProjectorMaterial_50mm_speed2_single` | `_MAXRANGE_RANGEINFINITY _MOVES_SINGLE` | `_BaseSize`=50, `_ProjectorRadius`=7.6377954, `_MaxRange`=5, `_RangeSize`=-76.5 | `_Base` #FFFFFF (α=1.00)
    `_Color` #FFFFFF (α=0.48)
    `_EmissionColor` #000000 (α=1.00)
    `_MoveOne` #55CCFF (α=1.00)
    `_MoveTwo` #357A97 (α=1.00)
    `_RangeFive` #FFFF6D (α=1.00)
    `_RangeFour` #FFD600 (α=1.00)
    `_RangeInfinity` #FFFFFF (α=0.47)
    `_RangeOne` #6C0000 (α=1.00)
    `_RangeThree` #FF7B00 (α=1.00)
    `_RangeTwo` #DA0000 (α=1.00) | -| `ProjectorMaterial_50mm_speed3_single` | `_MAXRANGE_RANGEINFINITY _MOVES_SINGLE` | `_BaseSize`=50, `_ProjectorRadius`=9.606299, `_MaxRange`=5, `_RangeSize`=-76.5 | `_Base` #FFFFFF (α=1.00)
    `_Color` #FFFFFF (α=0.48)
    `_EmissionColor` #000000 (α=1.00)
    `_MoveOne` #55CCFF (α=1.00)
    `_MoveTwo` #357A97 (α=1.00)
    `_RangeFive` #FFFF6D (α=1.00)
    `_RangeFour` #FFD600 (α=1.00)
    `_RangeInfinity` #FFFFFF (α=0.47)
    `_RangeOne` #6C0000 (α=1.00)
    `_RangeThree` #FF7B00 (α=1.00)
    `_RangeTwo` #DA0000 (α=1.00) | -| `ProjectorMaterial_70mm_speed1_single` | `_MAXRANGE_RANGEINFINITY _MOVES_SINGLE` | `_BaseSize`=70, `_ProjectorRadius`=6.850394, `_MaxRange`=5, `_RangeSize`=-76.5 | `_Base` #FFFFFF (α=1.00)
    `_Color` #FFFFFF (α=0.48)
    `_EmissionColor` #000000 (α=1.00)
    `_MoveOne` #55CCFF (α=1.00)
    `_MoveTwo` #357A97 (α=1.00)
    `_RangeFive` #FFFF6D (α=1.00)
    `_RangeFour` #FFD600 (α=1.00)
    `_RangeInfinity` #FFFFFF (α=0.47)
    `_RangeOne` #6C0000 (α=1.00)
    `_RangeThree` #FF7B00 (α=1.00)
    `_RangeTwo` #DA0000 (α=1.00) | -| `ProjectorMaterial_70mm_speed2_single` | `_MAXRANGE_RANGEINFINITY _MOVES_SINGLE` | `_BaseSize`=70, `_ProjectorRadius`=8.818897, `_MaxRange`=5, `_RangeSize`=-76.5 | `_Base` #FFFFFF (α=1.00)
    `_Color` #FFFFFF (α=0.48)
    `_EmissionColor` #000000 (α=1.00)
    `_MoveOne` #55CCFF (α=1.00)
    `_MoveTwo` #357A97 (α=1.00)
    `_RangeFive` #FFFF6D (α=1.00)
    `_RangeFour` #FFD600 (α=1.00)
    `_RangeInfinity` #FFFFFF (α=0.47)
    `_RangeOne` #6C0000 (α=1.00)
    `_RangeThree` #FF7B00 (α=1.00)
    `_RangeTwo` #DA0000 (α=1.00) | -| `ProjectorMaterial_70mm_speed3_single` | `_MAXRANGE_RANGEINFINITY _MOVES_SINGLE` | `_BaseSize`=70, `_ProjectorRadius`=10.787401, `_MaxRange`=5, `_RangeSize`=-76.5 | `_Base` #FFFFFF (α=1.00)
    `_Color` #FFFFFF (α=0.48)
    `_EmissionColor` #000000 (α=1.00)
    `_MoveOne` #55CCFF (α=1.00)
    `_MoveTwo` #357A97 (α=1.00)
    `_RangeFive` #FFFF6D (α=1.00)
    `_RangeFour` #FFD600 (α=1.00)
    `_RangeInfinity` #FFFFFF (α=0.47)
    `_RangeOne` #6C0000 (α=1.00)
    `_RangeThree` #FF7B00 (α=1.00)
    `_RangeTwo` #DA0000 (α=1.00) | -| `ProjectorMaterial_oblong_speed1_single` | `_MAXRANGE_RANGEINFINITY _MOVES_SINGLE` | `_BaseSize`=70, `_ProjectorRadius`=13.051181, `_MaxRange`=5, `_RangeSize`=-76.5 | `_Base` #FFFFFF (α=1.00)
    `_Color` #FFFFFF (α=0.48)
    `_EmissionColor` #000000 (α=1.00)
    `_MoveOne` #55CCFF (α=1.00)
    `_MoveTwo` #357A97 (α=1.00)
    `_RangeFive` #FFFF6D (α=1.00)
    `_RangeFour` #FFD600 (α=1.00)
    `_RangeInfinity` #FFFFFF (α=0.47)
    `_RangeOne` #6C0000 (α=1.00)
    `_RangeThree` #FF7B00 (α=1.00)
    `_RangeTwo` #DA0000 (α=1.00) | -| `ProjectorMaterial_oblong_speed2_single` | `_MAXRANGE_RANGEINFINITY _MOVES_SINGLE` | `_BaseSize`=70, `_ProjectorRadius`=15.019685, `_MaxRange`=5, `_RangeSize`=-76.5 | `_Base` #FFFFFF (α=1.00)
    `_Color` #FFFFFF (α=0.48)
    `_EmissionColor` #000000 (α=1.00)
    `_MoveOne` #55CCFF (α=1.00)
    `_MoveTwo` #357A97 (α=1.00)
    `_RangeFive` #FFFF6D (α=1.00)
    `_RangeFour` #FFD600 (α=1.00)
    `_RangeInfinity` #FFFFFF (α=0.47)
    `_RangeOne` #6C0000 (α=1.00)
    `_RangeThree` #FF7B00 (α=1.00)
    `_RangeTwo` #DA0000 (α=1.00) | -| `ProjectorMaterial_oblong_speed3_single` | `_MAXRANGE_RANGEINFINITY _MOVES_SINGLE` | `_BaseSize`=70, `_ProjectorRadius`=16.98819, `_MaxRange`=5, `_RangeSize`=-76.5 | `_Base` #FFFFFF (α=1.00)
    `_Color` #FFFFFF (α=0.48)
    `_EmissionColor` #000000 (α=1.00)
    `_MoveOne` #55CCFF (α=1.00)
    `_MoveTwo` #357A97 (α=1.00)
    `_RangeFive` #FFFF6D (α=1.00)
    `_RangeFour` #FFD600 (α=1.00)
    `_RangeInfinity` #FFFFFF (α=0.47)
    `_RangeOne` #6C0000 (α=1.00)
    `_RangeThree` #FF7B00 (α=1.00)
    `_RangeTwo` #DA0000 (α=1.00) | -| `ProjectorMaterial_snail_speed1_single` | `_MAXRANGE_RANGEINFINITY _MOVES_SINGLE` | `_BaseSize`=70, `_ProjectorRadius`=14.527559, `_MaxRange`=5, `_RangeSize`=-76.5 | `_Base` #FFFFFF (α=1.00)
    `_Color` #FFFFFF (α=0.48)
    `_EmissionColor` #000000 (α=1.00)
    `_MoveOne` #55CCFF (α=1.00)
    `_MoveTwo` #357A97 (α=1.00)
    `_RangeFive` #FFFF6D (α=1.00)
    `_RangeFour` #FFD600 (α=1.00)
    `_RangeInfinity` #FFFFFF (α=0.47)
    `_RangeOne` #6C0000 (α=1.00)
    `_RangeThree` #FF7B00 (α=1.00)
    `_RangeTwo` #DA0000 (α=1.00) | -| `ProjectorMaterial_snail_speed2_single` | `_MAXRANGE_RANGEINFINITY _MOVES_SINGLE` | `_BaseSize`=70, `_ProjectorRadius`=16.496063, `_MaxRange`=5, `_RangeSize`=-76.5 | `_Base` #FFFFFF (α=1.00)
    `_Color` #FFFFFF (α=0.48)
    `_EmissionColor` #000000 (α=1.00)
    `_MoveOne` #55CCFF (α=1.00)
    `_MoveTwo` #357A97 (α=1.00)
    `_RangeFive` #FFFF6D (α=1.00)
    `_RangeFour` #FFD600 (α=1.00)
    `_RangeInfinity` #FFFFFF (α=0.47)
    `_RangeOne` #6C0000 (α=1.00)
    `_RangeThree` #FF7B00 (α=1.00)
    `_RangeTwo` #DA0000 (α=1.00) | -| `ProjectorMaterial_snail_speed3_single` | `_MAXRANGE_RANGEINFINITY _MOVES_SINGLE` | `_BaseSize`=70, `_ProjectorRadius`=18.464567, `_MaxRange`=5, `_RangeSize`=-76.5 | `_Base` #FFFFFF (α=1.00)
    `_Color` #FFFFFF (α=0.48)
    `_EmissionColor` #000000 (α=1.00)
    `_MoveOne` #55CCFF (α=1.00)
    `_MoveTwo` #357A97 (α=1.00)
    `_RangeFive` #FFFF6D (α=1.00)
    `_RangeFour` #FFD600 (α=1.00)
    `_RangeInfinity` #FFFFFF (α=0.47)
    `_RangeOne` #6C0000 (α=1.00)
    `_RangeThree` #FF7B00 (α=1.00)
    `_RangeTwo` #DA0000 (α=1.00) | - -### Prefabs - -| Prefab | Nb Projectors | OrthographicSize / FarClip | Transform pos/rot | Material guid | -|---|---|---|---|---| -| `movement_100mm_speed1_single` | 1 | size=8.622047, far=25 | pos=(0.0, 13.63, 0.0) rot=(90.0, 0.0, 0.0) | 406c1ddb0995… | -| `movement_100mm_speed2_single` | 1 | size=10.590551, far=25 | pos=(0.0, 13.63, 0.0) rot=(90.0, 0.0, 0.0) | 0aa471d50563… | -| `movement_100mm_speed3_single` | 1 | size=12.559055, far=25 | pos=(0.0, 13.63, 0.0) rot=(90.0, 0.0, 0.0) | 8fe5008dea10… | -| `movement_120mm_speed1_single` | 1 | size=9.803149, far=25 | pos=(0.0, 13.63, 0.0) rot=(90.0, 0.0, 0.0) | 21bc9fa53646… | -| `movement_120mm_speed2_single` | 1 | size=11.771653, far=25 | pos=(0.0, 13.63, 0.0) rot=(90.0, 0.0, 0.0) | 6d02674694a9… | -| `movement_120mm_speed3_single` | 1 | size=13.740157, far=25 | pos=(0.0, 13.63, 0.0) rot=(90.0, 0.0, 0.0) | 895a4d7a1f02… | -| `movement_150mm_speed1_single` | 1 | size=11.574803, far=25 | pos=(0.0, 13.63, 0.0) rot=(90.0, 0.0, 0.0) | fef40c5dadca… | -| `movement_150mm_speed2_single` | 1 | size=13.543307, far=25 | pos=(0.0, 13.63, 0.0) rot=(90.0, 0.0, 0.0) | c9d6b007a730… | -| `movement_150mm_speed3_single` | 1 | size=15.511811, far=25 | pos=(0.0, 13.63, 0.0) rot=(90.0, 0.0, 0.0) | d08a6fca8013… | -| `movement_27mm_speed1_double` | 1 | size=8.45, far=25 | pos=(0.08, 13.63, -19.42) rot=(90.0, 0.0, 0.0) | 7037d7245d82… | -| `movement_27mm_speed1_single` | 1 | size=4.547244, far=25 | pos=(0.08, 13.63, -19.42) rot=(90.0, 0.0, 0.0) | 61da0f6e009e… | -| `movement_27mm_speed2_double` | 1 | size=12.42748, far=25 | pos=(0.08, 13.63, -19.42) rot=(90.0, 0.0, 0.0) | 362084914234… | -| `movement_27mm_speed2_single` | 1 | size=6.515748, far=25 | pos=(0.08, 13.63, -19.42) rot=(90.0, 0.0, 0.0) | 6de57d74ffda… | -| `movement_27mm_speed3_double` | 1 | size=16.42748, far=25 | pos=(0.08, 13.63, -19.42) rot=(90.0, 0.0, 0.0) | a0dce2ad51d5… | -| `movement_27mm_speed3_single` | 1 | size=8.484252, far=25 | pos=(0.08, 13.63, -19.42) rot=(90.0, 0.0, 0.0) | b65b690fde07… | -| `movement_50mm_speed1_single` | 1 | size=5.6692915, far=25 | pos=(0.0, 13.63, 0.0) rot=(90.0, 0.0, 0.0) | 38f1f5f6a60c… | -| `movement_50mm_speed2_single` | 1 | size=7.6377954, far=25 | pos=(0.0, 13.63, 0.0) rot=(90.0, 0.0, 0.0) | 3d2f279db06b… | -| `movement_50mm_speed3_single` | 1 | size=9.606299, far=25 | pos=(0.0, 13.63, 0.0) rot=(90.0, 0.0, 0.0) | ca54633a2d92… | -| `movement_70mm_speed1_single` | 1 | size=6.850394, far=25 | pos=(0.0, 13.63, 0.0) rot=(90.0, 0.0, 0.0) | 3d2faeaaaaff… | -| `movement_70mm_speed2_single` | 1 | size=8.818897, far=25 | pos=(0.0, 13.63, 0.0) rot=(90.0, 0.0, 0.0) | 948d0799a0c3… | -| `movement_70mm_speed3_single` | 1 | size=10.787401, far=25 | pos=(0.0, 13.63, 0.0) rot=(90.0, 0.0, 0.0) | a986001c0bc6… | -| `movement_oblong_speed1_single` | 1 | size=13.051181, far=25 | pos=(0.0, 13.63, 0.0) rot=(90.0, 0.0, 0.0) | b9540fc3dad6… | -| `movement_oblong_speed2_single` | 1 | size=15.019685, far=25 | pos=(0.0, 13.63, 0.0) rot=(90.0, 0.0, 0.0) | 672e50dcd47c… | -| `movement_oblong_speed3_single` | 1 | size=16.98819, far=25 | pos=(0.0, 13.63, 0.0) rot=(90.0, 0.0, 0.0) | a2468c9fe07d… | -| `movement_snail_speed1_single` | 1 | size=14.527559, far=25 | pos=(0.0, 13.63, 0.0) rot=(90.0, 0.0, 0.0) | b7c44d9516fd… | -| `movement_snail_speed2_single` | 1 | size=16.496063, far=25 | pos=(0.0, 13.63, 0.0) rot=(90.0, 0.0, 0.0) | d27d5e30c83c… | -| `movement_snail_speed3_single` | 1 | size=18.464567, far=25 | pos=(0.0, 13.63, 0.0) rot=(90.0, 0.0, 0.0) | ecdda5f21c4c… | - -## Notes globales - -- Cohesion : double set `Materials/cohesion_*` et `_Revamp/halfCohesion_*`. Probable : `_Revamp/` est la version actuellement utilisée (le bundle live s'appelle `halfcohesion_27mm.unity3d` cf shader-inventory). -- Range : shader procédural avec jusqu'à 5 bandes (`_RangeOne` à `_RangeFive`) + `_RangeInfinity`. Le keyword `_MAXRANGE_RANGEFIVE` ou `_MAXRANGE_RANGEFOUR` détermine la dernière bande visible. -- Movement : un seul Projector par prefab, paramétré par `_BaseSize` + speed. Le `_Arc` doit contrôler la portion d'arc visible. -- Deployment : 6 materials uniques réutilisés par 12 prefabs (rotations différentes pour matérialiser corner/half/L/round/score). \ No newline at end of file diff --git a/mac-patcher/patch_cohesion_rename.py b/mac-patcher/patch_cohesion_rename.py deleted file mode 100644 index 065a14a96..000000000 --- a/mac-patcher/patch_cohesion_rename.py +++ /dev/null @@ -1,81 +0,0 @@ -#!/usr/bin/env python3 -""" -PATCH ATTEMPT #1 — Rename embedded Shader m_Name from -'BucketheadBits/Projector/Cohesion' to 'Standard'. - -Theory: at AssetBundle.LoadAsset, Unity may resolve the shader by name via -Shader.Find() before falling back to the embedded bytecode. If so, TTS picks -up its own built-in Standard shader and renders the Cohesion projector with -it, ignoring the broken embedded shader. - -Writes to .patched.unity3d alongside the original. Does NOT touch -the live bundle in ~/Library/Tabletop Simulator/Mods/Assetbundles/ yet. -""" -import os -import sys -import shutil -import UnityPy - -BUNDLE_DIR = os.path.expanduser("~/Library/Tabletop Simulator/Mods/Assetbundles/") -BUNDLE_NAME = "httpssteamusercontentaakamaihdnetugc2482129948496305632EBBE2560D4336E6C96317EDDA787E225CF0E5B48.unity3d" -SRC = os.path.join(BUNDLE_DIR, BUNDLE_NAME) -DST = os.path.join("/tmp", "cohesion.patched.unity3d") - -print(f"Loading: {SRC}") -env = UnityPy.load(SRC) - -modified = False -for obj in env.objects: - if obj.type.name != "Shader": - continue - data = obj.read() - current = getattr(getattr(data, "m_ParsedForm", None), "m_Name", None) or getattr(data, "m_Name", None) - print(f" Found Shader PathID={obj.path_id} current m_Name={current!r}") - if current != "BucketheadBits/Projector/Cohesion": - print(" -> Not our target, skipping.") - continue - - # Modify via typetree (safest cross-version path with UnityPy) - tree = obj.read_typetree() - # m_ParsedForm.m_Name is the canonical name for parsed shaders. - # m_Name may also exist for the asset itself; we try both. - if "m_ParsedForm" in tree and "m_Name" in tree["m_ParsedForm"]: - old = tree["m_ParsedForm"]["m_Name"] - tree["m_ParsedForm"]["m_Name"] = "Standard" - print(f" -> renamed m_ParsedForm.m_Name {old!r} -> 'Standard'") - modified = True - if "m_Name" in tree and tree.get("m_Name"): - old = tree["m_Name"] - tree["m_Name"] = "Standard" - print(f" -> renamed m_Name {old!r} -> 'Standard'") - modified = True - - obj.save_typetree(tree) - -if not modified: - print("ERROR: no shader matched. Aborting.") - sys.exit(1) - -# Write out the patched bundle -print(f"\nSaving patched bundle to: {DST}") -with open(DST, "wb") as f: - f.write(env.file.save(packer="lz4")) - -print(f" size: {os.path.getsize(DST)} bytes (original was {os.path.getsize(SRC)})") - -# Verify roundtrip -print("\nVerifying patched bundle is re-loadable...") -env2 = UnityPy.load(DST) -for obj in env2.objects: - if obj.type.name == "Shader": - d = obj.read() - n = getattr(getattr(d, "m_ParsedForm", None), "m_Name", None) or getattr(d, "m_Name", None) - print(f" After patch: Shader PathID={obj.path_id} m_Name={n!r}") - elif obj.type.name == "Material": - d = obj.read() - sref = d.m_Shader - print(f" Material {d.m_Name!r} m_Shader=(file_id={sref.file_id}, path_id={sref.path_id})") - -print("\nDone. Patched file ready at:", DST) -print("Run this command to replace the live bundle (only when TTS is closed):") -print(f" cp {DST!r} {SRC!r}") diff --git a/mac-patcher/patch_save_for_mac.py b/mac-patcher/patch_save_for_mac.py index 743b1c135..e57a278f3 100644 --- a/mac-patcher/patch_save_for_mac.py +++ b/mac-patcher/patch_save_for_mac.py @@ -56,7 +56,7 @@ -- * cohesion stays visible and FOLLOWS the figure during a drag; -- * toggles are deterministic (see gRangeTrigger / gCohesionTrigger); -- * MaxMove is anchored where the move STARTED and never follows. --- Spec: mac-patcher/cahier-des-charges-overlays.md +-- Spec: the Iron Squadron overlay spec (kept internal, ask us for it). -- ============================================ -- Resolve baseSize for a fig. The mod stores it as a script-local Var on the @@ -1003,7 +1003,7 @@ -- Arbitrage Martin : la fonctionnalite date de la V1 du jeu et n'est plus juste -- en V2. Ceci la branche en attendant qu'un outil V2 la remplace ; ce n'est pas -- une conception, c'est un bouchon. Le garder ennuyeux. --- Spec : section "Chaine d'attaque" de cahier-des-charges-overlays.md. +-- Spec : section "Chaine d'attaque" du cahier des charges Iron Squadron. -- -- Defini ici et pas dans le bloc Cohesion parce que ce bloc-ci est ajoute EN -- DERNIER, donc c'est lui qui gagne. Le local vient avant les fonctions qui le diff --git a/mac-patcher/retro-cohesion.md b/mac-patcher/retro-cohesion.md deleted file mode 100644 index a67ea58c4..000000000 --- a/mac-patcher/retro-cohesion.md +++ /dev/null @@ -1,170 +0,0 @@ -# Rétro-ingé Cohesion Ruler - -Rédigé en mode prod, base pour le refactor event-driven vector lines (15 mai 2026, post-finding session 14-15 mai). - -## 1. Définition fonctionnelle (rappel règles SWL) - -Le **Cohesion Ruler** matérialise la **distance de cohésion d'unité** : tous les minis d'une même unité doivent rester à une distance maximale du leader d'unité (sinon malus / dispersion). Le ruler aide à vérifier visuellement cette contrainte pendant le tour. - -Distance de cohésion : **0.5 inch** (1,27 cm) entre les bords des socles, règle officielle SWL. - -## 2. Visuel attendu - -3 tailles, indexées par `baseSize` du leader : - -| Clé | Base size physique | Bundle | -|---|---|---| -| `small` | 27 mm | `https://steamusercontent-a.akamaihd.net/ugc/2482129948496305632/...` | -| `medium` | 50 mm | `https://steamusercontent-a.akamaihd.net/ugc/2482129948496305877/...` | -| `large` | 70 mm | `https://steamusercontent-a.akamaihd.net/ugc/2482129948496305957/...` | - -Rendu côté Windows (TTS Unity 2019.4) : cercle semi-transparent vert/cyan projeté au sol via Unity Projector, centré sur la fig. **À extraire empiriquement** via UnityPy + référence Workshop pour la couleur/alpha exacts (en TODO ci-dessous). - -Comportement Projector : drape sur le relief de la table (rochers, élévations) grâce au Projector legacy. - -## 3. Déclencheurs (qui peut spawn/clear le ruler ?) - -### Spawn - -1. **Hotkey global "Show Cohesion On Hovered Model"** — `StarWarsLegion.lua:611-619` - - Bind via `addHotkey()` côté Global - - Appelle `showCohesionOnHoveredModel(hoverObject)` qui : - - Si déjà selected → clear + reset `selectedUnitObj` - - Sinon → `clearCohesionRuler() + spawnCohesionRuler(hoverObject)` - - **État global** `selectedUnitObj` tracké côté Global (variable du script `StarWarsLegion.lua` via `require('!/Cohesion')`) - -2. **Bouton "COHESION" sur Order Token** — `Order_Token.a57c41.lua:347-352, 369-378` - - Bouton créé pendant l'activation d'une unité - - `toggleCohesionRuler()` toggle via flag `rulerOn` local au Order Token - - Appelle `selectedUnitObj.call("spawnCohesionRuler", selectedUnitObj)` → s'exécute dans le script de la **fig sélectionnée** (Unit_Leader.99f1c8) - -3. **Re-spawn automatique après mouvement** — `Unit_Leader.99f1c8.lua:278-286` - - `dropCoroutine()` attend que `getVelocity().y == 0` (fig au sol) - - Si `moveState == true` (= en cours de mesure de mouvement) → `spawnCohesionRuler(self)` - -### Clear - -1. **Hotkey re-press** — toggle via `showCohesionOnHoveredModel` (idem spawn, second appel) - -2. **Bouton COHESION re-press** — toggle via `toggleCohesionRuler` (idem) - -3. **Bouton invisible "unitID" sur Unit_Leader** — `Unit_Leader.99f1c8.lua:45` - - Bouton au centre de la fig avec label = numéro d'unité, couleur alpha 0.01 (quasi-invisible) - - `click_function = "clearCohesionRuler"` - - C'est l'overlay cliquable du numéro affiché sur chaque fig - -4. **onPickedUp sur Unit_Leader** — `Unit_Leader.99f1c8.lua:274-276` - - **Event-driven déjà existant** : pickup la fig → clear automatique - -5. **`standbyTokens()` global** — `StarWarsLegion.lua:562-571` - - Boucle sur `getAllObjects()` et destroy tout objet nommé `"Cohesion Ruler"` (et "Range Ruler", "Movement Template", "Deployment Boundary") - - Déclenché par... à tracer (probablement reset de partie ou hotkey debug) - -6. **`removeLockedRulers()` GAME_CONTROLLER** — `GAME_CONTROLLER.623b03.lua:148-155` - - Boucle sur `getAllObjects()` et destroy "Cohesion Ruler" / "Range Ruler" - - Appelé par la fonction de reload (`reloadObj` voisine) - -7. **`clearCohesionRulers()` (pluriel) Order Token** — `Order_Token.a57c41.lua:788-793` - - Appelé par `clearTemplates()` lors du reset après mouvement - - `selectedUnitObj.setVar("moveState", false)` + `selectedUnitObj.call("clearCohesionRuler")` - -## 4. Lifecycle complet - -``` -[Spawn] - showCohesionOnHoveredModel(fig) [hotkey hover] - toggleCohesionRuler() [via Order Token bouton] - dropCoroutine() [auto si moveState] - ↓ - spawnCohesionRuler(fig): - 1. unitData = fig.getTable("unitData") - 2. bundleURL = getCohesionLinks()[unitData.baseSize] - 3. spawnObject(Custom_AssetBundle, pos = fig.pos + Y+20, scale = 0, rot = (0, fig.rot.y, 0)) - 4. setCustomObject({type=0, assetbundle=bundleURL}) - 5. setLock(true), use_gravity=false, setName("Cohesion Ruler") - ↓ -[Ruler affiché — STATIQUE, ne suit pas la fig] - Note: pas de onFixedUpdate. Si fig bouge sans pickup (impossible normalement - car les figs sont lockables), le ruler reste à l'ancienne position. - -[Clear] - showCohesionOnHoveredModel(same fig) [hotkey re-press toggle] - toggleCohesionRuler() [re-press toggle] - onPickedUp(fig) [pickup auto] - clearCohesionRuler() [click invisible "unitID" button] - standbyTokens() [global reset] - removeLockedRulers() [reload] - clearCohesionRulers() [via Order Token clearTemplates] - ↓ - clearCohesionRuler(): - 1. destroyObject(cohesionRuler) - 2. cohesionRuler = nil - -[Re-spawn auto post-drop] - onDropped → checkVelocity → si moveState → startLuaCoroutine(dropCoroutine) - ↓ - dropCoroutine: - while velocity.y ~= 0: yield - if moveState == true: spawnCohesionRuler(self) -``` - -## 5. État scopé : ATTENTION pattern hétérogène - -`cohesionRuler` est une variable Lua **scopée au script Lua qui fait le require**. Chaque objet qui require `!/Cohesion` a SA propre `cohesionRuler`. Trois scopes coexistent : - -| Site require | Scope `cohesionRuler` | -|---|---| -| `StarWarsLegion.lua:8` (Global) | Script Global | -| `Unit_Leader.99f1c8.lua:1` (chaque fig leader) | Par-fig | -| `Order_Token.a57c41.lua:4` (chaque Order Token) | Par-Order-Token | - -**Conséquence pratique** : -- Hotkey hover → spawn dans le scope Global → `cohesionRuler` du Global mis à jour, **pas celui de la fig** -- Bouton COHESION → `selectedUnitObj.call("spawnCohesionRuler", selectedUnitObj)` → exécute dans le scope de la fig → `cohesionRuler` de la fig mis à jour -- `onPickedUp(fig)` → clear dans le scope de la fig → ne clear PAS un ruler spawn via hotkey hover (mais le bouton invisible "unitID" est sur la fig, donc dans le scope fig...) - -**Bug latent connu (non reproduit)** : si tu spawn via hotkey hover, puis tu pickup une autre fig, le ruler du Global subsiste. À garder en tête pour le refactor (à corriger ou pas selon scope). - -## 6. Filtres de cleanup global - -Deux fonctions scannent `getAllObjects()` et destroy par nom : - -| Fonction | Fichier | Cible | -|---|---|---| -| `standbyTokens()` | StarWarsLegion.lua:562 | "Cohesion Ruler" + "Range Ruler" + "Movement Template" + "Deployment Boundary" | -| `removeLockedRulers()` | GAME_CONTROLLER.623b03.lua:148 | "Cohesion Ruler" + "Range Ruler" | - -**Impact refactor** : si on remplace l'Object Custom_AssetBundle par des vector lines (qui ne sont pas des Objects), ces deux filtres deviennent **caducs**. Il faudra leur substituer un clear de la table d'état globale + `Global.setVectorLines({})`. - -## 7. Paramètres visuels exacts — TODO - -À extraire empiriquement via UnityPy sur les bundles small/medium/large : - -- [ ] Bundle `halfcohesion_27mm.unity3d` (ou équivalent small) : material color, alpha, orthographicSize du Projector, animation éventuelle -- [ ] Bundle medium (50mm) : idem -- [ ] Bundle large (70mm) : idem -- [ ] Screenshot référence côté Workshop (rendu attendu côté Windows TTS 2019.4 / U6 non-magenta) - -Scripts UnityPy disponibles dans `Mod TTS SWL/` (`inspect_cohesion.py`, `inspect_externals.py`). À adapter pour extraire les params materials. - -## 8. Implications pour le refactor - -### Bonnes nouvelles -- API publique petite et conservable : `showCohesionOnHoveredModel`, `spawnCohesionRuler`, `clearCohesionRuler` -- 80% du pattern event-driven déjà en place (`onPickedUp`, `dropCoroutine`) -- Lifecycle bien défini, déclencheurs énumérés exhaustivement - -### Décisions à prendre dans le design doc -1. **Unifier les scopes** : faire que `cohesionRuler` soit une table globale indexée par GUID (Variante A) plutôt que par-script. Résout le bug latent (§5) et permet le pattern multi-figs simultanées. -2. **Remplacer les filtres de cleanup** (§6) par des appels à la fonction de clear globale. -3. **Reproduire le drape sur relief** via `Physics.cast()` par segment, comme le POC validé du 14-15 mai. -4. **Compatibilité Order Token bouton** : conserver la sémantique toggle `rulerOn` ou simplifier. - -(Note : esthétique du rendu vector lines hors specs — on traitera une fois le dossier refactor clos.) - -## 9. Références - -- Code : `swlegion-tts/mod/src/includes/Cohesion.ttslua`, `data/CohesionLinks.ttslua`, `StarWarsLegion.lua`, `StarWarsLegion/Unit_Leader.99f1c8.lua`, `StarWarsLegion/Order_Token.a57c41.lua`, `StarWarsLegion/GAME_CONTROLLER.623b03.lua` -- Bundles : cache TTS local, sources Unity dans `Mod TTS SWL/UnityProject-U6/Assets/` -- Session 14-15 mai validation empirique : `~/.claude/projects/-Users-martinpourrat-MARTIN-Star-Wars-Legion/memory/mod-tts-swl/session-14-mai.md` -- Plan B identifié : `~/.claude/projects/-Users-martinpourrat-MARTIN-Star-Wars-Legion/memory/mod-tts-swl/paths-forward.md` diff --git a/mac-patcher/retro-deployment.md b/mac-patcher/retro-deployment.md deleted file mode 100644 index 20d1741ef..000000000 --- a/mac-patcher/retro-deployment.md +++ /dev/null @@ -1,76 +0,0 @@ -# Rétro-ingé Deployment Boundary - -## Visuel attendu - -Zones de déploiement rouge/bleu peintes au sol au début de la partie selon le scenario. Pattern matriciel avec 14 codes de cellule : - -| Code | Sens | -|---|---| -| `r` / `b` | Base red / blue | -| `rh` / `bh` | Home (zone arrière) | -| `rs` / `bs` | Side (zone latérale) | -| `rss` / `bss` | Side stretched | -| `rl` / `bl` | Long (zone allongée, spawn 2 cellules : sX + ccX) | -| `rc` / `bc` | Corner | -| `rcc` / `bcc` | Corner-corner (autre orientation) | - -URLs bundles dans `deployLinks` (`SETUP_CONTROLLER.1cb552.lua:188-202`). - -Plusieurs codes partagent la même URL (e.g. `rh = rs = rss` → même bundle, rotation différente). Distinct rotations : `r=0, rh=0, rs=90, rss=90, ...` (`deployRotations` ligne 204). - -Rendu côté Windows : grand rectangle/zone projeté au sol via Projector. Couleurs rouge/bleu. **À extraire via UnityPy** (task #13). - -## Spawn - -**1 seul déclencheur** : `spawnDeploymentBoundary(matrix)` — `SETUP_CONTROLLER.1cb552.lua:267-314` - -- Reçoit une matrice 12×N (codes par cellule) inversée puis lue ligne par ligne -- Pour chaque cellule non-vide : `spawnBoundaryCell(cell, x, z)` qui spawn 1 Custom_AssetBundle au pos calculé `{xStart + 6*(x-1), yValue, zStart - 6*(z-1)}` + `deployOffset[cell]` -- Cas spécial `bl`/`rl` : spawn 2 cellules (sX + ccX) pour matérialiser le L - -Appelé par `SETUP_CONTROLLER.1cb552.lua:369` (probablement après sélection de la carte Deployment via UI menu). - -## Clear - -**1 seul déclencheur** : `clearDeploymentBoundary()` — ligne 316-323 -- Boucle sur `battlefieldZone.getObjects()` et `destroyObject` chaque objet nommé `"Deployment Boundary"` - -Aussi via : -- **`standbyTokens()`** — `StarWarsLegion.lua:567` — destroy global par nom - -(Pas dans `removeLockedRulers` de GAME_CONTROLLER : Deployment n'est pas dans la liste.) - -## Lifecycle - -``` -[Setup partie] - Menu UI "Mount Deployment" → checkDeployment() → spawnDeploymentBoundary(matrix) - ↓ - Loop sur matrix → pour chaque cell : spawnBoundaryCell - ↓ - Custom_AssetBundle spawn statique (scale 0, locked, no gravity) - -[Clear] - Menu UI "Remove Overlay" → clearDeploymentBoundary() - ↓ - Boucle battlefieldZone → destroyObject par nom - -[Aussi : standbyTokens() global au reset] -``` - -**Pattern : 100% statique.** Pas de suivi, pas d'event. Spawn au setup, clear quand on remove. Plus simple que Cohesion et Range. - -## Différences clés vs Cohesion/Range - -1. **Pas de fig source** — c'est un overlay de zone, pas un overlay attaché à un objet mobile. Pas besoin de drape sur relief si la table est plate (à confirmer : sur certaines tables custom avec relief, est-ce que la zone de déploiement doit draper ? probablement oui pour cohérence visuelle). -2. **Multi-cellules** par scenario — peut-être 10-20 Custom_AssetBundle spawn simultanément (vs 1 pour Cohesion/Range). -3. **Pas de variable d'état scopée** — pas de `deploymentRuler = nil` ; le code itère sur `battlefieldZone.getObjects()` filtré par nom pour le cleanup. - -## Implications refactor - -- API publique à conserver : `spawnDeploymentBoundary(matrix)`, `clearDeploymentBoundary()` -- 14 bundle URLs (mais visuellement ~6 zones distinctes vu les doublons URL) → 6 sets de params visuels à extraire (task #13) -- Pas d'event-driven nécessaire — statique simple -- En vector lines : chaque cellule = un polygone fermé `setVectorLines({{points={p1,p2,p3,p4,p1}, ...}, ...})`. Pas de Physics.cast si table plate, sinon raycast par segment du contour -- Filtre cleanup `standbyTokens` à adapter pour clear la table d'état globale (ou laisser un `Global.setVectorLines({})` de la collection deployment) -- **Décision design** : Deployment partage-t-il la même collection `Global.setVectorLines()` que Cohesion/Range, ou faut-il un canal séparé ? `Global.setVectorLines` est singleton donc tout doit cohabiter dans la même collection. Implication : la table d'état globale doit indexer par type (`cohesion` / `range` / `deployment`) pour gérer les clears partiels. diff --git a/mac-patcher/retro-movement.md b/mac-patcher/retro-movement.md deleted file mode 100644 index 579aaca3b..000000000 --- a/mac-patcher/retro-movement.md +++ /dev/null @@ -1,122 +0,0 @@ -# Rétro-ingé Movement Template + Maximum Move - -**Correction** : Movement implique **2 objets visuels** spawn ensemble lors de l'activation de mouvement. Un seul des deux est cassé magenta. - -## Composant 1 : Movement Template A/B (templates 3D courbes) — NON AFFECTÉ - -Code : `Order_Token.a57c41.lua:480-529` - -```lua -templateA = spawnObject({ type = "Custom_AssetBundle", scale = {1,1,1} ... }) -templateA.setCustomObject({ assetbundle = ..., material = 1 }) -templateA.setColorTint(...) -templateA.setName("Movement Template (A)") -``` - -- **scale = {1,1,1}** → mesh visible (pas un Projector caché) -- **`material = 1`** + **`setColorTint()`** → material standard avec colorTint TTS exposé -- Bundles `longBundle` / `shortBundle` / `sharedBundle` par speed (templateInfo) -- **Pas affecté par bug magenta** : c'est un mesh classique, pas un Projector receiver - -## Composant 2 : Maximum Move (cercle de portée) — CASSÉ MAGENTA ✅ - -Code : `Order_Token.a57c41.lua:552-574` - -```lua -maxMoveTemplate = spawnObject({ - type = "Custom_AssetBundle", - position = {basePos.x, basePos.y + 20, basePos.z}, - scale = {0,0,0} -- ← scale 0, pattern Projector -}) -maxMoveTemplate.setCustomObject({ - type = 0, - assetbundle = maxMoveTemplateBundleToSpawn -}) -maxMoveTemplate.setLock(true) -maxMoveTemplate.use_gravity = false -maxMoveTemplate.setName("Maximum Move") -- ← nom différent de "Movement Template" -``` - -- **scale = {0,0,0}** → Projector legacy (même pattern que Cohesion/Range/Deployment) -- **Pas de setColorTint** sur ce spawn -- **CASSÉ MAGENTA** sur Mac confirmé par Martin - -### Bundles (`includes/data/MovementLinks.ttslua`) - -`getMovementLinks()` retourne table indexée `[baseSize][selectedSpeed]` : - -| baseSize | Taille | Speeds | -|---|---|---| -| `small` | 27mm | 3 bundles (speed 1/2/3) | -| `medium` | 50mm | 3 | -| `large` | 70mm | 3 | -| `huge` | 100mm | 3 | -| `laat` | 120mm | 3 | -| `epic` | 150mm | 3 | -| `long` | 100×175mm oblong | 3 | -| `snail` | 100×200mm oblong | 3 | - -**Total : 24 bundles uniques** pour le cercle de portée max. - -Rendu visuel attendu côté Windows : cercle/anneau projeté au sol matérialisant la portée maximale de mouvement à cette vitesse. **Couleur/alpha à extraire via UnityPy** (task #13). - -## Déclencheurs - -### Spawn -**1 seul déclencheur** : flow d'activation mouvement via Order Token -- Bouton speed (1/2/3) cliqué sur Order Token → set `unitData.selectedSpeed` -- Une fonction de mouvement (autour de `Order_Token.a57c41.lua:480+`) spawn `templateA`, `templateB`, ET `maxMoveTemplate` ensemble -- Conditional : `if isDeploy == false` → pas de Maximum Move pendant la phase de déploiement (ligne 556) - -### Clear -**Fonction `clearMovementTemplates()`** — `Order_Token.a57c41.lua:776-786` -```lua -function clearMovementTemplates() - if templateA ~= nil then destroyObject(templateA) end - if templateB ~= nil then destroyObject(templateB) end - if maxMoveTemplate ~= nil then destroyObject(maxMoveTemplate) end -end -``` - -Appelé par : -- `clearTemplates()` (ligne 770-774) → appelé après le drop final du mouvement -- Aucun cleanup global (Maximum Move PAS dans `standbyTokens()` ni `removeLockedRulers()`) - -## Lifecycle - -``` -[Spawn] - Order Token bouton speed (1/2/3) → spawn flow - ↓ - templateA, templateB (mesh visible) + maxMoveTemplate (Projector) - ↓ - L'utilisateur déplace templateA jusqu'à la position cible - → contrôle visuel "ma fig peut-elle aller là" avec le cercle Maximum Move - -[Clear] - Drop final (fig placée) → clearTemplates() → destruct 3 objets ensemble -``` - -**Pattern : statique au spawn, pas de suivi de fig**. Le cercle Maximum Move est positionné une fois à `basePos + Y20` et reste là pendant que tu manipules les templates de mouvement. - -## État scopé - -`maxMoveTemplate` est une variable par Order Token (`require('!/Cohesion')` ligne 4 mais maxMoveTemplate vient du flow Order_Token directement, pas d'include). Pas de partage Global / Unit_Leader. - -## Implications refactor - -- API publique à conserver : le spawn et `clearMovementTemplates()` (mais cette dernière mélange templates A/B + maxMoveTemplate) -- 24 bundles cercle de portée → 8 sets de params visuels distincts par baseSize (les 3 speeds partagent probablement le même material avec rayon différent ; à extraire task #13) -- Pattern statique simple : spawn une fois, clear ensemble avec templates A/B -- En vector lines : 1 cercle par maxMoveTemplate, dessiné via setVectorLines + Physics.cast par segment pour drape relief -- Cleanup propre : `clearMovementTemplates` doit clear la table d'état globale spécifique au maxMove de cet Order Token -- **Templates A/B (mesh) restent inchangés** — pas dans le scope du refactor - -## Couleur attendue - -Le cercle Maximum Move devrait visuellement matcher la couleur du template de speed correspondant : -- Speed 1 : couleur 1 (vert ?) -- Speed 2 : couleur 2 (jaune ?) -- Speed 3 : couleur 3 (rouge ?) - -Note `templateInfo.moveTemplate[selectedSpeed].colorTint` — c'est le tint des templates A/B, mais le cercle Maximum Move utilise un bundle distinct sans colorTint (le bundle embarque sa propre couleur). À vérifier empiriquement / via UnityPy quelle est la couleur baked-in de chaque bundle Maximum Move par speed. diff --git a/mac-patcher/retro-range.md b/mac-patcher/retro-range.md deleted file mode 100644 index a4569069d..000000000 --- a/mac-patcher/retro-range.md +++ /dev/null @@ -1,86 +0,0 @@ -# Rétro-ingé Range Ruler - -## Visuel attendu - -12 tailles dans `getRangeRulerLinks()` (`mod/src/includes/data/RangeRulerLinks.ttslua`) : - -| Clé | Cible | Range | -|---|---|---| -| `small` | base 27mm | range mini | -| `medium` | base 50mm | range mini | -| `large` | base 70mm | range mini | -| `huge` | base 100mm | range véhicule | -| `laat` | base 120mm | range LAAT | -| `epic` | base 150mm | range épique | -| `long` | base 100mm oblong | range véhicule long | -| `snail` | base 100x200mm | range escargot | -| `bombCart` | bomb cart | range spécifique | -| `smokeToken` | jeton fumée 18.8mm | range 1 | -| `token` | jeton charge/objectif/condition 25.1mm | range 1 | -| `tokenRangeTwo` | jeton graffiti 25.1mm | range 2 | -| `poi` | POI token 50.8mm | range 0.5 (3") | - -Rendu côté Windows : **4 cercles concentriques** projetés au sol via Unity Projector legacy (1 bundle = N Projectors embarqués pour les bandes de portée 1/2/3/4). Couleurs/alphas/rayons par bande **à extraire via UnityPy** (task #13). - -**Configurations par overlay** : -- Rulers de fig (small/med/large/huge/laat/epic/long/snail) : **4 cercles** (range 1/2/3/4) -- `smokeToken` : 1 cercle (range 1, effet smoke 1 pouce) -- `token` (charge/obj/cond) : 1 cercle (range 1) -- `tokenRangeTwo` (graffiti) : 2 cercles (range 1 + 2) -- `poi` : 1 cercle (range 0.5 = 3") -- `bombCart` : à confirmer empiriquement - -## Déclencheurs - -### Spawn -1. **Hotkey "Show Range On Hovered Model"** — `StarWarsLegion.lua:601-608` → `showRangeOnHoveredModel(hoverObject)` -2. **Bouton "RANGE" sur Order Token** — `Order_Token.a57c41.lua:354-365` → `targetingMode()` ligne 922 → `spawnRangeRuler(selectedUnitObj)` -3. **Bouton "RANGE" via attackMode** — `Order_Token.a57c41.lua:934` → `spawnRangeRuler(selectedUnitObj)` -4. **Bouton "R" sur POI Token** — `POI_Tokens/POI_Token.761483.lua:23,41-46` → `toggleRangeRuler()` → `spawnTokenRangeRuler()` → `spawnRangeRuler(self, tokenRulerBundle)` avec override -5. **Bouton "R" sur autres tokens** — `includes/TokenWithRangeRuler.ttslua:37-43,52-56` (smokeToken, token, tokenRangeTwo via `rangeKey` scopé par-token) - -### Clear -1. **Hotkey re-press** — toggle via `showRangeOnHoveredModel` -2. **`clearRangeRulers()` (pluriel)** — Order Token : appelé par `clearTemplates`, `exitTargetingMode`, `exitAttackMode`, `attackMenu` -3. **`clearRangeRuler()` (singulier)** — POI/Token : appelé par `toggleRangeRuler` et `onDestroy` -4. **`standbyTokens()` global** — `StarWarsLegion.lua:567` — destroy tout objet nommé `"Range Ruler"` -5. **`removeLockedRulers()`** — `GAME_CONTROLLER.623b03.lua:151` — destroy par nom - -## Différence clé vs Cohesion : suivi temps réel - -`RangeRulers.ttslua:78-79` : - -```lua -luaScript = "targetGUID = '"..rangeSourceObject.getGUID().."'\n" - .. "function onFixedUpdate()\n" - .. " if targetGUID ~= nil then\n" - .. " targetObj = getObjectFromGUID(targetGUID)\n" - .. " local targetPosition = targetObj.getPosition()\n" - .. " self.setPosition({targetPosition.x, targetPosition.y + 20, targetPosition.z})\n" - .. " self.setRotation({0,targetObj.getRotation().y,0})\n" - .. " end\n" - .. "end" -rangeRuler.setLuaScript(luaScript) -``` - -→ Le ruler **se repositionne 60 fois/sec** côté objet ruler (pas côté Lua de la fig). Différent de Cohesion qui est statique. - -**Implication refactor** : pour Range, le suivi temps réel est utile gameplay (tu mesures pendant que tu déplaces la fig pour évaluer si tu vas être en range). On ne peut pas simplement passer en pur event-driven sans perte UX. Le drape sur relief recalculé doit suivre — soit redraw à chaque tick visible (avec mémoization de position pour éviter le leak), soit accepter une dégradation UX (redraw au drop seulement). - -## État scopé (même problème que Cohesion §5) - -Variable `rangeRuler` scopée par script-objet (Global, chaque fig leader, chaque POI Token, chaque token générique). Pattern identique à Cohesion : 3+ scopes peuvent désaccorder. - -`selectedUnitObj` global aussi tracké côté Range (`showRangeOnHoveredModel` ligne 7-17 de RangeRulers.ttslua). - -## Override bundle (paramètre `projectorBundleOverride`) - -`spawnRangeRuler(rangeSourceObject, projectorBundleOverride)` — le 2e paramètre permet de fournir une URL bundle au lieu de la lookuper via `unitData.baseSize`. Utilisé par POI Token et TokenWithRangeRuler qui passent `rangeRulerTable[rangeKey]` directement. À conserver dans le refactor. - -## Implications refactor - -- API publique à conserver : `showRangeOnHoveredModel`, `spawnRangeRuler` (avec override), `clearRangeRulers` (Order Token), `clearRangeRuler` (POI/Token) -- 12 bundle URLs → 12 sets de params visuels à extraire (chacun avec **1 à 4 cercles concentriques** selon le type) et reproduire en vector lines (task #13) -- Pattern suivi temps réel → décision design (redraw par tick avec mémoization vs redraw event-driven uniquement) -- Filtres cleanup global (`standbyTokens`, `removeLockedRulers`) à adapter pour la table d'état -- Override `projectorBundleOverride` → s'inscrit naturellement dans une table d'état `{fig=obj, rangeKey="poi"}` ou similaire diff --git a/mac-patcher/scan_bundles.py b/mac-patcher/scan_bundles.py deleted file mode 100644 index eb5edfd22..000000000 --- a/mac-patcher/scan_bundles.py +++ /dev/null @@ -1,166 +0,0 @@ -#!/usr/bin/env python3 -"""Scan TTS AssetBundles for material -> shader references.""" -import UnityPy -import os -import sys -from collections import defaultdict, Counter - -BUNDLE_DIR = os.path.expanduser("~/Library/Tabletop Simulator/Mods/Assetbundles/") -STOCK_PREFIXES = ( - "Standard", - "Hidden/", - "Mobile/", - "Particles/", - "UI/", - "Sprites/", - "Skybox/", - "Legacy Shaders/", - "Universal Render Pipeline/", - "URP/", - "Unlit/", - "GUI/", - "Lightmap", - "VertexLit", - "Reflective/", - "Self-Illumin/", - "Transparent/", - "FX/", - "Nature/", - "TextMeshPro/", - "TextMesh Pro/", -) - -def is_stock(name: str) -> bool: - return any(name.startswith(p) for p in STOCK_PREFIXES) - -shader_to_bundles = defaultdict(set) -shader_material_count = Counter() -bundle_to_shaders = defaultdict(set) -embedded_shaders_per_bundle = defaultdict(set) -errors = [] -bundle_summary = [] - -bundles = sorted(f for f in os.listdir(BUNDLE_DIR) if f.endswith(".unity3d")) -print(f"Scanning {len(bundles)} bundles in {BUNDLE_DIR}\n", file=sys.stderr) - -for fname in bundles: - path = os.path.join(BUNDLE_DIR, fname) - short_id = fname.replace("httpssteamusercontentaakamaihdnetugc", "")[:20] - fsize = os.path.getsize(path) - n_mat = 0 - n_shader = 0 - n_tex = 0 - try: - env = UnityPy.load(path) - for obj in env.objects: - t = obj.type.name - if t == "Material": - n_mat += 1 - try: - data = obj.read() - shader_name = None - try: - sref = data.m_Shader - # Try multiple ways to resolve PPtr - try: - shader_obj = sref.deref() - except Exception: - shader_obj = None - if shader_obj is None: - try: - shader_obj_read = sref.read() - if shader_obj_read is not None: - shader_name = ( - getattr(getattr(shader_obj_read, "m_ParsedForm", None), "m_Name", None) - or getattr(shader_obj_read, "m_Name", None) - ) - except Exception: - pass - else: - sd = shader_obj.read() - shader_name = ( - getattr(getattr(sd, "m_ParsedForm", None), "m_Name", None) - or getattr(sd, "m_Name", None) - ) - except Exception as e: - errors.append(f"{short_id} mat shader resolve: {e!r}") - if not shader_name: - # PPtr fields - try: - file_id = getattr(data.m_Shader, "file_id", "?") - path_id = getattr(data.m_Shader, "path_id", "?") - shader_name = f"" - except Exception: - shader_name = "" - # Material name - mat_name = getattr(data, "m_Name", "") or "" - shader_to_bundles[shader_name].add(short_id) - shader_material_count[shader_name] += 1 - bundle_to_shaders[short_id].add((shader_name, mat_name)) - except Exception as e: - errors.append(f"{short_id} mat read err: {e!r}") - elif t == "Shader": - n_shader += 1 - try: - data = obj.read() - sname = ( - getattr(getattr(data, "m_ParsedForm", None), "m_Name", None) - or getattr(data, "m_Name", None) - ) - if sname: - embedded_shaders_per_bundle[short_id].add(sname) - except Exception as e: - errors.append(f"{short_id} shader read: {e!r}") - elif t in ("Texture2D", "Texture"): - n_tex += 1 - except Exception as e: - errors.append(f"{short_id}: load failed: {e!r}") - - bundle_summary.append((short_id, fsize, n_mat, n_shader, n_tex)) - -# === REPORT === -print("=" * 90) -print("BUNDLE SUMMARY (id_prefix, size_bytes, n_materials, n_shaders_embedded, n_textures)") -print("=" * 90) -for short_id, fsize, n_mat, n_shader, n_tex in bundle_summary: - print(f" {short_id} {fsize:>10} mats={n_mat:>3} shaders={n_shader:>2} tex={n_tex:>3}") - -print() -print("=" * 90) -print("SHADER FREQUENCY ACROSS ALL MATERIALS (sorted by usage)") -print("=" * 90) -for sname, count in shader_material_count.most_common(): - flag = " [CUSTOM?]" if not is_stock(sname) and not sname.startswith("4} mats / {n_bundles:>2} bundles {sname}{flag}") - -print() -print("=" * 90) -print("EMBEDDED SHADERS (shaders bundled INSIDE a .unity3d, sorted)") -print("=" * 90) -all_embedded = set() -for shaders in embedded_shaders_per_bundle.values(): - all_embedded.update(shaders) -print(f"\nDistinct embedded shaders: {len(all_embedded)}") -for s in sorted(all_embedded): - bundles_with = [b for b, ss in embedded_shaders_per_bundle.items() if s in ss] - print(f" - {s} ({len(bundles_with)} bundle(s): {','.join(bundles_with[:3])}{'...' if len(bundles_with) > 3 else ''})") - -print() -print("=" * 90) -print("BUNDLES REFERENCING NON-STOCK SHADERS (with material names)") -print("=" * 90) -for short_id, items in sorted(bundle_to_shaders.items()): - custom = [(s, m) for (s, m) in items if not is_stock(s) and not s.startswith("A2>%liFU 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 diff --git a/mod/data/mac-fallback-assets/deployment_red.png b/mod/data/mac-fallback-assets/deployment_red.png deleted file mode 100644 index a8e05c5e28d935439f57cf4d2f709049cdbfa337..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 856 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K5893O0R7}x|GzJD{c~2L|kcv5PuNX2iDDWKE z&}jGPHlw7BugI5IyNuHtmi)D5_;H*;;mjx+4S^9C0tvh1F7Idd-q+F|3d}JKp00i_ I>zopr0J6>oo&W#< diff --git a/mod/data/mac-fallback-assets/max_move_cyan.png b/mod/data/mac-fallback-assets/max_move_cyan.png deleted file mode 100644 index dc017745ade7c63aa858f7608a3ced343b7a245f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4124 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

    Bd<4L18 zPhy1_KviTWqb66G4Wh}(ygXz&9|O)f3uwdFCa!4?KlGMbAr;%khN$<(Y752wfi=7~ zWG4G*^5@_P?P@?2+hFLeI(3EmX(Km6l@0{RXC?DJIj|^xzb^^HF3sM z9~PS`6uUoN8GIH{0(P50y^o{>`Mwj7&yB=yv(@-6K(qgn8eWbySkKes&)x$Z9RE3* za02qV^R>uF*@S3(l2A;Yjo6Tj5aKKL4 zu=%7aeAiN__!24|{fT8`0nNkY9a?!V z2v_uGfr~Z0(yKMiEmatc!CA%v8h^#3B;(YCdOu0pdwj|uQwv`&QSUVCoau))5ypqA zv!Qu!vUoYgeZX8+>#Pj9vozsWiEZWlGfHL1JVgkn?@1cm$X4=nb3n3m3_fi@+k@bR zI+`%|Q{6+MP!xim!pt~U7Y=Q%(Yk-1WiTd4I^Gn3Bdu+VLTH}4D-^r-vkRISV5>kH z_so){ZNVQx)jgnCB}StZF&z|CWw3a>bf&5kaM)@1jK#ho#=CL?JWzdsqc%RefUiho z&(!|!c?lYt*PzcFW#g{)7KJFotcVp!ipMD&aeI^AG+})$1IEA4q{DHC!~98D?POGG ziYr^^Nql-nabO~oy#5I`Mb_#;?vq;tp5A1rqFQs-Xh0gm=h5H=FXm`Kh8GlDr#Yb$ zI)?Tu0v8aVDbMqfY_-$m`gwx=l6{5EabF9YCmj`u(w9C9 zQZ#cX>%Uh@9X5^i#>>R5QkyYzu{v%{TK_?U5GF2utp#f)5!r0$iXzi=g}_5*K@Fi zOA0w^<2+1nMESu5Oob^6aVXb9`9zevpj;W{T$H1^h)b1$D|H0EVLCs634DvniQJ$~8psD0W)Fkby;G_juxYBqbDUNaWx{ zaP)=HJLF^!rWA0qJxI816Nu#l~@=dv@RHBjpU2((sL j_or@ySp6?@>S;C418-OBbs(nX|BS)Y)z4*}Q$iB}(dK-T diff --git a/mod/data/mac-fallback-assets/range_fig_leader_huge.png b/mod/data/mac-fallback-assets/range_fig_leader_huge.png deleted file mode 100644 index 6ad39ebcba76a691f394fefe08f950cb75aa9228..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18811 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 diff --git a/mod/data/mac-fallback-assets/range_fig_leader_laat.png b/mod/data/mac-fallback-assets/range_fig_leader_laat.png deleted file mode 100644 index 3a2ac1d221b1d13e9c357efadb6afdb7fda6c4dd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19058 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 diff --git a/mod/data/mac-fallback-assets/range_fig_leader_large.png b/mod/data/mac-fallback-assets/range_fig_leader_large.png deleted file mode 100644 index c1baafb4cda99568d4f54cd6317be0e17ec5320f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18753 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 diff --git a/mod/data/mac-fallback-assets/range_fig_leader_snail_stadium.png b/mod/data/mac-fallback-assets/range_fig_leader_snail_stadium.png deleted file mode 100644 index 81c68a68c4138627192149b6f1f66b0ae59d152a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19127 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 diff --git a/mod/data/mac-fallback-assets/range_poi.png b/mod/data/mac-fallback-assets/range_poi.png deleted file mode 100644 index 5a282adb3a6a5f2a524b878032b466cb29a15285..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10364 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 diff --git a/mod/data/mac-fallback-assets/range_smokeToken.png b/mod/data/mac-fallback-assets/range_smokeToken.png deleted file mode 100644 index 5a282adb3a6a5f2a524b878032b466cb29a15285..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10364 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 diff --git a/mod/data/mac-fallback-assets/range_token.png b/mod/data/mac-fallback-assets/range_token.png deleted file mode 100644 index 5a282adb3a6a5f2a524b878032b466cb29a15285..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10364 zcmdUVd0bQ1x9>VhAb?0BIG`efC^%KY36KDB#1T`qYFmdmfYymvkb)u{!Gcx`Xs?A< zl=u@Z*j7-S5X56q(24N&3o;& zhqbmU{Cqo_^)Mr%j*}*in?WQ(Q$!}l_=)T_Fq){}*h%9?&k9X`a%c3;p1w!NUyVAE zdSrISk?WgBjvRkv?x4=>xPX|Pvq8p@B@N=?EA2Zy4WV^mLi+u5)4PW1&xa+Rz1#HZ zyFj9duU=RA2x&~=hAzDYR6CuBb+&%_a*Gk^tQn#v|J%iVEr}(PONA+)iv(n8LbQEx zRhHXYV*5j`TdvR3$JmhCiXrx>`Nq?h#*{XZNG)2D@^BnOv#p5SckPp$MZfztB5u+4 zjinPhlh#B)l;f(eu#O_yASEh2UmANH2z&by>7>ziE38Cx%9ltx)7a;QlL_f|K(r$g zhj9$MN?*JU&*y%|#Wi?$2>+MZnEiCnf^mDr3nr=-zD%Zs$) z*-{a$wOJ!awbf`+4`xVhzuzuNZcb_AVcp+q#7ENO#a@+^#9EVTH`>t^l9EIz={yBL*?Mf6Za_TOKXBup_UOH-2DY5qs4<5>^z^OjF_}#`sW% zrGWiHL`w7hcI^Hw42MZ9*;^suKHW^}VGJ$5tP?A{I8Y5{?K9UmOxgril6%twq`2CP_A8z@E#{@JMfLQmPXfF;*pf;e3DUGFcjkgQjVrfNlFHBRNzCZ z;nf{$iaWx0#jcbYRYoP>As%#ZBDv8RdU0& zxHK{BqvSbiZ#PoA*rk%(ca2a!4RU=9!X>+c%&%1$Q|C&d6(yZtO=!L@mt zM%^Y>5bh!%Q%HXt|6G8?_Fo4{ez|Wfmbh3q}>=H;Vc5Pzl#M-zh{vXf! zO-7Vy2XpwWAubMV*^M3x&qau+bgRUf*d^}E&UuF$(SjIHOD}=IRfok(6i#{eU@CTT`M5j#n=ucpQiajXAL;da5d43 zih+!3cTdt8RoaodTeaJ%X~gyn55-88jX0&g3+XwrF>y9v>jSn=t(%Fm+{@2R7f|En zSRrv!HDS6vMBbf=3WDwm&oXj%JH*GZ#=(?+8|xO6m2k-;VU~b)$X+mX)I+j!BH72q zdJ&bociUMINYZ?vEwP^i!4wElK;Y&icbkN8wl~&;C|VMcUmiCKZd^4P!)cukARkhx(i7qs-AjKO4jGbb|==+ zBXH;@l5emrAWA-${au}iKC71+lXj{mCHO%GmFyG`A^Q1s2PU}En4a*;&eG1Cj8*Y# z=tTi3w$}IGV?xI&D$GbeUXvc|KqXPJ1BiBcWc&fTVYUZ}g0;6NuM^OLuq_BUTk8kz zGNu2xUxB#gt2r{OFDZ7$A|~wdD4ucE|D_Mztyd#*{CIg`VDm3cZk*d1QpE5U7^lge zikDA>;ajGp^5hzFHaWG9Q*9DbCePG<`_bL*hno+MuD!Iw2szP3iW7+@kIxvZ!8U zO!UgbEoeByjt$#_2wa(*;;|Fkmn;|fVVbLmRa&X-X9)Ov>WBMEsdP_l7X&6v_K#;w zsrL7=*u5Jn!>{ZWQAlM4{NQbnCSZtwa&!s-v6b$DSz?Aw46_F1XUREXyNH`2+YHJw zO?mDZQVxS7lY2^#`{$;#>fSyf(PQ`ctgngtQ?`mo=~eyZ-oB*kEa^`0@Yl)9Oh{Ig zZ$$KHtzY%W0+KvaU^_mYd?Rc#ar13qXGKbo=PMHmzcd!Iyir9|55)e9Lxq%1P4dD{ z6_H$-4UJ~n!U!da^|F*sr2jS+6kk-&EA|!8SzQA5UytOcVbe+LV+(t_#0Po%m{4O% zEGQM-&n<>?*urX3F58Z=PmTrkDpgal6N%~{h>4Yj$g#`f6PVDxSw2J;{Uu8+Nf4F= zvlA{O1%ol6mDc%uMZtyrl8GFf0i; z`$smIMK{kS7L3v)a55&LUqgYpfTO$E9Js5saZMujL9QtbnpJ9t$;Bs?)AFesA(kc} z_C;SBet(*n=$FOuFZ$5%sw*(UF9C@!9BFvvG_+?eN_o+n$C4AH?z9eyr4{%+981f8 z+YM3DeqZo#G%e?LgK(N=O*&3s2C?L82k=wz^}89nNs;6xLHpZYGZRViA8w#fvde2G zwgY^Oh>f~76bCNPoP)NE+By(N9HrUYgIyW5G!WCI?BV$nwikRb{P?uRP-#|!Uq^wQ zxoeJga7gib0k`-ryh3jFcG*X5kR8$&qNj)F@?MOx(~$K<_Pe}}#qeZ!jz-r8qi4_j zU~fjdbU_t5%WwKtTasVZ1qi1b==o5FnJ~DQ-@jIXX1Hd-s8~`7h6F&ljGNO6aUcQ( zmQ*fXI>6$t4SyaHvBI!tK$8{5jf&%kc}~%3v(YFkomnU)3+)9MOxGi4MPwWGkb^To zy*5AZRw7PbL;OH}F*|z7^d-sS; zAA{jxH#d~G`K}@w9R)eJTBPW+MM48`0++|E)Hm@qAWEFEnMz~Ty}B*h{$(w^Q5k33SvRR`=rJ*a}7+v<{@z87u$vy2Xpi z3nRaA3#2*o8!KU(kIpG;5egRue1c;pH2?5Sv=ScPQl2~kuQ6DqWZ%E|#&LbbN0{Ii+1BIe zOYC6J6Ty5BH8}8pN8TktH_GLh3!PP=dtDNd?EXk*HwOH z&y#inu4xspw0yyavcFR#gW`f(OA2r1RgTLltox8eL&U8TRh~J0ww;cl{abac4)c%w zfKaU*R#{L4@#fN;To?ZVFm@Wlz2Z%x-1AY+?GK13>(wga^$j5@A0W`mN7jWJ$sT;J zJuCA2>I1fwv}v;5_Rixq03?KE{-^yENQ}sb_(@skb+oLV!Yy;o@+jD4_`fD9H`4R# znH1$`-qrox@+{xm3N}&FYJxZV6@~w-fx#0JY^c$&sA{UO@BNS(Ee`f~S<)FUg&+@` z=Uw*lpB4K%qATgGcnM3&3pYOfC$U?X*x!wm(3QNKzLf)0o$<=E`~$Pq&Yl0xl4nOW ziP64!RhF`{xj+8l?ncyZY`4%_tZL6gesFUBSAxvo@}}aKPfz;HX&wtKwh~uPe690i z&$s_wO8*n)oZXGH{l1ZrKOl%bKPYDt1+1NbkI(hFNAuemA=HEPxDMik`}D7O?KW(J@s$pq|s4mi9EuuBt-a@rpQ{ae{j4F2?3Y%9_f zA^SPcxli_>+vnP?fk6_=>hisJIWiuITJO8^t(5tu2On;xmY?ZsSj$pN8gPxb zbkgasE*mx$t$WKN@7IM6&1*R%d!960ooI|eeqaTJn9i88!_Bvkd@r8cN|0U*@h_$%E@5>j1zG%C3*!Q8}^a1EwdTRKs^j{4s zfX1l5@G3?RP7iOp#pq-PQi5aVbm#D=7<0LNpknaqmb*j(l^i*NzLN3-4{cYs2#vnu zr}@4=54^ulp)cET#VS1Tx@i@EDkTTB^gB-`^h{80F$$A-^^>ao>h7SMhL| z6Ykmyn2d8B9Q{>QjiGO|h`sa@KES@47xT36S(}Of9LPtBjBL^S8}4F(e9RS|U|3?p z8S9oi{-?8OV)`fm${tuAv)XU4Wa>8^Xp-R~T{d{pTbIE+7x}*~Qo`&owDh0cdw&TZ zNqw&Km!!LkUny77#HJy=i0uFB8!Db)2oDoG+0jn^(j?zG<^646PKr%HDaa{peG!mS z(*a|MRkZZ!MrVwWoEUAdPvAbvuAWbw8Le;#G-12f<}5VCc5H_F&6DB1CA;Up@-(Q6 zv$7kXOKW|+$kUF8jY_ul`f4{%52qg1^O_@Q*w&uRXrmFzeghhc-FHG#NM}F93By0u z9xrV1S~-PA9pZ<#?P+jtV=;Y3B8aWXEZ*x#tF+@`@|L$5o&_Z6nLZ7Tm8DC{-qYCh z2sBiKJy&@$+VKm*G2HU}g9emTiU+{wxg)iQZ;;9>6*SJf${P{I6D_+x=25HA* zI#RQ?Y1$@B+39!(yw~_kes!QhRpT+=sYjx(8y1B0o9$n6&}P z&Tn)9eEaBEE81=iiY)_R)2U0UuQ?!J#Cz)0MdjCeQ|BuFsvo@U20w=e-PHY#Bka`t zzBhdm^()#9teS$j^eNO&vm1_A^IL>rDu^Y4T*$v{D)!u&kwPV#-Qe_!U1$D?rjjjg zu#V!}J%7aVGZxHbau%j|7xH%9FcI27(TA}7_3QTGqT6N<9ShE!)p?HY)+qFog- zaUmo!oUMPHSq{%>d8`$NTA|xF%kzyD#pnVspK*%=i|on#-ZXe!?G;VZSRM;vaV~~; z;BIdhcV(3Jfipn#laLEC0jIe83npTA!}+NKPI>nj+F7+*vPEn~ZWz<{^b8VM119Qw zu+Xd0j`gPGkoyBhKd=4TTp*VQt^hShPls5N79hz)`g7hFdz0w76HHSZB@@W|1%|Y} zh=UZSNILbUu=Ua0KH1Hu?JZsFfMF&X51e`*2^Lh+<*<}M5j9orLw~({b$v8(Lu7bI zQ(9DSxNF6~;X~!tH~f_6nb0&Zx%%~X;-(p1`s0ISC)?ahJLM6mzo=-`%n?!Db1B4s zlU$bVOIim*1|hM2RJ@czlVZ(qb*@a->=)7Adlj(mI`@=%bB6sX>>_NlUUOeIg_Kqj zs5!SVEcqi5jjS&Lt$L5xEJKNgT*MTUbCPtWpmX z0Rh7fm33w)>7qyCfWbdEGrAuhmj^~3Zo(0e8)zPR2zk1lGA#d^qOk7~`hI_2f@Hg6 z_1r_2)bC0@a`}GA3)82PS|<6JXq0Nr0p$O>%BCW%SroR*LPWQ83L{eYuAYU2{qhU> zU5K5WJpJJ~QumTzYaO5(d|>zGN0F3!kH1R)+>GPRQrE_Zzjs8kPiNGU>~lgfK&%VV zGF4rwC&PA~XHHzFw<0|QTJS@DOiR)&_>E3HJKKa@V ziQqZ#-$z3mE08JIj`p5~z2r;3XzVyTksUVKG&kHB#6+_!PDwpAC8z_Xa|tvhGcp zKHzKb4aaTEf;+3QaJ1g}cKllba_8M!bLU8;pXU?lhO9ag=^gZwAyS288BEeuw@6H> zLAFu#&~{rkrn!%6iF8)XH$-Iyn7! z9wj(HKh}#c5%5ON^KkMKwUZmEnUh$#7Uq#@$j2?`V*4X(*PC6dHb!a-5m7N8QK;5K6aY?sD;&I}n#u{?)aHg|2(P-B7(5iJnzhP?Vg*E6qP3IpctR3=UvF8T1w;*UN?568?nu&py9CYO?+L4t|!7=fJ@`1 zS11^9LVNwt#!ba0NR)!Z3sik9eCEh<^DV59G%a4KwFUZ5Jo<6#CJr%AX$6$)Kv{;$ zl_{GMvJxvKt1$05P*yuP#z%*QPw6f&e+wXlFU|o#q2E?WYNw&R1=TEEka?uGpMX?m zpp+M&7y4qQ&qRVzhk6&jNNSLSh!Qk9vBrsL3i?xB8#f`Rtrj^D`_Md6IRa%k<4us- z%ePB|%#&fi8h{@{mCPUDbsFF}DXEPB{>VI1JqkrW09OON2H>|Wg*5jPSE$7oA*oOzGu4@B?RjK+T;6O#eSvg} z3DUWG;Z_lmD=HVRN>Z__-|Zxz2PlxqLwk)>NN>=Wdsdu?Ut?XWitpO&y0hcYV-%B@ncaR^Wy<-Old zI~QT#66&&2P@l!uW_8%g$a|xDsw2v}Ok63cs75>&_oRLk&B+OcQY&x{`o>Dg`T_hj z=m&@xwPm!O8mBz9t1Hb#aaPSFBI|Kdic{)@MTqR?eT^vts1JZT#zer)F^^!eHL!{( zS~^V6!1ZVgBSqQRMJT1~|1qr}*1+f|VkJ97(X{}bP!$hPc8a23{B=SdB0hU(i$G<* z#E$g>s?7u`yV^X0;=oBY;A4vLuNCq|Qmo}>=HRdw%v?B*deF!0;q4n~0QSY@zSe59 zv39H<>^-5AxODdp3D;Qw+n;CFxISklf(&<76qRir&cCN?`}ZF0Rp3Rk2?!X`Ta3!O eza-s>oMz^npIP1k8?TQD-=y(=;|`BeM*Syc!aU*t diff --git a/mod/data/mac-fallback-assets/range_tokenRangeTwo.png b/mod/data/mac-fallback-assets/range_tokenRangeTwo.png deleted file mode 100644 index 4a8a2f488e72d64ace0344269757f910d16f74ed..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12344 zcmd6Nc~}%z({FXp%CO7;BZ8oeAObEhfFcNi7EnMV8Y)cMt^ z+M)=aY$zHe0szA)fdMlBxJYtA$j5(D29HbwaPFBBFkx0g{-3`-%pP|0J6^Su`PdCZ zLM#Ja9x24-KUZx{D{G$-v~13#bmyidT^fJT^gPt5w*Z|Wh1t>~WSnv2A;9MvGPU0`4f<7=oOz+$E2WiMyCD3F3EmBpreqfc9_n8m56}Ls14Z* zf77W1{REq*>%Fhu?+O}g9#E#FuWqv+Xnc?kMOw5Gs82*d`=uuB$-r+eaZSL)tYGm@kmth_o%zxH0st^kn+!ZUWjI z0ESE65(j7UA@dl3c|fzkBiI5|I0xV_%{ob z(nwIGk`Nf86DZ9lf;tcBAfyK%osIOwW`S%_B&atcJwYdsjh_gT10)EiBW;QF9;Bxr z?S(YJhk@iCx`Q`gb$i;TLN=h)OX{D&l8ivf| z!VyQH3%DszGuaq24+CtHbP?LITR|Hm0`05~zK|be4EYlY$j6@O?@;<{DKJ4Ok&7R! za1V@(y9niI94?218k`axhD>vC2vZzlF%D7H^;i2Lcx2j5$b8<6)nyuj)+vn(^-C?G z7&}fvRZ@mHqAd?}&M5QQ3@*$S0fk)+mlD*R8lWLO6DYwsRH-Et<>HdoE^0~rAqE&5Ckixfk3oLO z5W=Vq0sQDDE=zI;rOm*>z{I13ktN8tpoD6_r(UB17_QS;pl?kfw@EA2Q7&SqMRYVn`6}!h? z0Jyd^IBg~BE~Hoi(5jmXwWy;Zl5PTGT}sQo6hZOT1_IQ(JdIYhi6E)&3c!i0BMIGp zL+D_aeByeNpwtnx)=mPT_f;h7c9DQS1RC<*F!4~GzYYDQ^;3Ont~*2rA%F8Nt3WiR z`LWF$XkRwuD4N)x9xn(eb{+Ur)=SVB3cLZ{bVR`TB7)LKrNEBdfxlA(m1q=)-dH|v z#sQN4$?6%vi$%#tU3n1cSweuv6{{(;FLTwgRyF8Oujg=PY%zqX#<&WPU7b6pN?~`M ziVsR|-0;~B;82Dhh6!w(K0*QNgICRgwx~F;v=C%tGvokndA_$Q77{W$fiu9@o%+Pm zB^-J!sts)9IXkmRdX^Pl3jvFL>`ZyE+#{TT&E@%1%|tLmb%F#*Ug91DDWo^ac_8D& zjr@-z2=5NXqcgm5uFXu4?7eCVbY{hO0mnc#EMqu8US8Ce=I`GM=p9zO0cOQ@{`LCJ zABTuNN6(SKFkECNH0F*v)9+Of0S^)>(dG1Y5KZ03>hY7-}!Yd<0ux?E` z0A0sKsz)8hp1na++>W* z0An=h^8Q3U)-T!KG=vA^JjdX*>fGji-T^vpEFu6p^PYE3B^Y}nT)>H|NmY|Y(A}T{ zpuec->^cnE6f3lHMNZWM*4u6?Xh)Zfa(pRF zU;ZACgL9(Bo=5rnyuilrY80}tjz#qi?9>e8QMNv{2sq}(`dN$U;YlZO0qg5G4v~Uk zha3l~DmQ$E+Qm)?9<^pZ9u?)t&H{HHwaBLg#Uf$@7KrG>Nzo{Fq<+gjDeyXrNPyEj zNB$8C(%<}X%J~y7pFkgvKSKu){ihPis9kPTU% zv!S(cM6~SeVkBm_1{;WINHRyUKk5&@lESu5334nb_g(Q(xs2Z&*;HC#wPi9 zROq+$1!JXbPt`Q3BvuYY;z0PAL!{ERv>sc1Z%vMKgyF4sPy@QW{4waQ@rTNqcKAM$ z#nU79`4jTgh0Ac%oAt;4>hDTE+6=eOz4cz0h)(TlMcx;-le3Pn((LlmqQ60Edv@Us z1sG^^2B4*kjlIu8)ZUqBm(E9vr{l`!HqC(ia%X$&>q7l07MAr|2{Yv^0!CO;{%Ml} z@)>7a{2mtj;Ca9N#QDfdd)A+R-~bWY95I@dljjQrY52oa;t}{9v3JoX?{%3U7i6Vb ziDX!i)8i1LXxBnl6gRIw^JQO;Oyn!EddoUJTHd|-uausYfjw_Hj3CE)b;{{(3)haS zKdb?SlIF=hB_a-lRq~lh2fI1dBeYe=WuTpS4i3(Q7+DvmXp7o+Q!LO~yJ1Hn&gHd9 z`;xAg-=MEv5Ch(Izxz^gSCX9&1HXlp#zeUTl!r7& z-FUgz73lgHy!dcPlJqrp;KGa|o^C&><??;Uul z56bMRf>>K#aqM?9>M@D; zu{ov7XmccCQ}LKl1YYaRb8d?H&F2Ufk2dh>!XB`fyj?Un5*SCPyXV+Gi*{(m&mSVP zq}TP1X*I0FKOD!r>Xg;{U6-pB|MgG^%CtGX-(Sc&{3G!D0;lPH-}AKMPW-NE>+L>7 z*sWkO`$?lu0d@GJX;*=dB>`(6g09_K%P+Hji%{}xE!nZ;l^7WEif?J_#& zf17$bh686GlDffo#R)VR94{V z+*KUS;vkM{mri_2`+^vh=)Bi?C3=}99sD_nAk{NY8q%NrX~2xT;w#zWrWdWfq^LZL zpeS{y<>uS&Kn;p?hY>%x!XaS~#jhNpDSBg*c#jX%tWC>hmX84n_SC?MpKd@G0wCA8 zO$6`K!14pA9UGT1oY^&e5Zb@zQyb0r+LZJZjZKuLqI`X8SKehnq(U3aYRu#a>st4Q zy?)JO6b5I1+XEW<&W`h?PfZZC7H!pu*Vez_gbiQGT7-HZVcuL}AsqJR;Fuk6MW*NgqK_OP@ntipzQo{^h{S=X!6u=2K*EAU}LP&lXP3)6jMw0=_>{*uxc@q~vHvwMaE#L(ZY(A_Yeq(_*HP^xX|bN7)U_uQVM5lh)jXiLu`q zg3LF~0*+i*L6cITR`Fe7*_tM}HQgCb^>7MZHWTvw7X^X&J8)Y(Ef@&9KA1b~Sl`T# zo53$VsWTH=N#?T_8`+{@9I<|}mXwL&P1JbxlwZ~Gs4*?WW!cMl^eaT;5SEj}_LFdh zq-M1^$nuN0D55M5PciLq14$lzcc!rtp=jkSL2iiz_rrGlBcXk7??| zeOJ_LO55y*!K{YuoDKEME%C90Zwp_=Js^mWw=fj#wYPz_b(NeEX7Hp(;O-(MsimPqXrIT<&b(6FYWqA>o zVd!vh8p4v6`C4w@7+Mvf)rZuczXC{TR5g*#jcfkyxN?^ea_{`AUxKs7pCLm2k{)pa zNx-(^wAAxUF4SW9(hFYTbz40Fzr+sY2tFv|S04SQr@%AB3S|6v*RyXfyB$KEu}9}4 zAi`khtD$i1*((0J54iE72o{1cEAa||%Y`EaKfD?2`D_0O2iuksusCim$MVAnci9ne zVzPtZBqEzGcaI;GmmM(l{%}O`t>(*v!+>&XS*0aDoTQVWdm#qeURLwJc&dKf zZx%Q?)^3xcK9@jjTn=YkzfG}g)SU(0K+ss=lc*xiYw)AQl$}reMYZEXM4&N?_tN1T z7yb~8;*WYmG6TWSb`F=&43GCd+uAL=`EMN*4HClr3(x!J*REm3*aK6FU@1(GOAo2- ztiEx{do|*&{$6n#@yAZ}K;l3Ne6i+@|BC)5{IWnFQb@_5B2oySpAuO~K%@u|R+N?h1>$&mfP4v0UDW$=el5v+Z- zz!zVx&JbtOOaG6J#lLV*z+C zo!IAHmAs2 z-Nu90axZH6f8kEO^J?Lfo-f|Ty%LiK+E08ydAjG@Zh{U);MR9?@E=wKv*+Q7-7fd1 z=KYsmK3JKCmHCIA<6pQ8YGQY?Gw4KTxV!r!D*S>m4$J;wogemAyW>silkV{M{_LkE z5840!U;SYld!q5j&g*{HQx@<$luaWV`gaJwec05$4;{As&$0f!t^fZC-S3J=3=6xJ z$LZMrVjF)e0jK_9_fvhHe4lhj{BIO^qPg^IyyawL|2G@+Z)MGDc=?8e$+<%{qxw9I z2ItVfSI3~ZE8*RGv?*-NTyyt*|NVl0vo?Rb%L3mL#b-FXkN;EdznKKP$DQsA@nzSI zv%9dDJDA6?d6g9@tWvZwrLC9$bx<{&g@17VpJxj7)_mpSm;XGJzlwSR?}PWf$1KmM zF{%GDz#&*8w!d62fR6GQ_~yS`S#?(Yd!R?U5ogd(s8=U?84Co4h_3x+u;lb$2Q$SMAEy>ZC=fU5-6rZG~w+~&)r_fdV7h`ox>q}umsifP14g+PO%ygzOG5oJ6_ZUo8x zi-T(VZIfQ-$0D!NE5saRX7O%CY5#IMO6#vTfh5h#!hFGp zwS=u+?SpH1(X@pFry892Mj!5I#1Q5oLl8s7%jLL3pRnB*Rc42;;($k`>HowF4nRLh zFd-nWI4*TIkABIjhVI{PhP^4sH+h+PZ0Va`0$$e>X~zB_ zKImVl{f61%`8VLGY?#7>{Hq5<0VAP=4@pau1pS~mD3$1Z+<)8M(AAT$eN6_L*0*V? zh*qC+ptfGG4}kF-SM}Ss`JG(`P;=veo&g@k8*bIT7)~~m(5`1!s7;D$Sc$W?V!_?Y zmO!OR-=3;I!;BHWd4_m^)-B#v?$QekU7LXkX$er`qdERq7u?u(jYGH8ZlpH$?#O;~ zgq#RKN8SD#au#j3m%-ZKS~y<~fCvt_yCHDh=p_!z{|9jWBqRV%R4x#3vCGABb3(Dl z%jiS|bPQp~*}SU|0m+&KKav{T;x5DBL9%Uv9zCLVIaNq9D_9nZ?PNTO&;Gi`{fNG0 z!_!QAarw7A`T;&h7${)rZ!IL*6xFYp&3AW6`_TP#M^@D(*C-yfwq=BD!YVd&P!^H0 z5%E$rVom%F%Ef@j5EAn2M?t`Et4NcENDOzJ_@m*l%AUA|7LjBS4yPKONRxf@Sx)@@ z!luKh;DaR?WP1q%F?_6#1dh@@UaYQZXJ^iwG*}E3&nk(XO-qn78N;1PaSwopy$v#0 z2AR*c6I;V(^z}wpI_a|klEx?`8a(!2HRm8{G4RL7z9x9#I~)Jga|&}}^WTjXuD8SNxK0q}^e3Nc{Dr5rOmk7> zxfwas@ASwxj%u3fBI6A3d<<6t-^~S|)`0{ai|;~9?K?QU1tz}lOY!YVl3iv|USYwP zV6u%K`6*EI&Jpw|Zi=QTsI{;M6Mk^mO~JA7_!_Q^JVU4=^}(Ua9rNT`@fek(uD$0r zK9LRQuaucYnNTB+xx=?H1gym8usOzEsgs;0_AS2rHW;ywa)Dph@|iuOK{NO-wvId-d$BW8&$ zJVTC}f?xYMOdUw&;4*8iG-uL>LB4=cK9k_*3(lWi=+(FqCPF?|H<&;B>Ba9od(g2} z{k z(R!6x(_0>`hVX}2#}HsaP4@F;Tyt*p4PLa}*Di1%j!o1+N5*KNWl~}mYAk)t^6uWv zhVN=bGOq$_T7&QDN_~*YBOzPwJrpFq?b(Ghi!HLC#-RKyl)qvIl%I%LCg~t%w6^z* z<1vO)v3O-Skw2wb5IDV~rvg36&(CHP5q9ky#co5|3ynv5RH8LYwbl#^=_x%!0QFQ; zC~2Oe6=)nSL5wamI?z$Etw>zGv#{s9BOFwaFs4vaK2a-(4(TYZ!VZhZDMs)XOI{Po zftFy25=ztSjQIv1u*50m;uLd@XYJwa(CY+wz9F53L&|5p+CVV^r97nP&`fxt;essl z{>D^FOv$eFxJO{xD3hxKWufouZo&9_BM@p_vngEJ2b3}T@mijP?s~Dh>UAhsX>$xP z`7-)KjPJ(_+9UAszmqQ|6q}Ec=UA=FC$$rkJ5jt*T^ezOb^B~EW?$`xgJjypUkWBv zCZ(C!+?V@7f=z*$Ef)uZ_I>g&vGmfqqrw7H~P4s z+`zAq>`RYf-mDgR`|@UHx*#J=UfU16+pn8#(HC*>zO0*m=P?0B@7Za;grZ3ALav`( zh{V9ws`(OJ13yGWVbdJw{VOV8m>JWA!`jbdi4L0E)?Ka6eFv>6&iU(!;Y zE;dCNv!`Td8Ywfj9)V(mJnh6ER~5>iv_jKlodN^@W+WMGS{Ih zJ+>uXU9(bgv|?wp*{BHg*SFqBQRQj%lLCg*xFWyL!R4d{n<=*ZLF2> z&nDn5yT$r{$!4K*QLHZuoz04%(v_oV~u`>PJ8mz*vBA{55d`{S79JdDuxwJs6> zeYrmM;76O$xO`*%F%ceJnSu0MdC!~USn7tO8RotV1)Z-Ec6;JZNfoB>Q#?^nGbGNZ z6jSln>X7I2+?Sn!1T&6J#g|uwS7H6gs@O1`X+&e%Rrr7TM`_FDg28b;kau?ZJz5LpyuvS z?C^QsorggLGqktt;HGz_u?URfno%uDjjHW4KxdMH(SOB~?#2Nkh-j2xX~SO?zm`lT z7{}hyhV6;_v6jLki%qJ3EP!ZGAy-@OY0q73%>=%;e5jdF3N!FjSw$UO#^u3PkF#h9 zzHwuYU@69Jc55Ez9kQ50FeJ9QY8j_iIM$W57t1H>9l zK_{Fg@{kg6qC7uHnu9NNwXNL`9v@=MCLv*?He`%D2yZRY z18Q00JewI<;o|>yh0B->drY(CF5EJWpc0Jm=(@_!n;al%snu~j56dF#IBW^ctiMZW z))Zq2&6dvH)1+|pH#L^fka3O=!!h>OZT*Okpn97&WR5$gY3uZXnbsKMIuomS{QIkT zG~5hSlWpF(lN3Q&7)1h1l1I(hNYXQ`DzW59|D_oWC zx$`S56l&CAp^&)Ec8?>%m7zw!m^DuNY9>@~xQb;|lPk8Z)ds=xn>id3bT|=vENi+s z6jPadE~r;Y;cR^omN?z@4#aAaN4+IZOO1|>e2P_@ST3O9l^tq{0s0P--fcr1K)cWh z)6gG^rhHVMc%v=8oc1(H0JU}NaeA#LU3Feq0hSTO0hxWARqb)01>qP~UC4c^^*Ig9 zB*cEOIY^h$gz?`brvVsVS1d2WLd12d3uxJkebWBK9IznK4h;%{!fU(~1sB$0Xd}-k za}hy8>K#E}%~;a_@YsS`LbzevRrk3&Xoor3;md!;JQcd`{PG4azT~$J$iF!fYaY)!5K5!RfwF^GJZ+DP6;b;g5g`Z4{ok#fLGh5^DT(8IPn`{)m33c%m+22yQ}FaVNKs``&kgA78;nMn|n7X;RYXywyi|Vz}nAq=>IctNy^b>)-^!{ zlpwH!IP5kQyOM6jI|b`qBaQ(C%>R2}Kk9j6sbx$*M!BO+h5SbRqh6M}agHevU=V?@%D(D84lz z%=ZY!0%jYmv*=7ursEKa@Nr-(MA`XR;v`SSGHA~NYbCzUGD~k`K^`(C;;pCe$f36* z&DI%BaNy9lk;d{QAh2D8bQscQNKZq$80lLMTsn}OOnW1}1=|N;I~K*lMr=36_CZKb z#P+#3yH_}geF`D$5Ox7uL$+^*kXlXpQfPy?`s#G7q~4E~zkfHW-d`kU@QwxdP$3mV z`a%_odISuG6?$Fp0u`zqGnFv+uMubskZDt>ka0mKTV%?e>IjGQ-a!RwSH`^#_x0Yw zDRlL+QO95&wg=#qCmVbnLWOT(De`Ef4G?A8O7vFHTizyGj9ZCj3O!$sLh`enmP3;O u>q1Sg+17GcO=EHSJXO9z466&@rA)~BH2w&+?Erccm@+Xq;9EcChW`T!pR+#z diff --git a/mod/data/mac-fallback-assets/silh_exact_long_1.obj b/mod/data/mac-fallback-assets/silh_exact_long_1.obj deleted file mode 100644 index 964564c5c..000000000 --- a/mod/data/mac-fallback-assets/silh_exact_long_1.obj +++ /dev/null @@ -1,369 +0,0 @@ -# rebuilt from silh_vanilla_long_2.obj with a 45deg smoothing angle -v 1.470364 -0.000000 -2.849121 -v 1.470364 -0.000000 -2.849121 -v 1.795074 -0.000000 -2.401143 -v 1.795074 -0.000000 -2.401143 -v -0.000000 0.000321 -1.903831 -v 2.000166 0.000321 -1.903831 -v 2.000166 0.000321 -1.903831 -v 1.042536 -0.000000 -3.163317 -v 1.042536 -0.000000 -3.163317 -v 2.000166 0.000322 1.915038 -v 2.000166 0.000322 1.915038 -v 0.614881 -0.000000 -3.363181 -v 0.614881 -0.000000 -3.363181 -v -0.000000 0.000322 1.915038 -v 1.470364 1.000000 -2.849121 -v 1.470364 1.000000 -2.849121 -v 1.042536 1.000000 -3.163317 -v 1.042536 1.000000 -3.163317 -v 1.795074 1.000000 -2.401144 -v 1.795074 1.000000 -2.401144 -v 0.614881 1.000000 -3.363182 -v 0.614881 1.000000 -3.363182 -v -0.000000 0.999678 -1.903831 -v 2.000166 0.999678 -1.903831 -v 2.000166 0.999678 -1.903831 -v -0.000000 1.000000 -3.460686 -v -0.000000 1.000000 -3.460686 -v -0.000000 0.999679 1.915038 -v 2.000166 0.999679 1.915038 -v 2.000166 0.999679 1.915038 -v -0.000000 -0.000000 -3.460686 -v -0.000000 -0.000000 -3.460686 -v 1.821423 0.000000 2.387772 -v 1.821423 0.000000 2.387772 -v 1.821423 1.000000 2.387771 -v 1.821423 1.000000 2.387771 -v -0.614881 1.000000 -3.363182 -v -0.614881 1.000000 -3.363182 -v 1.529514 0.000000 2.783466 -v 1.529514 0.000000 2.783466 -v 1.529514 1.000000 2.783466 -v 1.529514 1.000000 2.783466 -v 1.071173 1.000000 3.162351 -v 1.071173 1.000000 3.162351 -v -2.000043 0.999679 1.915038 -v -2.000043 0.999679 1.915038 -v 1.071173 0.000000 3.162352 -v 1.071173 0.000000 3.162352 -v 0.614881 0.000000 3.370249 -v 0.614881 0.000000 3.370249 -v -0.000000 0.000000 3.467756 -v -0.000000 0.000000 3.467756 -v 0.614881 1.000000 3.370249 -v 0.614881 1.000000 3.370249 -v -0.614881 -0.000000 -3.363181 -v -0.614881 -0.000000 -3.363181 -v -0.000000 1.000000 3.467755 -v -0.000000 1.000000 3.467755 -v -1.042536 1.000000 -3.163317 -v -1.042536 1.000000 -3.163317 -v -0.614881 0.000000 3.370249 -v -0.614881 0.000000 3.370249 -v -1.042536 -0.000000 -3.163317 -v -1.042536 -0.000000 -3.163317 -v -0.614881 1.000000 3.370249 -v -0.614881 1.000000 3.370249 -v -1.470364 1.000000 -2.849121 -v -1.470364 1.000000 -2.849121 -v -1.071173 0.000000 3.162352 -v -1.071173 0.000000 3.162352 -v -1.470364 -0.000000 -2.849121 -v -1.470364 -0.000000 -2.849121 -v -1.795074 1.000000 -2.401144 -v -1.795074 1.000000 -2.401144 -v -1.071173 1.000000 3.162351 -v -1.071173 1.000000 3.162351 -v -1.795074 -0.000000 -2.401143 -v -1.795074 -0.000000 -2.401143 -v -2.000043 0.999678 -1.903831 -v -2.000043 0.999678 -1.903831 -v -2.000043 0.000321 -1.903831 -v -2.000043 0.000321 -1.903831 -v -2.000043 0.000322 1.915038 -v -2.000043 0.000322 1.915038 -v -1.529514 0.000000 2.783466 -v -1.529514 0.000000 2.783466 -v -1.529514 1.000000 2.783466 -v -1.529514 1.000000 2.783466 -v -1.821423 1.000000 2.387771 -v -1.821423 1.000000 2.387771 -v -1.821423 0.000000 2.387772 -v -1.821423 0.000000 2.387772 -vt 0.325826 0.000000 -vt 0.325826 0.000000 -vt 0.352171 0.000000 -vt 0.352171 0.000000 -vt 0.250000 0.000322 -vt 0.378927 0.000322 -vt 0.378927 0.000322 -vt 0.300669 0.000000 -vt 0.300669 0.000000 -vt 0.621540 0.000322 -vt 0.621540 0.000322 -vt 0.278780 0.000000 -vt 0.278780 0.000000 -vt 0.750000 0.000322 -vt 0.325826 0.999999 -vt 0.325826 0.999999 -vt 0.300669 0.999999 -vt 0.300669 0.999999 -vt 0.352171 0.999999 -vt 0.352171 0.999999 -vt 0.278780 0.999999 -vt 0.278780 0.999999 -vt 0.250000 0.999678 -vt 0.378927 0.999678 -vt 0.378927 0.999678 -vt 0.250000 0.999999 -vt 0.250000 0.999999 -vt 0.750000 0.999678 -vt 0.621540 0.999678 -vt 0.621540 0.999678 -vt 0.250000 0.000000 -vt 0.250000 0.000000 -vt 0.646286 0.000001 -vt 0.646286 0.000001 -vt 0.646286 1.000000 -vt 0.646286 1.000000 -vt 0.221220 0.999999 -vt 0.221220 0.999999 -vt 0.670031 0.000001 -vt 0.670031 0.000001 -vt 0.670031 1.000000 -vt 0.670031 1.000000 -vt 0.698021 1.000000 -vt 0.698021 1.000000 -vt 0.878455 0.999678 -vt 0.878455 0.999678 -vt 0.698021 0.000001 -vt 0.698021 0.000001 -vt 0.721279 0.000001 -vt 0.721279 0.000001 -vt 0.750000 0.000001 -vt 0.750000 0.000001 -vt 0.721279 1.000000 -vt 0.721279 1.000000 -vt 0.221220 0.000000 -vt 0.221220 0.000000 -vt 0.750000 1.000000 -vt 0.750000 1.000000 -vt 0.199331 0.999999 -vt 0.199331 0.999999 -vt 0.778721 0.000001 -vt 0.778721 0.000001 -vt 0.199331 0.000000 -vt 0.199331 0.000000 -vt 0.778721 1.000000 -vt 0.778721 1.000000 -vt 0.174174 0.999999 -vt 0.174174 0.999999 -vt 0.801979 0.000001 -vt 0.801979 0.000001 -vt 0.174174 0.000000 -vt 0.174174 0.000000 -vt 0.147829 0.999999 -vt 0.147829 0.999999 -vt 0.801979 1.000000 -vt 0.801979 1.000000 -vt 0.147829 0.000000 -vt 0.147829 0.000000 -vt 0.121078 0.999678 -vt 0.121078 0.999678 -vt 0.121078 0.000322 -vt 0.121078 0.000322 -vt 0.878455 0.000322 -vt 0.878455 0.000322 -vt 0.829969 0.000001 -vt 0.829969 0.000001 -vt 0.829969 1.000000 -vt 0.829969 1.000000 -vt 0.853714 1.000000 -vt 0.853714 1.000000 -vt 0.853714 0.000001 -vt 0.853714 0.000001 -vn -0.000133 -1.000000 0.000134 -vn 0.671666 -0.000000 -0.740855 -vn -0.000075 -1.000000 0.000377 -vn 0.853214 -0.000000 -0.521562 -vn -0.000000 -1.000000 0.000201 -vn 0.000000 -1.000000 0.000323 -vn 0.980936 -0.000000 -0.194331 -vn -0.000101 -1.000000 0.000172 -vn 0.481628 -0.000000 -0.876376 -vn 0.000000 -1.000000 -0.000227 -vn 0.983710 0.000000 0.179763 -vn -0.000059 -1.000000 0.000195 -vn 0.247695 -0.000000 -0.968838 -vn -0.000000 -1.000000 -0.000205 -vn 0.745032 -0.000000 -0.667029 -vn -0.000133 1.000000 0.000133 -vn 0.538045 -0.000000 -0.842916 -vn -0.000101 1.000000 0.000171 -vn 0.891717 -0.000000 -0.452593 -vn -0.000075 1.000000 0.000377 -vn 0.337399 -0.000000 -0.941362 -vn -0.000059 1.000000 0.000195 -vn -0.000000 1.000000 0.000200 -vn 0.000000 1.000000 0.000215 -vn 0.980936 -0.000000 -0.194331 -vn 0.000000 1.000000 0.000206 -vn 0.052785 -0.000000 -0.998606 -vn -0.000000 1.000000 -0.000205 -vn 0.983710 0.000000 0.179763 -vn 0.000000 1.000000 -0.000340 -vn -0.052785 -0.000000 -0.998606 -vn -0.000000 -1.000000 0.000207 -vn 0.899312 0.000000 0.437307 -vn -0.000074 -1.000000 -0.000394 -vn -0.000074 1.000000 -0.000395 -vn 0.855397 0.000000 0.517973 -vn -0.247695 -0.000000 -0.968838 -vn 0.000059 1.000000 0.000195 -vn -0.000136 -1.000000 -0.000130 -vn 0.753856 0.000000 0.657040 -vn -0.000136 1.000000 -0.000130 -vn 0.697622 0.000000 0.716466 -vn -0.000104 1.000000 -0.000168 -vn 0.492575 0.000000 0.870270 -vn -0.000000 1.000000 -0.000227 -vn -0.983731 0.000000 0.179650 -vn -0.000104 -1.000000 -0.000168 -vn 0.567323 0.000000 0.823495 -vn -0.000059 -1.000000 -0.000196 -vn 0.331301 0.000000 0.943525 -vn 0.000000 -1.000000 -0.000207 -vn 0.052786 0.000000 0.998606 -vn 0.244600 0.000000 0.969624 -vn -0.000059 1.000000 -0.000196 -vn -0.337399 -0.000000 -0.941362 -vn 0.000059 -1.000000 0.000195 -vn -0.052786 0.000000 0.998606 -vn 0.000000 1.000000 -0.000207 -vn -0.481628 -0.000000 -0.876376 -vn 0.000101 1.000000 0.000171 -vn -0.244600 0.000000 0.969624 -vn 0.000059 -1.000000 -0.000196 -vn -0.538045 -0.000000 -0.842916 -vn 0.000101 -1.000000 0.000172 -vn -0.331301 0.000000 0.943525 -vn 0.000059 1.000000 -0.000196 -vn -0.671666 -0.000000 -0.740855 -vn 0.000133 1.000000 0.000133 -vn -0.492575 0.000000 0.870270 -vn 0.000104 -1.000000 -0.000168 -vn -0.745032 -0.000000 -0.667029 -vn 0.000133 -1.000000 0.000134 -vn 0.000075 1.000000 0.000377 -vn -0.853250 -0.000000 -0.521502 -vn -0.567323 0.000000 0.823495 -vn 0.000104 1.000000 -0.000168 -vn 0.000075 -1.000000 0.000377 -vn -0.891781 -0.000000 -0.452466 -vn 0.000000 1.000000 0.000323 -vn -0.980957 -0.000000 -0.194227 -vn 0.000000 -1.000000 0.000216 -vn -0.980957 -0.000000 -0.194227 -vn -0.983731 0.000000 0.179650 -vn -0.000000 -1.000000 -0.000340 -vn 0.000136 -1.000000 -0.000130 -vn -0.697622 0.000000 0.716466 -vn 0.000136 1.000000 -0.000130 -vn -0.753856 0.000000 0.657040 -vn 0.000074 1.000000 -0.000395 -vn -0.899379 0.000000 0.437169 -vn 0.000074 -1.000000 -0.000394 -vn -0.855436 0.000000 0.517909 -f 1/1/1 3/3/3 5/5/5 -f 3/3/3 6/6/6 5/5/5 -f 8/8/8 1/1/1 5/5/5 -f 5/5/5 6/6/6 10/10/10 -f 12/12/12 8/8/8 5/5/5 -f 14/14/14 5/5/5 10/10/10 -f 2/2/2 15/15/15 4/4/4 -f 9/9/9 17/17/17 2/2/2 -f 17/17/17 15/15/15 2/2/2 -f 15/15/15 19/19/19 4/4/4 -f 4/4/4 19/19/19 7/7/7 -f 21/21/21 17/17/17 9/9/9 -f 13/13/13 21/21/21 9/9/9 -f 16/16/16 18/18/18 23/23/23 -f 20/20/20 16/16/16 23/23/23 -f 18/18/18 22/22/22 23/23/23 -f 24/24/24 20/20/20 23/23/23 -f 19/19/19 25/25/25 7/7/7 -f 22/22/22 26/26/26 23/23/23 -f 27/27/27 21/21/21 13/13/13 -f 24/24/24 23/23/23 28/28/28 -f 7/7/7 25/25/25 29/29/29 -f 30/30/30 24/24/24 28/28/28 -f 11/11/11 7/7/7 29/29/29 -f 31/31/31 27/27/27 13/13/13 -f 32/32/32 12/12/12 5/5/5 -f 11/11/11 29/29/29 33/33/33 -f 10/10/10 34/34/34 14/14/14 -f 35/35/35 30/30/30 28/28/28 -f 29/29/29 36/36/36 33/33/33 -f 37/37/37 27/27/27 31/31/31 -f 26/26/26 38/38/38 23/23/23 -f 34/34/34 39/39/39 14/14/14 -f 33/33/33 36/36/36 40/40/40 -f 41/41/41 35/35/35 28/28/28 -f 36/36/36 42/42/42 40/40/40 -f 43/43/43 41/41/41 28/28/28 -f 28/28/28 23/23/23 45/45/45 -f 39/39/39 47/47/47 14/14/14 -f 40/40/40 42/42/42 48/48/48 -f 42/42/42 44/44/44 48/48/48 -f 47/47/47 49/49/49 14/14/14 -f 48/48/48 44/44/44 50/50/50 -f 49/49/49 51/51/51 14/14/14 -f 44/44/44 53/53/53 50/50/50 -f 54/54/54 43/43/43 28/28/28 -f 50/50/50 53/53/53 52/52/52 -f 55/55/55 37/37/37 31/31/31 -f 56/56/56 32/32/32 5/5/5 -f 53/53/53 57/57/57 52/52/52 -f 58/58/58 54/54/54 28/28/28 -f 59/59/59 37/37/37 55/55/55 -f 38/38/38 60/60/60 23/23/23 -f 52/52/52 57/57/57 61/61/61 -f 51/51/51 62/62/62 14/14/14 -f 63/63/63 59/59/59 55/55/55 -f 64/64/64 56/56/56 5/5/5 -f 57/57/57 65/65/65 61/61/61 -f 66/66/66 58/58/58 28/28/28 -f 67/67/67 59/59/59 63/63/63 -f 60/60/60 68/68/68 23/23/23 -f 61/61/61 65/65/65 69/69/69 -f 62/62/62 70/70/70 14/14/14 -f 71/71/71 67/67/67 63/63/63 -f 72/72/72 64/64/64 5/5/5 -f 68/68/68 73/73/73 23/23/23 -f 74/74/74 67/67/67 71/71/71 -f 65/65/65 75/75/75 69/69/69 -f 76/76/76 66/66/66 28/28/28 -f 77/77/77 72/72/72 5/5/5 -f 78/78/78 74/74/74 71/71/71 -f 73/73/73 79/79/79 23/23/23 -f 80/80/80 74/74/74 78/78/78 -f 23/23/23 79/79/79 45/45/45 -f 81/81/81 77/77/77 5/5/5 -f 82/82/82 80/80/80 78/78/78 -f 81/81/81 5/5/5 14/14/14 -f 80/80/80 82/82/82 83/83/83 -f 46/46/46 80/80/80 83/83/83 -f 84/84/84 81/81/81 14/14/14 -f 70/70/70 85/85/85 14/14/14 -f 69/69/69 75/75/75 86/86/86 -f 87/87/87 76/76/76 28/28/28 -f 75/75/75 88/88/88 86/86/86 -f 89/89/89 28/28/28 45/45/45 -f 90/90/90 46/46/46 83/83/83 -f 89/89/89 87/87/87 28/28/28 -f 91/91/91 84/84/84 14/14/14 -f 85/85/85 91/91/91 14/14/14 -f 86/86/86 88/88/88 92/92/92 -f 92/92/92 90/90/90 83/83/83 -f 88/88/88 90/90/90 92/92/92 diff --git a/mod/data/mac-fallback-assets/silh_exact_snail_1.obj b/mod/data/mac-fallback-assets/silh_exact_snail_1.obj deleted file mode 100644 index 33f916f49..000000000 --- a/mod/data/mac-fallback-assets/silh_exact_snail_1.obj +++ /dev/null @@ -1,369 +0,0 @@ -# rebuilt from silh_vanilla_snail_2.obj with a 45deg smoothing angle -v 1.470364 -0.000000 -3.273221 -v 1.470364 -0.000000 -3.273221 -v 1.795074 -0.000000 -2.825244 -v 1.795074 -0.000000 -2.825244 -v -0.000000 0.000321 -2.327931 -v 2.000166 0.000321 -2.327931 -v 2.000166 0.000321 -2.327931 -v 1.042536 -0.000000 -3.587417 -v 1.042536 -0.000000 -3.587417 -v 2.000166 0.000322 2.328190 -v 2.000166 0.000322 2.328190 -v 0.614881 -0.000001 -3.787282 -v 0.614881 -0.000001 -3.787282 -v -0.000000 0.000322 2.328190 -v 1.470364 1.000000 -3.273222 -v 1.470364 1.000000 -3.273222 -v 1.042536 1.000000 -3.587418 -v 1.042536 1.000000 -3.587418 -v 1.795074 1.000000 -2.825244 -v 1.795074 1.000000 -2.825244 -v 0.614881 1.000000 -3.787282 -v 0.614881 1.000000 -3.787282 -v -0.000000 0.999678 -2.327931 -v 2.000166 0.999678 -2.327931 -v 2.000166 0.999678 -2.327931 -v -0.000000 0.999999 -3.884787 -v -0.000000 0.999999 -3.884787 -v -0.000000 0.999679 2.328190 -v 2.000166 0.999679 2.328190 -v 2.000166 0.999679 2.328190 -v -0.000000 -0.000001 -3.884786 -v -0.000000 -0.000001 -3.884786 -v 1.821423 0.000000 2.800923 -v 1.821423 0.000000 2.800923 -v 1.821423 1.000000 2.800923 -v 1.821423 1.000000 2.800923 -v -0.614881 1.000000 -3.787282 -v -0.614881 1.000000 -3.787282 -v 1.529514 0.000000 3.196618 -v 1.529514 0.000000 3.196618 -v 1.529514 1.000000 3.196618 -v 1.529514 1.000000 3.196618 -v 1.071173 1.000000 3.575503 -v 1.071173 1.000000 3.575503 -v -2.000043 0.999679 2.328190 -v -2.000043 0.999679 2.328190 -v 1.071173 0.000000 3.575503 -v 1.071173 0.000000 3.575503 -v 0.614881 0.000001 3.783401 -v 0.614881 0.000001 3.783401 -v -0.000000 0.000001 3.880907 -v -0.000000 0.000001 3.880907 -v 0.614881 1.000000 3.783401 -v 0.614881 1.000000 3.783401 -v -0.614881 -0.000001 -3.787282 -v -0.614881 -0.000001 -3.787282 -v -0.000000 1.000000 3.880907 -v -0.000000 1.000000 3.880907 -v -1.042536 1.000000 -3.587418 -v -1.042536 1.000000 -3.587418 -v -0.614881 0.000001 3.783401 -v -0.614881 0.000001 3.783401 -v -1.042536 -0.000000 -3.587417 -v -1.042536 -0.000000 -3.587417 -v -0.614881 1.000000 3.783401 -v -0.614881 1.000000 3.783401 -v -1.470364 1.000000 -3.273222 -v -1.470364 1.000000 -3.273222 -v -1.071173 0.000000 3.575503 -v -1.071173 0.000000 3.575503 -v -1.470364 -0.000000 -3.273221 -v -1.470364 -0.000000 -3.273221 -v -1.795074 1.000000 -2.825244 -v -1.795074 1.000000 -2.825244 -v -1.071173 1.000000 3.575503 -v -1.071173 1.000000 3.575503 -v -1.795074 -0.000000 -2.825244 -v -1.795074 -0.000000 -2.825244 -v -2.000043 0.999678 -2.327931 -v -2.000043 0.999678 -2.327931 -v -2.000043 0.000321 -2.327931 -v -2.000043 0.000321 -2.327931 -v -2.000043 0.000322 2.328190 -v -2.000043 0.000322 2.328190 -v -1.529514 0.000000 3.196618 -v -1.529514 0.000000 3.196618 -v -1.529514 1.000000 3.196618 -v -1.529514 1.000000 3.196618 -v -1.821423 1.000000 2.800923 -v -1.821423 1.000000 2.800923 -v -1.821423 0.000000 2.800923 -v -1.821423 0.000000 2.800923 -vt 0.317195 0.000000 -vt 0.317195 0.000000 -vt 0.340085 0.000000 -vt 0.340085 0.000000 -vt 0.250000 0.000322 -vt 0.362970 0.000322 -vt 0.362970 0.000322 -vt 0.295012 0.000000 -vt 0.295012 0.000000 -vt 0.637039 0.000322 -vt 0.637039 0.000322 -vt 0.275616 0.000000 -vt 0.275616 0.000000 -vt 0.750000 0.000322 -vt 0.317195 0.999999 -vt 0.317195 0.999999 -vt 0.295012 0.999999 -vt 0.295012 0.999999 -vt 0.340085 0.999999 -vt 0.340085 0.999999 -vt 0.275616 0.999999 -vt 0.275616 0.999999 -vt 0.250000 0.999678 -vt 0.362970 0.999678 -vt 0.362970 0.999678 -vt 0.250000 0.999999 -vt 0.250000 0.999999 -vt 0.750000 0.999678 -vt 0.637039 0.999678 -vt 0.637039 0.999678 -vt 0.250000 0.000000 -vt 0.250000 0.000000 -vt 0.658234 0.000001 -vt 0.658234 0.000001 -vt 0.658234 1.000000 -vt 0.658234 1.000000 -vt 0.224384 0.999999 -vt 0.224384 0.999999 -vt 0.678972 0.000001 -vt 0.678972 0.000001 -vt 0.678972 1.000000 -vt 0.678972 1.000000 -vt 0.703674 1.000000 -vt 0.703674 1.000000 -vt 0.862957 0.999678 -vt 0.862957 0.999678 -vt 0.703674 0.000001 -vt 0.703674 0.000001 -vt 0.724358 0.000001 -vt 0.724358 0.000001 -vt 0.750000 0.000001 -vt 0.750000 0.000001 -vt 0.724358 1.000000 -vt 0.724358 1.000000 -vt 0.224384 0.000000 -vt 0.224384 0.000000 -vt 0.750000 1.000000 -vt 0.750000 1.000000 -vt 0.204988 0.999999 -vt 0.204988 0.999999 -vt 0.775642 0.000001 -vt 0.775642 0.000001 -vt 0.204988 0.000000 -vt 0.204988 0.000000 -vt 0.775642 1.000000 -vt 0.775642 1.000000 -vt 0.182805 0.999999 -vt 0.182805 0.999999 -vt 0.796326 0.000001 -vt 0.796326 0.000001 -vt 0.182805 0.000000 -vt 0.182805 0.000000 -vt 0.159915 0.999999 -vt 0.159915 0.999999 -vt 0.796326 1.000000 -vt 0.796326 1.000000 -vt 0.159915 0.000000 -vt 0.159915 0.000000 -vt 0.137035 0.999678 -vt 0.137035 0.999678 -vt 0.137035 0.000322 -vt 0.137035 0.000322 -vt 0.862957 0.000322 -vt 0.862957 0.000322 -vt 0.821028 0.000001 -vt 0.821028 0.000001 -vt 0.821028 1.000000 -vt 0.821028 1.000000 -vt 0.841766 1.000000 -vt 0.841766 1.000000 -vt 0.841766 0.000001 -vt 0.841766 0.000001 -vn -0.000133 -1.000000 0.000134 -vn 0.671666 -0.000000 -0.740855 -vn -0.000075 -1.000000 0.000377 -vn 0.853214 -0.000000 -0.521562 -vn -0.000000 -1.000000 0.000201 -vn 0.000000 -1.000000 0.000323 -vn 0.980936 -0.000000 -0.194331 -vn -0.000101 -1.000000 0.000172 -vn 0.481628 -0.000000 -0.876376 -vn 0.000000 -1.000000 -0.000227 -vn 0.983710 0.000000 0.179763 -vn -0.000059 -1.000000 0.000195 -vn 0.247695 -0.000000 -0.968838 -vn -0.000000 -1.000000 -0.000205 -vn 0.745032 -0.000000 -0.667029 -vn -0.000133 1.000000 0.000133 -vn 0.538045 -0.000000 -0.842916 -vn -0.000101 1.000000 0.000171 -vn 0.891717 -0.000000 -0.452593 -vn -0.000075 1.000000 0.000377 -vn 0.337399 -0.000000 -0.941362 -vn -0.000059 1.000000 0.000195 -vn -0.000000 1.000000 0.000200 -vn 0.000000 1.000000 0.000215 -vn 0.980936 -0.000000 -0.194331 -vn -0.000000 1.000000 0.000206 -vn 0.052785 -0.000000 -0.998606 -vn -0.000000 1.000000 -0.000205 -vn 0.983710 0.000000 0.179763 -vn 0.000000 1.000000 -0.000340 -vn -0.052785 -0.000000 -0.998606 -vn -0.000000 -1.000000 0.000207 -vn 0.899312 0.000000 0.437307 -vn -0.000074 -1.000000 -0.000394 -vn -0.000074 1.000000 -0.000395 -vn 0.855397 0.000000 0.517973 -vn -0.247695 -0.000000 -0.968838 -vn 0.000059 1.000000 0.000195 -vn -0.000136 -1.000000 -0.000130 -vn 0.753856 0.000000 0.657040 -vn -0.000136 1.000000 -0.000130 -vn 0.697622 0.000000 0.716466 -vn -0.000105 1.000000 -0.000168 -vn 0.492575 0.000000 0.870270 -vn -0.000000 1.000000 -0.000227 -vn -0.983731 0.000000 0.179650 -vn -0.000104 -1.000000 -0.000168 -vn 0.567323 0.000000 0.823495 -vn -0.000059 -1.000000 -0.000196 -vn 0.331301 0.000000 0.943525 -vn 0.000000 -1.000000 -0.000207 -vn 0.052786 0.000000 0.998606 -vn 0.244600 0.000000 0.969624 -vn -0.000059 1.000000 -0.000196 -vn -0.337399 -0.000000 -0.941362 -vn 0.000059 -1.000000 0.000195 -vn -0.052786 0.000000 0.998606 -vn 0.000000 1.000000 -0.000207 -vn -0.481628 -0.000000 -0.876376 -vn 0.000101 1.000000 0.000171 -vn -0.244600 0.000000 0.969624 -vn 0.000059 -1.000000 -0.000196 -vn -0.538045 -0.000000 -0.842916 -vn 0.000101 -1.000000 0.000172 -vn -0.331301 0.000000 0.943525 -vn 0.000059 1.000000 -0.000196 -vn -0.671666 -0.000000 -0.740855 -vn 0.000133 1.000000 0.000133 -vn -0.492575 0.000000 0.870270 -vn 0.000104 -1.000000 -0.000168 -vn -0.745032 -0.000000 -0.667029 -vn 0.000133 -1.000000 0.000134 -vn 0.000075 1.000000 0.000377 -vn -0.853250 -0.000000 -0.521502 -vn -0.567323 0.000000 0.823495 -vn 0.000105 1.000000 -0.000168 -vn 0.000075 -1.000000 0.000377 -vn -0.891781 -0.000000 -0.452466 -vn 0.000000 1.000000 0.000323 -vn -0.980957 -0.000000 -0.194227 -vn 0.000000 -1.000000 0.000216 -vn -0.980957 -0.000000 -0.194227 -vn -0.983731 0.000000 0.179650 -vn -0.000000 -1.000000 -0.000340 -vn 0.000136 -1.000000 -0.000130 -vn -0.697622 0.000000 0.716466 -vn 0.000136 1.000000 -0.000130 -vn -0.753856 0.000000 0.657040 -vn 0.000074 1.000000 -0.000395 -vn -0.899379 0.000000 0.437169 -vn 0.000074 -1.000000 -0.000394 -vn -0.855436 0.000000 0.517909 -f 1/1/1 3/3/3 5/5/5 -f 3/3/3 6/6/6 5/5/5 -f 8/8/8 1/1/1 5/5/5 -f 5/5/5 6/6/6 10/10/10 -f 12/12/12 8/8/8 5/5/5 -f 14/14/14 5/5/5 10/10/10 -f 2/2/2 15/15/15 4/4/4 -f 9/9/9 17/17/17 2/2/2 -f 17/17/17 15/15/15 2/2/2 -f 15/15/15 19/19/19 4/4/4 -f 4/4/4 19/19/19 7/7/7 -f 21/21/21 17/17/17 9/9/9 -f 13/13/13 21/21/21 9/9/9 -f 16/16/16 18/18/18 23/23/23 -f 20/20/20 16/16/16 23/23/23 -f 18/18/18 22/22/22 23/23/23 -f 24/24/24 20/20/20 23/23/23 -f 19/19/19 25/25/25 7/7/7 -f 22/22/22 26/26/26 23/23/23 -f 27/27/27 21/21/21 13/13/13 -f 24/24/24 23/23/23 28/28/28 -f 7/7/7 25/25/25 29/29/29 -f 30/30/30 24/24/24 28/28/28 -f 11/11/11 7/7/7 29/29/29 -f 31/31/31 27/27/27 13/13/13 -f 32/32/32 12/12/12 5/5/5 -f 11/11/11 29/29/29 33/33/33 -f 10/10/10 34/34/34 14/14/14 -f 35/35/35 30/30/30 28/28/28 -f 29/29/29 36/36/36 33/33/33 -f 37/37/37 27/27/27 31/31/31 -f 26/26/26 38/38/38 23/23/23 -f 34/34/34 39/39/39 14/14/14 -f 33/33/33 36/36/36 40/40/40 -f 41/41/41 35/35/35 28/28/28 -f 36/36/36 42/42/42 40/40/40 -f 43/43/43 41/41/41 28/28/28 -f 28/28/28 23/23/23 45/45/45 -f 39/39/39 47/47/47 14/14/14 -f 40/40/40 42/42/42 48/48/48 -f 42/42/42 44/44/44 48/48/48 -f 47/47/47 49/49/49 14/14/14 -f 48/48/48 44/44/44 50/50/50 -f 49/49/49 51/51/51 14/14/14 -f 44/44/44 53/53/53 50/50/50 -f 54/54/54 43/43/43 28/28/28 -f 50/50/50 53/53/53 52/52/52 -f 55/55/55 37/37/37 31/31/31 -f 56/56/56 32/32/32 5/5/5 -f 53/53/53 57/57/57 52/52/52 -f 58/58/58 54/54/54 28/28/28 -f 59/59/59 37/37/37 55/55/55 -f 38/38/38 60/60/60 23/23/23 -f 52/52/52 57/57/57 61/61/61 -f 51/51/51 62/62/62 14/14/14 -f 63/63/63 59/59/59 55/55/55 -f 64/64/64 56/56/56 5/5/5 -f 57/57/57 65/65/65 61/61/61 -f 66/66/66 58/58/58 28/28/28 -f 67/67/67 59/59/59 63/63/63 -f 60/60/60 68/68/68 23/23/23 -f 61/61/61 65/65/65 69/69/69 -f 62/62/62 70/70/70 14/14/14 -f 71/71/71 67/67/67 63/63/63 -f 72/72/72 64/64/64 5/5/5 -f 68/68/68 73/73/73 23/23/23 -f 74/74/74 67/67/67 71/71/71 -f 65/65/65 75/75/75 69/69/69 -f 76/76/76 66/66/66 28/28/28 -f 77/77/77 72/72/72 5/5/5 -f 78/78/78 74/74/74 71/71/71 -f 73/73/73 79/79/79 23/23/23 -f 80/80/80 74/74/74 78/78/78 -f 23/23/23 79/79/79 45/45/45 -f 81/81/81 77/77/77 5/5/5 -f 82/82/82 80/80/80 78/78/78 -f 81/81/81 5/5/5 14/14/14 -f 80/80/80 82/82/82 83/83/83 -f 46/46/46 80/80/80 83/83/83 -f 84/84/84 81/81/81 14/14/14 -f 70/70/70 85/85/85 14/14/14 -f 69/69/69 75/75/75 86/86/86 -f 87/87/87 76/76/76 28/28/28 -f 75/75/75 88/88/88 86/86/86 -f 89/89/89 28/28/28 45/45/45 -f 90/90/90 46/46/46 83/83/83 -f 89/89/89 87/87/87 28/28/28 -f 91/91/91 84/84/84 14/14/14 -f 85/85/85 91/91/91 14/14/14 -f 86/86/86 88/88/88 92/92/92 -f 92/92/92 90/90/90 83/83/83 -f 88/88/88 90/90/90 92/92/92 diff --git a/mod/data/mac-fallback-assets/silh_shaped_long_1.obj b/mod/data/mac-fallback-assets/silh_shaped_long_1.obj deleted file mode 100644 index 3377f3a52..000000000 --- a/mod/data/mac-fallback-assets/silh_shaped_long_1.obj +++ /dev/null @@ -1,374 +0,0 @@ -# This file uses centimeters as units for non-parametric coordinates. - -mtllib silhouette_shorter.mtl -v 1.175695 -0.000000 -3.171242 -v 1.618197 -0.000000 -2.827718 -v -0.000000 -0.000000 0.749407 -v -1.175695 -0.000000 -3.171242 -v -1.618197 -0.000000 -2.827718 -v -1.618197 1.000230 -2.827718 -v -1.175695 1.000230 -3.171242 -v -0.618092 -0.000000 3.391803 -v -1.175695 -0.000000 3.171242 -v 1.902307 -0.000000 -2.394839 -v -0.618092 -0.000000 -3.391803 -v -0.618092 1.000230 -3.391803 -v -1.902307 -0.000000 -2.394839 -v -1.902307 1.000230 -2.394839 -v -0.000000 -0.000000 3.467800 -v 2.000200 -0.000000 0.749407 -v 1.902307 -0.000000 2.394839 -v 0.618092 -0.000000 3.391803 -v -0.000000 -0.000000 -3.467800 -v -0.000000 1.000230 -3.467800 -v -2.000200 -0.000000 0.749407 -v -2.000200 1.000230 0.749407 -v 1.618197 -0.000000 2.827710 -v 1.175684 -0.000000 3.171242 -v 0.618092 -0.000000 -3.391803 -v 0.618092 1.000230 -3.391803 -v -1.902307 -0.000000 2.394839 -v -1.902307 1.000230 2.394839 -v 1.175695 1.000230 -3.171242 -v -1.618197 -0.000000 2.827710 -v -1.618197 1.000230 2.827710 -v -1.175695 1.000230 3.171242 -v 1.618197 1.000230 -2.827718 -v -0.119870 0.920840 -1.982612 -v -0.000000 0.920840 0.749407 -v -0.087093 0.920840 -2.008058 -v -0.045784 0.920840 -2.024392 -v -0.140911 0.920840 -1.950543 -v -0.000000 0.920840 -2.030021 -v -0.148162 0.920840 0.749407 -v 0.045784 0.920840 -2.024392 -v -0.140911 0.920840 1.950543 -v 0.087093 0.920840 -2.008058 -v -0.119870 0.920840 1.982612 -v -0.087093 0.920840 2.008058 -v 0.119870 0.920840 -1.982612 -v -0.045784 0.920840 2.024392 -v 0.140911 0.920840 -1.950543 -v -0.000000 0.920840 2.030021 -v 0.148162 0.920840 0.749407 -v 0.140911 0.920840 1.950543 -v 0.045784 0.920840 2.024392 -v 0.087093 0.920840 2.008058 -v 0.119870 0.920840 1.982612 -v -0.618092 1.000230 3.391803 -v 1.902307 1.000230 -2.394839 -v -0.087093 1.000230 -2.008058 -v -0.119870 1.000230 -1.982612 -v -0.000000 1.000230 3.467800 -v 2.000200 1.000230 0.749407 -v -0.045784 1.000230 -2.024392 -v -0.140911 1.000230 -1.950543 -v -0.000000 1.000230 -2.030021 -v -0.148162 1.000230 0.749407 -v 0.045784 1.000230 -2.024392 -v -0.140911 1.000230 1.950543 -v 1.902307 1.000230 2.394839 -v 0.618092 1.000230 3.391803 -v 0.087093 1.000230 -2.008058 -v -0.119870 1.000230 1.982612 -v 1.618197 1.000230 2.827710 -v 1.175684 1.000230 3.171242 -v -0.087093 1.000230 2.008058 -v 0.119870 1.000230 -1.982612 -v -0.045784 1.000230 2.024392 -v 0.140911 1.000230 -1.950543 -v -0.000000 1.000230 2.030021 -v 0.148162 1.000230 0.749407 -v 0.140911 1.000230 1.950543 -v 0.045784 1.000230 2.024392 -v 0.087093 1.000230 2.008058 -v 0.119870 1.000230 1.982612 -vt 0.266842 0.029841 -vt 0.301409 0.064408 -vt 0.175000 0.150000 -vt 0.125000 0.312500 -vt 0.137500 0.312500 -vt 0.137500 0.688440 -vt 0.125000 0.688440 -vt 0.126716 0.304853 -vt 0.083159 0.282659 -vt 0.323603 0.107966 -vt 0.112500 0.312500 -vt 0.112500 0.688440 -vt 0.150000 0.312500 -vt 0.150000 0.688440 -vt 0.175000 0.312500 -vt 0.331250 0.156250 -vt 0.323603 0.204534 -vt 0.223284 0.304853 -vt 0.100000 0.312500 -vt 0.100000 0.688440 -vt 0.162500 0.312500 -vt 0.162500 0.688440 -vt 0.301409 0.248091 -vt 0.266841 0.282659 -vt 0.087500 0.312500 -vt 0.087500 0.688440 -vt 0.175000 0.312500 -vt 0.175000 0.688440 -vt 0.075000 0.312500 -vt 0.075000 0.688440 -vt 0.187500 0.312500 -vt 0.187500 0.688440 -vt 0.200000 0.312500 -vt 0.200000 0.688440 -vt 0.062500 0.312500 -vt 0.062500 0.688440 -vt 0.048591 0.064409 -vt 0.175000 0.150000 -vt 0.083159 0.029841 -vt 0.126716 0.007647 -vt 0.026397 0.107966 -vt 0.175000 -0.000000 -vt 0.018750 0.156250 -vt 0.223284 0.007647 -vt 0.026397 0.204534 -vt 0.266842 0.029841 -vt 0.048591 0.248091 -vt 0.083159 0.282659 -vt 0.301409 0.064408 -vt 0.126716 0.304853 -vt 0.323603 0.107966 -vt 0.175000 0.312500 -vt 0.331250 0.156250 -vt 0.323603 0.204534 -vt 0.223284 0.304853 -vt 0.266841 0.282659 -vt 0.301409 0.248091 -vt 0.212500 0.312500 -vt 0.212500 0.688440 -vt 0.050000 0.312500 -vt 0.050000 0.688440 -vt 0.168197 0.847327 -vt 0.083159 0.970159 -vt 0.048591 0.935591 -vt 0.165636 0.844766 -vt 0.225000 0.312500 -vt 0.225000 0.688440 -vt 0.287500 0.312500 -vt 0.300000 0.312500 -vt 0.300000 0.688440 -vt 0.287500 0.688440 -vt 0.171423 0.848971 -vt 0.126716 0.992353 -vt 0.026397 0.892034 -vt 0.163992 0.841540 -vt 0.175000 0.849537 -vt 0.175000 1.000000 -vt 0.018750 0.843750 -vt 0.163426 0.837963 -vt 0.178577 0.848971 -vt 0.223284 0.992353 -vt 0.026397 0.795466 -vt 0.163992 0.834386 -vt 0.275000 0.312500 -vt 0.275000 0.688440 -vt 0.237500 0.312500 -vt 0.237500 0.688440 -vt 0.181803 0.847327 -vt 0.266841 0.970159 -vt 0.048591 0.751909 -vt 0.165636 0.831160 -vt 0.262500 0.312500 -vt 0.262500 0.688440 -vt 0.250000 0.312500 -vt 0.250000 0.688440 -vt 0.125000 0.312500 -vt 0.125000 0.688440 -vt 0.137500 0.688440 -vt 0.137500 0.312500 -vt 0.112500 0.312500 -vt 0.112500 0.688440 -vt 0.150000 0.688440 -vt 0.150000 0.312500 -vt 0.100000 0.312500 -vt 0.100000 0.688440 -vt 0.162500 0.688440 -vt 0.162500 0.312500 -vt 0.087500 0.312500 -vt 0.087500 0.688440 -vt 0.175000 0.688440 -vt 0.175000 0.312500 -vt 0.075000 0.312500 -vt 0.075000 0.688440 -vt 0.187500 0.688440 -vt 0.187500 0.312500 -vt 0.200000 0.688440 -vt 0.200000 0.312500 -vt 0.062500 0.312500 -vt 0.062500 0.688440 -vt 0.212500 0.688440 -vt 0.212500 0.312500 -vt 0.050000 0.312500 -vt 0.050000 0.688440 -vt 0.225000 0.688440 -vt 0.225000 0.312500 -vt 0.287500 0.312500 -vt 0.287500 0.688440 -vt 0.300000 0.688440 -vt 0.300000 0.312500 -vt 0.275000 0.312500 -vt 0.275000 0.688440 -vt 0.237500 0.688440 -vt 0.237500 0.312500 -vt 0.250000 0.688440 -vt 0.250000 0.312500 -vt 0.262500 0.312500 -vt 0.262500 0.688440 -vt 0.083159 0.717341 -vt 0.168197 0.828599 -vt 0.184364 0.844766 -vt 0.301409 0.935591 -vt 0.126716 0.695147 -vt 0.171423 0.826955 -vt 0.186008 0.841540 -vt 0.323603 0.892034 -vt 0.175000 0.687500 -vt 0.175000 0.826389 -vt 0.186574 0.837963 -vt 0.331250 0.843750 -vt 0.186008 0.834386 -vt 0.323603 0.795466 -vt 0.223284 0.695147 -vt 0.178577 0.826955 -vt 0.184364 0.831160 -vt 0.301409 0.751908 -vt 0.266842 0.717341 -vt 0.181803 0.828599 -vt 0.048591 0.248091 -vt 0.026397 0.204534 -vt 0.223284 0.007647 -vt 0.018750 0.156250 -vt 0.175000 -0.000000 -vt 0.026397 0.107966 -vt 0.126716 0.007647 -vt 0.048591 0.064409 -vt 0.083159 0.029841 -s 1 -g silhouette_shorter -usemtl lambert2SG -f 1/1 2/2 3/3 -s 2 -f 4/4 5/5 6/6 7/7 -s 1 -f 8/8 9/9 3/3 -f 2/2 10/10 3/3 -s 2 -f 11/11 4/4 7/7 12/12 -f 5/5 13/13 14/14 6/6 -s 1 -f 15/15 8/8 3/3 -f 10/10 16/16 3/3 -f 16/16 17/17 3/3 -f 18/18 15/15 3/3 -s 2 -f 19/19 11/11 12/12 20/20 -f 13/13 21/21 22/22 14/14 -s 1 -f 17/17 23/23 3/3 -f 24/24 18/18 3/3 -f 23/23 24/24 3/3 -s 2 -f 25/25 19/19 20/20 26/26 -f 21/21 27/27 28/28 22/22 -f 1/29 25/25 26/26 29/30 -f 27/27 30/31 31/32 28/28 -f 30/31 9/33 32/34 31/32 -f 2/35 1/29 29/30 33/36 -s 4 -f 34/37 35/38 36/39 -f 36/39 35/38 37/40 -f 38/41 35/38 34/37 -f 37/40 35/38 39/42 -f 40/43 35/38 38/41 -f 39/42 35/38 41/44 -f 42/45 35/38 40/43 -f 41/44 35/38 43/46 -f 44/47 35/38 42/45 -f 45/48 35/38 44/47 -f 43/46 35/38 46/49 -f 47/50 35/38 45/48 -f 46/49 35/38 48/51 -f 49/52 35/38 47/50 -f 48/51 35/38 50/53 -f 50/53 35/38 51/54 -f 52/55 35/38 49/52 -f 53/56 35/38 52/55 -f 51/54 35/38 54/57 -f 54/57 35/38 53/56 -s 2 -f 9/33 8/58 55/59 32/34 -f 10/60 2/35 33/36 56/61 -s 5 -f 57/62 7/63 6/64 58/65 -s 2 -f 8/58 15/66 59/67 55/59 -f 16/68 10/69 56/70 60/71 -s 5 -f 61/72 12/73 7/63 57/62 -f 58/65 6/64 14/74 62/75 -f 63/76 20/77 12/73 61/72 -f 62/75 14/74 22/78 64/79 -f 65/80 26/81 20/77 63/76 -f 64/79 22/78 28/82 66/83 -s 2 -f 17/84 16/68 60/71 67/85 -f 15/66 18/86 68/87 59/67 -s 5 -f 69/88 29/89 26/81 65/80 -f 66/83 28/82 31/90 70/91 -s 2 -f 23/92 17/84 67/85 71/93 -f 18/86 24/94 72/95 68/87 -s 6 -f 36/96 57/97 58/98 34/99 -f 37/100 61/101 57/97 36/96 -f 34/99 58/98 62/102 38/103 -f 39/104 63/105 61/101 37/100 -f 38/103 62/102 64/106 40/107 -f 41/108 65/109 63/105 39/104 -f 40/107 64/106 66/110 42/111 -s 2 -f 24/94 23/92 71/93 72/95 -s 6 -f 43/112 69/113 65/109 41/108 -f 42/111 66/110 70/114 44/115 -f 44/115 70/114 73/116 45/117 -f 46/118 74/119 69/113 43/112 -f 45/117 73/116 75/120 47/121 -f 48/122 76/123 74/119 46/118 -f 47/121 75/120 77/124 49/125 -f 50/126 78/127 76/128 48/129 -f 51/130 79/131 78/127 50/126 -f 49/125 77/124 80/132 52/133 -f 52/133 80/132 81/134 53/135 -f 54/136 82/137 79/131 51/130 -f 53/135 81/134 82/137 54/136 -s 5 -f 70/91 31/90 32/138 73/139 -f 74/140 33/141 29/89 69/88 -f 73/139 32/138 55/142 75/143 -f 76/144 56/145 33/141 74/140 -f 75/143 55/142 59/146 77/147 -f 78/148 60/149 56/145 76/144 -f 79/150 67/151 60/149 78/148 -f 77/147 59/146 68/152 80/153 -f 82/154 71/155 67/151 79/150 -f 80/153 68/152 72/156 81/157 -f 81/157 72/156 71/155 82/154 -s 1 -f 9/9 30/158 3/3 -f 30/158 27/159 3/3 -f 25/160 1/1 3/3 -f 27/159 21/161 3/3 -f 19/162 25/160 3/3 -f 21/161 13/163 3/3 -f 11/164 19/162 3/3 -f 13/163 5/165 3/3 -f 4/166 11/164 3/3 -f 5/165 4/166 3/3 diff --git a/mod/data/mac-fallback-assets/silh_shaped_snail_1.obj b/mod/data/mac-fallback-assets/silh_shaped_snail_1.obj deleted file mode 100644 index 5c6086c11..000000000 --- a/mod/data/mac-fallback-assets/silh_shaped_snail_1.obj +++ /dev/null @@ -1,374 +0,0 @@ -# This file uses centimeters as units for non-parametric coordinates. - -mtllib silhouette_shorter.mtl -v 1.175695 -0.000000 -3.587517 -v 1.618197 -0.000000 -3.243152 -v -0.000000 -0.000000 0.770270 -v -1.175695 -0.000000 -3.587517 -v -1.618197 -0.000000 -3.243152 -v -1.618197 1.000230 -3.243152 -v -1.175695 1.000230 -3.587517 -v -0.618092 -0.000000 3.808617 -v -1.175695 -0.000000 3.587517 -v 1.902307 -0.000000 -2.809213 -v -0.618092 -0.000000 -3.808617 -v -0.618092 1.000230 -3.808617 -v -1.902307 -0.000000 -2.809213 -v -1.902307 1.000230 -2.809213 -v -0.000000 -0.000000 3.884800 -v 2.000200 -0.000000 0.770270 -v 1.902307 -0.000000 2.809213 -v 0.618092 -0.000000 3.808617 -v -0.000000 -0.000000 -3.884800 -v -0.000000 1.000230 -3.884800 -v -2.000200 -0.000000 0.770270 -v -2.000200 1.000230 0.770270 -v 1.618197 -0.000000 3.243144 -v 1.175684 -0.000000 3.587517 -v 0.618092 -0.000000 -3.808617 -v 0.618092 1.000230 -3.808617 -v -1.902307 -0.000000 2.809213 -v -1.902307 1.000230 2.809213 -v 1.175695 1.000230 -3.587517 -v -1.618197 -0.000000 3.243144 -v -1.618197 1.000230 3.243144 -v -1.175695 1.000230 3.587517 -v 1.618197 1.000230 -3.243152 -v -0.119870 0.920840 -2.395978 -v -0.000000 0.920840 0.770270 -v -0.087093 0.920840 -2.421485 -v -0.045784 0.920840 -2.437860 -v -0.140911 0.920840 -2.363830 -v -0.000000 0.920840 -2.443503 -v -0.148162 0.920840 0.770270 -v 0.045784 0.920840 -2.437860 -v -0.140911 0.920840 2.363830 -v 0.087093 0.920840 -2.421485 -v -0.119870 0.920840 2.395978 -v -0.087093 0.920840 2.421485 -v 0.119870 0.920840 -2.395978 -v -0.045784 0.920840 2.437860 -v 0.140911 0.920840 -2.363830 -v -0.000000 0.920840 2.443503 -v 0.148162 0.920840 0.770270 -v 0.140911 0.920840 2.363830 -v 0.045784 0.920840 2.437860 -v 0.087093 0.920840 2.421485 -v 0.119870 0.920840 2.395978 -v -0.618092 1.000230 3.808617 -v 1.902307 1.000230 -2.809213 -v -0.087093 1.000230 -2.421485 -v -0.119870 1.000230 -2.395978 -v -0.000000 1.000230 3.884800 -v 2.000200 1.000230 0.770270 -v -0.045784 1.000230 -2.437860 -v -0.140911 1.000230 -2.363830 -v -0.000000 1.000230 -2.443503 -v -0.148162 1.000230 0.770270 -v 0.045784 1.000230 -2.437860 -v -0.140911 1.000230 2.363830 -v 1.902307 1.000230 2.809213 -v 0.618092 1.000230 3.808617 -v 0.087093 1.000230 -2.421485 -v -0.119870 1.000230 2.395978 -v 1.618197 1.000230 3.243144 -v 1.175684 1.000230 3.587517 -v -0.087093 1.000230 2.421485 -v 0.119870 1.000230 -2.395978 -v -0.045784 1.000230 2.437860 -v 0.140911 1.000230 -2.363830 -v -0.000000 1.000230 2.443503 -v 0.148162 1.000230 0.770270 -v 0.140911 1.000230 2.363830 -v 0.045784 1.000230 2.437860 -v 0.087093 1.000230 2.421485 -v 0.119870 1.000230 2.395978 -vt 0.266842 0.029841 -vt 0.301409 0.064408 -vt 0.175000 0.150000 -vt 0.125000 0.312500 -vt 0.137500 0.312500 -vt 0.137500 0.688440 -vt 0.125000 0.688440 -vt 0.126716 0.304853 -vt 0.083159 0.282659 -vt 0.323603 0.107966 -vt 0.112500 0.312500 -vt 0.112500 0.688440 -vt 0.150000 0.312500 -vt 0.150000 0.688440 -vt 0.175000 0.312500 -vt 0.331250 0.156250 -vt 0.323603 0.204534 -vt 0.223284 0.304853 -vt 0.100000 0.312500 -vt 0.100000 0.688440 -vt 0.162500 0.312500 -vt 0.162500 0.688440 -vt 0.301409 0.248091 -vt 0.266841 0.282659 -vt 0.087500 0.312500 -vt 0.087500 0.688440 -vt 0.175000 0.312500 -vt 0.175000 0.688440 -vt 0.075000 0.312500 -vt 0.075000 0.688440 -vt 0.187500 0.312500 -vt 0.187500 0.688440 -vt 0.200000 0.312500 -vt 0.200000 0.688440 -vt 0.062500 0.312500 -vt 0.062500 0.688440 -vt 0.048591 0.064409 -vt 0.175000 0.150000 -vt 0.083159 0.029841 -vt 0.126716 0.007647 -vt 0.026397 0.107966 -vt 0.175000 -0.000000 -vt 0.018750 0.156250 -vt 0.223284 0.007647 -vt 0.026397 0.204534 -vt 0.266842 0.029841 -vt 0.048591 0.248091 -vt 0.083159 0.282659 -vt 0.301409 0.064408 -vt 0.126716 0.304853 -vt 0.323603 0.107966 -vt 0.175000 0.312500 -vt 0.331250 0.156250 -vt 0.323603 0.204534 -vt 0.223284 0.304853 -vt 0.266841 0.282659 -vt 0.301409 0.248091 -vt 0.212500 0.312500 -vt 0.212500 0.688440 -vt 0.050000 0.312500 -vt 0.050000 0.688440 -vt 0.168197 0.847327 -vt 0.083159 0.970159 -vt 0.048591 0.935591 -vt 0.165636 0.844766 -vt 0.225000 0.312500 -vt 0.225000 0.688440 -vt 0.287500 0.312500 -vt 0.300000 0.312500 -vt 0.300000 0.688440 -vt 0.287500 0.688440 -vt 0.171423 0.848971 -vt 0.126716 0.992353 -vt 0.026397 0.892034 -vt 0.163992 0.841540 -vt 0.175000 0.849537 -vt 0.175000 1.000000 -vt 0.018750 0.843750 -vt 0.163426 0.837963 -vt 0.178577 0.848971 -vt 0.223284 0.992353 -vt 0.026397 0.795466 -vt 0.163992 0.834386 -vt 0.275000 0.312500 -vt 0.275000 0.688440 -vt 0.237500 0.312500 -vt 0.237500 0.688440 -vt 0.181803 0.847327 -vt 0.266841 0.970159 -vt 0.048591 0.751909 -vt 0.165636 0.831160 -vt 0.262500 0.312500 -vt 0.262500 0.688440 -vt 0.250000 0.312500 -vt 0.250000 0.688440 -vt 0.125000 0.312500 -vt 0.125000 0.688440 -vt 0.137500 0.688440 -vt 0.137500 0.312500 -vt 0.112500 0.312500 -vt 0.112500 0.688440 -vt 0.150000 0.688440 -vt 0.150000 0.312500 -vt 0.100000 0.312500 -vt 0.100000 0.688440 -vt 0.162500 0.688440 -vt 0.162500 0.312500 -vt 0.087500 0.312500 -vt 0.087500 0.688440 -vt 0.175000 0.688440 -vt 0.175000 0.312500 -vt 0.075000 0.312500 -vt 0.075000 0.688440 -vt 0.187500 0.688440 -vt 0.187500 0.312500 -vt 0.200000 0.688440 -vt 0.200000 0.312500 -vt 0.062500 0.312500 -vt 0.062500 0.688440 -vt 0.212500 0.688440 -vt 0.212500 0.312500 -vt 0.050000 0.312500 -vt 0.050000 0.688440 -vt 0.225000 0.688440 -vt 0.225000 0.312500 -vt 0.287500 0.312500 -vt 0.287500 0.688440 -vt 0.300000 0.688440 -vt 0.300000 0.312500 -vt 0.275000 0.312500 -vt 0.275000 0.688440 -vt 0.237500 0.688440 -vt 0.237500 0.312500 -vt 0.250000 0.688440 -vt 0.250000 0.312500 -vt 0.262500 0.312500 -vt 0.262500 0.688440 -vt 0.083159 0.717341 -vt 0.168197 0.828599 -vt 0.184364 0.844766 -vt 0.301409 0.935591 -vt 0.126716 0.695147 -vt 0.171423 0.826955 -vt 0.186008 0.841540 -vt 0.323603 0.892034 -vt 0.175000 0.687500 -vt 0.175000 0.826389 -vt 0.186574 0.837963 -vt 0.331250 0.843750 -vt 0.186008 0.834386 -vt 0.323603 0.795466 -vt 0.223284 0.695147 -vt 0.178577 0.826955 -vt 0.184364 0.831160 -vt 0.301409 0.751908 -vt 0.266842 0.717341 -vt 0.181803 0.828599 -vt 0.048591 0.248091 -vt 0.026397 0.204534 -vt 0.223284 0.007647 -vt 0.018750 0.156250 -vt 0.175000 -0.000000 -vt 0.026397 0.107966 -vt 0.126716 0.007647 -vt 0.048591 0.064409 -vt 0.083159 0.029841 -s 1 -g silhouette_shorter -usemtl lambert2SG -f 1/1 2/2 3/3 -s 2 -f 4/4 5/5 6/6 7/7 -s 1 -f 8/8 9/9 3/3 -f 2/2 10/10 3/3 -s 2 -f 11/11 4/4 7/7 12/12 -f 5/5 13/13 14/14 6/6 -s 1 -f 15/15 8/8 3/3 -f 10/10 16/16 3/3 -f 16/16 17/17 3/3 -f 18/18 15/15 3/3 -s 2 -f 19/19 11/11 12/12 20/20 -f 13/13 21/21 22/22 14/14 -s 1 -f 17/17 23/23 3/3 -f 24/24 18/18 3/3 -f 23/23 24/24 3/3 -s 2 -f 25/25 19/19 20/20 26/26 -f 21/21 27/27 28/28 22/22 -f 1/29 25/25 26/26 29/30 -f 27/27 30/31 31/32 28/28 -f 30/31 9/33 32/34 31/32 -f 2/35 1/29 29/30 33/36 -s 4 -f 34/37 35/38 36/39 -f 36/39 35/38 37/40 -f 38/41 35/38 34/37 -f 37/40 35/38 39/42 -f 40/43 35/38 38/41 -f 39/42 35/38 41/44 -f 42/45 35/38 40/43 -f 41/44 35/38 43/46 -f 44/47 35/38 42/45 -f 45/48 35/38 44/47 -f 43/46 35/38 46/49 -f 47/50 35/38 45/48 -f 46/49 35/38 48/51 -f 49/52 35/38 47/50 -f 48/51 35/38 50/53 -f 50/53 35/38 51/54 -f 52/55 35/38 49/52 -f 53/56 35/38 52/55 -f 51/54 35/38 54/57 -f 54/57 35/38 53/56 -s 2 -f 9/33 8/58 55/59 32/34 -f 10/60 2/35 33/36 56/61 -s 5 -f 57/62 7/63 6/64 58/65 -s 2 -f 8/58 15/66 59/67 55/59 -f 16/68 10/69 56/70 60/71 -s 5 -f 61/72 12/73 7/63 57/62 -f 58/65 6/64 14/74 62/75 -f 63/76 20/77 12/73 61/72 -f 62/75 14/74 22/78 64/79 -f 65/80 26/81 20/77 63/76 -f 64/79 22/78 28/82 66/83 -s 2 -f 17/84 16/68 60/71 67/85 -f 15/66 18/86 68/87 59/67 -s 5 -f 69/88 29/89 26/81 65/80 -f 66/83 28/82 31/90 70/91 -s 2 -f 23/92 17/84 67/85 71/93 -f 18/86 24/94 72/95 68/87 -s 6 -f 36/96 57/97 58/98 34/99 -f 37/100 61/101 57/97 36/96 -f 34/99 58/98 62/102 38/103 -f 39/104 63/105 61/101 37/100 -f 38/103 62/102 64/106 40/107 -f 41/108 65/109 63/105 39/104 -f 40/107 64/106 66/110 42/111 -s 2 -f 24/94 23/92 71/93 72/95 -s 6 -f 43/112 69/113 65/109 41/108 -f 42/111 66/110 70/114 44/115 -f 44/115 70/114 73/116 45/117 -f 46/118 74/119 69/113 43/112 -f 45/117 73/116 75/120 47/121 -f 48/122 76/123 74/119 46/118 -f 47/121 75/120 77/124 49/125 -f 50/126 78/127 76/128 48/129 -f 51/130 79/131 78/127 50/126 -f 49/125 77/124 80/132 52/133 -f 52/133 80/132 81/134 53/135 -f 54/136 82/137 79/131 51/130 -f 53/135 81/134 82/137 54/136 -s 5 -f 70/91 31/90 32/138 73/139 -f 74/140 33/141 29/89 69/88 -f 73/139 32/138 55/142 75/143 -f 76/144 56/145 33/141 74/140 -f 75/143 55/142 59/146 77/147 -f 78/148 60/149 56/145 76/144 -f 79/150 67/151 60/149 78/148 -f 77/147 59/146 68/152 80/153 -f 82/154 71/155 67/151 79/150 -f 80/153 68/152 72/156 81/157 -f 81/157 72/156 71/155 82/154 -s 1 -f 9/9 30/158 3/3 -f 30/158 27/159 3/3 -f 25/160 1/1 3/3 -f 27/159 21/161 3/3 -f 19/162 25/160 3/3 -f 21/161 13/163 3/3 -f 11/164 19/162 3/3 -f 13/163 5/165 3/3 -f 4/166 11/164 3/3 -f 5/165 4/166 3/3 diff --git a/mod/data/mac-fallback-assets/silh_vanilla_long_1.obj b/mod/data/mac-fallback-assets/silh_vanilla_long_1.obj deleted file mode 100644 index 5663009dd..000000000 --- a/mod/data/mac-fallback-assets/silh_vanilla_long_1.obj +++ /dev/null @@ -1,190 +0,0 @@ -g silh_new_long_1in -v -0 0.000321194326 -1.90383077 -v 1.79507375 -3.19731583E-07 -2.40114331 -v 1.47036397 -3.79383408E-07 -2.84912109 -v 2.00016642 0.000321194326 -1.90383077 -v 1.04253602 -4.21221131E-07 -3.16331697 -v 2.00016642 0.000321702857 1.91503835 -v 0.61488086 -4.4783468E-07 -3.36318135 -v -0 0.000321702857 1.91503823 -v 1.47036397 0.999999642 -2.84912133 -v 1.04253602 0.999999583 -3.1633172 -v 1.79507375 0.999999702 -2.40114355 -v 0.61488086 0.999999523 -3.36318159 -v -0 0.999678314 -1.90383089 -v 2.00016642 0.999678314 -1.90383089 -v -0 0.999999523 -3.46068621 -v -0 0.999678791 1.91503811 -v 2.00016642 0.999678791 1.91503823 -v -0 -4.608182E-07 -3.46068597 -v 1.82142329 3.1795102E-07 2.38777161 -v 1.82142329 1.00000036 2.38777137 -v -0.61488086 0.999999523 -3.36318159 -v 1.52951431 3.70640919E-07 2.7834661 -v 1.52951431 1.00000036 2.78346586 -v 1.07117271 1.00000048 3.16235137 -v -2.00004268 0.999678791 1.91503823 -v 1.07117271 4.21092579E-07 3.16235161 -v 0.61488086 4.48775808E-07 3.37024903 -v -0 4.61759583E-07 3.46775556 -v 0.61488086 1.00000048 3.37024879 -v -0.61488086 -4.4783468E-07 -3.36318135 -v -0 1.00000048 3.46775532 -v -1.04253602 0.999999583 -3.1633172 -v -0.61488086 4.48775808E-07 3.37024903 -v -1.04253602 -4.21221131E-07 -3.16331697 -v -0.61488086 1.00000048 3.37024879 -v -1.47036397 0.999999642 -2.84912133 -v -1.07117271 4.21092579E-07 3.16235161 -v -1.47036397 -3.79383408E-07 -2.84912109 -v -1.79507375 0.999999702 -2.40114355 -v -1.07117271 1.00000048 3.16235137 -v -1.79507375 -3.19731583E-07 -2.40114331 -v -2.00004268 0.999678314 -1.90383089 -v -2.00004268 0.000321194326 -1.90383077 -v -2.00004268 0.000321702857 1.91503835 -v -1.52951431 3.70640919E-07 2.7834661 -v -1.52951431 1.00000036 2.78346586 -v -1.82142329 1.00000036 2.38777137 -v -1.82142329 3.1795102E-07 2.38777161 -vn -0 -1 0 -vn 0.702909827 -0.673609495 -0.228403121 -vn 0.597922504 -0.673625469 -0.434416264 -vn 0.739097834 -0.673598051 0 -vn 0.434390396 -0.673585176 -0.597986639 -vn 0.739097834 -0.673598051 0 -vn 0.228402525 -0.673507571 -0.703007638 -vn -0 -1 0 -vn 0.597922444 0.67362529 -0.434416443 -vn 0.434390366 0.673584998 -0.597986817 -vn 0.702909887 0.673609436 -0.2284033 -vn 0.228402525 0.673507333 -0.703007877 -vn -0 1 0 -vn 0.739097834 0.673598051 0 -vn -0 0.673597932 -0.739097953 -vn -0 1 0 -vn 0.739097834 0.673598051 0 -vn -0 -0.67359823 -0.739097774 -vn 0.702909887 -0.673609436 0.2284033 -vn 0.702909827 0.673609495 0.228403121 -vn -0.228403196 0.673609316 -0.702909946 -vn 0.597986698 -0.673584998 0.434390455 -vn 0.597986758 0.673585176 0.434390277 -vn 0.434416384 0.673625469 0.597922385 -vn -0.739097834 0.673598051 0 -vn 0.434416354 -0.67362529 0.597922564 -vn 0.228403196 -0.673609316 0.702909946 -vn -0 -0.673493445 0.739193082 -vn 0.228403226 0.673609614 0.702909768 -vn -0.228403226 -0.673609614 -0.702909768 -vn -0 0.673493803 0.739192903 -vn -0.434500784 0.673501134 -0.598001182 -vn -0.228402525 -0.673507333 0.703007877 -vn -0.434500784 -0.673501253 -0.598000944 -vn -0.228402525 0.673507571 0.703007638 -vn -0.598001063 0.673501134 -0.434500873 -vn -0.434500784 -0.673501134 0.598001182 -vn -0.598001063 -0.673501253 -0.434500694 -vn -0.702909887 0.673609436 -0.2284033 -vn -0.434500784 0.673501253 0.598000944 -vn -0.702909827 -0.673609495 -0.228403121 -vn -0.739097834 0.673598051 0 -vn -0.739097834 -0.673598051 0 -vn -0.739097834 -0.673598051 0 -vn -0.598001063 -0.673501134 0.434500873 -vn -0.598001063 0.673501253 0.434500694 -vn -0.702909827 0.673609495 0.228403121 -vn -0.702909887 -0.673609436 0.2284033 -g silh_new_long_1in_0 -f 3//3 2//2 1//1 -f 2//2 4//4 1//1 -f 5//5 3//3 1//1 -f 1//1 4//4 6//6 -f 7//7 5//5 1//1 -f 8//8 1//1 6//6 -f 3//3 9//9 2//2 -f 5//5 10//10 3//3 -f 10//10 9//9 3//3 -f 9//9 11//11 2//2 -f 2//2 11//11 4//4 -f 12//12 10//10 5//5 -f 7//7 12//12 5//5 -f 9//9 10//10 13//13 -f 11//11 9//9 13//13 -f 10//10 12//12 13//13 -f 14//14 11//11 13//13 -f 11//11 14//14 4//4 -f 12//12 15//15 13//13 -f 15//15 12//12 7//7 -f 14//14 13//13 16//16 -f 4//4 14//14 17//17 -f 17//17 14//14 16//16 -f 6//6 4//4 17//17 -f 18//18 15//15 7//7 -f 18//18 7//7 1//1 -f 6//6 17//17 19//19 -f 6//6 19//19 8//8 -f 20//20 17//17 16//16 -f 17//17 20//20 19//19 -f 21//21 15//15 18//18 -f 15//15 21//21 13//13 -f 19//19 22//22 8//8 -f 19//19 20//20 22//22 -f 23//23 20//20 16//16 -f 20//20 23//23 22//22 -f 24//24 23//23 16//16 -f 16//16 13//13 25//25 -f 22//22 26//26 8//8 -f 22//22 23//23 26//26 -f 23//23 24//24 26//26 -f 26//26 27//27 8//8 -f 26//26 24//24 27//27 -f 27//27 28//28 8//8 -f 24//24 29//29 27//27 -f 29//29 24//24 16//16 -f 27//27 29//29 28//28 -f 30//30 21//21 18//18 -f 30//30 18//18 1//1 -f 29//29 31//31 28//28 -f 31//31 29//29 16//16 -f 32//32 21//21 30//30 -f 21//21 32//32 13//13 -f 28//28 31//31 33//33 -f 28//28 33//33 8//8 -f 34//34 32//32 30//30 -f 34//34 30//30 1//1 -f 31//31 35//35 33//33 -f 35//35 31//31 16//16 -f 36//36 32//32 34//34 -f 32//32 36//36 13//13 -f 33//33 35//35 37//37 -f 33//33 37//37 8//8 -f 38//38 36//36 34//34 -f 38//38 34//34 1//1 -f 36//36 39//39 13//13 -f 39//39 36//36 38//38 -f 35//35 40//40 37//37 -f 40//40 35//35 16//16 -f 41//41 38//38 1//1 -f 41//41 39//39 38//38 -f 39//39 42//42 13//13 -f 42//42 39//39 41//41 -f 13//13 42//42 25//25 -f 43//43 41//41 1//1 -f 43//43 42//42 41//41 -f 43//43 1//1 8//8 -f 42//42 43//43 44//44 -f 25//25 42//42 44//44 -f 44//44 43//43 8//8 -f 37//37 45//45 8//8 -f 37//37 40//40 45//45 -f 46//46 40//40 16//16 -f 40//40 46//46 45//45 -f 47//47 16//16 25//25 -f 47//47 25//25 44//44 -f 47//47 46//46 16//16 -f 48//48 44//44 8//8 -f 45//45 48//48 8//8 -f 45//45 46//46 48//48 -f 48//48 47//47 44//44 -f 46//46 47//47 48//48 diff --git a/mod/data/mac-fallback-assets/silh_vanilla_long_2.obj b/mod/data/mac-fallback-assets/silh_vanilla_long_2.obj deleted file mode 100644 index 6fdc4bf89..000000000 --- a/mod/data/mac-fallback-assets/silh_vanilla_long_2.obj +++ /dev/null @@ -1,190 +0,0 @@ -g silh_new_long_1in -v -0 0.000321194326 -1.90383077 -v 1.79507375 -3.19731583E-07 -2.40114331 -v 1.47036397 -3.79383408E-07 -2.84912109 -v 2.00016642 0.000321194326 -1.90383077 -v 1.04253602 -4.21221131E-07 -3.16331697 -v 2.00016642 0.000321702857 1.91503835 -v 0.61488086 -4.4783468E-07 -3.36318135 -v -0 0.000321702857 1.91503823 -v 1.47036397 0.999999642 -2.84912133 -v 1.04253602 0.999999583 -3.1633172 -v 1.79507375 0.999999702 -2.40114355 -v 0.61488086 0.999999523 -3.36318159 -v -0 0.999678314 -1.90383089 -v 2.00016642 0.999678314 -1.90383089 -v -0 0.999999523 -3.46068621 -v -0 0.999678791 1.91503811 -v 2.00016642 0.999678791 1.91503823 -v -0 -4.608182E-07 -3.46068597 -v 1.82142329 3.1795102E-07 2.38777161 -v 1.82142329 1.00000036 2.38777137 -v -0.61488086 0.999999523 -3.36318159 -v 1.52951431 3.70640919E-07 2.7834661 -v 1.52951431 1.00000036 2.78346586 -v 1.07117271 1.00000048 3.16235137 -v -2.00004268 0.999678791 1.91503823 -v 1.07117271 4.21092579E-07 3.16235161 -v 0.61488086 4.48775808E-07 3.37024903 -v -0 4.61759583E-07 3.46775556 -v 0.61488086 1.00000048 3.37024879 -v -0.61488086 -4.4783468E-07 -3.36318135 -v -0 1.00000048 3.46775532 -v -1.04253602 0.999999583 -3.1633172 -v -0.61488086 4.48775808E-07 3.37024903 -v -1.04253602 -4.21221131E-07 -3.16331697 -v -0.61488086 1.00000048 3.37024879 -v -1.47036397 0.999999642 -2.84912133 -v -1.07117271 4.21092579E-07 3.16235161 -v -1.47036397 -3.79383408E-07 -2.84912109 -v -1.79507375 0.999999702 -2.40114355 -v -1.07117271 1.00000048 3.16235137 -v -1.79507375 -3.19731583E-07 -2.40114331 -v -2.00004268 0.999678314 -1.90383089 -v -2.00004268 0.000321194326 -1.90383077 -v -2.00004268 0.000321702857 1.91503835 -v -1.52951431 3.70640919E-07 2.7834661 -v -1.52951431 1.00000036 2.78346586 -v -1.82142329 1.00000036 2.38777137 -v -1.82142329 3.1795102E-07 2.38777161 -vt 0.250000 0.000322 -vt 0.352171 0.000000 -vt 0.325826 0.000000 -vt 0.378927 0.000322 -vt 0.300669 0.000000 -vt 0.621540 0.000322 -vt 0.278780 0.000000 -vt 0.750000 0.000322 -vt 0.325826 0.999999 -vt 0.300669 0.999999 -vt 0.352171 0.999999 -vt 0.278780 0.999999 -vt 0.250000 0.999678 -vt 0.378927 0.999678 -vt 0.250000 0.999999 -vt 0.750000 0.999678 -vt 0.621540 0.999678 -vt 0.250000 0.000000 -vt 0.646286 0.000001 -vt 0.646286 1.000000 -vt 0.221220 0.999999 -vt 0.670031 0.000001 -vt 0.670031 1.000000 -vt 0.698021 1.000000 -vt 0.878455 0.999678 -vt 0.698021 0.000001 -vt 0.721279 0.000001 -vt 0.750000 0.000001 -vt 0.721279 1.000000 -vt 0.221220 0.000000 -vt 0.750000 1.000000 -vt 0.199331 0.999999 -vt 0.778721 0.000001 -vt 0.199331 0.000000 -vt 0.778721 1.000000 -vt 0.174174 0.999999 -vt 0.801979 0.000001 -vt 0.174174 0.000000 -vt 0.147829 0.999999 -vt 0.801979 1.000000 -vt 0.147829 0.000000 -vt 0.121078 0.999678 -vt 0.121078 0.000322 -vt 0.878455 0.000322 -vt 0.829969 0.000001 -vt 0.829969 1.000000 -vt 0.853714 1.000000 -vt 0.853714 0.000001 -g silh_new_long_1in_0 -f 3/3 2/2 1/1 -f 2/2 4/4 1/1 -f 5/5 3/3 1/1 -f 1/1 4/4 6/6 -f 7/7 5/5 1/1 -f 8/8 1/1 6/6 -f 3/3 9/9 2/2 -f 5/5 10/10 3/3 -f 10/10 9/9 3/3 -f 9/9 11/11 2/2 -f 2/2 11/11 4/4 -f 12/12 10/10 5/5 -f 7/7 12/12 5/5 -f 9/9 10/10 13/13 -f 11/11 9/9 13/13 -f 10/10 12/12 13/13 -f 14/14 11/11 13/13 -f 11/11 14/14 4/4 -f 12/12 15/15 13/13 -f 15/15 12/12 7/7 -f 14/14 13/13 16/16 -f 4/4 14/14 17/17 -f 17/17 14/14 16/16 -f 6/6 4/4 17/17 -f 18/18 15/15 7/7 -f 18/18 7/7 1/1 -f 6/6 17/17 19/19 -f 6/6 19/19 8/8 -f 20/20 17/17 16/16 -f 17/17 20/20 19/19 -f 21/21 15/15 18/18 -f 15/15 21/21 13/13 -f 19/19 22/22 8/8 -f 19/19 20/20 22/22 -f 23/23 20/20 16/16 -f 20/20 23/23 22/22 -f 24/24 23/23 16/16 -f 16/16 13/13 25/25 -f 22/22 26/26 8/8 -f 22/22 23/23 26/26 -f 23/23 24/24 26/26 -f 26/26 27/27 8/8 -f 26/26 24/24 27/27 -f 27/27 28/28 8/8 -f 24/24 29/29 27/27 -f 29/29 24/24 16/16 -f 27/27 29/29 28/28 -f 30/30 21/21 18/18 -f 30/30 18/18 1/1 -f 29/29 31/31 28/28 -f 31/31 29/29 16/16 -f 32/32 21/21 30/30 -f 21/21 32/32 13/13 -f 28/28 31/31 33/33 -f 28/28 33/33 8/8 -f 34/34 32/32 30/30 -f 34/34 30/30 1/1 -f 31/31 35/35 33/33 -f 35/35 31/31 16/16 -f 36/36 32/32 34/34 -f 32/32 36/36 13/13 -f 33/33 35/35 37/37 -f 33/33 37/37 8/8 -f 38/38 36/36 34/34 -f 38/38 34/34 1/1 -f 36/36 39/39 13/13 -f 39/39 36/36 38/38 -f 35/35 40/40 37/37 -f 40/40 35/35 16/16 -f 41/41 38/38 1/1 -f 41/41 39/39 38/38 -f 39/39 42/42 13/13 -f 42/42 39/39 41/41 -f 13/13 42/42 25/25 -f 43/43 41/41 1/1 -f 43/43 42/42 41/41 -f 43/43 1/1 8/8 -f 42/42 43/43 44/44 -f 25/25 42/42 44/44 -f 44/44 43/43 8/8 -f 37/37 45/45 8/8 -f 37/37 40/40 45/45 -f 46/46 40/40 16/16 -f 40/40 46/46 45/45 -f 47/47 16/16 25/25 -f 47/47 25/25 44/44 -f 47/47 46/46 16/16 -f 48/48 44/44 8/8 -f 45/45 48/48 8/8 -f 45/45 46/46 48/48 -f 48/48 47/47 44/44 -f 46/46 47/47 48/48 diff --git a/mod/data/mac-fallback-assets/silh_vanilla_snail_1.obj b/mod/data/mac-fallback-assets/silh_vanilla_snail_1.obj deleted file mode 100644 index 2d6a45220..000000000 --- a/mod/data/mac-fallback-assets/silh_vanilla_snail_1.obj +++ /dev/null @@ -1,190 +0,0 @@ -g silh_new_snail_1in -v -0 0.000321137864 -2.32793117 -v 1.79507375 -3.76203957E-07 -2.82524371 -v 1.47036397 -4.3585581E-07 -3.27322149 -v 2.00016642 0.000321137864 -2.32793117 -v 1.04253602 -4.77693504E-07 -3.58741736 -v 2.00016642 0.000321757863 2.32819009 -v 0.61488086 -5.04307081E-07 -3.78728175 -v -0 0.000321757863 2.32818985 -v 1.47036397 0.999999583 -3.27322173 -v 1.04253602 0.999999523 -3.5874176 -v 1.79507375 0.999999642 -2.82524395 -v 0.61488086 0.999999523 -3.78728199 -v -0 0.999678254 -2.3279314 -v 2.00016642 0.999678254 -2.3279314 -v -0 0.999999464 -3.88478661 -v -0 0.99967885 2.32818961 -v 2.00016642 0.99967885 2.32818985 -v -0 -5.17290573E-07 -3.88478637 -v 1.82142329 3.72965502E-07 2.80092335 -v 1.82142329 1.00000036 2.80092311 -v -0.61488086 0.999999523 -3.78728199 -v 1.52951431 4.25655401E-07 3.19661784 -v 1.52951431 1.00000048 3.1966176 -v 1.07117271 1.00000048 3.57550311 -v -2.00004268 0.99967885 2.32818985 -v 1.07117271 4.76107061E-07 3.57550335 -v 0.61488086 5.03790261E-07 3.78340077 -v -0 5.16774094E-07 3.8809073 -v 0.61488086 1.00000048 3.78340054 -v -0.61488086 -5.04307081E-07 -3.78728175 -v -0 1.00000048 3.88090706 -v -1.04253602 0.999999523 -3.5874176 -v -0.61488086 5.03790261E-07 3.78340077 -v -1.04253602 -4.77693504E-07 -3.58741736 -v -0.61488086 1.00000048 3.78340054 -v -1.47036397 0.999999583 -3.27322173 -v -1.07117271 4.76107061E-07 3.57550335 -v -1.47036397 -4.3585581E-07 -3.27322149 -v -1.79507375 0.999999642 -2.82524395 -v -1.07117271 1.00000048 3.57550311 -v -1.79507375 -3.76203957E-07 -2.82524371 -v -2.00004268 0.999678254 -2.3279314 -v -2.00004268 0.000321137864 -2.32793117 -v -2.00004268 0.000321757863 2.32819009 -v -1.52951431 4.25655401E-07 3.19661784 -v -1.52951431 1.00000048 3.1966176 -v -1.82142329 1.00000036 2.80092311 -v -1.82142329 3.72965502E-07 2.80092335 -vn -0 -1 0 -vn 0.702909827 -0.673609495 -0.228403121 -vn 0.597922504 -0.673625469 -0.434416264 -vn 0.739097834 -0.673598051 0 -vn 0.434390396 -0.673585176 -0.597986639 -vn 0.739097834 -0.673598051 0 -vn 0.228402525 -0.673507571 -0.703007638 -vn -0 -1 0 -vn 0.597922444 0.67362529 -0.434416443 -vn 0.434390366 0.673584998 -0.597986817 -vn 0.702909887 0.673609436 -0.2284033 -vn 0.228402525 0.673507333 -0.703007877 -vn -0 1 0 -vn 0.739097834 0.673598051 0 -vn -0 0.673597932 -0.739097953 -vn -0 1 0 -vn 0.739097834 0.673598051 0 -vn -0 -0.67359823 -0.739097774 -vn 0.702909887 -0.673609436 0.2284033 -vn 0.702909827 0.673609495 0.228403121 -vn -0.228403196 0.673609316 -0.702909946 -vn 0.597986698 -0.673584998 0.434390455 -vn 0.597986758 0.673585176 0.434390277 -vn 0.434416384 0.673625469 0.597922385 -vn -0.739097834 0.673598051 0 -vn 0.434416354 -0.67362529 0.597922564 -vn 0.228403196 -0.673609316 0.702909946 -vn -0 -0.673493445 0.739193082 -vn 0.228403226 0.673609614 0.702909768 -vn -0.228403226 -0.673609614 -0.702909768 -vn -0 0.673493803 0.739192903 -vn -0.434500784 0.673501134 -0.598001182 -vn -0.228402525 -0.673507333 0.703007877 -vn -0.434500784 -0.673501253 -0.598000944 -vn -0.228402525 0.673507571 0.703007638 -vn -0.598001063 0.673501134 -0.434500873 -vn -0.434500784 -0.673501134 0.598001182 -vn -0.598001063 -0.673501253 -0.434500694 -vn -0.702909887 0.673609436 -0.2284033 -vn -0.434500784 0.673501253 0.598000944 -vn -0.702909827 -0.673609495 -0.228403121 -vn -0.739097834 0.673598051 0 -vn -0.739097834 -0.673598051 0 -vn -0.739097834 -0.673598051 0 -vn -0.598001063 -0.673501134 0.434500873 -vn -0.598001063 0.673501253 0.434500694 -vn -0.702909827 0.673609495 0.228403121 -vn -0.702909887 -0.673609436 0.2284033 -g silh_new_snail_1in_0 -f 3//3 2//2 1//1 -f 2//2 4//4 1//1 -f 5//5 3//3 1//1 -f 1//1 4//4 6//6 -f 7//7 5//5 1//1 -f 8//8 1//1 6//6 -f 3//3 9//9 2//2 -f 5//5 10//10 3//3 -f 10//10 9//9 3//3 -f 9//9 11//11 2//2 -f 2//2 11//11 4//4 -f 12//12 10//10 5//5 -f 7//7 12//12 5//5 -f 9//9 10//10 13//13 -f 11//11 9//9 13//13 -f 10//10 12//12 13//13 -f 14//14 11//11 13//13 -f 11//11 14//14 4//4 -f 12//12 15//15 13//13 -f 15//15 12//12 7//7 -f 14//14 13//13 16//16 -f 4//4 14//14 17//17 -f 17//17 14//14 16//16 -f 6//6 4//4 17//17 -f 18//18 15//15 7//7 -f 18//18 7//7 1//1 -f 6//6 17//17 19//19 -f 6//6 19//19 8//8 -f 20//20 17//17 16//16 -f 17//17 20//20 19//19 -f 21//21 15//15 18//18 -f 15//15 21//21 13//13 -f 19//19 22//22 8//8 -f 19//19 20//20 22//22 -f 23//23 20//20 16//16 -f 20//20 23//23 22//22 -f 24//24 23//23 16//16 -f 16//16 13//13 25//25 -f 22//22 26//26 8//8 -f 22//22 23//23 26//26 -f 23//23 24//24 26//26 -f 26//26 27//27 8//8 -f 26//26 24//24 27//27 -f 27//27 28//28 8//8 -f 24//24 29//29 27//27 -f 29//29 24//24 16//16 -f 27//27 29//29 28//28 -f 30//30 21//21 18//18 -f 30//30 18//18 1//1 -f 29//29 31//31 28//28 -f 31//31 29//29 16//16 -f 32//32 21//21 30//30 -f 21//21 32//32 13//13 -f 28//28 31//31 33//33 -f 28//28 33//33 8//8 -f 34//34 32//32 30//30 -f 34//34 30//30 1//1 -f 31//31 35//35 33//33 -f 35//35 31//31 16//16 -f 36//36 32//32 34//34 -f 32//32 36//36 13//13 -f 33//33 35//35 37//37 -f 33//33 37//37 8//8 -f 38//38 36//36 34//34 -f 38//38 34//34 1//1 -f 36//36 39//39 13//13 -f 39//39 36//36 38//38 -f 35//35 40//40 37//37 -f 40//40 35//35 16//16 -f 41//41 38//38 1//1 -f 41//41 39//39 38//38 -f 39//39 42//42 13//13 -f 42//42 39//39 41//41 -f 13//13 42//42 25//25 -f 43//43 41//41 1//1 -f 43//43 42//42 41//41 -f 43//43 1//1 8//8 -f 42//42 43//43 44//44 -f 25//25 42//42 44//44 -f 44//44 43//43 8//8 -f 37//37 45//45 8//8 -f 37//37 40//40 45//45 -f 46//46 40//40 16//16 -f 40//40 46//46 45//45 -f 47//47 16//16 25//25 -f 47//47 25//25 44//44 -f 47//47 46//46 16//16 -f 48//48 44//44 8//8 -f 45//45 48//48 8//8 -f 45//45 46//46 48//48 -f 48//48 47//47 44//44 -f 46//46 47//47 48//48 diff --git a/mod/data/mac-fallback-assets/silh_vanilla_snail_2.obj b/mod/data/mac-fallback-assets/silh_vanilla_snail_2.obj deleted file mode 100644 index 273151d66..000000000 --- a/mod/data/mac-fallback-assets/silh_vanilla_snail_2.obj +++ /dev/null @@ -1,190 +0,0 @@ -g silh_new_snail_1in -v -0 0.000321137864 -2.32793117 -v 1.79507375 -3.76203957E-07 -2.82524371 -v 1.47036397 -4.3585581E-07 -3.27322149 -v 2.00016642 0.000321137864 -2.32793117 -v 1.04253602 -4.77693504E-07 -3.58741736 -v 2.00016642 0.000321757863 2.32819009 -v 0.61488086 -5.04307081E-07 -3.78728175 -v -0 0.000321757863 2.32818985 -v 1.47036397 0.999999583 -3.27322173 -v 1.04253602 0.999999523 -3.5874176 -v 1.79507375 0.999999642 -2.82524395 -v 0.61488086 0.999999523 -3.78728199 -v -0 0.999678254 -2.3279314 -v 2.00016642 0.999678254 -2.3279314 -v -0 0.999999464 -3.88478661 -v -0 0.99967885 2.32818961 -v 2.00016642 0.99967885 2.32818985 -v -0 -5.17290573E-07 -3.88478637 -v 1.82142329 3.72965502E-07 2.80092335 -v 1.82142329 1.00000036 2.80092311 -v -0.61488086 0.999999523 -3.78728199 -v 1.52951431 4.25655401E-07 3.19661784 -v 1.52951431 1.00000048 3.1966176 -v 1.07117271 1.00000048 3.57550311 -v -2.00004268 0.99967885 2.32818985 -v 1.07117271 4.76107061E-07 3.57550335 -v 0.61488086 5.03790261E-07 3.78340077 -v -0 5.16774094E-07 3.8809073 -v 0.61488086 1.00000048 3.78340054 -v -0.61488086 -5.04307081E-07 -3.78728175 -v -0 1.00000048 3.88090706 -v -1.04253602 0.999999523 -3.5874176 -v -0.61488086 5.03790261E-07 3.78340077 -v -1.04253602 -4.77693504E-07 -3.58741736 -v -0.61488086 1.00000048 3.78340054 -v -1.47036397 0.999999583 -3.27322173 -v -1.07117271 4.76107061E-07 3.57550335 -v -1.47036397 -4.3585581E-07 -3.27322149 -v -1.79507375 0.999999642 -2.82524395 -v -1.07117271 1.00000048 3.57550311 -v -1.79507375 -3.76203957E-07 -2.82524371 -v -2.00004268 0.999678254 -2.3279314 -v -2.00004268 0.000321137864 -2.32793117 -v -2.00004268 0.000321757863 2.32819009 -v -1.52951431 4.25655401E-07 3.19661784 -v -1.52951431 1.00000048 3.1966176 -v -1.82142329 1.00000036 2.80092311 -v -1.82142329 3.72965502E-07 2.80092335 -vt 0.250000 0.000322 -vt 0.340085 0.000000 -vt 0.317195 0.000000 -vt 0.362970 0.000322 -vt 0.295012 0.000000 -vt 0.637039 0.000322 -vt 0.275616 0.000000 -vt 0.750000 0.000322 -vt 0.317195 0.999999 -vt 0.295012 0.999999 -vt 0.340085 0.999999 -vt 0.275616 0.999999 -vt 0.250000 0.999678 -vt 0.362970 0.999678 -vt 0.250000 0.999999 -vt 0.750000 0.999678 -vt 0.637039 0.999678 -vt 0.250000 0.000000 -vt 0.658234 0.000001 -vt 0.658234 1.000000 -vt 0.224384 0.999999 -vt 0.678972 0.000001 -vt 0.678972 1.000000 -vt 0.703674 1.000000 -vt 0.862957 0.999678 -vt 0.703674 0.000001 -vt 0.724358 0.000001 -vt 0.750000 0.000001 -vt 0.724358 1.000000 -vt 0.224384 0.000000 -vt 0.750000 1.000000 -vt 0.204988 0.999999 -vt 0.775642 0.000001 -vt 0.204988 0.000000 -vt 0.775642 1.000000 -vt 0.182805 0.999999 -vt 0.796326 0.000001 -vt 0.182805 0.000000 -vt 0.159915 0.999999 -vt 0.796326 1.000000 -vt 0.159915 0.000000 -vt 0.137035 0.999678 -vt 0.137035 0.000322 -vt 0.862957 0.000322 -vt 0.821028 0.000001 -vt 0.821028 1.000000 -vt 0.841766 1.000000 -vt 0.841766 0.000001 -g silh_new_snail_1in_0 -f 3/3 2/2 1/1 -f 2/2 4/4 1/1 -f 5/5 3/3 1/1 -f 1/1 4/4 6/6 -f 7/7 5/5 1/1 -f 8/8 1/1 6/6 -f 3/3 9/9 2/2 -f 5/5 10/10 3/3 -f 10/10 9/9 3/3 -f 9/9 11/11 2/2 -f 2/2 11/11 4/4 -f 12/12 10/10 5/5 -f 7/7 12/12 5/5 -f 9/9 10/10 13/13 -f 11/11 9/9 13/13 -f 10/10 12/12 13/13 -f 14/14 11/11 13/13 -f 11/11 14/14 4/4 -f 12/12 15/15 13/13 -f 15/15 12/12 7/7 -f 14/14 13/13 16/16 -f 4/4 14/14 17/17 -f 17/17 14/14 16/16 -f 6/6 4/4 17/17 -f 18/18 15/15 7/7 -f 18/18 7/7 1/1 -f 6/6 17/17 19/19 -f 6/6 19/19 8/8 -f 20/20 17/17 16/16 -f 17/17 20/20 19/19 -f 21/21 15/15 18/18 -f 15/15 21/21 13/13 -f 19/19 22/22 8/8 -f 19/19 20/20 22/22 -f 23/23 20/20 16/16 -f 20/20 23/23 22/22 -f 24/24 23/23 16/16 -f 16/16 13/13 25/25 -f 22/22 26/26 8/8 -f 22/22 23/23 26/26 -f 23/23 24/24 26/26 -f 26/26 27/27 8/8 -f 26/26 24/24 27/27 -f 27/27 28/28 8/8 -f 24/24 29/29 27/27 -f 29/29 24/24 16/16 -f 27/27 29/29 28/28 -f 30/30 21/21 18/18 -f 30/30 18/18 1/1 -f 29/29 31/31 28/28 -f 31/31 29/29 16/16 -f 32/32 21/21 30/30 -f 21/21 32/32 13/13 -f 28/28 31/31 33/33 -f 28/28 33/33 8/8 -f 34/34 32/32 30/30 -f 34/34 30/30 1/1 -f 31/31 35/35 33/33 -f 35/35 31/31 16/16 -f 36/36 32/32 34/34 -f 32/32 36/36 13/13 -f 33/33 35/35 37/37 -f 33/33 37/37 8/8 -f 38/38 36/36 34/34 -f 38/38 34/34 1/1 -f 36/36 39/39 13/13 -f 39/39 36/36 38/38 -f 35/35 40/40 37/37 -f 40/40 35/35 16/16 -f 41/41 38/38 1/1 -f 41/41 39/39 38/38 -f 39/39 42/42 13/13 -f 42/42 39/39 41/41 -f 13/13 42/42 25/25 -f 43/43 41/41 1/1 -f 43/43 42/42 41/41 -f 43/43 1/1 8/8 -f 42/42 43/43 44/44 -f 25/25 42/42 44/44 -f 44/44 43/43 8/8 -f 37/37 45/45 8/8 -f 37/37 40/40 45/45 -f 46/46 40/40 16/16 -f 40/40 46/46 45/45 -f 47/47 16/16 25/25 -f 47/47 25/25 44/44 -f 47/47 46/46 16/16 -f 48/48 44/44 8/8 -f 45/45 48/48 8/8 -f 45/45 46/46 48/48 -f 48/48 47/47 44/44 -f 46/46 47/47 48/48 diff --git a/mod/data/mac-fallback-assets/silhouette_mac_fallback.unity3d b/mod/data/mac-fallback-assets/silhouette_mac_fallback.unity3d deleted file mode 100644 index 15bb9258a1c225572de9b686b6595455abfe184f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10922 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 Mcz6b}|N5b`;!*7d-NFt$0T)itaU*PL^9 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 Pz5Lk%{^eWpC1U;y0=YU6 diff --git a/mod/data/mac-fallback-assets/stadium_long_2.obj b/mod/data/mac-fallback-assets/stadium_long_2.obj deleted file mode 100644 index b996946a5..000000000 --- a/mod/data/mac-fallback-assets/stadium_long_2.obj +++ /dev/null @@ -1,456 +0,0 @@ -o stadium -v -1.96850 0.00000 1.47638 -v -1.95166 0.00000 1.73332 -v -1.90142 0.00000 1.98587 -v -1.81866 0.00000 2.22969 -v -1.70477 0.00000 2.46063 -v -1.56172 0.00000 2.67473 -v -1.39194 0.00000 2.86832 -v -1.19835 0.00000 3.03810 -v -0.98425 0.00000 3.18115 -v -0.75331 0.00000 3.29504 -v -0.50949 0.00000 3.37780 -v -0.25694 0.00000 3.42804 -v -0.00000 0.00000 3.44488 -v 0.25694 0.00000 3.42804 -v 0.50949 0.00000 3.37780 -v 0.75331 0.00000 3.29504 -v 0.98425 0.00000 3.18115 -v 1.19835 0.00000 3.03810 -v 1.39194 0.00000 2.86832 -v 1.56172 0.00000 2.67473 -v 1.70477 0.00000 2.46063 -v 1.81866 0.00000 2.22969 -v 1.90142 0.00000 1.98587 -v 1.95166 0.00000 1.73332 -v 1.96850 0.00000 1.47638 -v 1.96850 0.00000 -1.47638 -v 1.95166 0.00000 -1.73332 -v 1.90142 0.00000 -1.98587 -v 1.81866 0.00000 -2.22969 -v 1.70477 0.00000 -2.46063 -v 1.56172 0.00000 -2.67473 -v 1.39194 0.00000 -2.86832 -v 1.19835 0.00000 -3.03810 -v 0.98425 0.00000 -3.18115 -v 0.75331 0.00000 -3.29504 -v 0.50949 0.00000 -3.37780 -v 0.25694 0.00000 -3.42804 -v 0.00000 0.00000 -3.44488 -v -0.25694 0.00000 -3.42804 -v -0.50949 0.00000 -3.37780 -v -0.75331 0.00000 -3.29504 -v -0.98425 0.00000 -3.18115 -v -1.19835 0.00000 -3.03810 -v -1.39194 0.00000 -2.86832 -v -1.56172 0.00000 -2.67473 -v -1.70477 0.00000 -2.46063 -v -1.81866 0.00000 -2.22969 -v -1.90142 0.00000 -1.98587 -v -1.95166 0.00000 -1.73332 -v -1.96850 0.00000 -1.47638 -v -1.96850 1.00000 1.47638 -v -1.95166 1.00000 1.73332 -v -1.90142 1.00000 1.98587 -v -1.81866 1.00000 2.22969 -v -1.70477 1.00000 2.46063 -v -1.56172 1.00000 2.67473 -v -1.39194 1.00000 2.86832 -v -1.19835 1.00000 3.03810 -v -0.98425 1.00000 3.18115 -v -0.75331 1.00000 3.29504 -v -0.50949 1.00000 3.37780 -v -0.25694 1.00000 3.42804 -v -0.00000 1.00000 3.44488 -v 0.25694 1.00000 3.42804 -v 0.50949 1.00000 3.37780 -v 0.75331 1.00000 3.29504 -v 0.98425 1.00000 3.18115 -v 1.19835 1.00000 3.03810 -v 1.39194 1.00000 2.86832 -v 1.56172 1.00000 2.67473 -v 1.70477 1.00000 2.46063 -v 1.81866 1.00000 2.22969 -v 1.90142 1.00000 1.98587 -v 1.95166 1.00000 1.73332 -v 1.96850 1.00000 1.47638 -v 1.96850 1.00000 -1.47638 -v 1.95166 1.00000 -1.73332 -v 1.90142 1.00000 -1.98587 -v 1.81866 1.00000 -2.22969 -v 1.70477 1.00000 -2.46063 -v 1.56172 1.00000 -2.67473 -v 1.39194 1.00000 -2.86832 -v 1.19835 1.00000 -3.03810 -v 0.98425 1.00000 -3.18115 -v 0.75331 1.00000 -3.29504 -v 0.50949 1.00000 -3.37780 -v 0.25694 1.00000 -3.42804 -v 0.00000 1.00000 -3.44488 -v -0.25694 1.00000 -3.42804 -v -0.50949 1.00000 -3.37780 -v -0.75331 1.00000 -3.29504 -v -0.98425 1.00000 -3.18115 -v -1.19835 1.00000 -3.03810 -v -1.39194 1.00000 -2.86832 -v -1.56172 1.00000 -2.67473 -v -1.70477 1.00000 -2.46063 -v -1.81866 1.00000 -2.22969 -v -1.90142 1.00000 -1.98587 -v -1.95166 1.00000 -1.73332 -v -1.96850 1.00000 -1.47638 -v 0.00000 0.00000 0.00000 -v 0.00000 1.00000 0.00000 -vt 0.00000 0.0 -vt 0.01410 0.0 -vt 0.02819 0.0 -vt 0.04229 0.0 -vt 0.05639 0.0 -vt 0.07049 0.0 -vt 0.08458 0.0 -vt 0.09868 0.0 -vt 0.11278 0.0 -vt 0.12688 0.0 -vt 0.14097 0.0 -vt 0.15507 0.0 -vt 0.16917 0.0 -vt 0.18327 0.0 -vt 0.19736 0.0 -vt 0.21146 0.0 -vt 0.22556 0.0 -vt 0.23966 0.0 -vt 0.25375 0.0 -vt 0.26785 0.0 -vt 0.28195 0.0 -vt 0.29605 0.0 -vt 0.31014 0.0 -vt 0.32424 0.0 -vt 0.33834 0.0 -vt 0.50000 0.0 -vt 0.51410 0.0 -vt 0.52819 0.0 -vt 0.54229 0.0 -vt 0.55639 0.0 -vt 0.57049 0.0 -vt 0.58458 0.0 -vt 0.59868 0.0 -vt 0.61278 0.0 -vt 0.62688 0.0 -vt 0.64097 0.0 -vt 0.65507 0.0 -vt 0.66917 0.0 -vt 0.68327 0.0 -vt 0.69736 0.0 -vt 0.71146 0.0 -vt 0.72556 0.0 -vt 0.73966 0.0 -vt 0.75375 0.0 -vt 0.76785 0.0 -vt 0.78195 0.0 -vt 0.79605 0.0 -vt 0.81014 0.0 -vt 0.82424 0.0 -vt 0.83834 0.0 -vt 0.00000 1.0 -vt 0.01410 1.0 -vt 0.02819 1.0 -vt 0.04229 1.0 -vt 0.05639 1.0 -vt 0.07049 1.0 -vt 0.08458 1.0 -vt 0.09868 1.0 -vt 0.11278 1.0 -vt 0.12688 1.0 -vt 0.14097 1.0 -vt 0.15507 1.0 -vt 0.16917 1.0 -vt 0.18327 1.0 -vt 0.19736 1.0 -vt 0.21146 1.0 -vt 0.22556 1.0 -vt 0.23966 1.0 -vt 0.25375 1.0 -vt 0.26785 1.0 -vt 0.28195 1.0 -vt 0.29605 1.0 -vt 0.31014 1.0 -vt 0.32424 1.0 -vt 0.33834 1.0 -vt 0.50000 1.0 -vt 0.51410 1.0 -vt 0.52819 1.0 -vt 0.54229 1.0 -vt 0.55639 1.0 -vt 0.57049 1.0 -vt 0.58458 1.0 -vt 0.59868 1.0 -vt 0.61278 1.0 -vt 0.62688 1.0 -vt 0.64097 1.0 -vt 0.65507 1.0 -vt 0.66917 1.0 -vt 0.68327 1.0 -vt 0.69736 1.0 -vt 0.71146 1.0 -vt 0.72556 1.0 -vt 0.73966 1.0 -vt 0.75375 1.0 -vt 0.76785 1.0 -vt 0.78195 1.0 -vt 0.79605 1.0 -vt 0.81014 1.0 -vt 0.82424 1.0 -vt 0.83834 1.0 -vt 0.5 0.5 -vn -1.00000 0.00000 0.00000 -vn -0.99144 0.00000 0.13053 -vn -0.96593 0.00000 0.25882 -vn -0.92388 0.00000 0.38268 -vn -0.86603 0.00000 0.50000 -vn -0.79335 0.00000 0.60876 -vn -0.70711 0.00000 0.70711 -vn -0.60876 0.00000 0.79335 -vn -0.50000 0.00000 0.86603 -vn -0.38268 0.00000 0.92388 -vn -0.25882 0.00000 0.96593 -vn -0.13053 0.00000 0.99144 -vn -0.00000 0.00000 1.00000 -vn 0.13053 0.00000 0.99144 -vn 0.25882 0.00000 0.96593 -vn 0.38268 0.00000 0.92388 -vn 0.50000 0.00000 0.86603 -vn 0.60876 0.00000 0.79335 -vn 0.70711 0.00000 0.70711 -vn 0.79335 0.00000 0.60876 -vn 0.86603 0.00000 0.50000 -vn 0.92388 0.00000 0.38268 -vn 0.96593 0.00000 0.25882 -vn 0.99144 0.00000 0.13053 -vn 1.00000 0.00000 0.00000 -vn 1.00000 0.00000 -0.00000 -vn 0.99144 0.00000 -0.13053 -vn 0.96593 0.00000 -0.25882 -vn 0.92388 0.00000 -0.38268 -vn 0.86603 0.00000 -0.50000 -vn 0.79335 0.00000 -0.60876 -vn 0.70711 0.00000 -0.70711 -vn 0.60876 0.00000 -0.79335 -vn 0.50000 0.00000 -0.86603 -vn 0.38268 0.00000 -0.92388 -vn 0.25882 0.00000 -0.96593 -vn 0.13053 0.00000 -0.99144 -vn 0.00000 0.00000 -1.00000 -vn -0.13053 0.00000 -0.99144 -vn -0.25882 0.00000 -0.96593 -vn -0.38268 0.00000 -0.92388 -vn -0.50000 0.00000 -0.86603 -vn -0.60876 0.00000 -0.79335 -vn -0.70711 0.00000 -0.70711 -vn -0.79335 0.00000 -0.60876 -vn -0.86603 0.00000 -0.50000 -vn -0.92388 0.00000 -0.38268 -vn -0.96593 0.00000 -0.25882 -vn -0.99144 0.00000 -0.13053 -vn -1.00000 0.00000 -0.00000 -vn 0 -1 0 -vn 0 1 0 -f 1/1/1 2/2/2 52/52/2 -f 1/1/1 52/52/2 51/51/1 -f 101/101/51 2/2/51 1/1/51 -f 102/101/52 51/51/52 52/52/52 -f 2/2/2 3/3/3 53/53/3 -f 2/2/2 53/53/3 52/52/2 -f 101/101/51 3/3/51 2/2/51 -f 102/101/52 52/52/52 53/53/52 -f 3/3/3 4/4/4 54/54/4 -f 3/3/3 54/54/4 53/53/3 -f 101/101/51 4/4/51 3/3/51 -f 102/101/52 53/53/52 54/54/52 -f 4/4/4 5/5/5 55/55/5 -f 4/4/4 55/55/5 54/54/4 -f 101/101/51 5/5/51 4/4/51 -f 102/101/52 54/54/52 55/55/52 -f 5/5/5 6/6/6 56/56/6 -f 5/5/5 56/56/6 55/55/5 -f 101/101/51 6/6/51 5/5/51 -f 102/101/52 55/55/52 56/56/52 -f 6/6/6 7/7/7 57/57/7 -f 6/6/6 57/57/7 56/56/6 -f 101/101/51 7/7/51 6/6/51 -f 102/101/52 56/56/52 57/57/52 -f 7/7/7 8/8/8 58/58/8 -f 7/7/7 58/58/8 57/57/7 -f 101/101/51 8/8/51 7/7/51 -f 102/101/52 57/57/52 58/58/52 -f 8/8/8 9/9/9 59/59/9 -f 8/8/8 59/59/9 58/58/8 -f 101/101/51 9/9/51 8/8/51 -f 102/101/52 58/58/52 59/59/52 -f 9/9/9 10/10/10 60/60/10 -f 9/9/9 60/60/10 59/59/9 -f 101/101/51 10/10/51 9/9/51 -f 102/101/52 59/59/52 60/60/52 -f 10/10/10 11/11/11 61/61/11 -f 10/10/10 61/61/11 60/60/10 -f 101/101/51 11/11/51 10/10/51 -f 102/101/52 60/60/52 61/61/52 -f 11/11/11 12/12/12 62/62/12 -f 11/11/11 62/62/12 61/61/11 -f 101/101/51 12/12/51 11/11/51 -f 102/101/52 61/61/52 62/62/52 -f 12/12/12 13/13/13 63/63/13 -f 12/12/12 63/63/13 62/62/12 -f 101/101/51 13/13/51 12/12/51 -f 102/101/52 62/62/52 63/63/52 -f 13/13/13 14/14/14 64/64/14 -f 13/13/13 64/64/14 63/63/13 -f 101/101/51 14/14/51 13/13/51 -f 102/101/52 63/63/52 64/64/52 -f 14/14/14 15/15/15 65/65/15 -f 14/14/14 65/65/15 64/64/14 -f 101/101/51 15/15/51 14/14/51 -f 102/101/52 64/64/52 65/65/52 -f 15/15/15 16/16/16 66/66/16 -f 15/15/15 66/66/16 65/65/15 -f 101/101/51 16/16/51 15/15/51 -f 102/101/52 65/65/52 66/66/52 -f 16/16/16 17/17/17 67/67/17 -f 16/16/16 67/67/17 66/66/16 -f 101/101/51 17/17/51 16/16/51 -f 102/101/52 66/66/52 67/67/52 -f 17/17/17 18/18/18 68/68/18 -f 17/17/17 68/68/18 67/67/17 -f 101/101/51 18/18/51 17/17/51 -f 102/101/52 67/67/52 68/68/52 -f 18/18/18 19/19/19 69/69/19 -f 18/18/18 69/69/19 68/68/18 -f 101/101/51 19/19/51 18/18/51 -f 102/101/52 68/68/52 69/69/52 -f 19/19/19 20/20/20 70/70/20 -f 19/19/19 70/70/20 69/69/19 -f 101/101/51 20/20/51 19/19/51 -f 102/101/52 69/69/52 70/70/52 -f 20/20/20 21/21/21 71/71/21 -f 20/20/20 71/71/21 70/70/20 -f 101/101/51 21/21/51 20/20/51 -f 102/101/52 70/70/52 71/71/52 -f 21/21/21 22/22/22 72/72/22 -f 21/21/21 72/72/22 71/71/21 -f 101/101/51 22/22/51 21/21/51 -f 102/101/52 71/71/52 72/72/52 -f 22/22/22 23/23/23 73/73/23 -f 22/22/22 73/73/23 72/72/22 -f 101/101/51 23/23/51 22/22/51 -f 102/101/52 72/72/52 73/73/52 -f 23/23/23 24/24/24 74/74/24 -f 23/23/23 74/74/24 73/73/23 -f 101/101/51 24/24/51 23/23/51 -f 102/101/52 73/73/52 74/74/52 -f 24/24/24 25/25/25 75/75/25 -f 24/24/24 75/75/25 74/74/24 -f 101/101/51 25/25/51 24/24/51 -f 102/101/52 74/74/52 75/75/52 -f 25/25/25 26/26/26 76/76/26 -f 25/25/25 76/76/26 75/75/25 -f 101/101/51 26/26/51 25/25/51 -f 102/101/52 75/75/52 76/76/52 -f 26/26/26 27/27/27 77/77/27 -f 26/26/26 77/77/27 76/76/26 -f 101/101/51 27/27/51 26/26/51 -f 102/101/52 76/76/52 77/77/52 -f 27/27/27 28/28/28 78/78/28 -f 27/27/27 78/78/28 77/77/27 -f 101/101/51 28/28/51 27/27/51 -f 102/101/52 77/77/52 78/78/52 -f 28/28/28 29/29/29 79/79/29 -f 28/28/28 79/79/29 78/78/28 -f 101/101/51 29/29/51 28/28/51 -f 102/101/52 78/78/52 79/79/52 -f 29/29/29 30/30/30 80/80/30 -f 29/29/29 80/80/30 79/79/29 -f 101/101/51 30/30/51 29/29/51 -f 102/101/52 79/79/52 80/80/52 -f 30/30/30 31/31/31 81/81/31 -f 30/30/30 81/81/31 80/80/30 -f 101/101/51 31/31/51 30/30/51 -f 102/101/52 80/80/52 81/81/52 -f 31/31/31 32/32/32 82/82/32 -f 31/31/31 82/82/32 81/81/31 -f 101/101/51 32/32/51 31/31/51 -f 102/101/52 81/81/52 82/82/52 -f 32/32/32 33/33/33 83/83/33 -f 32/32/32 83/83/33 82/82/32 -f 101/101/51 33/33/51 32/32/51 -f 102/101/52 82/82/52 83/83/52 -f 33/33/33 34/34/34 84/84/34 -f 33/33/33 84/84/34 83/83/33 -f 101/101/51 34/34/51 33/33/51 -f 102/101/52 83/83/52 84/84/52 -f 34/34/34 35/35/35 85/85/35 -f 34/34/34 85/85/35 84/84/34 -f 101/101/51 35/35/51 34/34/51 -f 102/101/52 84/84/52 85/85/52 -f 35/35/35 36/36/36 86/86/36 -f 35/35/35 86/86/36 85/85/35 -f 101/101/51 36/36/51 35/35/51 -f 102/101/52 85/85/52 86/86/52 -f 36/36/36 37/37/37 87/87/37 -f 36/36/36 87/87/37 86/86/36 -f 101/101/51 37/37/51 36/36/51 -f 102/101/52 86/86/52 87/87/52 -f 37/37/37 38/38/38 88/88/38 -f 37/37/37 88/88/38 87/87/37 -f 101/101/51 38/38/51 37/37/51 -f 102/101/52 87/87/52 88/88/52 -f 38/38/38 39/39/39 89/89/39 -f 38/38/38 89/89/39 88/88/38 -f 101/101/51 39/39/51 38/38/51 -f 102/101/52 88/88/52 89/89/52 -f 39/39/39 40/40/40 90/90/40 -f 39/39/39 90/90/40 89/89/39 -f 101/101/51 40/40/51 39/39/51 -f 102/101/52 89/89/52 90/90/52 -f 40/40/40 41/41/41 91/91/41 -f 40/40/40 91/91/41 90/90/40 -f 101/101/51 41/41/51 40/40/51 -f 102/101/52 90/90/52 91/91/52 -f 41/41/41 42/42/42 92/92/42 -f 41/41/41 92/92/42 91/91/41 -f 101/101/51 42/42/51 41/41/51 -f 102/101/52 91/91/52 92/92/52 -f 42/42/42 43/43/43 93/93/43 -f 42/42/42 93/93/43 92/92/42 -f 101/101/51 43/43/51 42/42/51 -f 102/101/52 92/92/52 93/93/52 -f 43/43/43 44/44/44 94/94/44 -f 43/43/43 94/94/44 93/93/43 -f 101/101/51 44/44/51 43/43/51 -f 102/101/52 93/93/52 94/94/52 -f 44/44/44 45/45/45 95/95/45 -f 44/44/44 95/95/45 94/94/44 -f 101/101/51 45/45/51 44/44/51 -f 102/101/52 94/94/52 95/95/52 -f 45/45/45 46/46/46 96/96/46 -f 45/45/45 96/96/46 95/95/45 -f 101/101/51 46/46/51 45/45/51 -f 102/101/52 95/95/52 96/96/52 -f 46/46/46 47/47/47 97/97/47 -f 46/46/46 97/97/47 96/96/46 -f 101/101/51 47/47/51 46/46/51 -f 102/101/52 96/96/52 97/97/52 -f 47/47/47 48/48/48 98/98/48 -f 47/47/47 98/98/48 97/97/47 -f 101/101/51 48/48/51 47/47/51 -f 102/101/52 97/97/52 98/98/52 -f 48/48/48 49/49/49 99/99/49 -f 48/48/48 99/99/49 98/98/48 -f 101/101/51 49/49/51 48/48/51 -f 102/101/52 98/98/52 99/99/52 -f 49/49/49 50/50/50 100/100/50 -f 49/49/49 100/100/50 99/99/49 -f 101/101/51 50/50/51 49/49/51 -f 102/101/52 99/99/52 100/100/52 -f 50/50/50 1/1/1 51/51/1 -f 50/50/50 51/51/1 100/100/50 -f 101/101/51 1/1/51 50/50/51 -f 102/101/52 100/100/52 51/51/52 diff --git a/mod/data/mac-fallback-assets/stadium_long_3.obj b/mod/data/mac-fallback-assets/stadium_long_3.obj deleted file mode 100644 index 7a9e6c3b2..000000000 --- a/mod/data/mac-fallback-assets/stadium_long_3.obj +++ /dev/null @@ -1,374 +0,0 @@ -# This file uses centimeters as units for non-parametric coordinates. - -mtllib silhouette_shorter.mtl -v 1.15608 -0.00000 -3.06758 -v 1.59120 -0.00000 -2.63246 -v -0.00000 -0.00000 -0.00000 -v -1.15608 -0.00000 -3.06758 -v -1.59120 -0.00000 -2.63246 -v -1.59120 1.00023 -2.63246 -v -1.15608 1.00023 -3.06758 -v -0.60778 -0.00000 3.34695 -v -1.15608 -0.00000 3.06758 -v 1.87057 -0.00000 -2.08416 -v -0.60778 -0.00000 -3.34695 -v -0.60778 1.00023 -3.34695 -v -1.87057 -0.00000 -2.08416 -v -1.87057 1.00023 -2.08416 -v -0.00000 -0.00000 3.44321 -v 1.96683 -0.00000 -0.00000 -v 1.87057 -0.00000 2.08416 -v 0.60778 -0.00000 3.34695 -v -0.00000 -0.00000 -3.44321 -v -0.00000 1.00023 -3.44321 -v -1.96683 -0.00000 -0.00000 -v -1.96683 1.00023 -0.00000 -v 1.59120 -0.00000 2.63245 -v 1.15607 -0.00000 3.06758 -v 0.60778 -0.00000 -3.34695 -v 0.60778 1.00023 -3.34695 -v -1.87057 -0.00000 2.08416 -v -1.87057 1.00023 2.08416 -v 1.15608 1.00023 -3.06758 -v -1.59120 -0.00000 2.63245 -v -1.59120 1.00023 2.63245 -v -1.15608 1.00023 3.06758 -v 1.59120 1.00023 -2.63246 -v -0.11787 0.92084 -1.56202 -v -0.00000 0.92084 -0.00000 -v -0.08564 0.92084 -1.59425 -v -0.04502 0.92084 -1.61494 -v -0.13856 0.92084 -1.52140 -v -0.00000 0.92084 -1.62207 -v -0.14569 0.92084 -0.00000 -v 0.04502 0.92084 -1.61494 -v -0.13856 0.92084 1.52140 -v 0.08564 0.92084 -1.59425 -v -0.11787 0.92084 1.56202 -v -0.08564 0.92084 1.59425 -v 0.11787 0.92084 -1.56202 -v -0.04502 0.92084 1.61494 -v 0.13856 0.92084 -1.52140 -v -0.00000 0.92084 1.62207 -v 0.14569 0.92084 -0.00000 -v 0.13856 0.92084 1.52140 -v 0.04502 0.92084 1.61494 -v 0.08564 0.92084 1.59425 -v 0.11787 0.92084 1.56202 -v -0.60778 1.00023 3.34695 -v 1.87057 1.00023 -2.08416 -v -0.08564 1.00023 -1.59425 -v -0.11787 1.00023 -1.56202 -v -0.00000 1.00023 3.44321 -v 1.96683 1.00023 -0.00000 -v -0.04502 1.00023 -1.61494 -v -0.13856 1.00023 -1.52140 -v -0.00000 1.00023 -1.62207 -v -0.14569 1.00023 -0.00000 -v 0.04502 1.00023 -1.61494 -v -0.13856 1.00023 1.52140 -v 1.87057 1.00023 2.08416 -v 0.60778 1.00023 3.34695 -v 0.08564 1.00023 -1.59425 -v -0.11787 1.00023 1.56202 -v 1.59120 1.00023 2.63245 -v 1.15607 1.00023 3.06758 -v -0.08564 1.00023 1.59425 -v 0.11787 1.00023 -1.56202 -v -0.04502 1.00023 1.61494 -v 0.13856 1.00023 -1.52140 -v -0.00000 1.00023 1.62207 -v 0.14569 1.00023 -0.00000 -v 0.13856 1.00023 1.52140 -v 0.04502 1.00023 1.61494 -v 0.08564 1.00023 1.59425 -v 0.11787 1.00023 1.56202 -vt 0.266842 0.029841 -vt 0.301409 0.064408 -vt 0.175000 0.150000 -vt 0.125000 0.312500 -vt 0.137500 0.312500 -vt 0.137500 0.688440 -vt 0.125000 0.688440 -vt 0.126716 0.304853 -vt 0.083159 0.282659 -vt 0.323603 0.107966 -vt 0.112500 0.312500 -vt 0.112500 0.688440 -vt 0.150000 0.312500 -vt 0.150000 0.688440 -vt 0.175000 0.312500 -vt 0.331250 0.156250 -vt 0.323603 0.204534 -vt 0.223284 0.304853 -vt 0.100000 0.312500 -vt 0.100000 0.688440 -vt 0.162500 0.312500 -vt 0.162500 0.688440 -vt 0.301409 0.248091 -vt 0.266841 0.282659 -vt 0.087500 0.312500 -vt 0.087500 0.688440 -vt 0.175000 0.312500 -vt 0.175000 0.688440 -vt 0.075000 0.312500 -vt 0.075000 0.688440 -vt 0.187500 0.312500 -vt 0.187500 0.688440 -vt 0.200000 0.312500 -vt 0.200000 0.688440 -vt 0.062500 0.312500 -vt 0.062500 0.688440 -vt 0.048591 0.064409 -vt 0.175000 0.150000 -vt 0.083159 0.029841 -vt 0.126716 0.007647 -vt 0.026397 0.107966 -vt 0.175000 -0.000000 -vt 0.018750 0.156250 -vt 0.223284 0.007647 -vt 0.026397 0.204534 -vt 0.266842 0.029841 -vt 0.048591 0.248091 -vt 0.083159 0.282659 -vt 0.301409 0.064408 -vt 0.126716 0.304853 -vt 0.323603 0.107966 -vt 0.175000 0.312500 -vt 0.331250 0.156250 -vt 0.323603 0.204534 -vt 0.223284 0.304853 -vt 0.266841 0.282659 -vt 0.301409 0.248091 -vt 0.212500 0.312500 -vt 0.212500 0.688440 -vt 0.050000 0.312500 -vt 0.050000 0.688440 -vt 0.168197 0.847327 -vt 0.083159 0.970159 -vt 0.048591 0.935591 -vt 0.165636 0.844766 -vt 0.225000 0.312500 -vt 0.225000 0.688440 -vt 0.287500 0.312500 -vt 0.300000 0.312500 -vt 0.300000 0.688440 -vt 0.287500 0.688440 -vt 0.171423 0.848971 -vt 0.126716 0.992353 -vt 0.026397 0.892034 -vt 0.163992 0.841540 -vt 0.175000 0.849537 -vt 0.175000 1.000000 -vt 0.018750 0.843750 -vt 0.163426 0.837963 -vt 0.178577 0.848971 -vt 0.223284 0.992353 -vt 0.026397 0.795466 -vt 0.163992 0.834386 -vt 0.275000 0.312500 -vt 0.275000 0.688440 -vt 0.237500 0.312500 -vt 0.237500 0.688440 -vt 0.181803 0.847327 -vt 0.266841 0.970159 -vt 0.048591 0.751909 -vt 0.165636 0.831160 -vt 0.262500 0.312500 -vt 0.262500 0.688440 -vt 0.250000 0.312500 -vt 0.250000 0.688440 -vt 0.125000 0.312500 -vt 0.125000 0.688440 -vt 0.137500 0.688440 -vt 0.137500 0.312500 -vt 0.112500 0.312500 -vt 0.112500 0.688440 -vt 0.150000 0.688440 -vt 0.150000 0.312500 -vt 0.100000 0.312500 -vt 0.100000 0.688440 -vt 0.162500 0.688440 -vt 0.162500 0.312500 -vt 0.087500 0.312500 -vt 0.087500 0.688440 -vt 0.175000 0.688440 -vt 0.175000 0.312500 -vt 0.075000 0.312500 -vt 0.075000 0.688440 -vt 0.187500 0.688440 -vt 0.187500 0.312500 -vt 0.200000 0.688440 -vt 0.200000 0.312500 -vt 0.062500 0.312500 -vt 0.062500 0.688440 -vt 0.212500 0.688440 -vt 0.212500 0.312500 -vt 0.050000 0.312500 -vt 0.050000 0.688440 -vt 0.225000 0.688440 -vt 0.225000 0.312500 -vt 0.287500 0.312500 -vt 0.287500 0.688440 -vt 0.300000 0.688440 -vt 0.300000 0.312500 -vt 0.275000 0.312500 -vt 0.275000 0.688440 -vt 0.237500 0.688440 -vt 0.237500 0.312500 -vt 0.250000 0.688440 -vt 0.250000 0.312500 -vt 0.262500 0.312500 -vt 0.262500 0.688440 -vt 0.083159 0.717341 -vt 0.168197 0.828599 -vt 0.184364 0.844766 -vt 0.301409 0.935591 -vt 0.126716 0.695147 -vt 0.171423 0.826955 -vt 0.186008 0.841540 -vt 0.323603 0.892034 -vt 0.175000 0.687500 -vt 0.175000 0.826389 -vt 0.186574 0.837963 -vt 0.331250 0.843750 -vt 0.186008 0.834386 -vt 0.323603 0.795466 -vt 0.223284 0.695147 -vt 0.178577 0.826955 -vt 0.184364 0.831160 -vt 0.301409 0.751908 -vt 0.266842 0.717341 -vt 0.181803 0.828599 -vt 0.048591 0.248091 -vt 0.026397 0.204534 -vt 0.223284 0.007647 -vt 0.018750 0.156250 -vt 0.175000 -0.000000 -vt 0.026397 0.107966 -vt 0.126716 0.007647 -vt 0.048591 0.064409 -vt 0.083159 0.029841 -s 1 -g silhouette_shorter -usemtl lambert2SG -f 1/1 2/2 3/3 -s 2 -f 4/4 5/5 6/6 7/7 -s 1 -f 8/8 9/9 3/3 -f 2/2 10/10 3/3 -s 2 -f 11/11 4/4 7/7 12/12 -f 5/5 13/13 14/14 6/6 -s 1 -f 15/15 8/8 3/3 -f 10/10 16/16 3/3 -f 16/16 17/17 3/3 -f 18/18 15/15 3/3 -s 2 -f 19/19 11/11 12/12 20/20 -f 13/13 21/21 22/22 14/14 -s 1 -f 17/17 23/23 3/3 -f 24/24 18/18 3/3 -f 23/23 24/24 3/3 -s 2 -f 25/25 19/19 20/20 26/26 -f 21/21 27/27 28/28 22/22 -f 1/29 25/25 26/26 29/30 -f 27/27 30/31 31/32 28/28 -f 30/31 9/33 32/34 31/32 -f 2/35 1/29 29/30 33/36 -s 4 -f 34/37 35/38 36/39 -f 36/39 35/38 37/40 -f 38/41 35/38 34/37 -f 37/40 35/38 39/42 -f 40/43 35/38 38/41 -f 39/42 35/38 41/44 -f 42/45 35/38 40/43 -f 41/44 35/38 43/46 -f 44/47 35/38 42/45 -f 45/48 35/38 44/47 -f 43/46 35/38 46/49 -f 47/50 35/38 45/48 -f 46/49 35/38 48/51 -f 49/52 35/38 47/50 -f 48/51 35/38 50/53 -f 50/53 35/38 51/54 -f 52/55 35/38 49/52 -f 53/56 35/38 52/55 -f 51/54 35/38 54/57 -f 54/57 35/38 53/56 -s 2 -f 9/33 8/58 55/59 32/34 -f 10/60 2/35 33/36 56/61 -s 5 -f 57/62 7/63 6/64 58/65 -s 2 -f 8/58 15/66 59/67 55/59 -f 16/68 10/69 56/70 60/71 -s 5 -f 61/72 12/73 7/63 57/62 -f 58/65 6/64 14/74 62/75 -f 63/76 20/77 12/73 61/72 -f 62/75 14/74 22/78 64/79 -f 65/80 26/81 20/77 63/76 -f 64/79 22/78 28/82 66/83 -s 2 -f 17/84 16/68 60/71 67/85 -f 15/66 18/86 68/87 59/67 -s 5 -f 69/88 29/89 26/81 65/80 -f 66/83 28/82 31/90 70/91 -s 2 -f 23/92 17/84 67/85 71/93 -f 18/86 24/94 72/95 68/87 -s 6 -f 36/96 57/97 58/98 34/99 -f 37/100 61/101 57/97 36/96 -f 34/99 58/98 62/102 38/103 -f 39/104 63/105 61/101 37/100 -f 38/103 62/102 64/106 40/107 -f 41/108 65/109 63/105 39/104 -f 40/107 64/106 66/110 42/111 -s 2 -f 24/94 23/92 71/93 72/95 -s 6 -f 43/112 69/113 65/109 41/108 -f 42/111 66/110 70/114 44/115 -f 44/115 70/114 73/116 45/117 -f 46/118 74/119 69/113 43/112 -f 45/117 73/116 75/120 47/121 -f 48/122 76/123 74/119 46/118 -f 47/121 75/120 77/124 49/125 -f 50/126 78/127 76/128 48/129 -f 51/130 79/131 78/127 50/126 -f 49/125 77/124 80/132 52/133 -f 52/133 80/132 81/134 53/135 -f 54/136 82/137 79/131 51/130 -f 53/135 81/134 82/137 54/136 -s 5 -f 70/91 31/90 32/138 73/139 -f 74/140 33/141 29/89 69/88 -f 73/139 32/138 55/142 75/143 -f 76/144 56/145 33/141 74/140 -f 75/143 55/142 59/146 77/147 -f 78/148 60/149 56/145 76/144 -f 79/150 67/151 60/149 78/148 -f 77/147 59/146 68/152 80/153 -f 82/154 71/155 67/151 79/150 -f 80/153 68/152 72/156 81/157 -f 81/157 72/156 71/155 82/154 -s 1 -f 9/9 30/158 3/3 -f 30/158 27/159 3/3 -f 25/160 1/1 3/3 -f 27/159 21/161 3/3 -f 19/162 25/160 3/3 -f 21/161 13/163 3/3 -f 11/164 19/162 3/3 -f 13/163 5/165 3/3 -f 4/166 11/164 3/3 -f 5/165 4/166 3/3 diff --git a/mod/data/mac-fallback-assets/stadium_snail_2.obj b/mod/data/mac-fallback-assets/stadium_snail_2.obj deleted file mode 100644 index 84b04623d..000000000 --- a/mod/data/mac-fallback-assets/stadium_snail_2.obj +++ /dev/null @@ -1,456 +0,0 @@ -o stadium -v -1.96850 0.00000 1.96851 -v -1.95166 0.00000 2.22545 -v -1.90142 0.00000 2.47800 -v -1.81866 0.00000 2.72182 -v -1.70477 0.00000 2.95276 -v -1.56172 0.00000 3.16686 -v -1.39194 0.00000 3.36045 -v -1.19835 0.00000 3.53023 -v -0.98425 0.00000 3.67328 -v -0.75331 0.00000 3.78717 -v -0.50949 0.00000 3.86993 -v -0.25694 0.00000 3.92017 -v -0.00000 0.00000 3.93701 -v 0.25694 0.00000 3.92017 -v 0.50949 0.00000 3.86993 -v 0.75331 0.00000 3.78717 -v 0.98425 0.00000 3.67328 -v 1.19835 0.00000 3.53023 -v 1.39194 0.00000 3.36045 -v 1.56172 0.00000 3.16686 -v 1.70477 0.00000 2.95276 -v 1.81866 0.00000 2.72182 -v 1.90142 0.00000 2.47800 -v 1.95166 0.00000 2.22545 -v 1.96850 0.00000 1.96851 -v 1.96850 0.00000 -1.96851 -v 1.95166 0.00000 -2.22545 -v 1.90142 0.00000 -2.47800 -v 1.81866 0.00000 -2.72182 -v 1.70477 0.00000 -2.95276 -v 1.56172 0.00000 -3.16686 -v 1.39194 0.00000 -3.36045 -v 1.19835 0.00000 -3.53023 -v 0.98425 0.00000 -3.67328 -v 0.75331 0.00000 -3.78717 -v 0.50949 0.00000 -3.86993 -v 0.25694 0.00000 -3.92017 -v 0.00000 0.00000 -3.93701 -v -0.25694 0.00000 -3.92017 -v -0.50949 0.00000 -3.86993 -v -0.75331 0.00000 -3.78717 -v -0.98425 0.00000 -3.67328 -v -1.19835 0.00000 -3.53023 -v -1.39194 0.00000 -3.36045 -v -1.56172 0.00000 -3.16686 -v -1.70477 0.00000 -2.95276 -v -1.81866 0.00000 -2.72182 -v -1.90142 0.00000 -2.47800 -v -1.95166 0.00000 -2.22545 -v -1.96850 0.00000 -1.96851 -v -1.96850 1.00000 1.96851 -v -1.95166 1.00000 2.22545 -v -1.90142 1.00000 2.47800 -v -1.81866 1.00000 2.72182 -v -1.70477 1.00000 2.95276 -v -1.56172 1.00000 3.16686 -v -1.39194 1.00000 3.36045 -v -1.19835 1.00000 3.53023 -v -0.98425 1.00000 3.67328 -v -0.75331 1.00000 3.78717 -v -0.50949 1.00000 3.86993 -v -0.25694 1.00000 3.92017 -v -0.00000 1.00000 3.93701 -v 0.25694 1.00000 3.92017 -v 0.50949 1.00000 3.86993 -v 0.75331 1.00000 3.78717 -v 0.98425 1.00000 3.67328 -v 1.19835 1.00000 3.53023 -v 1.39194 1.00000 3.36045 -v 1.56172 1.00000 3.16686 -v 1.70477 1.00000 2.95276 -v 1.81866 1.00000 2.72182 -v 1.90142 1.00000 2.47800 -v 1.95166 1.00000 2.22545 -v 1.96850 1.00000 1.96851 -v 1.96850 1.00000 -1.96851 -v 1.95166 1.00000 -2.22545 -v 1.90142 1.00000 -2.47800 -v 1.81866 1.00000 -2.72182 -v 1.70477 1.00000 -2.95276 -v 1.56172 1.00000 -3.16686 -v 1.39194 1.00000 -3.36045 -v 1.19835 1.00000 -3.53023 -v 0.98425 1.00000 -3.67328 -v 0.75331 1.00000 -3.78717 -v 0.50949 1.00000 -3.86993 -v 0.25694 1.00000 -3.92017 -v 0.00000 1.00000 -3.93701 -v -0.25694 1.00000 -3.92017 -v -0.50949 1.00000 -3.86993 -v -0.75331 1.00000 -3.78717 -v -0.98425 1.00000 -3.67328 -v -1.19835 1.00000 -3.53023 -v -1.39194 1.00000 -3.36045 -v -1.56172 1.00000 -3.16686 -v -1.70477 1.00000 -2.95276 -v -1.81866 1.00000 -2.72182 -v -1.90142 1.00000 -2.47800 -v -1.95166 1.00000 -2.22545 -v -1.96850 1.00000 -1.96851 -v 0.00000 0.00000 0.00000 -v 0.00000 1.00000 0.00000 -vt 0.00000 0.0 -vt 0.01273 0.0 -vt 0.02545 0.0 -vt 0.03818 0.0 -vt 0.05090 0.0 -vt 0.06363 0.0 -vt 0.07636 0.0 -vt 0.08908 0.0 -vt 0.10181 0.0 -vt 0.11453 0.0 -vt 0.12726 0.0 -vt 0.13999 0.0 -vt 0.15271 0.0 -vt 0.16544 0.0 -vt 0.17816 0.0 -vt 0.19089 0.0 -vt 0.20361 0.0 -vt 0.21634 0.0 -vt 0.22907 0.0 -vt 0.24179 0.0 -vt 0.25452 0.0 -vt 0.26724 0.0 -vt 0.27997 0.0 -vt 0.29270 0.0 -vt 0.30542 0.0 -vt 0.50000 0.0 -vt 0.51273 0.0 -vt 0.52545 0.0 -vt 0.53818 0.0 -vt 0.55090 0.0 -vt 0.56363 0.0 -vt 0.57636 0.0 -vt 0.58908 0.0 -vt 0.60181 0.0 -vt 0.61453 0.0 -vt 0.62726 0.0 -vt 0.63999 0.0 -vt 0.65271 0.0 -vt 0.66544 0.0 -vt 0.67816 0.0 -vt 0.69089 0.0 -vt 0.70361 0.0 -vt 0.71634 0.0 -vt 0.72907 0.0 -vt 0.74179 0.0 -vt 0.75452 0.0 -vt 0.76724 0.0 -vt 0.77997 0.0 -vt 0.79270 0.0 -vt 0.80542 0.0 -vt 0.00000 1.0 -vt 0.01273 1.0 -vt 0.02545 1.0 -vt 0.03818 1.0 -vt 0.05090 1.0 -vt 0.06363 1.0 -vt 0.07636 1.0 -vt 0.08908 1.0 -vt 0.10181 1.0 -vt 0.11453 1.0 -vt 0.12726 1.0 -vt 0.13999 1.0 -vt 0.15271 1.0 -vt 0.16544 1.0 -vt 0.17816 1.0 -vt 0.19089 1.0 -vt 0.20361 1.0 -vt 0.21634 1.0 -vt 0.22907 1.0 -vt 0.24179 1.0 -vt 0.25452 1.0 -vt 0.26724 1.0 -vt 0.27997 1.0 -vt 0.29270 1.0 -vt 0.30542 1.0 -vt 0.50000 1.0 -vt 0.51273 1.0 -vt 0.52545 1.0 -vt 0.53818 1.0 -vt 0.55090 1.0 -vt 0.56363 1.0 -vt 0.57636 1.0 -vt 0.58908 1.0 -vt 0.60181 1.0 -vt 0.61453 1.0 -vt 0.62726 1.0 -vt 0.63999 1.0 -vt 0.65271 1.0 -vt 0.66544 1.0 -vt 0.67816 1.0 -vt 0.69089 1.0 -vt 0.70361 1.0 -vt 0.71634 1.0 -vt 0.72907 1.0 -vt 0.74179 1.0 -vt 0.75452 1.0 -vt 0.76724 1.0 -vt 0.77997 1.0 -vt 0.79270 1.0 -vt 0.80542 1.0 -vt 0.5 0.5 -vn -1.00000 0.00000 0.00000 -vn -0.99144 0.00000 0.13053 -vn -0.96593 0.00000 0.25882 -vn -0.92388 0.00000 0.38268 -vn -0.86603 0.00000 0.50000 -vn -0.79335 0.00000 0.60876 -vn -0.70711 0.00000 0.70711 -vn -0.60876 0.00000 0.79335 -vn -0.50000 0.00000 0.86603 -vn -0.38268 0.00000 0.92388 -vn -0.25882 0.00000 0.96593 -vn -0.13053 0.00000 0.99144 -vn -0.00000 0.00000 1.00000 -vn 0.13053 0.00000 0.99144 -vn 0.25882 0.00000 0.96593 -vn 0.38268 0.00000 0.92388 -vn 0.50000 0.00000 0.86603 -vn 0.60876 0.00000 0.79335 -vn 0.70711 0.00000 0.70711 -vn 0.79335 0.00000 0.60876 -vn 0.86603 0.00000 0.50000 -vn 0.92388 0.00000 0.38268 -vn 0.96593 0.00000 0.25882 -vn 0.99144 0.00000 0.13053 -vn 1.00000 0.00000 0.00000 -vn 1.00000 0.00000 -0.00000 -vn 0.99144 0.00000 -0.13053 -vn 0.96593 0.00000 -0.25882 -vn 0.92388 0.00000 -0.38268 -vn 0.86603 0.00000 -0.50000 -vn 0.79335 0.00000 -0.60876 -vn 0.70711 0.00000 -0.70711 -vn 0.60876 0.00000 -0.79335 -vn 0.50000 0.00000 -0.86603 -vn 0.38268 0.00000 -0.92388 -vn 0.25882 0.00000 -0.96593 -vn 0.13053 0.00000 -0.99144 -vn 0.00000 0.00000 -1.00000 -vn -0.13053 0.00000 -0.99144 -vn -0.25882 0.00000 -0.96593 -vn -0.38268 0.00000 -0.92388 -vn -0.50000 0.00000 -0.86603 -vn -0.60876 0.00000 -0.79335 -vn -0.70711 0.00000 -0.70711 -vn -0.79335 0.00000 -0.60876 -vn -0.86603 0.00000 -0.50000 -vn -0.92388 0.00000 -0.38268 -vn -0.96593 0.00000 -0.25882 -vn -0.99144 0.00000 -0.13053 -vn -1.00000 0.00000 -0.00000 -vn 0 -1 0 -vn 0 1 0 -f 1/1/1 2/2/2 52/52/2 -f 1/1/1 52/52/2 51/51/1 -f 101/101/51 2/2/51 1/1/51 -f 102/101/52 51/51/52 52/52/52 -f 2/2/2 3/3/3 53/53/3 -f 2/2/2 53/53/3 52/52/2 -f 101/101/51 3/3/51 2/2/51 -f 102/101/52 52/52/52 53/53/52 -f 3/3/3 4/4/4 54/54/4 -f 3/3/3 54/54/4 53/53/3 -f 101/101/51 4/4/51 3/3/51 -f 102/101/52 53/53/52 54/54/52 -f 4/4/4 5/5/5 55/55/5 -f 4/4/4 55/55/5 54/54/4 -f 101/101/51 5/5/51 4/4/51 -f 102/101/52 54/54/52 55/55/52 -f 5/5/5 6/6/6 56/56/6 -f 5/5/5 56/56/6 55/55/5 -f 101/101/51 6/6/51 5/5/51 -f 102/101/52 55/55/52 56/56/52 -f 6/6/6 7/7/7 57/57/7 -f 6/6/6 57/57/7 56/56/6 -f 101/101/51 7/7/51 6/6/51 -f 102/101/52 56/56/52 57/57/52 -f 7/7/7 8/8/8 58/58/8 -f 7/7/7 58/58/8 57/57/7 -f 101/101/51 8/8/51 7/7/51 -f 102/101/52 57/57/52 58/58/52 -f 8/8/8 9/9/9 59/59/9 -f 8/8/8 59/59/9 58/58/8 -f 101/101/51 9/9/51 8/8/51 -f 102/101/52 58/58/52 59/59/52 -f 9/9/9 10/10/10 60/60/10 -f 9/9/9 60/60/10 59/59/9 -f 101/101/51 10/10/51 9/9/51 -f 102/101/52 59/59/52 60/60/52 -f 10/10/10 11/11/11 61/61/11 -f 10/10/10 61/61/11 60/60/10 -f 101/101/51 11/11/51 10/10/51 -f 102/101/52 60/60/52 61/61/52 -f 11/11/11 12/12/12 62/62/12 -f 11/11/11 62/62/12 61/61/11 -f 101/101/51 12/12/51 11/11/51 -f 102/101/52 61/61/52 62/62/52 -f 12/12/12 13/13/13 63/63/13 -f 12/12/12 63/63/13 62/62/12 -f 101/101/51 13/13/51 12/12/51 -f 102/101/52 62/62/52 63/63/52 -f 13/13/13 14/14/14 64/64/14 -f 13/13/13 64/64/14 63/63/13 -f 101/101/51 14/14/51 13/13/51 -f 102/101/52 63/63/52 64/64/52 -f 14/14/14 15/15/15 65/65/15 -f 14/14/14 65/65/15 64/64/14 -f 101/101/51 15/15/51 14/14/51 -f 102/101/52 64/64/52 65/65/52 -f 15/15/15 16/16/16 66/66/16 -f 15/15/15 66/66/16 65/65/15 -f 101/101/51 16/16/51 15/15/51 -f 102/101/52 65/65/52 66/66/52 -f 16/16/16 17/17/17 67/67/17 -f 16/16/16 67/67/17 66/66/16 -f 101/101/51 17/17/51 16/16/51 -f 102/101/52 66/66/52 67/67/52 -f 17/17/17 18/18/18 68/68/18 -f 17/17/17 68/68/18 67/67/17 -f 101/101/51 18/18/51 17/17/51 -f 102/101/52 67/67/52 68/68/52 -f 18/18/18 19/19/19 69/69/19 -f 18/18/18 69/69/19 68/68/18 -f 101/101/51 19/19/51 18/18/51 -f 102/101/52 68/68/52 69/69/52 -f 19/19/19 20/20/20 70/70/20 -f 19/19/19 70/70/20 69/69/19 -f 101/101/51 20/20/51 19/19/51 -f 102/101/52 69/69/52 70/70/52 -f 20/20/20 21/21/21 71/71/21 -f 20/20/20 71/71/21 70/70/20 -f 101/101/51 21/21/51 20/20/51 -f 102/101/52 70/70/52 71/71/52 -f 21/21/21 22/22/22 72/72/22 -f 21/21/21 72/72/22 71/71/21 -f 101/101/51 22/22/51 21/21/51 -f 102/101/52 71/71/52 72/72/52 -f 22/22/22 23/23/23 73/73/23 -f 22/22/22 73/73/23 72/72/22 -f 101/101/51 23/23/51 22/22/51 -f 102/101/52 72/72/52 73/73/52 -f 23/23/23 24/24/24 74/74/24 -f 23/23/23 74/74/24 73/73/23 -f 101/101/51 24/24/51 23/23/51 -f 102/101/52 73/73/52 74/74/52 -f 24/24/24 25/25/25 75/75/25 -f 24/24/24 75/75/25 74/74/24 -f 101/101/51 25/25/51 24/24/51 -f 102/101/52 74/74/52 75/75/52 -f 25/25/25 26/26/26 76/76/26 -f 25/25/25 76/76/26 75/75/25 -f 101/101/51 26/26/51 25/25/51 -f 102/101/52 75/75/52 76/76/52 -f 26/26/26 27/27/27 77/77/27 -f 26/26/26 77/77/27 76/76/26 -f 101/101/51 27/27/51 26/26/51 -f 102/101/52 76/76/52 77/77/52 -f 27/27/27 28/28/28 78/78/28 -f 27/27/27 78/78/28 77/77/27 -f 101/101/51 28/28/51 27/27/51 -f 102/101/52 77/77/52 78/78/52 -f 28/28/28 29/29/29 79/79/29 -f 28/28/28 79/79/29 78/78/28 -f 101/101/51 29/29/51 28/28/51 -f 102/101/52 78/78/52 79/79/52 -f 29/29/29 30/30/30 80/80/30 -f 29/29/29 80/80/30 79/79/29 -f 101/101/51 30/30/51 29/29/51 -f 102/101/52 79/79/52 80/80/52 -f 30/30/30 31/31/31 81/81/31 -f 30/30/30 81/81/31 80/80/30 -f 101/101/51 31/31/51 30/30/51 -f 102/101/52 80/80/52 81/81/52 -f 31/31/31 32/32/32 82/82/32 -f 31/31/31 82/82/32 81/81/31 -f 101/101/51 32/32/51 31/31/51 -f 102/101/52 81/81/52 82/82/52 -f 32/32/32 33/33/33 83/83/33 -f 32/32/32 83/83/33 82/82/32 -f 101/101/51 33/33/51 32/32/51 -f 102/101/52 82/82/52 83/83/52 -f 33/33/33 34/34/34 84/84/34 -f 33/33/33 84/84/34 83/83/33 -f 101/101/51 34/34/51 33/33/51 -f 102/101/52 83/83/52 84/84/52 -f 34/34/34 35/35/35 85/85/35 -f 34/34/34 85/85/35 84/84/34 -f 101/101/51 35/35/51 34/34/51 -f 102/101/52 84/84/52 85/85/52 -f 35/35/35 36/36/36 86/86/36 -f 35/35/35 86/86/36 85/85/35 -f 101/101/51 36/36/51 35/35/51 -f 102/101/52 85/85/52 86/86/52 -f 36/36/36 37/37/37 87/87/37 -f 36/36/36 87/87/37 86/86/36 -f 101/101/51 37/37/51 36/36/51 -f 102/101/52 86/86/52 87/87/52 -f 37/37/37 38/38/38 88/88/38 -f 37/37/37 88/88/38 87/87/37 -f 101/101/51 38/38/51 37/37/51 -f 102/101/52 87/87/52 88/88/52 -f 38/38/38 39/39/39 89/89/39 -f 38/38/38 89/89/39 88/88/38 -f 101/101/51 39/39/51 38/38/51 -f 102/101/52 88/88/52 89/89/52 -f 39/39/39 40/40/40 90/90/40 -f 39/39/39 90/90/40 89/89/39 -f 101/101/51 40/40/51 39/39/51 -f 102/101/52 89/89/52 90/90/52 -f 40/40/40 41/41/41 91/91/41 -f 40/40/40 91/91/41 90/90/40 -f 101/101/51 41/41/51 40/40/51 -f 102/101/52 90/90/52 91/91/52 -f 41/41/41 42/42/42 92/92/42 -f 41/41/41 92/92/42 91/91/41 -f 101/101/51 42/42/51 41/41/51 -f 102/101/52 91/91/52 92/92/52 -f 42/42/42 43/43/43 93/93/43 -f 42/42/42 93/93/43 92/92/42 -f 101/101/51 43/43/51 42/42/51 -f 102/101/52 92/92/52 93/93/52 -f 43/43/43 44/44/44 94/94/44 -f 43/43/43 94/94/44 93/93/43 -f 101/101/51 44/44/51 43/43/51 -f 102/101/52 93/93/52 94/94/52 -f 44/44/44 45/45/45 95/95/45 -f 44/44/44 95/95/45 94/94/44 -f 101/101/51 45/45/51 44/44/51 -f 102/101/52 94/94/52 95/95/52 -f 45/45/45 46/46/46 96/96/46 -f 45/45/45 96/96/46 95/95/45 -f 101/101/51 46/46/51 45/45/51 -f 102/101/52 95/95/52 96/96/52 -f 46/46/46 47/47/47 97/97/47 -f 46/46/46 97/97/47 96/96/46 -f 101/101/51 47/47/51 46/46/51 -f 102/101/52 96/96/52 97/97/52 -f 47/47/47 48/48/48 98/98/48 -f 47/47/47 98/98/48 97/97/47 -f 101/101/51 48/48/51 47/47/51 -f 102/101/52 97/97/52 98/98/52 -f 48/48/48 49/49/49 99/99/49 -f 48/48/48 99/99/49 98/98/48 -f 101/101/51 49/49/51 48/48/51 -f 102/101/52 98/98/52 99/99/52 -f 49/49/49 50/50/50 100/100/50 -f 49/49/49 100/100/50 99/99/49 -f 101/101/51 50/50/51 49/49/51 -f 102/101/52 99/99/52 100/100/52 -f 50/50/50 1/1/1 51/51/1 -f 50/50/50 51/51/1 100/100/50 -f 101/101/51 1/1/51 50/50/51 -f 102/101/52 100/100/52 51/51/52 diff --git a/mod/data/mac-fallback-assets/stadium_snail_3.obj b/mod/data/mac-fallback-assets/stadium_snail_3.obj deleted file mode 100644 index 01d49a74d..000000000 --- a/mod/data/mac-fallback-assets/stadium_snail_3.obj +++ /dev/null @@ -1,374 +0,0 @@ -# This file uses centimeters as units for non-parametric coordinates. - -mtllib silhouette_shorter.mtl -v 1.15608 -0.00000 -3.55971 -v 1.59120 -0.00000 -3.12459 -v -0.00000 -0.00000 -0.00000 -v -1.15608 -0.00000 -3.55971 -v -1.59120 -0.00000 -3.12459 -v -1.59120 1.00023 -3.12459 -v -1.15608 1.00023 -3.55971 -v -0.60778 -0.00000 3.83908 -v -1.15608 -0.00000 3.55971 -v 1.87057 -0.00000 -2.57629 -v -0.60778 -0.00000 -3.83908 -v -0.60778 1.00023 -3.83908 -v -1.87057 -0.00000 -2.57629 -v -1.87057 1.00023 -2.57629 -v -0.00000 -0.00000 3.93534 -v 1.96683 -0.00000 -0.00000 -v 1.87057 -0.00000 2.57629 -v 0.60778 -0.00000 3.83908 -v -0.00000 -0.00000 -3.93534 -v -0.00000 1.00023 -3.93534 -v -1.96683 -0.00000 -0.00000 -v -1.96683 1.00023 -0.00000 -v 1.59120 -0.00000 3.12458 -v 1.15607 -0.00000 3.55971 -v 0.60778 -0.00000 -3.83908 -v 0.60778 1.00023 -3.83908 -v -1.87057 -0.00000 2.57629 -v -1.87057 1.00023 2.57629 -v 1.15608 1.00023 -3.55971 -v -1.59120 -0.00000 3.12458 -v -1.59120 1.00023 3.12458 -v -1.15608 1.00023 3.55971 -v 1.59120 1.00023 -3.12459 -v -0.11787 0.92084 -2.05415 -v -0.00000 0.92084 -0.00000 -v -0.08564 0.92084 -2.08638 -v -0.04502 0.92084 -2.10707 -v -0.13856 0.92084 -2.01353 -v -0.00000 0.92084 -2.11420 -v -0.14569 0.92084 -0.00000 -v 0.04502 0.92084 -2.10707 -v -0.13856 0.92084 2.01353 -v 0.08564 0.92084 -2.08638 -v -0.11787 0.92084 2.05415 -v -0.08564 0.92084 2.08638 -v 0.11787 0.92084 -2.05415 -v -0.04502 0.92084 2.10707 -v 0.13856 0.92084 -2.01353 -v -0.00000 0.92084 2.11420 -v 0.14569 0.92084 -0.00000 -v 0.13856 0.92084 2.01353 -v 0.04502 0.92084 2.10707 -v 0.08564 0.92084 2.08638 -v 0.11787 0.92084 2.05415 -v -0.60778 1.00023 3.83908 -v 1.87057 1.00023 -2.57629 -v -0.08564 1.00023 -2.08638 -v -0.11787 1.00023 -2.05415 -v -0.00000 1.00023 3.93534 -v 1.96683 1.00023 -0.00000 -v -0.04502 1.00023 -2.10707 -v -0.13856 1.00023 -2.01353 -v -0.00000 1.00023 -2.11420 -v -0.14569 1.00023 -0.00000 -v 0.04502 1.00023 -2.10707 -v -0.13856 1.00023 2.01353 -v 1.87057 1.00023 2.57629 -v 0.60778 1.00023 3.83908 -v 0.08564 1.00023 -2.08638 -v -0.11787 1.00023 2.05415 -v 1.59120 1.00023 3.12458 -v 1.15607 1.00023 3.55971 -v -0.08564 1.00023 2.08638 -v 0.11787 1.00023 -2.05415 -v -0.04502 1.00023 2.10707 -v 0.13856 1.00023 -2.01353 -v -0.00000 1.00023 2.11420 -v 0.14569 1.00023 -0.00000 -v 0.13856 1.00023 2.01353 -v 0.04502 1.00023 2.10707 -v 0.08564 1.00023 2.08638 -v 0.11787 1.00023 2.05415 -vt 0.266842 0.029841 -vt 0.301409 0.064408 -vt 0.175000 0.150000 -vt 0.125000 0.312500 -vt 0.137500 0.312500 -vt 0.137500 0.688440 -vt 0.125000 0.688440 -vt 0.126716 0.304853 -vt 0.083159 0.282659 -vt 0.323603 0.107966 -vt 0.112500 0.312500 -vt 0.112500 0.688440 -vt 0.150000 0.312500 -vt 0.150000 0.688440 -vt 0.175000 0.312500 -vt 0.331250 0.156250 -vt 0.323603 0.204534 -vt 0.223284 0.304853 -vt 0.100000 0.312500 -vt 0.100000 0.688440 -vt 0.162500 0.312500 -vt 0.162500 0.688440 -vt 0.301409 0.248091 -vt 0.266841 0.282659 -vt 0.087500 0.312500 -vt 0.087500 0.688440 -vt 0.175000 0.312500 -vt 0.175000 0.688440 -vt 0.075000 0.312500 -vt 0.075000 0.688440 -vt 0.187500 0.312500 -vt 0.187500 0.688440 -vt 0.200000 0.312500 -vt 0.200000 0.688440 -vt 0.062500 0.312500 -vt 0.062500 0.688440 -vt 0.048591 0.064409 -vt 0.175000 0.150000 -vt 0.083159 0.029841 -vt 0.126716 0.007647 -vt 0.026397 0.107966 -vt 0.175000 -0.000000 -vt 0.018750 0.156250 -vt 0.223284 0.007647 -vt 0.026397 0.204534 -vt 0.266842 0.029841 -vt 0.048591 0.248091 -vt 0.083159 0.282659 -vt 0.301409 0.064408 -vt 0.126716 0.304853 -vt 0.323603 0.107966 -vt 0.175000 0.312500 -vt 0.331250 0.156250 -vt 0.323603 0.204534 -vt 0.223284 0.304853 -vt 0.266841 0.282659 -vt 0.301409 0.248091 -vt 0.212500 0.312500 -vt 0.212500 0.688440 -vt 0.050000 0.312500 -vt 0.050000 0.688440 -vt 0.168197 0.847327 -vt 0.083159 0.970159 -vt 0.048591 0.935591 -vt 0.165636 0.844766 -vt 0.225000 0.312500 -vt 0.225000 0.688440 -vt 0.287500 0.312500 -vt 0.300000 0.312500 -vt 0.300000 0.688440 -vt 0.287500 0.688440 -vt 0.171423 0.848971 -vt 0.126716 0.992353 -vt 0.026397 0.892034 -vt 0.163992 0.841540 -vt 0.175000 0.849537 -vt 0.175000 1.000000 -vt 0.018750 0.843750 -vt 0.163426 0.837963 -vt 0.178577 0.848971 -vt 0.223284 0.992353 -vt 0.026397 0.795466 -vt 0.163992 0.834386 -vt 0.275000 0.312500 -vt 0.275000 0.688440 -vt 0.237500 0.312500 -vt 0.237500 0.688440 -vt 0.181803 0.847327 -vt 0.266841 0.970159 -vt 0.048591 0.751909 -vt 0.165636 0.831160 -vt 0.262500 0.312500 -vt 0.262500 0.688440 -vt 0.250000 0.312500 -vt 0.250000 0.688440 -vt 0.125000 0.312500 -vt 0.125000 0.688440 -vt 0.137500 0.688440 -vt 0.137500 0.312500 -vt 0.112500 0.312500 -vt 0.112500 0.688440 -vt 0.150000 0.688440 -vt 0.150000 0.312500 -vt 0.100000 0.312500 -vt 0.100000 0.688440 -vt 0.162500 0.688440 -vt 0.162500 0.312500 -vt 0.087500 0.312500 -vt 0.087500 0.688440 -vt 0.175000 0.688440 -vt 0.175000 0.312500 -vt 0.075000 0.312500 -vt 0.075000 0.688440 -vt 0.187500 0.688440 -vt 0.187500 0.312500 -vt 0.200000 0.688440 -vt 0.200000 0.312500 -vt 0.062500 0.312500 -vt 0.062500 0.688440 -vt 0.212500 0.688440 -vt 0.212500 0.312500 -vt 0.050000 0.312500 -vt 0.050000 0.688440 -vt 0.225000 0.688440 -vt 0.225000 0.312500 -vt 0.287500 0.312500 -vt 0.287500 0.688440 -vt 0.300000 0.688440 -vt 0.300000 0.312500 -vt 0.275000 0.312500 -vt 0.275000 0.688440 -vt 0.237500 0.688440 -vt 0.237500 0.312500 -vt 0.250000 0.688440 -vt 0.250000 0.312500 -vt 0.262500 0.312500 -vt 0.262500 0.688440 -vt 0.083159 0.717341 -vt 0.168197 0.828599 -vt 0.184364 0.844766 -vt 0.301409 0.935591 -vt 0.126716 0.695147 -vt 0.171423 0.826955 -vt 0.186008 0.841540 -vt 0.323603 0.892034 -vt 0.175000 0.687500 -vt 0.175000 0.826389 -vt 0.186574 0.837963 -vt 0.331250 0.843750 -vt 0.186008 0.834386 -vt 0.323603 0.795466 -vt 0.223284 0.695147 -vt 0.178577 0.826955 -vt 0.184364 0.831160 -vt 0.301409 0.751908 -vt 0.266842 0.717341 -vt 0.181803 0.828599 -vt 0.048591 0.248091 -vt 0.026397 0.204534 -vt 0.223284 0.007647 -vt 0.018750 0.156250 -vt 0.175000 -0.000000 -vt 0.026397 0.107966 -vt 0.126716 0.007647 -vt 0.048591 0.064409 -vt 0.083159 0.029841 -s 1 -g silhouette_shorter -usemtl lambert2SG -f 1/1 2/2 3/3 -s 2 -f 4/4 5/5 6/6 7/7 -s 1 -f 8/8 9/9 3/3 -f 2/2 10/10 3/3 -s 2 -f 11/11 4/4 7/7 12/12 -f 5/5 13/13 14/14 6/6 -s 1 -f 15/15 8/8 3/3 -f 10/10 16/16 3/3 -f 16/16 17/17 3/3 -f 18/18 15/15 3/3 -s 2 -f 19/19 11/11 12/12 20/20 -f 13/13 21/21 22/22 14/14 -s 1 -f 17/17 23/23 3/3 -f 24/24 18/18 3/3 -f 23/23 24/24 3/3 -s 2 -f 25/25 19/19 20/20 26/26 -f 21/21 27/27 28/28 22/22 -f 1/29 25/25 26/26 29/30 -f 27/27 30/31 31/32 28/28 -f 30/31 9/33 32/34 31/32 -f 2/35 1/29 29/30 33/36 -s 4 -f 34/37 35/38 36/39 -f 36/39 35/38 37/40 -f 38/41 35/38 34/37 -f 37/40 35/38 39/42 -f 40/43 35/38 38/41 -f 39/42 35/38 41/44 -f 42/45 35/38 40/43 -f 41/44 35/38 43/46 -f 44/47 35/38 42/45 -f 45/48 35/38 44/47 -f 43/46 35/38 46/49 -f 47/50 35/38 45/48 -f 46/49 35/38 48/51 -f 49/52 35/38 47/50 -f 48/51 35/38 50/53 -f 50/53 35/38 51/54 -f 52/55 35/38 49/52 -f 53/56 35/38 52/55 -f 51/54 35/38 54/57 -f 54/57 35/38 53/56 -s 2 -f 9/33 8/58 55/59 32/34 -f 10/60 2/35 33/36 56/61 -s 5 -f 57/62 7/63 6/64 58/65 -s 2 -f 8/58 15/66 59/67 55/59 -f 16/68 10/69 56/70 60/71 -s 5 -f 61/72 12/73 7/63 57/62 -f 58/65 6/64 14/74 62/75 -f 63/76 20/77 12/73 61/72 -f 62/75 14/74 22/78 64/79 -f 65/80 26/81 20/77 63/76 -f 64/79 22/78 28/82 66/83 -s 2 -f 17/84 16/68 60/71 67/85 -f 15/66 18/86 68/87 59/67 -s 5 -f 69/88 29/89 26/81 65/80 -f 66/83 28/82 31/90 70/91 -s 2 -f 23/92 17/84 67/85 71/93 -f 18/86 24/94 72/95 68/87 -s 6 -f 36/96 57/97 58/98 34/99 -f 37/100 61/101 57/97 36/96 -f 34/99 58/98 62/102 38/103 -f 39/104 63/105 61/101 37/100 -f 38/103 62/102 64/106 40/107 -f 41/108 65/109 63/105 39/104 -f 40/107 64/106 66/110 42/111 -s 2 -f 24/94 23/92 71/93 72/95 -s 6 -f 43/112 69/113 65/109 41/108 -f 42/111 66/110 70/114 44/115 -f 44/115 70/114 73/116 45/117 -f 46/118 74/119 69/113 43/112 -f 45/117 73/116 75/120 47/121 -f 48/122 76/123 74/119 46/118 -f 47/121 75/120 77/124 49/125 -f 50/126 78/127 76/128 48/129 -f 51/130 79/131 78/127 50/126 -f 49/125 77/124 80/132 52/133 -f 52/133 80/132 81/134 53/135 -f 54/136 82/137 79/131 51/130 -f 53/135 81/134 82/137 54/136 -s 5 -f 70/91 31/90 32/138 73/139 -f 74/140 33/141 29/89 69/88 -f 73/139 32/138 55/142 75/143 -f 76/144 56/145 33/141 74/140 -f 75/143 55/142 59/146 77/147 -f 78/148 60/149 56/145 76/144 -f 79/150 67/151 60/149 78/148 -f 77/147 59/146 68/152 80/153 -f 82/154 71/155 67/151 79/150 -f 80/153 68/152 72/156 81/157 -f 81/157 72/156 71/155 82/154 -s 1 -f 9/9 30/158 3/3 -f 30/158 27/159 3/3 -f 25/160 1/1 3/3 -f 27/159 21/161 3/3 -f 19/162 25/160 3/3 -f 21/161 13/163 3/3 -f 11/164 19/162 3/3 -f 13/163 5/165 3/3 -f 4/166 11/164 3/3 -f 5/165 4/166 3/3 From c1b328f2d8b33776525485bc5aef0624fd8c9ce1 Mon Sep 17 00:00:00 2001 From: Martin Pourrat Date: Fri, 14 Aug 2026 15:18:30 +0200 Subject: [PATCH 42/42] Ship our docs as .txt, and correct what they claimed Our four markdown files become plain text, so the only .md left in the repo are the ones that were already yours. They were also out of date, in ways that mattered: - mac-patcher/README described the decal-and-vector-lines engine and gave the Unity 6 shader bug as the root cause. Neither has been true since 12 August: rendering moved to real Projectors, and the root cause is bundles built without a Metal variant. Rewritten around what the module actually is, an optional overlay behind an off-by-default button, plus the attack chain marked as the stopgap it is. - mac-support-package/README and the release README still said eight bundles had no surviving sources and stayed broken. They have been grafted since 12 August: nothing is left broken on Mac. Both now carry the second root cause too, the vertex-colour one, which is the half that matters for the minis they will build next. - "byte-identical to what is published today" is dropped. The Windows SubShader comes from our rebuild, not from the published file. What is true, and enough, is that the merge does not touch it. - The patcher's own docstring said it was a Mac cohesion fallback spawning vector lines. The injected markers keep their historical "mac" names, since the idempotence pass matches them by regex. Counts throughout are now the ones the inventories give: 266 bundles referenced, 152 repaired (143 rebuilt, 9 grafted), 114 that were never broken. Bench: 36 checks, green. Co-Authored-By: Claude Opus 5 (1M context) --- mac-patcher/README.md | 70 --------------- mac-patcher/README.txt | 78 +++++++++++++++++ mac-patcher/patch_save_for_mac.py | 18 ++-- mac-patcher/proposals-upstream.md | 108 ----------------------- mac-patcher/proposals-upstream.txt | 98 +++++++++++++++++++++ mac-patcher/tools/README.md | 109 ----------------------- mac-patcher/tools/README.txt | 111 ++++++++++++++++++++++++ mac-support-package/README.md | 103 ---------------------- mac-support-package/README.txt | 135 +++++++++++++++++++++++++++++ 9 files changed, 435 insertions(+), 395 deletions(-) delete mode 100644 mac-patcher/README.md create mode 100644 mac-patcher/README.txt delete mode 100644 mac-patcher/proposals-upstream.md create mode 100644 mac-patcher/proposals-upstream.txt delete mode 100644 mac-patcher/tools/README.md create mode 100644 mac-patcher/tools/README.txt delete mode 100644 mac-support-package/README.md create mode 100644 mac-support-package/README.txt diff --git a/mac-patcher/README.md b/mac-patcher/README.md deleted file mode 100644 index 22166ff25..000000000 --- a/mac-patcher/README.md +++ /dev/null @@ -1,70 +0,0 @@ -# mac-patcher - -Python patcher that injects Mac-compatibility fallbacks into a SWL TTS save -file. Works around the TTS Unity 6 (Berserk) shader bug where vanilla -AssetBundle Projectors (range rulers, cohesion halos, movement templates, -deployment zones, silhouettes) render as a magenta rectangle on macOS -because the custom shader bundled by Allen White (Dicewrench) fails to load -under Unity 6 Metal. - -## What it does - -For each affected object script in a `TS_Save_N.json`: - -- **Cohesion / Range / Maximum Move / Deployment / Silhouette**: routes the - visualization through a Mac-friendly path (vector lines + decal PNGs) - built into the Global script. The vanilla bundle path stays available - for per-seat opt-in (see "Mac TTS U6 Patch" floating panel). - -- **SIL button**: renames `click_function = "toggleSilhouettes"` to - `"macToggleSil"` + injects a forwarder. Empirically the engine silently - swallows the original click_function name in Mac mode (the button plays - its sound/animation but the function is never invoked). The rename - bypasses the issue entirely. - -- **clearSilhouette nil guard**: upstream `clearSilhouette()` derefs - `removeAttachments()[1]` which is nil when `silhouetteState` is true but - the physical silhouette attachment has been lost across save reloads. - Patched to guard the nil case + reset state in onload. - -- **Order Token Speed/Move button overrides**: inlines vanilla bodies of - `changeSpeed1/2/3` and `moveForward/Backwards/Left/Right` to capture - the clicking player's color (`macActivePlayerForMove`) for per-seat - routing. Inlined rather than wrapped because the List Builder copies the - block to Command Token Custom_Models which lack the vanilla - Order_Token function bodies (wrap+call_orig would crash with "attempt - to call a nil value"). - -## Usage - -```bash -# Setup once -python3 -m venv venv -source venv/bin/activate -pip install -r requirements.txt - -# Patch a save -python3 patch_save_for_mac.py [--reload] -``` - -The patcher writes only to ``. Point that at a slot under -`~/Library/Tabletop Simulator/Saves/` if you want TTS to pick it up in -Games -> Save & Load. - -`--reload` hot-pushes the patched scripts to a running TTS instance via the -External Editor API (no need to restart TTS). - -## Idempotence - -All patches are idempotent: a re-run on an already-patched save strips the -previous Mac patch block from Global (via marker regex) and re-injects -fresh. Per-object wrappers are also stripped before re-injection. - -## Files - -- `patch_save_for_mac.py` - main patcher -- `proposals-upstream.md` - the work we offered to do, for the maintainers -- `tools/` - the bundle repair chain, documented in `tools/README.md`: - build, merge the per-platform SubShaders, graft a Metal SubShader into a - 2019.1 bundle, inventory the mod's bundles, install the result into the - local TTS cache diff --git a/mac-patcher/README.txt b/mac-patcher/README.txt new file mode 100644 index 000000000..249817fff --- /dev/null +++ b/mac-patcher/README.txt @@ -0,0 +1,78 @@ +mac-patcher +=========== + +A Python patcher that injects the Iron Squadron overlay module into a SWL TTS +save file. It is optional, it sits behind a single table-wide button that is off +by default, and with the button off the mod behaves exactly as it does today. + +It has nothing to do with the magenta bug any more. That one is fixed in the +bundles themselves, which is the mergeable part of this branch; see +mac-support-package/ and mac-patcher/tools/. This module is the separate offer +described in proposals-upstream.txt, kept here so you can look at it before +deciding whether you want any of it. + + +WHAT IT ADDS + + Cohesion on the five base sizes the mod does not cover. getCohesionLinks() + ships 27, 50 and 70 mm, so on 100, 120 and 150 mm bases and on the two oblong + ones, spawnCohesionRuler returns early and nothing appears. 35 units are in + that case. + + Cohesion that follows a model while it is being dragged, instead of + disappearing on pickup and coming back stale on drop. + + Deterministic toggles. The vanilla range and cohesion buttons respawn their + Projector rather than toggling it, so a double click leaves two of them. + + A maximum-move template anchored where the move started, rather than one that + follows the model as it goes. + + A white cohesion band at range 0.5 on the eight unit-leader range templates, + and matching rings on objective and condition tokens. + +Rendering goes through real Projectors, in bundles built the same way as the +repaired ones. Nothing is drawn in Lua. + + +USAGE + + # Setup once + python3 -m venv venv + source venv/bin/activate + pip install -r requirements.txt + + # Patch a save + python3 patch_save_for_mac.py [--reload] + +The patcher writes only to . Point that at a slot under +~/Library/Tabletop Simulator/Saves/ if you want TTS to pick it up in +Games -> Save & Load. + +--reload hot-pushes the patched scripts to a running TTS instance via the +External Editor API, so there is no need to restart TTS. + + +IDEMPOTENCE + +All patches are idempotent. A re-run on an already patched save strips the +previous block from Global via a marker regex and re-injects a fresh one. +Per-object wrappers are stripped before re-injection too. + + +ONE KNOWN STOPGAP + +The Order Token's ATTACK chain is routed through this module so that it does not +leave two overlapping rulers on screen. The feature itself dates from V1 and its +measurements are not accurate under V2 rules, so treat it as a stopgap to be +replaced or removed, not as a design. + + +FILES + + patch_save_for_mac.py the patcher + proposals-upstream.txt what we are offering to build, for the maintainers + tools/ the bundle repair chain, documented in tools/README.txt: + build, merge the per-platform SubShaders, graft a Metal + SubShader into a 2019.1 bundle, inventory the mod's + bundles, install the result into the local TTS cache diff --git a/mac-patcher/patch_save_for_mac.py b/mac-patcher/patch_save_for_mac.py index e57a278f3..0e9dc5694 100644 --- a/mac-patcher/patch_save_for_mac.py +++ b/mac-patcher/patch_save_for_mac.py @@ -1,16 +1,24 @@ #!/usr/bin/env python3 """ -Patch a TTS save JSON (SWL mod beta) to add Mac Cohesion fallback. +Inject the optional Iron Squadron overlay module into a SWL TTS save JSON. + +It sits behind a single table-wide button, off by default, and adds what the +vanilla mod does not have: cohesion on the five base sizes it skips, cohesion +that follows a model while it is dragged, deterministic toggles instead of +respawns, a maximum-move template anchored where the move started, and a range +0.5 band on the range templates. Rendering goes through real Projectors, in +bundles built like the repaired ones, so nothing is drawn in Lua. + +Not to be confused with the magenta fix: that one lives in the bundles, and is +this branch's mergeable content. This module is the separate offer described in +proposals-upstream.txt. The names below still say "mac" for historical reasons +and because the injected markers are matched by regex on re-runs. Two-part patch: 1. Append manager + event handlers to the Global LuaScript. 2. Replace the inline Cohesion block in Unit_Leader (99f1c8) and Order_Token (a57c41) with delegated stubs that call the Global manager via Global.call. -The native hotkey "Show Cohesion On Hovered Model" and the Order Token -"COHESION" button automatically use the patched code afterwards - they -spawn vector-lines rings instead of legacy Custom_AssetBundle Projectors. - Usage: python3 patch_save_for_mac.py """ diff --git a/mac-patcher/proposals-upstream.md b/mac-patcher/proposals-upstream.md deleted file mode 100644 index a0487b690..000000000 --- a/mac-patcher/proposals-upstream.md +++ /dev/null @@ -1,108 +0,0 @@ -# Proposals for the maintainers, before we spend the time - -Iron Squadron, 12 August 2026. - -Everything below is **work we are offering to do**, not work we have done. We -would rather hear "no thanks" now than hand you a pull request you never asked -for. Each item says what is missing today, what it would cost us, and what it -changes for players. - -Context, in one line: we rebuilt the mod's custom-shader bundles so they carry a -Metal SubShader alongside the DirectX one, which fixes the magenta Projectors on -macOS. Working through that, we ran into two gaps that have nothing to do with -macOS. They affect Windows players exactly the same way. - ---- - -## 1. Cohesion is missing on 35 units - -`getCohesionLinks()` ships three bundles: 27 mm, 50 mm and 70 mm. -`spawnCohesionRuler` ends with - -```lua -if cohesionBundleToSpawn == nil then return end -``` - -so on any other base the cohesion ruler simply does not appear. Counting the -`size` field across `contrib/cards`: - -| base size | units | examples | -|---|---|---| -| `huge` (100 mm) | 16 | T-47 Airspeeder, AT-ST | -| `epic` (150 mm) | 12 | AT-AP, LAAT/i Gunship | -| `long` (100 mm oblong) | 3 | A-A5 Speeder Truck, Occupier Tank | -| `laat` (120 mm) | 2 | LAAT/LE Patrol Transport | -| `snail` (100×200 mm oblong) | 2 | Persuader-Class Tank Droid | - -**What we would build.** Cohesion is the base outline offset outwards by range -0.5, whatever the base's shape. That is not our interpretation, it is what the -existing bundles measure: their radii are 3.531, 3.984 and 4.378 inches for 27, -50 and 70 mm bases, i.e. the base radius plus **3.000 inches** in all three -cases. - -The three missing round sizes are nearly free: `BB_CohesionProjector.shader` is -procedural, driven by `_BaseSize`, so each one is a material and a prefab, with -no new art. - -The two oblong sizes need a shader that offsets a stadium rather than a circle, -and that maths already exists in this repo: `BB_OblongRangeProjector.shader` -takes a `_BaseCenterPointGap`. A cohesion variant is a merge of two shaders you -already own. - -**Cost to you: none.** We build, we test on both platforms, you review. - ---- - -## 2. The range template could carry the cohesion ring - -Same measurement, shown where players already look. A thin white ring at range -0.5 from the base edge, added to `BB_RangeProjector` and its oblong variant, on -the eight unit-leader sizes. Not on tokens: an objective or a POI is not a unit, -so cohesion means nothing there. - -This one is a genuine change to something that already works, so it is the item -we most want your opinion on before touching it. - ---- - -## 3. The question underneath both: opt-in or for everyone? - -We also maintain a small Lua layer that adds behaviours the vanilla mod does not -have — cohesion that follows a model while it is being dragged, range and -cohesion toggles that are deterministic instead of respawning, a maximum-move -template anchored where the move started. It sits behind a single table-wide -button, off by default, and it leaves the original mod strictly untouched when -off. - -Rendering, however, no longer goes through that layer: it is in the bundles now. -So an enriched range template would be seen by **everyone, in both button -states**. Keeping it optional means publishing a second set of range bundles for -the button to select, which roughly doubles what we produce. - -Three ways to go, and it is your call: - -1. **For everyone.** Simplest, and hard to argue against for item 1, since the - vanilla mod shows nothing at all on those 35 units today. -2. **Behind the button.** Nothing imposed, players compare and decide. More work - on our side, and we are fine with that. -3. **Item 1 for everyone, item 2 behind the button.** Our own preference: the - missing cohesion is a gap to fill, the enriched range template is a taste - question. - ---- - -## Separately, two upstream bugs we already carry a fix for - -Neither is macOS-specific and neither needs a decision from you. Say the word -and we will send them as their own small pull request. - -- `clearSilhouette()` dereferences `removeAttachments()[1]` without checking it. - `silhouetteState` survives a save reload while the physical attachments do - not, so loading a game saved with silhouettes up and clicking SIL crashes the - object's script. -- The SIL and LCK buttons land on top of the model on `long` and `snail` bases: - `calculateButtonZOffset` uses a single per-size radius with no axis handling. - ---- - -Contact: Iron Squadron, French Star Wars Legion association — https://iron-squadron.fr diff --git a/mac-patcher/proposals-upstream.txt b/mac-patcher/proposals-upstream.txt new file mode 100644 index 000000000..ca80d2a18 --- /dev/null +++ b/mac-patcher/proposals-upstream.txt @@ -0,0 +1,98 @@ +Proposals for the maintainers, before we spend the time +======================================================= + +Iron Squadron, 12 August 2026. + +Everything below is work we are offering to do, not work we have done. We would +rather hear "no thanks" now than hand you a pull request you never asked for. +Each item says what is missing today, what it would cost us, and what it changes +for players. + +Context, in one line: we rebuilt the mod's custom-shader bundles so they carry a +Metal SubShader alongside the DirectX one, which fixes the magenta Projectors on +macOS. Working through that, we ran into two gaps that have nothing to do with +macOS. They affect Windows players exactly the same way. + + +1. COHESION IS MISSING ON 35 UNITS + +getCohesionLinks() ships three bundles: 27 mm, 50 mm and 70 mm. +spawnCohesionRuler ends with + + if cohesionBundleToSpawn == nil then return end + +so on any other base the cohesion ruler simply does not appear. Counting the +size field across contrib/cards: + + huge (100 mm) 16 units T-47 Airspeeder, AT-ST + epic (150 mm) 12 units AT-AP, LAAT/i Gunship + long (100 mm oblong) 3 units A-A5 Speeder Truck, Occupier Tank + laat (120 mm) 2 units LAAT/LE Patrol Transport + snail (100x200 oblong) 2 units Persuader-Class Tank Droid + +What we would build. Cohesion is the base outline offset outwards by range 0.5, +whatever the base's shape. That is not our interpretation, it is what the +existing bundles measure: their radii are 3.531, 3.984 and 4.378 inches for 27, +50 and 70 mm bases, i.e. the base radius plus 3.000 inches in all three cases. + +The three missing round sizes are nearly free: BB_CohesionProjector.shader is +procedural, driven by _BaseSize, so each one is a material and a prefab, with no +new art. + +The two oblong sizes need a shader that offsets a stadium rather than a circle, +and that maths already exists in this repo: BB_OblongRangeProjector.shader takes +a _BaseCenterPointGap. A cohesion variant is a merge of two shaders you already +own. + +Cost to you: none. We build, we test on both platforms, you review. + + +2. THE RANGE TEMPLATE COULD CARRY THE COHESION RING + +Same measurement, shown where players already look. A thin white ring at range +0.5 from the base edge, added to BB_RangeProjector and its oblong variant, on the +eight unit-leader sizes. Not on tokens: an objective or a POI is not a unit, so +cohesion means nothing there. + +This one is a genuine change to something that already works, so it is the item +we most want your opinion on before touching it. + + +3. THE QUESTION UNDERNEATH BOTH: OPT-IN OR FOR EVERYONE? + +We also maintain a small Lua layer that adds behaviours the vanilla mod does not +have: cohesion that follows a model while it is being dragged, range and cohesion +toggles that are deterministic instead of respawning, a maximum-move template +anchored where the move started. It sits behind a single table-wide button, off +by default, and it leaves the original mod strictly untouched when off. + +Rendering, however, no longer goes through that layer: it is in the bundles now. +So an enriched range template would be seen by everyone, in both button states. +Keeping it optional means publishing a second set of range bundles for the button +to select, which roughly doubles what we produce. + +Three ways to go, and it is your call: + +1. For everyone. Simplest, and hard to argue against for item 1, since the + vanilla mod shows nothing at all on those 35 units today. +2. Behind the button. Nothing imposed, players compare and decide. More work on + our side, and we are fine with that. +3. Item 1 for everyone, item 2 behind the button. Our own preference: the missing + cohesion is a gap to fill, the enriched range template is a taste question. + + +SEPARATELY, TWO UPSTREAM BUGS WE ALREADY CARRY A FIX FOR + +Neither is macOS-specific and neither needs a decision from you. Say the word and +we will send them as their own small pull request. + +- clearSilhouette() dereferences removeAttachments()[1] without checking it. + silhouetteState survives a save reload while the physical attachments do not, + so loading a game saved with silhouettes up and clicking SIL crashes the + object's script. +- The SIL and LCK buttons land on top of the model on long and snail bases: + calculateButtonZOffset uses a single per-size radius with no axis handling. + + +Contact: Iron Squadron, French Star Wars Legion association, +https://iron-squadron.fr diff --git a/mac-patcher/tools/README.md b/mac-patcher/tools/README.md deleted file mode 100644 index 8a50ecab7..000000000 --- a/mac-patcher/tools/README.md +++ /dev/null @@ -1,109 +0,0 @@ -# Outils de réparation Mac des AssetBundles - -Ces scripts ont produit la réparation Mac du mod. Ils sont ici pour être -retrouvables et reproductibles, pas pour être jolis : ce sont des outils -d'atelier, en français, à usage interne Iron Squadron. - -Le paquet destiné aux développeurs du mod, en anglais, est ailleurs : -`mac-support-package/`. - -## Les deux causes racines - -**1. Pas de variante Metal.** Les bundles ont été compilés pour -`StandaloneWindows64` uniquement, entre 2019 et 2022. Quand TTS est passé à -Metal sur Mac, leurs shaders custom n'avaient aucune variante pour cette API : -figurines magenta. Rien à voir avec Unity 6, contrairement à ce qu'on a cru -pendant des semaines. - -**2. La couleur de sommet vaut zéro sur Metal.** Les shaders d'effets lumineux -lisent `v.color`, un canal que **aucun mesh du mod ne possède** (mesuré : 1 seul -sur 408, et il n'a pas de shader custom). DirectX et OpenGL remplacent un canal -absent par du blanc, Metal par du noir. Les passes étant en `Blend One One`, -multipliées par zéro elles n'ajoutent rien : sabres, yeux et boucliers éteints, -sans que rien ne paraisse cassé. Touche 12 bundles. - -## La chaîne, dans l'ordre - -Deux voies selon qu'on a les sources du modèle ou non. - -### Voie rebuild — quand les sources existent - -``` -patch_shader_precision.py --apply # fixed/half -> float (précision Metal) -patch_shader_vertexcolor.py --apply # v.color -> blanc (effets lumineux) -Unity 6 -executeMethod BuildAllTargets.Run -target mac -out AssetBundles-mac -merge_all_bundles.py AssetBundles-win AssetBundles-mac AssetBundles-dual -patch_shader_precision.py --restore # remet les sources d'origine -DUAL_DIR=AssetBundles-dual install_dual_to_cache.py --install -``` - -On ne rebuilde que la cible macOS : le SubShader Windows du bundle publié reste -bit pour bit celui d'aujourd'hui. - -### Voie greffe — quand il n'y a pas de sources - -C'est la voie des 8 orphelins, et la seule à dérive nulle : le bundle publié -garde ses maillages, ses textures et ses matériaux inchangés, on ne lui ajoute -qu'un SubShader. - -``` -Unity 2019.1.9f1 -executeMethod BuildMetalGraft.Run -out AssetBundles-graft -graft_metal_2019_1.py -install_grafted_to_cache.py --install -``` - -**La version d'Unity doit correspondre à celle du bundle publié.** Les 248 -bundles se répartissent sur cinq versions : 2019.4.19f1 (144), 2019.1.9f1 (83), -2019.1.0f2 (11), 2019.4.40f1 (9), 5.3.4f1 (1). Elle se lit dans les 200 premiers -octets du fichier, en clair après la signature `UnityFS`. - -Entre 2019.1 et 2019.4, la sérialisation des shaders change : les tables du blob -passent de plates à imbriquées. D'où deux scripts de fusion qui refusent chacun -le format de l'autre : - -| script | format | produit par | -|---|---|---| -| `merge_subshader_platforms.py` | listes imbriquées, champ `stageCounts` | Unity 6 | -| `graft_metal_2019_1.py` | listes plates | Unity 2019.1 | - -## Pourquoi un SubShader entier et pas une passe fusionnée - -Les tables de liaison de paramètres (`m_NameIndices`, `m_CommonParameters`, -`m_ConstantBufferBindings`) sont stockées **une fois par passe** et partagées par -toutes les plateformes. DirectX et OpenGL cohabitent parce qu'ils partagent -cette disposition. Metal, lui, éclate les globals en `VGlobals`/`FGlobals` et -remet les offsets à zéro : greffer un programme Metal dans une passe DirectX lui -donne les mauvaises liaisons, et il rend faux **sans aucun message d'erreur**. - -Un shader peut en revanche déclarer plusieurs SubShaders, chacun avec ses -propres passes donc ses propres tables. On empile donc le SubShader macOS -derrière celui d'origine : Unity descend au suivant quand le premier n'a pas de -variante pour l'API courante. - -## Pièges rencontrés - -- **La sauvegarde ne se juge pas à son existence mais à son contenu.** Un bundle - simplement *déposé* au premier passage existe au second et se fait sauvegarder - alors que c'est déjà le nôtre. 60 entrées sur 114 étaient dans ce cas. Le - garde-fou est `is_ours()` : aucun bundle publié ne porte de variante Metal, - donc en trouver une prouve que le fichier vient de nous. -- **Toujours greffer depuis le bundle publié**, jamais depuis un bundle déjà - greffé, sinon on empile les SubShaders à chaque passage. -- **macOS tue les vieux éditeurs Unity** au lancement (`SIGKILL`, aucun log - écrit), avec une alerte « Unity est endommagé ». Ce n'est pas une quarantaine : - la réponse est Réglages Système → Confidentialité et sécurité → « Ouvrir quand - même ». Ne jamais cliquer « Placer dans la corbeille ». -- **Certains shaders sont en latin-1** (l'en-tête « © Allen White ») : lire en - binaire, ne pas réencoder. -- **UnityPy** : `m_Colors` donne des dictionnaires modifiables, `m_Floats` des - tuples immuables. Pour modifier un float, reconstruire la liste. -- **zsh ne découpe pas les variables non quotées** : pour une longue liste de - chemins, passer par `bash -c` avec un tableau. - -## Ce qu'on ne touche jamais - -- Les bundles **sans shader custom** : ils n'ont jamais été cassés. -- `stunt_double_bot_1` : son rebuild ajoute un socle absent du bundle publié. -- Les **Custom Models** (`mesh` + `diffuse` au lieu de `bundle`) : TTS leur - applique son propre matériau, ils ne peuvent pas être magenta. Ils sont - majoritaires dans le mod. diff --git a/mac-patcher/tools/README.txt b/mac-patcher/tools/README.txt new file mode 100644 index 000000000..1d6b8ea16 --- /dev/null +++ b/mac-patcher/tools/README.txt @@ -0,0 +1,111 @@ +Outils de réparation Mac des AssetBundles +========================================= + +Ces scripts ont produit la réparation Mac du mod. Ils sont ici pour être +retrouvables et reproductibles, pas pour être jolis : ce sont des outils +d'atelier, en français, à usage interne Iron Squadron. + +Le paquet destiné aux développeurs du mod, en anglais, est ailleurs : +mac-support-package/. + + +LES DEUX CAUSES RACINES + +1. Pas de variante Metal. Les bundles ont été compilés pour + StandaloneWindows64 uniquement, entre 2019 et 2022. Quand TTS est passé à + Metal sur Mac, leurs shaders custom n'avaient aucune variante pour cette + API : figurines magenta. Rien à voir avec Unity 6, contrairement à ce qu'on + a cru pendant des semaines. + +2. La couleur de sommet vaut zéro sur Metal. Les shaders d'effets lumineux + lisent v.color, un canal qu'aucun mesh du mod ne possède (mesuré : 1 seul + sur 408, et il n'a pas de shader custom). DirectX et OpenGL remplacent un + canal absent par du blanc, Metal par du noir. Les passes étant en + Blend One One, multipliées par zéro elles n'ajoutent rien : sabres, yeux et + boucliers éteints, sans que rien ne paraisse cassé. Touche 12 bundles. + + +LA CHAÎNE, DANS L'ORDRE + +Deux voies selon qu'on a les sources du modèle ou non. Les 152 bundles à +réparer se répartissent en 143 par rebuild et 9 par greffe. + + Voie rebuild, quand les sources existent + + patch_shader_precision.py --apply # fixed/half -> float (précision Metal) + patch_shader_vertexcolor.py --apply # v.color -> blanc (effets lumineux) + Unity 6 -executeMethod BuildAllTargets.Run -target mac -out AssetBundles-mac + merge_all_bundles.py AssetBundles-win AssetBundles-mac AssetBundles-dual + patch_shader_precision.py --restore # remet les sources d'origine + DUAL_DIR=AssetBundles-dual install_dual_to_cache.py --install + + On ne rebuilde que la cible macOS : le SubShader Windows du bundle fusionné + est celui du build Windows, que la fusion ne touche pas. + + Voie greffe, quand il n'y a pas de sources + + Unity 2019.1.9f1 -executeMethod BuildMetalGraft.Run -out AssetBundles-graft + graft_metal_2019_1.py + install_grafted_to_cache.py --install + + C'est la voie à dérive nulle : le bundle publié garde ses maillages, ses + textures et ses matériaux inchangés, on ne lui ajoute qu'un SubShader. C'est + la voie des 8 orphelins sans sources, et aussi celle de stunt_double_bot_1, + écarté du rebuild parce que celui-ci lui ajoutait un socle que l'objet publié + n'a pas. + + La version d'Unity doit correspondre à celle du bundle publié. Les 248 + bundles se répartissent sur cinq versions : 2019.4.19f1 (144), 2019.1.9f1 + (83), 2019.1.0f2 (11), 2019.4.40f1 (9), 5.3.4f1 (1). Elle se lit dans les 200 + premiers octets du fichier, en clair après la signature UnityFS. + + Entre 2019.1 et 2019.4, la sérialisation des shaders change : les tables du + blob passent de plates à imbriquées. D'où deux scripts de fusion qui refusent + chacun le format de l'autre : + + merge_subshader_platforms.py listes imbriquées, champ stageCounts, Unity 6 + graft_metal_2019_1.py listes plates, Unity 2019.1 + + +POURQUOI UN SUBSHADER ENTIER ET PAS UNE PASSE FUSIONNÉE + +Les tables de liaison de paramètres (m_NameIndices, m_CommonParameters, +m_ConstantBufferBindings) sont stockées une fois par passe et partagées par +toutes les plateformes. DirectX et OpenGL cohabitent parce qu'ils partagent +cette disposition. Metal, lui, éclate les globals en VGlobals/FGlobals et remet +les offsets à zéro : greffer un programme Metal dans une passe DirectX lui donne +les mauvaises liaisons, et il rend faux sans aucun message d'erreur. + +Un shader peut en revanche déclarer plusieurs SubShaders, chacun avec ses +propres passes donc ses propres tables. On empile donc le SubShader macOS +derrière celui d'origine : Unity descend au suivant quand le premier n'a pas de +variante pour l'API courante. + + +PIÈGES RENCONTRÉS + +- La sauvegarde ne se juge pas à son existence mais à son contenu. Un bundle + simplement déposé au premier passage existe au second et se fait sauvegarder + alors que c'est déjà le nôtre. 60 entrées sur 114 étaient dans ce cas. Le + garde-fou est is_ours() : aucun bundle publié ne porte de variante Metal, donc + en trouver une prouve que le fichier vient de nous. +- Toujours greffer depuis le bundle publié, jamais depuis un bundle déjà greffé, + sinon on empile les SubShaders à chaque passage. +- macOS tue les vieux éditeurs Unity au lancement (SIGKILL, aucun log écrit), + avec une alerte « Unity est endommagé ». Ce n'est pas une quarantaine : la + réponse est Réglages Système -> Confidentialité et sécurité -> « Ouvrir quand + même ». Ne jamais cliquer « Placer dans la corbeille ». +- Certains shaders sont en latin-1 (l'en-tête « © Allen White ») : lire en + binaire, ne pas réencoder. +- UnityPy : m_Colors donne des dictionnaires modifiables, m_Floats des tuples + immuables. Pour modifier un float, reconstruire la liste. +- zsh ne découpe pas les variables non quotées : pour une longue liste de + chemins, passer par bash -c avec un tableau. + + +CE QU'ON NE TOUCHE JAMAIS + +- Les bundles sans shader custom : ils n'ont jamais été cassés. 114 sur 266. +- Les Custom Models (mesh + diffuse au lieu de bundle) : TTS leur applique son + propre matériau, ils ne peuvent pas être magenta. Ils sont majoritaires dans + le mod. diff --git a/mac-support-package/README.md b/mac-support-package/README.md deleted file mode 100644 index 84f5895ea..000000000 --- a/mac-support-package/README.md +++ /dev/null @@ -1,103 +0,0 @@ -# Making the mod's AssetBundles work on Mac - -Short version: **build each bundle twice and merge the two files.** One extra step -in whoever builds the bundles, and every mini from then on renders correctly on -both platforms. Nothing changes for Windows players. - ---- - -## What is broken and why - -Shader variants inside an AssetBundle are compiled **per graphics API**, decided -by the build target. The mod's bundles were built for Windows, so they carry -`d3d11` and `glcore` variants (we scanned them: 60 of 62 shaders are exactly that -pair). That was correct at the time, and it is why the mod used to work on Mac: -TTS ran OpenGL there. - -Since **TTS v14** the Mac player runs **Metal** and has no usable OpenGL path -left. `-force-glcore` reaches the process and is silently ignored. So the custom -shaders never find a variant they can load. TTS substitutes the Standard shader -where it can, which is why minis show their raw team-colour mask, and renders -**magenta** where it cannot, which is why the projectors look worst. - -Nothing is wrong with the shader code. It was simply never compiled for Metal. - -## The fix, in two parts - -### 1. One shader-source change, worth doing once and for all - -In `ColorReplacer.shader` (and the other `BucketheadBits` shaders), the team -colour swap is computed in `fixed` precision: - -```hlsl -fixed ramp = 1.0 - distance(c.rgb, _SwapColor.rgb); -fixed swapMask = saturate((ramp - _SwapCutoff) * _SwapContrast); -``` - -On DirectX, `fixed` and `half` are treated as **32-bit floats**. On Metal, `half` -is a real **16-bit float**. The mask is a near-binary threshold amplified by -`_SwapContrast` (5.0 by default), so in 16 bits the pixels sitting near the -threshold flip at random: speckled bases, cape linings left green, magenta -fringes along the swapped areas. - -**Changing `fixed` and `half` to `float` in these shaders is a no-op on Windows** -(they were already 32-bit there) and fixes Metal for good. That is the cleanest -place to fix it: once, in the source. - -### 2. Build each bundle twice, then merge - -Unity cannot produce a single bundle covering both platforms: ask for Metal in a -Windows build and it silently drops it. But a `Shader` object can declare several -**SubShaders**, and Unity falls through to the next one when the first has no -variant for the current graphics API. - -So: build the prefab for `StandaloneWindows64`, build it again for -`StandaloneOSX`, and stack the macOS SubShader behind the Windows one in the same -file. - -``` -# 1. build both (Editor menu: Assets > Build Bundle (Windows + macOS)) -# -> BiPlatformBundles/win/ and BiPlatformBundles/mac/ - -# 2. merge -pip install UnityPy -python3 merge_subshader_bundles.py BiPlatformBundles/win/ \ - BiPlatformBundles/mac/ - -# 3. upload as usual -``` - -The Windows SubShader stays first and byte-identical, so Windows players get -exactly what they get today. The extra SubShader is inert for them. - -## Files here - -- `BuildBiPlatformBundle.cs` — drop into any `Editor/` folder. Adds - **Assets > Build Bundle (Windows + macOS)**, and works in batch mode via - `-executeMethod BuildBiPlatformBundle.Run`. -- `merge_subshader_bundles.py` — the merge step. Requires `UnityPy`. - -## One trap, if you go digging - -Merging the variants **inside a single pass** does not work. The parameter -binding tables (`m_NameIndices`, `m_CommonParameters`, -`m_ConstantBufferBindings`) are stored once per pass and shared by every platform -in it, and Metal lays them out differently from DirectX (`VGlobals`/`FGlobals` -instead of `$Globals`, offsets reset to zero). The result loads, logs nothing, -and renders wrong, which costs a lot of time to diagnose. A SubShader carries its -own tables. It is also why `d3d11` and `glcore` coexist happily in the current -bundles: those two share the layout. - -## Status on our side - -Tested in game on **both** platforms with the same merged file: an A-A5 Speeder -Truck renders correctly on Mac and on Windows. - -Of the 190 bundles the mod references, 105 use no custom shader and were never -broken. 85 are affected, and 77 of those are already rebuilt and running. The -remaining 8 belong to seven older units nobody has the sources for any more -(Yoda, the Wookiee Warriors line, the Wookiee Chieftain, the Raddaugh Gnasp -Fluttercraft, the Infantry Support Platform, and the shared materials bundle used -by Kalani and Kraken). Those need a different route, or their sources. - -Happy to help wire this into your build, or to hand over the rebuilt bundles. diff --git a/mac-support-package/README.txt b/mac-support-package/README.txt new file mode 100644 index 000000000..57f671f62 --- /dev/null +++ b/mac-support-package/README.txt @@ -0,0 +1,135 @@ +Making the mod's AssetBundles work on Mac +========================================= + +Short version: build each bundle twice and merge the two files. One extra step +for whoever builds the bundles, and every mini from then on renders correctly on +both platforms. Nothing changes for Windows players. + + +WHAT IS BROKEN AND WHY + +Shader variants inside an AssetBundle are compiled per graphics API, decided by +the build target. The mod's bundles were built for Windows, so they carry d3d11 +and glcore variants (we scanned them: 60 of 62 shaders are exactly that pair). +That was correct at the time, and it is why the mod used to work on Mac: TTS ran +OpenGL there. + +Since TTS v14 the Mac player runs Metal and has no usable OpenGL path left. +-force-glcore reaches the process and is silently ignored. So the custom shaders +never find a variant they can load. TTS substitutes the Standard shader where it +can, which is why minis show their raw team-colour mask, and renders magenta +where it cannot, which is why the projectors look worst. + +Nothing is wrong with the shader code. It was simply never compiled for Metal. + + +THE FIX, IN THREE PARTS + +1. Two shader-source changes, worth doing once and for all +---------------------------------------------------------- + +In ColorReplacer.shader (and the other BucketheadBits shaders), the team colour +swap is computed in fixed precision: + + fixed ramp = 1.0 - distance(c.rgb, _SwapColor.rgb); + fixed swapMask = saturate((ramp - _SwapCutoff) * _SwapContrast); + +On DirectX, fixed and half are treated as 32-bit floats. On Metal, half is a real +16-bit float. The mask is a near-binary threshold amplified by _SwapContrast (5.0 +by default), so in 16 bits the pixels sitting near the threshold flip at random: +speckled bases, cape linings left green, magenta fringes along the swapped areas. + +Changing fixed and half to float in these shaders is a no-op on Windows (they +were already 32-bit there) and fixes Metal for good. That is the cleanest place +to fix it: once, in the source. + +The second change matters most for whatever you build next, because it hits any +mini with a glow effect. The BucketheadBits glow shaders multiply their effect by +the vertex colour: + + o.v.x = min(1.0f, viewSat * v.color.a); + float4 lerpColor = _FarColor * pow(...) * i.col.r * _Contrast; + +No mesh in the mod carries a Color channel. When the channel is missing, DirectX +and OpenGL hand the shader white (1,1,1,1) and the effect lights up; Metal hands +it black (0,0,0,0). The passes are Blend One One, so multiplied by zero they add +exactly nothing. The mesh renders, the glow does not, and nothing is logged. + +This one is nasty precisely because it is invisible: it does not go magenta, it +does not error, the model just looks flat on Mac. It had switched off 12 bundles +worth of lightsabers, IG-88's eyes and the Droideka's shield without anyone +noticing. Replacing v.color with white in these shaders restores exactly what +Windows already receives, and is a no-op there. We checked every mesh in the +published bundles first: exactly one carries a Color channel, and it uses no +custom shader. + +2. Build each bundle twice, then merge +-------------------------------------- + +Unity cannot produce a single bundle covering both platforms: ask for Metal in a +Windows build and it silently drops it. But a Shader object can declare several +SubShaders, and Unity falls through to the next one when the first has no variant +for the current graphics API. + +So: build the prefab for StandaloneWindows64, build it again for StandaloneOSX, +and stack the macOS SubShader behind the Windows one in the same file. + + # 1. build both (Editor menu: Assets > Build Bundle (Windows + macOS)) + # -> BiPlatformBundles/win/ and BiPlatformBundles/mac/ + + # 2. merge + pip install UnityPy + python3 merge_subshader_bundles.py BiPlatformBundles/win/ \ + BiPlatformBundles/mac/ + + # 3. upload as usual + +The Windows SubShader stays first and the merge does not touch it, so Windows +players get exactly what they get today. The extra SubShader is inert for them. + +3. When the sources are gone, graft instead of rebuilding +--------------------------------------------------------- + +Some of the older units have no usable sources any more, and one had a rebuild +that no longer matched the object you publish. You do not need the sources: a +Metal SubShader can be grafted straight into the published bundle. + +The one thing that matters is building the graft in the same Unity version the +bundle was made with. These were made with 2019.1.9f1, not the 2019.4 we first +assumed, and a graft from the wrong version loads without complaint and renders +wrong. Nine bundles took this route, with no model rebuilt and nothing else about +them touched. + + +FILES HERE + + BuildBiPlatformBundle.cs drop into any Editor/ folder. Adds + Assets > Build Bundle (Windows + macOS), and works + in batch mode via + -executeMethod BuildBiPlatformBundle.Run + merge_subshader_bundles.py the merge step. Requires UnityPy. + + +ONE TRAP, IF YOU GO DIGGING + +Merging the variants inside a single pass does not work. The parameter binding +tables (m_NameIndices, m_CommonParameters, m_ConstantBufferBindings) are stored +once per pass and shared by every platform in it, and Metal lays them out +differently from DirectX (VGlobals/FGlobals instead of $Globals, offsets reset to +zero). The result loads, logs nothing, and renders wrong, which costs a lot of +time to diagnose. A SubShader carries its own tables. It is also why d3d11 and +glcore coexist happily in the current bundles: those two share the layout. + + +STATUS ON OUR SIDE + +Tested in game on both platforms with the same merged file: an A-A5 Speeder Truck +renders correctly on Mac and on Windows. + +Of the 266 bundles the mod references, 114 use no custom shader and were never +broken. The other 152 are all repaired: 143 rebuilt from sources and merged, 9 +grafted. Nothing is left broken on Mac. They are running here, and they are +downloadable from the release linked in PR #600 if you want to try them before +deciding anything. + +Happy to help wire this into your build, or to hand over the repaired bundles.