
This is a client-side rendering optimization mod for SlashBlade: Resharped, designed to eliminate severe FPS drops when holding a blade, swinging, rendering dropped blades, using shaders, or loading YSM models.
In one sentence: holding FPS doubles, swinging triples, and dropped high-poly blades get a 30x boost.
Mod Version: 1.0.2
Test Configuration: AMD Ryzen 7 9700X + NVIDIA RTX 5070 Ti
Second-person perspective, BSL shaders, Blade: Alchemy Kingdom
| Scenario | Vanilla | Accelerated Render | A Belated Gift | Improvement (vs Vanilla) |
|---|---|---|---|---|
| Holding Blade | 359 | 412 | 810 | +126% |
| Swinging | 220 | 248 | 620 | +182% |
| 17 High-Poly Dropped Blades | 61 | 425 | 730 | +1097% |
| Scenario | Vanilla | Accelerated Render | A Belated Gift | Improvement (vs Vanilla) |
|---|---|---|---|---|
| Holding Blade | 208 | 330 | 381 | +83% |
| Swinging | 115 | 153 | 365 | +217% |
| 17 High-Poly Dropped Blades | 29 | 240 | 258 | +1134% |
| Scenario | Vanilla | Accelerated Render | A Belated Gift | Improvement (vs Vanilla) |
|---|---|---|---|---|
| No Shaders · Holding | 374 | 398 | 724 | +94% |
| No Shaders · Swinging | 208 | 362 | 605 | +191% |
| Shaders · Holding | 215 | 301 | 374 | +74% |
| Shaders · Swinging | 172 | 261 | 345 | +101% |
Vanilla rendering traverses every group, face, and vertex of the OBJ model on each frame. This mod "bakes" the data into a GPU-friendly format at load time, then simply reuses it every frame thereafter.
Blade bodies, sheaths, item icons, blades on stands, and dropped blades all share a 96 MiB LRU cache. The second time the same blade appears, it reuses the data already uploaded to VRAM instead of resubmitting vertices.
Enchantment glints also get their own dedicated static cache, so they no longer drag down performance.
Vanilla calculates full PMD vertex skinning for every swing, even though only two bone anchor points are actually used. This mod skips the useless vertex calculations and keeps only the bone poses.
Full detail at close range, fewer layers at medium range, and only the core body at long range — with further simplification under shaders.
Models, textures, and RenderTypes are pre-warmed before you even enter the game. No sudden stutter when swinging a blade or opening your inventory for the first time.
Caches are automatically cleared when you exit a world or reload resources — performance stays consistent over time.
Retains the RenderOverrideEvent. If dynamic UVs, dynamic transparency, or uncacheable meshes are detected, it automatically falls back to vanilla rendering — no crashes.
Not compatible with [Accelerated Render] — both mods overlap in functionality. Installing them together may cause rendering glitches or performance degradation.
This API is intended for SlashBlade addons that need to replace the slash effect model or texture. The addon only selects the resources, while A Belated Gift continues to handle distance-based LOD, shader compatibility, mesh optimization, and resource warm-up.
After adopting this API, an addon must not use a Mixin to cancel SlashEffectRenderer.render. Cancelling that method prevents the registry from being reached.
Register the rule from an enqueued FMLClientSetupEvent task:
import cn.star.a_belated_gift.api.client.SlashEffectRenderRegistry;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.player.Player;
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
private static final ResourceLocation RULE_ID =
new ResourceLocation("example", "special_blade_slash");
private static final ResourceLocation SLASH_TEXTURE =
new ResourceLocation("example", "model/util/special_slash.png");
private static void onClientSetup(FMLClientSetupEvent event) {
event.enqueueWork(() -> SlashEffectRenderRegistry.registerTexture(
RULE_ID,
100,
effect -> effect.getOwner() instanceof Player player
&& player.getMainHandItem().is(EXAMPLE_BLADE.get()),
SLASH_TEXTURE
));
}
registerTexture continues to use SlashBlade's default model/util/slash.obj model.
import cn.star.a_belated_gift.api.client.SlashEffectRenderDefinition;
import cn.star.a_belated_gift.api.client.SlashEffectRenderRegistry;
private static final SlashEffectRenderDefinition SPECIAL_SLASH =
new SlashEffectRenderDefinition(
new ResourceLocation("example", "model/util/special_slash.obj"),
new ResourceLocation("example", "model/util/special_slash.png")
);
private static void onClientSetup(FMLClientSetupEvent event) {
event.enqueueWork(() -> SlashEffectRenderRegistry.register(
new ResourceLocation("example", "special_blade_slash"),
100,
effect -> effect.getOwner() instanceof Player player
&& player.getMainHandItem().is(EXAMPLE_BLADE.get()),
SPECIAL_SLASH
));
}
This register overload automatically adds the definition's OBJ and texture to the warm-up list.
Implement SlashEffectRenderProvider when the definition must be selected dynamically from the effect state:
import cn.star.a_belated_gift.api.client.SlashEffectRenderDefinition;
import cn.star.a_belated_gift.api.client.SlashEffectRenderProvider;
import mods.flammpfeil.slashblade.entity.EntitySlashEffect;
import java.util.Collection;
import java.util.List;
public final class ExampleSlashProvider implements SlashEffectRenderProvider {
private static final SlashEffectRenderDefinition BLUE =
SlashEffectRenderDefinition.withTexture(
new ResourceLocation("example", "model/util/blue_slash.png"));
private static final SlashEffectRenderDefinition RED =
SlashEffectRenderDefinition.withTexture(
new ResourceLocation("example", "model/util/red_slash.png"));
@Override
public SlashEffectRenderDefinition resolve(EntitySlashEffect effect) {
if (!(effect.getOwner() instanceof Player player)
|| !player.getMainHandItem().is(EXAMPLE_BLADE.get())) {
return null;
}
return effect.getIsCritical() ? RED : BLUE;
}
@Override
public Collection<SlashEffectRenderDefinition> warmupDefinitions() {
return List.of(BLUE, RED);
}
}
event.enqueueWork(() -> SlashEffectRenderRegistry.register(
new ResourceLocation("example", "dynamic_slash"),
200,
new ExampleSlashProvider()
));
Returning null from resolve means that the current rule does not match. The registry then checks the next provider. Every resource that may be returned should be declared through warmupDefinitions.
null definition wins.boolean removed = SlashEffectRenderRegistry.unregister(
new ResourceLocation("example", "special_blade_slash")
);
Unregistering only affects subsequent slash effect selection. Resources that have already been warmed are managed by Minecraft's resource lifecycle.