Mineuniverse
Mods
Fantasy Performance Fix (FantasyPF)

Fantasy Performance Fix (FantasyPF)

MOD
Fixed an issue where using ..Fantasy Ending.. caused the frame rate to drop by approximately 10 FPS.
by 15a_igoa
Download Claim this project
107 downloads
0 likes
Updated Oct 14, 2026
0 hypes
Addons Bug Fixes Performance
Advertisement Remove ads with Premium →

This mod was created with the assistance of Claude (Anthropic). このModはAnthropic社のAIモデル「Claude」の支援を受けて作成されました。

English


Fantasy Ending's EntityASMUtil.getHealthDelta(LivingEntity) acquires a SynchedEntityData ReadWriteLock on every single call. This method is called from nearly every LivingEntity#getHealth() call in the game (redirected there via ASM, through special_getHealth), as well as from special_getHealthDelta / special_isAlive / special_isDeadOrDying. Because health bars, nameplates, and other rendering code call getHealth() extremely often, this added up to a non-trivial cost on the render thread.

This mod is an external Mixin patch — it does not modify Fantasy Ending's own source at all. It works by:

  1. Adding a cached delta-value field to LivingEntity (HealthDeltaEC)
  2. Hooking Entity#onSyncedDataUpdated (the common callback fired for both local writes and incoming network sync packets) to invalidate the cache only when FE_GET_HEALTH_DATA actually changes
  3. Injecting into EntityASMUtil#getHealthDelta so that, when the cache is valid, the lock-based read is skipped entirely and the cached value is returned immediately

Why not just hook setHealthDelta?

FE_GET_HEALTH_DATA is network-synced data. On the client, its value can change purely from an incoming sync packet — without setHealthDelta ever being called locally (e.g. when another player's or mob's health is synced to you). Relying on setHealthDelta alone would miss that path and leave stale cached values on the client, so this mod hooks vanilla Entity#onSyncedDataUpdated instead, which fires for both paths. Note that in Minecraft 1.20.1, onSyncedDataUpdated has two overloads (EntityDataAccessor<?> for local writes, List<SynchedEntityData.DataValue<?>> for batched network sync) — both are hooked explicitly by full method descriptor to avoid Mixin's ambiguous by-name resolution.

Known limitations

  • special_isAlive / special_isDeadOrDying also call getHealthDelta internally, so they benefit from this cache automatically. The same invalidation logic applies, but please report anything that looks off around health-based alive/dead checks.
  • Scope is intentionally limited to getHealthDelta. Other costs found during profiling (PostProcessingShaders#renderShaders/canUse, GoetyRevelationFix's ClientEventsHandler#drawTrails) are out of scope for this mod.

日本語


Fantasy Ending の EntityASMUtil.getHealthDelta(LivingEntity) は、呼ばれるたびに SynchedEntityDataのReadWriteLockを取得してから値を読みに行く実装になっています。 このメソッドはASMによってLivingEntity#getHealth()のほぼ全呼び出し(special_getHealth 経由)や、special_getHealthDelta/special_isAlive/special_isDeadOrDyingからも 呼ばれるため、体力バーやネームプレート表示などRender thread側の描画コードから 極めて高頻度に叩かれ、無視できないコストになっていました。

このModは Fantasy Ending本体のソースは一切書き換えず、外付けのMixinパッチとして

  1. LivingEntityにdelta値のキャッシュ用フィールドを追加 (HealthDeltaEC)
  2. Entity#onSyncedDataUpdated(ローカルでの書き込み・ネットワーク同期パケット受信の どちらでも呼ばれる共通フック)を検知して、FE_GET_HEALTH_DATAが実際に更新された 時だけキャッシュを無効化する
  3. EntityASMUtil#getHealthDeltaにMixinを差し込み、キャッシュが有効なら ReadWriteLockを伴う読み取りそのものをスキップして即座にキャッシュ値を返す

という形で実現しています。

なぜsetHealthDeltaの呼び出しだけをトリガーにしなかったか

FE_GET_HEALTH_DATAはネットワーク同期対象のデータです。クライアント側では、 setHealthDeltaをローカルで一度も呼ばなくても、サーバーからの同期パケット受信 だけでこの値が書き換わるケースがあります(他プレイヤーやMobの体力表示など)。 setHealthDeltaの呼び出しだけをトリガーにすると、このケースを取りこぼして クライアント側で古い値が表示され続けるバグになるため、あえて vanilla の Entity#onSyncedDataUpdated側で検知する設計にしています。1.20.1では onSyncedDataUpdatedに2つのオーバーロード(ローカル書き込み用の EntityDataAccessor<?>版、ネットワーク同期パケットの一括反映用の List<SynchedEntityData.DataValue<?>>版)が存在するため、Mixinの あいまいな名前解決を避けるべく両方とも完全なディスクリプタ指定でフックしています。

既知の注意点

  • special_isAlive/special_isDeadOrDyingも内部でgetHealthDeltaを呼んでいるため、 今回のキャッシュの恩恵を自動的に受けます。無効化ロジックは同じなので基本問題ない はずですが、体力に応じた生死判定まわりで挙動がおかしいと感じたら教えてください。
  • 今回はスコープをgetHealthDelta一点に絞っています。プロファイルで見つかった PostProcessingShaders#renderShaders/canUseやClientEventsHandler#drawTrails (GoetyRevelationFix側)は今回のパッチ範囲外です。
FantasyPF-1.20.1-1.0.0.jar
MC Client, 1.20.1, Forge, Server
Beta 2026-10-04 Get
Advertisement Remove ads with Premium →

You Might Also Like