Tell us about your Suggestion
ServerResourcesConfig.java
ServerPartyConfig.java
ServerMiscConfig.java
ServerMapsConfig.java
ServerLootConfig.java
ServerLevelingConfig.java
ServerDifficultyConfig.java
ServerCurrencyConfig.java
ClientUiConfig.java
ClientRenderingConfig.java
ClientOverlaysConfig.java
Proposal for upstream (based on a working fork of 6.1.15 / MC 1.20.1 Forge, all changes implemented and compiling). Author: Rayman's modpack fork. Happy to share diffs/PR if interested.
TL;DR
- Split the two monolithic TOMLs into 11 thematic files — same fields, zero callsite changes, much easier for server admins to navigate.
- Expose ~30 hardcoded balance constants as config keys (XP curves, weapon damage multi, i-frames, loot internals, ailment timings, dodge/block internals, mob rarity ratios).
- Add spell range multipliers — fixes the well-known archer-vs-mage range imbalance with 5 keys and 6 one-line code changes.
- Optionally route environmental damage (lava/fall/freeze/…) through MnS resistances so players can't cheese map mobs into lava.
Everything below is implemented with a facade pattern that keeps ServerContainer.get().X.get() / ClientConfigs.CLIENT.X.get() callsites untouched — only the spec registration moves.
1. Config file split (11 files instead of 2)
Problem: mmorpg-server.toml mixes loot rates, XP, map gen, party and misc in one flat file; mmorpg-client.toml mixes tooltips, overlays and particles. Admins constantly scroll/search.
Proposed layout under config/mine_and_slash/:
| File |
Contents |
client-ui.toml |
tooltips, number formatting, GUI type/position, zoom |
client-overlays.toml |
mob HP bars, status/spell hotbar overlays, presets |
client-rendering.toml |
floating damage, particles, animations, warnings |
server-loot.toml |
all 14 droprates + loot internals (see §2) |
server-leveling.toml |
XP gain/loss/debt/rested + curve exponents (see §2) |
server-difficulty.toml |
mob scaling, level-distance penalty, PvP, damage knobs |
server-maps.toml |
map gen radii, room counts, mob pack sizes, variance |
server-resources.toml |
regen, energy/block costs + ailment timings (see §2) |
server-party.toml |
party radius, team distance, max characters |
server-currency.toml |
favor, prophecy |
server-misc.toml |
bans, stations, logging, spells section (see §3) |
Implementation: each file is a small ForgeConfigSpec class whose constructor assigns into the existing ServerContainer / ClientConfigs singleton fields. The legacy classes lose their static {} spec builders and become passive holders. Hundreds of existing callsites compile unchanged. MMORPG.java registers 11 specs instead of 2.
2. Hardcoded constants worth exposing
All verified against 6.1.15 sources; each is a single .get() substitution at the source site.
Leveling (LevelUtils.java)
| Constant |
Source |
Suggested key |
Default |
XP curve exponent 2.4F |
LevelUtils:54 |
EXP_CURVE_EXPONENT |
2.4 |
XP reward exponent 1.1F |
LevelUtils:63 |
EXP_REWARD_CURVE_EXPONENT |
1.1 |
Mob base XP 50 |
LevelUtils:60 |
MOB_EXP_BASE |
50 |
Mob XP level factor 4 |
LevelUtils:60 |
MOB_EXP_LEVEL_FACTOR |
4 |
Damage (DamageEvent.java)
| Constant |
Source |
Suggested key |
wepdmgMulti = 1 baseline |
DamageEvent:77 |
WEAPON_DAMAGE_MULTI |
invulnerableTime = 0 resets |
DamageEvent:658,661,721 |
DISABLE_INVULNERABLE_FRAMES (bool) + INVULNERABLE_FRAMES_OVERRIDE (int 0–20) |
Loot internals
| Constant |
Source |
Suggested key |
Mob HP loot divisor 40F |
LootUtils:49 |
MOB_HEALTH_LOOT_DIVISOR |
Roll cap per iter 75F |
LootUtils:74 |
WHILE_ROLL_MAX_CHANCE_PER_ITER |
Chest higher-rarity 75 |
LootChestBlueprint:16 |
LOOT_CHEST_HIGHER_RARITY_CHANCE |
Chest item count 5 |
LootChestBlueprint:41 |
LOOT_CHEST_FIXED_ITEM_COUNT |
Jewel higher-rarity 50 |
JewelBlueprint:24 |
JEWEL_HIGHER_RARITY_CHANCE |
Low-level boost 10 / 2.0 |
LootInfo:228-229 |
LOW_LEVEL_BOOST_THRESHOLD / LOW_LEVEL_BOOST_MULTI |
Combat / defense
| Constant |
Source |
Suggested key |
Dodge max multi 0.8F |
DodgeRating:67 |
DODGE_RATING_MAX_MULTI |
Dodge rating for max 100 |
DodgeRating:72 |
DODGE_RATING_VALUE_FOR_MAX |
Block reduction 50% |
BlockChance:77 |
BLOCK_DAMAGE_REDUCTION_PCT |
Ailments (EntityAilmentData.java, Ailment.java)
| Constant |
Source |
Suggested key |
DoT min duration 21 |
EntityAilmentData:113 |
DOT_MIN_DURATION_TICKS |
Freeze slow duration 100 |
EntityAilmentData:159 |
FREEZE_SLOW_DURATION_TICKS |
Strength decay interval 20 |
EntityAilmentData:179 |
STRENGTH_DECAY_INTERVAL_TICKS |
DoT tick interval 20 |
EntityAilmentData:189 |
DOT_TICK_INTERVAL_TICKS |
Cleanup interval 400 |
EntityAilmentData:232 |
CLEANUP_INTERVAL_TICKS |
% HP for full strength 0.25F |
Ailment:32 |
PCT_HP_FOR_FULL_STRENGTH |
Mob rarity (MobRarity.java)
| Constant |
Source |
Suggested key |
Loot multi ratio 0.5F |
MobRarity:21 |
RARITY_LOOT_MULTI_RATIO |
Damage multi ratio 0.25F |
MobRarity:32 |
RARITY_DAMAGE_MULTI_RATIO |
Misc
| Constant |
Source |
Suggested key |
Death event cooldown 100 |
OnPlayerDeath:26 |
DEATH_EVENT_COOLDOWN_TICKS |
Dungeon placement attempts 300 |
MapData:145 |
MAX_DUNGEON_PLACEMENT_ATTEMPTS |
Dungeon length 30 chunks |
MapData:203 |
DUNGEON_LENGTH_CHUNKS |
Plus three global spell economy multipliers (no per-spell datapack edits needed for coarse tuning): SPELL_GLOBAL_COOLDOWN_MULTI, SPELL_GLOBAL_CAST_TIME_MULTI, SPELL_GLOBAL_MANA_COST_MULTI.
3. Spell range multipliers (archer vs mage balance)
The problem: bows use vanilla arrow physics — effective range 50+ blocks. Spell projectile range is hard-capped by LIFESPAN_TICKS × PROJECTILE_SPEED from spell JSON. Fireball: 8 ticks × 2.5 speed ≈ 20 blocks. A bow user kills a mage before the mage is even in casting range. Per-spell datapack edits are impractical for modpack makers (200+ spells).
The fix — 5 keys in a [spells] section:
| Key |
Default |
Range |
Applied at |
SPELL_PROJ_LIFESPAN_MULTI |
1.0 |
0.1–10 |
SimpleProjectileEntity:611 (setDeathTime) |
SPELL_PROJ_SPEED_MULTI |
1.0 |
0.1–5 |
SummonProjectileAction:54 (builder.shootSpeed) |
SPELL_AOE_RADIUS_MULTI |
1.0 |
0.1–5 |
AoeSelector:33 (stacks with AREA_MULTI) |
SPELL_RAYCAST_DISTANCE_MULTI |
1.0 |
0.1–5 |
RayCastSelector + InFrontSelector |
PROJECTILE_AUTOTARGET_RADIUS |
15 |
1–64 |
ProjectileCastHelper:115 (replaces hardcoded 15) |
Six one-line changes total. Defaults of 1.0 are bit-identical to current behaviour. A server admin sets SPELL_PROJ_LIFESPAN_MULTI = 2.5 and mages can finally answer back at ~50 blocks.
4. Environmental damage through MnS resistances (optional, toggleable)
The problem: OnNonPlayerDamageEntityEvent:39-46 early-returns for any damage source that is not a LivingEntity. Lava, fall, freeze, drown, explosions hit vanilla HP directly — players cheese strong map mobs by knocking them into lava or off cliffs, bypassing all MnS resistances.
The fix: a small router (EnvironmentalDamageRouter) mapping vanilla damage types to MnS elements:
| Vanilla type |
Element |
Resist |
| LAVA / IN_FIRE / ON_FIRE / HOT_FLOOR |
Fire |
fire resist |
| FREEZE / DROWN |
Water |
water resist |
| LIGHTNING_BOLT |
Lightning |
lightning resist |
| MAGIC / WITHER |
Chaos |
chaos resist |
| EXPLOSION / FALL / FALLING_BLOCK / ANVIL / CACTUS / etc. |
Physical |
armor |
Recursion is guarded by the existing DmgSourceUtils.isMyDmgSource tag; player magic-shield drain path is untouched; map-world cancel stays the outer guard. Gated behind ROUTE_ENV_DAMAGE_THROUGH_MNS (bool, default true in our fork — could default false upstream for compat).
5. Small QoL items found along the way
- Spell icon fallback:
Spell icon getter returns the path unchecked; ~20 internal/debug spells (*_basic, test_spell, …) render pink-checkerboard in the spell tree. Reusing Stat.MISSING_ICON when ResourceManager.getResource(loc).isEmpty() fixes it in 3 lines.
- Back button: none of the hub sub-screens (Talents, Ascendancy, Spells, Stats, Map, Prophecy, Wiki, …) have a back button — only Esc. Adding a
parentScreen field + goBack() to BaseScreen and threading the hub reference through MainHubButton gives every sub-screen one-click return.
Compatibility notes
- The facade pattern means zero changes at the hundreds of
ServerContainer.get().X.get() callsites — only spec construction/registration moves.
- The split is breaking for existing TOMLs (old files are ignored, new ones generate with defaults). A one-time migration reader could be added if upstream wants a smooth path; we chose a clean break for our pack.
- All new keys default to current hardcoded values → default behaviour is bit-identical.
All of the above is running on a live 1.20.1 server. Diffs available on request.
Tell us about your Suggestion
ServerResourcesConfig.java
ServerPartyConfig.java
ServerMiscConfig.java
ServerMapsConfig.java
ServerLootConfig.java
ServerLevelingConfig.java
ServerDifficultyConfig.java
ServerCurrencyConfig.java
ClientUiConfig.java
ClientRenderingConfig.java
ClientOverlaysConfig.java
Proposal for upstream (based on a working fork of 6.1.15 / MC 1.20.1 Forge, all changes implemented and compiling). Author: Rayman's modpack fork. Happy to share diffs/PR if interested.
TL;DR
Everything below is implemented with a facade pattern that keeps
ServerContainer.get().X.get()/ClientConfigs.CLIENT.X.get()callsites untouched — only the spec registration moves.1. Config file split (11 files instead of 2)
Problem:
mmorpg-server.tomlmixes loot rates, XP, map gen, party and misc in one flat file;mmorpg-client.tomlmixes tooltips, overlays and particles. Admins constantly scroll/search.Proposed layout under
config/mine_and_slash/:client-ui.tomlclient-overlays.tomlclient-rendering.tomlserver-loot.tomlserver-leveling.tomlserver-difficulty.tomlserver-maps.tomlserver-resources.tomlserver-party.tomlserver-currency.tomlserver-misc.tomlImplementation: each file is a small
ForgeConfigSpecclass whose constructor assigns into the existingServerContainer/ClientConfigssingleton fields. The legacy classes lose theirstatic {}spec builders and become passive holders. Hundreds of existing callsites compile unchanged.MMORPG.javaregisters 11 specs instead of 2.2. Hardcoded constants worth exposing
All verified against 6.1.15 sources; each is a single
.get()substitution at the source site.Leveling (
LevelUtils.java)2.4FLevelUtils:54EXP_CURVE_EXPONENT1.1FLevelUtils:63EXP_REWARD_CURVE_EXPONENT50LevelUtils:60MOB_EXP_BASE4LevelUtils:60MOB_EXP_LEVEL_FACTORDamage (
DamageEvent.java)wepdmgMulti = 1baselineDamageEvent:77WEAPON_DAMAGE_MULTIinvulnerableTime = 0resetsDamageEvent:658,661,721DISABLE_INVULNERABLE_FRAMES(bool) +INVULNERABLE_FRAMES_OVERRIDE(int 0–20)Loot internals
40FLootUtils:49MOB_HEALTH_LOOT_DIVISOR75FLootUtils:74WHILE_ROLL_MAX_CHANCE_PER_ITER75LootChestBlueprint:16LOOT_CHEST_HIGHER_RARITY_CHANCE5LootChestBlueprint:41LOOT_CHEST_FIXED_ITEM_COUNT50JewelBlueprint:24JEWEL_HIGHER_RARITY_CHANCE10/2.0LootInfo:228-229LOW_LEVEL_BOOST_THRESHOLD/LOW_LEVEL_BOOST_MULTICombat / defense
0.8FDodgeRating:67DODGE_RATING_MAX_MULTI100DodgeRating:72DODGE_RATING_VALUE_FOR_MAX50%BlockChance:77BLOCK_DAMAGE_REDUCTION_PCTAilments (
EntityAilmentData.java,Ailment.java)21EntityAilmentData:113DOT_MIN_DURATION_TICKS100EntityAilmentData:159FREEZE_SLOW_DURATION_TICKS20EntityAilmentData:179STRENGTH_DECAY_INTERVAL_TICKS20EntityAilmentData:189DOT_TICK_INTERVAL_TICKS400EntityAilmentData:232CLEANUP_INTERVAL_TICKS0.25FAilment:32PCT_HP_FOR_FULL_STRENGTHMob rarity (
MobRarity.java)0.5FMobRarity:21RARITY_LOOT_MULTI_RATIO0.25FMobRarity:32RARITY_DAMAGE_MULTI_RATIOMisc
100OnPlayerDeath:26DEATH_EVENT_COOLDOWN_TICKS300MapData:145MAX_DUNGEON_PLACEMENT_ATTEMPTS30chunksMapData:203DUNGEON_LENGTH_CHUNKSPlus three global spell economy multipliers (no per-spell datapack edits needed for coarse tuning):
SPELL_GLOBAL_COOLDOWN_MULTI,SPELL_GLOBAL_CAST_TIME_MULTI,SPELL_GLOBAL_MANA_COST_MULTI.3. Spell range multipliers (archer vs mage balance)
The problem: bows use vanilla arrow physics — effective range 50+ blocks. Spell projectile range is hard-capped by
LIFESPAN_TICKS × PROJECTILE_SPEEDfrom spell JSON. Fireball: 8 ticks × 2.5 speed ≈ 20 blocks. A bow user kills a mage before the mage is even in casting range. Per-spell datapack edits are impractical for modpack makers (200+ spells).The fix — 5 keys in a
[spells]section:SPELL_PROJ_LIFESPAN_MULTISimpleProjectileEntity:611(setDeathTime)SPELL_PROJ_SPEED_MULTISummonProjectileAction:54(builder.shootSpeed)SPELL_AOE_RADIUS_MULTIAoeSelector:33(stacks withAREA_MULTI)SPELL_RAYCAST_DISTANCE_MULTIRayCastSelector+InFrontSelectorPROJECTILE_AUTOTARGET_RADIUSProjectileCastHelper:115(replaces hardcoded 15)Six one-line changes total. Defaults of 1.0 are bit-identical to current behaviour. A server admin sets
SPELL_PROJ_LIFESPAN_MULTI = 2.5and mages can finally answer back at ~50 blocks.4. Environmental damage through MnS resistances (optional, toggleable)
The problem:
OnNonPlayerDamageEntityEvent:39-46early-returns for any damage source that is not a LivingEntity. Lava, fall, freeze, drown, explosions hit vanilla HP directly — players cheese strong map mobs by knocking them into lava or off cliffs, bypassing all MnS resistances.The fix: a small router (
EnvironmentalDamageRouter) mapping vanilla damage types to MnS elements:Recursion is guarded by the existing
DmgSourceUtils.isMyDmgSourcetag; player magic-shield drain path is untouched; map-world cancel stays the outer guard. Gated behindROUTE_ENV_DAMAGE_THROUGH_MNS(bool, default true in our fork — could default false upstream for compat).5. Small QoL items found along the way
Spellicon getter returns the path unchecked; ~20 internal/debug spells (*_basic,test_spell, …) render pink-checkerboard in the spell tree. ReusingStat.MISSING_ICONwhenResourceManager.getResource(loc).isEmpty()fixes it in 3 lines.parentScreenfield +goBack()toBaseScreenand threading the hub reference throughMainHubButtongives every sub-screen one-click return.Compatibility notes
ServerContainer.get().X.get()callsites — only spec construction/registration moves.All of the above is running on a live 1.20.1 server. Diffs available on request.