Fort様専用・作業記録
THM-Addons のパケットマイナーを QuinnAddon へ移植し、原典の不具合9件を直した作業の全記録。公開ページの日本語版に、Fort様向けの補足を加えたもの。
compileJava → jar → remapJar まで完走し、jar にモジュールとミックスイン3本が入っている。| ファイル | 中身 |
|---|---|
| fixed/ Speedmine.java | 不具合9件を直した版。1,440行。採用するのはこちら |
| port-only/ Speedmine.java | 挙動は原典のまま、ビルドが通る形にしただけの版。1,384行。比較の基準点 |
| changes.diff | 上2つの差分249行。修正だけを独立して読める |
| mixin/ 3本 | シーケンス番号・リブレイクのロールバック・Air Miner の接地偽装 |
| ファイル | 中身 |
|---|---|
| QuinnAddon-Test -0.1.0.jar |
テスター用。Speedmine と2モジュールのみ。48KB。mod id もパッケージも本家と別なので共存できる |
| quinnaddon-test -source.zip |
その jar を作ったプロジェクト一式 |
| QuinnAddon-v0.4.0 -with-speedmine.jar |
本家のタグ v0.4.0 に全部マージしてビルドが通ることの証明。リリースではない |
| SHA256SUMS.txt | 上3つのハッシュ |
ハッシュが証明するのは「転送中に化けていないこと」だけで、中身の安全性は何も保証しない。だから同じ場所にソースを置いてある。
原典のヘッダに、次の記載がある。これは好意ではなく使用条件。
Copyright (c) THM Addons contributors. Credit the devs, keep the link.
By using this code you agree to the license terms and to keep your repo public.
したがって移植版にも THM へのリンクと出典を残した。QuinnAddon は public なので「公開リポジトリのままにする」条件も満たしている。このヘッダを消すとライセンス違反になるので、Quinn にもそう伝えてある。クローズドソース配布が選べなかったのも、この条項による。
THM は Mojang マッピング、QuinnAddon は Yarn。全クラス名・メソッド名が違うので、1行もそのままでは通らない。加えて THM は自前の支援クラスに依存しており、QuinnAddon にはどれも存在しない。
| THM | 移植版 |
|---|---|
| Mojangマッピング | Yarn。mc.level→mc.world、ServerboundPlayerActionPacket→PlayerActionC2SPacket |
| InventoryManager | サーバースロットの自前追跡(UpdateSelectedSlotC2SPacket) |
| RangeUtils | ファイル内の isInRange() / closestFace() |
| RenderUtilsTHM | Render3DEvent.renderer.box() |
| 手書きの採掘速度式 | BlockUtils.getBreakDelta(slot, state)。Meteor が既に持っていた |
| ClientLevelミックスイン | Meteor の BlockUpdateEvent |
| シーケンス送信アクセサ | 同じ発想で、自前のインボーカーを ClientPlayerInteractionManager に |
| PaketLimiter等 | 削除。THM固有 |
| fromTag()設定移行 | 削除。移行対象なし |
とくに大きいのは採掘速度の式。THM はこれを手書きし、しかも2箇所に重複して、内容が食い違っていた。Meteor が同じ計算を持っているので、移植版では丸ごと消えている。ワールド更新用のミックスインも不要になった。
設定は35項目すべて移植済みで、欠落も追加もない。以下は挙動の差で、いずれも QuinnAddon に対応する仕組みが無いことに由来する。
isUsingItem() のみ。AutoTotemPlus と枠を奪い合うなら共有ロックが要るBLOCK_BREAK_SPEED 属性だけ掛けていない。通常1.0なので実害はほぼ無い断ったクリックが完全に無反応だった
判定前にイベントを cancel していたため、multitask off でアイテム使用中にブロックを左クリックすると、パケット採掘もバニラ採掘もせず何も起きなかった。引き受けたときだけ cancel するようにした。
requestBreak がモジュール全体を止めうる
空気かどうかしか見ていないため、掘れないブロックを渡されると進捗ゼロのまま primary 枠を永久に占有した。検証と3秒の停滞タイムアウトを追加。原典の未使用フィールド startMs は、このタイムアウトを入れ忘れた痕跡に見える。
キュー追加1箇所だけ immutable() が無い
他3箇所には付いていた。現在の呼び出し元では表に出ないが、MutableBlockPos が1つ入るだけで中身が後から書き換わる。
差し替えられたブロックを掘り続ける
開始時の state を保持したまま削除判定だけが現在のワールドを見るため、古い硬度で進捗が進み、破壊パーティクルも別ブロックのものになる。
surround が1段ずれる
敵の Y を Math.round していたため、ハーフブロック・雪・ソウルサンドの上でリング全体が上にずれる。floor に修正。
死亡モーション中の敵を狙う
isSpectator は見ていたが isAlive を見ていなかった。
道具探索が「道具なし」を返せない
初期値 -1 は素手でも超えるため、該当分岐が全部死にコード。同点で常に低い番号が勝つので、手に持っている最適な道具からわざわざ持ち替えていた。選択中スロットを起点にした。
同じタイムアウトが単位違いで二重管理
ms と ns で別々に書かれていた。定数1つから導出するようにした。
枠線が rebreak-mode Off を無視
他のリブレイク判定は全てモードを見ているのに、描画だけ見ていなかった。
tps-sync の既定 off。 進捗が実時間×20tick前提になり、ラグ時に STOP が早すぎる。ping から閾値を出す、19TPS を切ったら自動同期、といった対応は「修正」ではなく「機能追加」なので別件にしたMinecraft 1.21.11、Yarn 1.21.11+build.3、meteor-client:1.21.11-SNAPSHOT でビルド成功。gradlew build が compileJava → jar → remapJar まで完走し、jar に Speedmine.class とアクセサ3本が入っている。
途中で実際に出た不具合は1件。PendingUpdateManager は net.minecraft.client.network にあり(client.world ではない)、ClientWorld.getPendingUpdateManager() は非公開だった。これが2本目のミックスインが要る理由。怪しいと事前に挙げていた isGliding()・PlayerMoveC2SPacket.Full・getSelectedSlot() は全て正しかった。
覆っていないこと: ゲーム内で一度も動かしていない。ミックスインはコンパイルも登録も済んでいるが、実行時に適用されるか、実戦のアンチチートがどう反応するかは未検証。
Quinn の元投稿は「FutureClient / Mio の speedmine、とくに insta rebreak の水準か」だった。全文を読んだ上での所見。
Strict は確認待ち、Strong は確認も TPS 待ちも飛ばす、Bypass は1回確認が取れるまで Strict でその後 Strong。アンチチートを見ながら攻撃性を上げる設計OnPacket ではサーバーの更新到着に即応し、次の client tick を待たない。速さの源はここdebug-rebreak が秒間の確定リブレイク数をモジュール名の横に出す。作者が数字を見ながら詰めた形跡実際に同水準かは読んで分かることではなく測って分かることで、ゲーム内未検証。ただし答えは設定1つ分の距離にある。debug-rebreak を入れて、他のクライアントも同条件で並べて数字を比べればよい。
どちらも依頼外。Fort様の持ち込みで、こちらの判断で入れた。Speedmine はどちらにも依存していないので、外しても何も壊れない。公開ページにも「頼まれていない」と明記してある。
両方とも、そもそもコンパイルが通らなかった。 InventoryCleaner は Category.Misc(Category はクラスで、正しくは Categories)。AutoAccept は存在しない Addon クラスと utils.Utils を参照し、さらに GameProfile.getName() が record 化で name() になっていた。
/tpy を送っていた。PvPサーバーでは実害がある。チャット形式のメッセージを無視し、名前がタブリストに実在することを要求するようにした/tpy も設定項目にした未対応:InventoryCleaner のオフハンド(走査範囲外)、AutoAccept のチャット判定が発見的手法である点(珍しい文面形式なら抜けうる。タブリスト照合がその保険)。
SurroundPlus と LogStripper が各自で持ち替え、Speedmine も自前で追跡する羽目になった。cpvp では置きながら掘るので同時に動き、いずれどちらかが相手の手元から道具を奪う。THM は単一の InventoryManager に全モジュールが優先度を問い合わせる形で解決している。この移植で唯一、モジュールの内側では直せない差fabric.mod.json が "id": "addon-template" なので、テンプレートを未改造で使った他のアドオンと衝突する。sources もテンプレートのリポジトリを指したままv0.4.0 が指すコミットで build.gradle.kts が 0.2.3 のまま。ソースからビルドした人だけが踏むFort様に指摘されて見つかった、私の側の不手際。公開ページには書いていない。
swap-mode の表示名を消していた。「Keep for Next Tick」等のラベルが、素の定数名で表示される状態だった原因は、移植中に「これは THM 固有だから落としてよい」と判断したものの中に、固有でないものが混ざっていたこと。設定35項目とメソッドを機械的に突き合わせて洗い出し、全部直した。最初からその突き合わせをしてから報告すべきだった。
もう1件、公開ページの <section> 開始タグを節の差し替え時に落とし、HTML構造を壊していた。見た目はほぼ変わらなかったが、後で気づいて修復した。