File Details
Runic Skills 1.0.0 (Forge 1.20.1)
- R
- Apr 24, 2026
- 1.15 MB
- 1.1K
- 1.20.1
- Forge
File Name
runicskills-1.0.0.jar
Supported Versions
- 1.20.1
Curse Maven Snippet
[1.0.0] - 2026-04-24
First stable release. Consolidates all 0.9.x work (item-lock master toggle, perk/passive kill switches, perk-swap cooldown, perk-group datapacks, Legendary Tabs hardening, tooltip/config fixes) under a 1.0 milestone. No further pre-1.0 versions will be cut.
Added
maxActivePerksconfig (HandlerCommonConfig, groupgeneral, default0= unlimited, range0–256). Caps the number of perks a player can have enabled at once. Enforced server-side inTogglePerkSPon therank 0 → ≥1transition (rank-ups on already-active perks bypass the cap, matching existing school-attunement semantics). Iron's Spells school attunements count against this cap in addition toironsMaxSchoolSelections. Mirrored throughCommonConfigSyncCP.disabledPerks/disabledPassiveskill-switch lists (HandlerCommonConfig,@ListGroupofString). Disabled entries cannot be enabled / leveled-up and their effects are suppressed; rank and level data are preserved in NBT so re-enabling restores state. Perks:Perk.isEnabled()returnsfalsefor disabled perks, so every event handler short-circuits automatically. Passives:RegistryAttributes.modifierAttributespassesenabled=falsetoamplifyAttribute, which removes the modifier — single choke point means all attribute effects drop to zero./skillsreloadnow re-runsmodifierAttributesfor every connected player so passive-disable changes take effect without relog. Registry path ("berserker") and full-id ("runicskills:berserker") forms are both accepted. Mirrored throughCommonConfigSyncCP.perkSwapCooldownTicksconfig (HandlerCommonConfig, default0= no cooldown, range0–72000). Per-player cooldown between perk enables. Piggybacks on the existingperkCooldownsmap via newSkillCapability.COOLDOWN_PERK_SWAPconstant, which already ticks down every server tick viaTickEventHandler. Applies only on rank-0 → rank-≥1 transitions; rank-ups and disables bypass. Persists in save NBT so logging out during cooldown preserves remaining time.skillLevelUpCostMultiplierconfig (HandlerCommonConfig, default1.0, range0.1–10.0). Scales the vanilla XP cost of leveling a skill. Applied in bothSkillLevelUpSP.requiredPoints(XP-points cost) andrequiredExperienceLevels(level-gate) so high-level players can't bypass an increased cost. Mirrored throughCommonConfigSyncCPso the GUI cost display stays synced with the server.- Data-driven perk groups — new datapack loader at
data/<namespace>/perk_groups/*.json. Schema:{ "max_active": int, "perks": [string], "message": string? }. New classes:PerkGroup(record),PerkGroupManager(static volatile map,firstBlockingGroup(capability, perkName)helper),PerkGroupsReloadListener(extends ForgeSimpleJsonResourceReloadListener, subscribed viaAddReloadListenerEvent),PerkGroupsSyncCP(new PLAY_TO_CLIENT packet, sent on login and/skillsreload). Enforced inTogglePerkSPalongside the existing hardcoded school-attunement check — both systems run independently. No default groups are shipped; opt-in for pack makers. Lenient JSON parsing tolerates trailing commas / comments. Per-file parse errors are logged and skipped without blocking the rest of the load.
Changed
- Bumped network channel
PROTOCOL_VERSIONfrom3to4. Wire format ofCommonConfigSyncCPhas grown (six new fields:maxActivePerks,disabledPerks,disabledPassives,perkSwapCooldownTicks,skillLevelUpCostMultiplier; plus the newPerkGroupsSyncCPpacket). Old clients connected to 0.9.9 servers (and vice versa) will get a clean connection refusal instead of a silent state-corruption bug. Please ensure clients and servers update together. /skillsreloadnow also broadcastsPerkGroupsSyncCPto every connected player so datapack perk-group changes propagate without relog.Perk.isEnabled(Player)andPerk.isEnabled()now consultRegistryPerks.isDisabled(perk)before returning true, covering every perk-effect event handler in a single choke point.RegistryAttributes.modifierAttributesnow checksRegistryPassives.isDisabled(passive)per-passive and removes rather than adds the attribute modifier for disabled entries.
Fixed
- Item-lock requirement tooltips ignored the
enableItemLocksmaster toggle.RegistryClientEvents.onTooltipDisplayappended the "Requirements:" block wheneverHandlerSkill.getValue(...)returned a non-null list, without consulting the config that gates server-side enforcement inSkillCapability.canUse(...). Players who disabled item locks could freely use tools like the trident but still saw "Requires Level X" text, leading to widespread confusion that the lock was still active. Fixed by checkingHandlerCommonConfig.HANDLER.instance().enableItemLocksbefore rendering — when locks are off, the requirement block is hidden so the UI matches enforcement. The synced value fromCommonConfigSyncCPis authoritative on joined clients; pre-join/main-menu tooltips fall back to the local config value, matching the existing behavior ofClientCapabilityAccess.canUseItemClient. - Mod failed to load when Legendary Tabs was not installed.
RunicSkillsClient$ClientProxyis a@Mod.EventBusSubscriberclass, so Forge'sAutomaticEventSubscriber.injectloads it at mod construction viaClass.forName(..., true, loader). TheclientSetupmethod contained an inline lambda() -> TabsMenu.register(new LegendaryTabRunicSkills()), which the Java compiler desugared into a syntheticlambda$clientSetup$3method on ClientProxy itself. The JVM verifier walks that method body at class-load time, finds theINVOKESTATIC sfiomn/.../TabsMenu.register(TabBase)+NEW com/otectus/.../LegendaryTabRunicSkillspair, and has to check thatLegendaryTabRunicSkillsis assignable toTabBase. That assignability check eager-resolvesTabBase, which fails withNoClassDefFoundErrorwhen Legendary Tabs is absent — even though theif (LegendaryTabsIntegration.isModLoaded())guard means the lambda would never actually run. Fixed by replacing the inline lambda with a method referenceLegendaryTabsClientIntegration::registerTabthat delegates to a newregisterTab()static method on the existing client-integration class. ClientProxy's bytecode now only referencesLegendaryTabsClientIntegration(a plain class not in the optional-mod namespace); thesfiomn.*types stay confined toLegendaryTabsClientIntegrationandLegendaryTabRunicSkills, which are only class-loaded when theisModLoaded()guard passes. The inlinesfiomn.legendarytabs.api.tabs_menu.TabsMenu.register(...)call and the now-unusedimport com.otectus.runicskills.client.gui.LegendaryTabRunicSkillswere removed fromRunicSkillsClient.java. - Skill-selection hover border misaligned.
skill_card_hover.pngis 74×26 (a symmetric green halo with 4px of glow on each horizontal side of the underlying 66×26 button), butRunicSkillsScreen.drawOverviewwas passingOVERVIEW_SLOT_WIDTH(66) as both the blit size and thetextureWidthargument toGuiGraphics.blit. With a mis-declared texture width, OpenGL normalised UV against 66 while the image is really 74 pixels wide — so the entire halo got squashed horizontally into the 66-wide button rect, pulling the visible border inside the button outline instead of glowing around it. Fixed by introducingOVERVIEW_HOVER_TEX_WIDTH/HEIGHTconstants (74×26), passing them as the real texture dimensions, and shifting the blit position by(74-66)/2 = 4pxleft so the halo sits centered around the button with the expected 4px outer glow on each side. - Skill-selection tooltip could be overpainted by adjacent cells.
drawOverviewwas callingUtils.drawToolTipinside the skill-iteration loop, so any cell drawn after the hovered one (specifically the right-column neighbour) rendered on top of the tooltip. Fixed by capturing the hovered skill in a local, completing the loop, and rendering the tooltip once after every cell has painted. Defensive against future art changes even though the 74×26 halo fits entirely within the 11px inter-column gap.
Notes
- Vanilla
/reloadupdates perk-group state server-side but does not auto-push to clients (matches existing lock-items behavior). Use/skillsreloadfor full propagation. - All five new config options default to behavior-preserving values (
0, empty list,1.0); upgrading an existing world changes nothing until the admin opts in. - No NBT schema changes; save-compatible with 0.9.7.

