Active Spell Overlay Customization Request
Willem07 opened this issue · 4 comments
Feature description
Please add my changes to the Active Spell in the user interface so it can be moved around the screen.
Feel free to edit the icon's position according to your preferences; it is centered by default.
package io.redspace.ironsspellbooks.gui.overlays;
import com.mojang.blaze3d.systems.RenderSystem;
import io.redspace.ironsspellbooks.IronsSpellbooks;
import io.redspace.ironsspellbooks.api.registry.SpellRegistry;
import io.redspace.ironsspellbooks.api.spells.AbstractSpell;
import io.redspace.ironsspellbooks.api.spells.ISpellContainer;
import io.redspace.ironsspellbooks.config.ClientConfigs;
import io.redspace.ironsspellbooks.item.CastingItem;
import io.redspace.ironsspellbooks.item.Scroll;
import io.redspace.ironsspellbooks.player.ClientMagicData;
import io.redspace.ironsspellbooks.registries.ItemRegistry;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.renderer.GameRenderer;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.client.gui.overlay.ForgeGui;
import net.minecraftforge.client.gui.overlay.IGuiOverlay;
public class ActiveSpellOverlay implements IGuiOverlay {
public static ActiveSpellOverlay instance = new ActiveSpellOverlay();
protected static final ResourceLocation WIDGETS_LOCATION = new ResourceLocation("textures/gui/widgets.png");
public final static ResourceLocation TEXTURE = new ResourceLocation(IronsSpellbooks.MODID, "textures/gui/icons.png");
public enum Anchor {
Center, TopLeft, TopRight, BottomLeft, BottomRight
}
public void render(ForgeGui gui, GuiGraphics guiHelper, float partialTick, int screenWidth, int screenHeight) {
Player player = Minecraft.getInstance().player;
if (player == null) return;
ItemStack stack = player.getMainHandItem();
AbstractSpell spell;
if (hasRightClickCasting(stack.getItem())) {
if (ISpellContainer.isSpellContainer(stack)) {
spell = ISpellContainer.get(stack).getSpellAtIndex(0).getSpell();
} else {
spell = ClientMagicData.getSpellSelectionManager().getSelectedSpellData().getSpell();
}
} else {
stack = player.getOffhandItem();
if (hasRightClickCasting(stack.getItem())) {
if (ISpellContainer.isSpellContainer(stack)) {
spell = ISpellContainer.get(stack).getSpellAtIndex(0).getSpell();
} else {
spell = ClientMagicData.getSpellSelectionManager().getSelectedSpellData().getSpell();
}
} else {
return;
}
}
if (stack.isEmpty() || spell == SpellRegistry.none()) {
return;
}
// Get position settings from ClientConfigs
int configOffsetX = ClientConfigs.ACTIVE_SPELL_OVERLAY_X_OFFSET.get();
int configOffsetY = ClientConfigs.ACTIVE_SPELL_OVERLAY_Y_OFFSET.get();
Anchor anchor = ClientConfigs.ACTIVE_SPELL_OVERLAY_ANCHOR.get();
// Determine the position based on the binding
int positionX = getPositionX(anchor, screenWidth) + configOffsetX;
int positionY = getPositionY(anchor, screenHeight) + configOffsetY;
guiHelper.blit(WIDGETS_LOCATION, positionX, positionY, 24, 22, 29, 24);
guiHelper.blit(spell.getSpellIconResource(), positionX + 3, positionY + 4, 0, 0, 16, 16, 16, 16);
float cooldownPercent = ClientMagicData.getCooldownPercent(spell);
if (cooldownPercent > 0 && !stack.getItem().equals(ItemRegistry.SCROLL.get())) {
int pixels = (int) (16 * cooldownPercent + 1f);
guiHelper.blit(TEXTURE, positionX + 3, positionY + 20 - pixels, 47, 87, 16, pixels);
}
}
private static boolean hasRightClickCasting(Item item) {
return item instanceof Scroll || item instanceof CastingItem;
}
private static int getPositionX(Anchor anchor, int screenWidth) {
switch (anchor) {
case TopLeft: return 20; // You can customize it as you wish
case TopRight: return screenWidth - 20 - 29; // Adjust the width and height of the icon
case BottomLeft: return 20; // Customize it as you like
case BottomRight: return screenWidth - 20 - 29; // Adjust the width and height of the icon
case Center:
default: return screenWidth / 2 - 14; // For the center, you can set the offset
}
}
private static int getPositionY(Anchor anchor, int screenHeight) {
switch (anchor) {
case TopLeft:
case TopRight: return 20; // Height for the top corners
case BottomLeft:
case BottomRight: return screenHeight - 20 - 24; // Adjust the height of the icon
case Center:
default: return screenHeight / 2 - 12; // For the center
}
}
}
package io.redspace.ironsspellbooks.config;
import io.redspace.ironsspellbooks.gui.overlays.ManaBarOverlay;
import io.redspace.ironsspellbooks.gui.overlays.RecastOverlay;
import io.redspace.ironsspellbooks.gui.overlays.SpellBarOverlay;
import io.redspace.ironsspellbooks.gui.overlays.ActiveSpellOverlay; // Added for the new class
import io.redspace.ironsspellbooks.gui.overlays.ManaBarOverlay.Anchor;
import io.redspace.ironsspellbooks.gui.overlays.ManaBarOverlay.Display;
import net.minecraftforge.common.ForgeConfigSpec;
public class ClientConfigs {
public static final ForgeConfigSpec.Builder BUILDER = new ForgeConfigSpec.Builder();
public static final ForgeConfigSpec.ConfigValue<Boolean> SHOW_FIRST_PERSON_ARMS;
public static final ForgeConfigSpec.ConfigValue<Boolean> SHOW_FIRST_PERSON_ITEMS;
public static final ForgeConfigSpec.ConfigValue<Boolean> REPLACE_GHAST_FIREBALL;
public static final ForgeConfigSpec.ConfigValue<Boolean> REPLACE_BLAZE_FIREBALL;
public static final ForgeConfigSpec.ConfigValue<Integer> MANA_BAR_Y_OFFSET;
public static final ForgeConfigSpec.ConfigValue<Integer> MANA_BAR_X_OFFSET;
public static final ForgeConfigSpec.ConfigValue<Integer> MANA_TEXT_X_OFFSET;
public static final ForgeConfigSpec.ConfigValue<Integer> MANA_TEXT_Y_OFFSET;
public static final ForgeConfigSpec.ConfigValue<Boolean> MANA_BAR_TEXT_VISIBLE;
public static final ForgeConfigSpec.ConfigValue<Boolean> ENABLE_BOSS_MUSIC;
public static final ForgeConfigSpec.ConfigValue<ManaBarOverlay.Anchor> MANA_BAR_ANCHOR;
public static final ForgeConfigSpec.ConfigValue<ManaBarOverlay.Display> MANA_BAR_DISPLAY;
public static final ForgeConfigSpec.ConfigValue<ManaBarOverlay.Display> SPELL_BAR_DISPLAY;
public static final ForgeConfigSpec.ConfigValue<Integer> SPELL_BAR_Y_OFFSET;
public static final ForgeConfigSpec.ConfigValue<Integer> SPELL_BAR_X_OFFSET;
public static final ForgeConfigSpec.ConfigValue<SpellBarOverlay.Anchor> SPELL_BAR_ANCHOR;
public static final ForgeConfigSpec.ConfigValue<RecastOverlay.Anchor> RECAST_ANCHOR;
public static final ForgeConfigSpec.ConfigValue<Integer> RECAST_Y_OFFSET;
public static final ForgeConfigSpec.ConfigValue<Integer> RECAST_X_OFFSET;
public static final ForgeConfigSpec.ConfigValue<ActiveSpellOverlay.Anchor> ACTIVE_SPELL_OVERLAY_ANCHOR;
// New parameters for ActiveSpellOverlay
public static final ForgeConfigSpec.ConfigValue<Integer> ACTIVE_SPELL_OVERLAY_X_OFFSET;
public static final ForgeConfigSpec.ConfigValue<Integer> ACTIVE_SPELL_OVERLAY_Y_OFFSET;
public static final ForgeConfigSpec SPEC;
public ClientConfigs() {
}
static {
BUILDER.comment("##############################################################################################");
BUILDER.comment("## ##");
BUILDER.comment("## ##");
BUILDER.comment("## ##");
BUILDER.comment("## ##");
BUILDER.comment("## ##");
BUILDER.comment("## ATTENTION: These are client configs. For gameplay settings, go to the SERVER CONFIGS ##");
BUILDER.comment("## ##");
BUILDER.comment("## ##");
BUILDER.comment("## ##");
BUILDER.comment("## ##");
BUILDER.comment("## ##");
BUILDER.comment("##############################################################################################");
BUILDER.comment("");
// Configuration for ManaBar
BUILDER.push("UI");
BUILDER.push("ManaBar");
BUILDER.comment("By default (Contextual), the mana bar only appears when you are holding a magic item or are not at max mana.");
MANA_BAR_DISPLAY = BUILDER.defineEnum("manaBarDisplay", Display.Contextual);
BUILDER.comment("Used to adjust mana bar's position (11 is one full hunger bar up).");
MANA_BAR_X_OFFSET = BUILDER.define("manaBarXOffset", 0);
MANA_BAR_Y_OFFSET = BUILDER.define("manaBarYOffset", 0);
MANA_BAR_TEXT_VISIBLE = BUILDER.define("manaBarTextVisible", true);
MANA_BAR_ANCHOR = BUILDER.defineEnum("manaBarAnchor", Anchor.Hunger);
MANA_TEXT_X_OFFSET = BUILDER.define("manaTextXOffset", 0);
MANA_TEXT_Y_OFFSET = BUILDER.define("manaTextYOffset", 0);
BUILDER.pop();
// Configuration for SpellBar
BUILDER.push("SpellBar");
BUILDER.comment("By default (Always), the spell bar always shows the spells in your equipped spellbook. Contextual will hide them when not in use.");
SPELL_BAR_DISPLAY = BUILDER.defineEnum("spellBarDisplay", Display.Always);
BUILDER.comment("Used to adjust spell bar's position.");
SPELL_BAR_X_OFFSET = BUILDER.define("spellBarXOffset", 0);
SPELL_BAR_Y_OFFSET = BUILDER.define("spellBarYOffset", 0);
SPELL_BAR_ANCHOR = BUILDER.defineEnum("spellBarAnchor", SpellBarOverlay.Anchor.Hotbar);
BUILDER.pop();
// Configuration for RecastOverlay
BUILDER.push("RecastOverlay");
RECAST_ANCHOR = BUILDER.defineEnum("recastAnchor", RecastOverlay.Anchor.TopCenter);
RECAST_X_OFFSET = BUILDER.define("recastXOffset", 0);
RECAST_Y_OFFSET = BUILDER.define("recastYOffset", 0);
BUILDER.pop();
// Configuration for ActiveSpellOverlay
BUILDER.push("ActiveSpellOverlay");
BUILDER.comment("Adjusts the position of the Active Spell Overlay on the screen.");
ACTIVE_SPELL_OVERLAY_X_OFFSET = BUILDER.define("activeSpellOverlayXOffset", 0);
ACTIVE_SPELL_OVERLAY_Y_OFFSET = BUILDER.define("activeSpellOverlayYOffset", 0);
ACTIVE_SPELL_OVERLAY_ANCHOR = BUILDER.defineEnum("activeSpellOverlayAnchor", ActiveSpellOverlay.Anchor.Center);
BUILDER.pop();
// Configuration for Animations
BUILDER.push("Animations");
BUILDER.comment("What to render in first person while casting.");
SHOW_FIRST_PERSON_ARMS = BUILDER.define("showFirstPersonArms", true);
SHOW_FIRST_PERSON_ITEMS = BUILDER.define("showFirstPersonItems", true);
BUILDER.pop();
// Configuration for Renderers
BUILDER.push("Renderers");
BUILDER.comment("By default, both fireballs are replaced with an enhanced model used by fire spells.");
REPLACE_GHAST_FIREBALL = BUILDER.define("replaceGhastFireballs", true);
REPLACE_BLAZE_FIREBALL = BUILDER.define("replaceBlazeFireballs", true);
BUILDER.pop();
// Configuration for Music
BUILDER.push("Music");
ENABLE_BOSS_MUSIC = BUILDER.define("enableBossMusic", true);
BUILDER.pop();
SPEC = BUILDER.build();
}
}
How it improves the player experience
Some interfaces from other mods overlap with the active spell, so I decided to move it to a different location.
Your request makes sense it is just not at the top of our list to look at right now. If you wanted to get it into the mod in the short term a pull request with the changes would be the way to go.
I have a few thoughts on this.
- What version of the mod are you referring to?
- If we add configurability to this it should follow the same mechanics as our other overlays (see SpellBarOverlay for how it does anchoring + offsets.)
- Any suggested code changes of this scale should come in the form of a pull request.
- The default configuration for a change like this should be to mirror the current behavior
Mod Version: irons_spellbooks-1.20.1-3.4.0.2
I’m not a programming expert, and this was my first time coding in Java.
I made some changes to my modpack to prevent conflicts with interfaces from other mods, and I wanted to share a small addition for customizing the config, which requests a feature for interface customization.
I was surprised to find that any interface from your mod could be moved, except for the active spell.
If it’s convenient for you, feel free to take a small part of the code and develop it further in the future to integrate it into the mod itself.
closing because feature requests are now exclusively being handled on discord https://discord.gg/TRzEdrndM2