Tags
Creators
Details
All versions
1.2.1
Release
Combat Toggle 1.2.1 (Forge 1.20.1)4 months ago 251
Uploaded by
Compatibility
Minecraft: Java Edition
1.19.2
Platform
Forge
Supported environments
Server-side
Client and server
Changes
1.2.1
Bug Fixes
- PvP enforcement now cancels at
LivingAttackEventinstead ofLivingHurtEvent. Cancelling at the old event happened after knockback, hurt sound, andPLAYER_HURT_ENTITYhad already fired — letting attackers chain free knockback shots on Peace targets. The new path stops the entire hurt pipeline before any side effects.LivingHurtEventremains as a defence-in-depth fallback that also clears residual knockback velocity. (REVIEW 1.1, 3.4) - Indirect-damage PvP loopholes closed. Attacker resolution now walks the full ownership chain: direct hits, projectiles,
primed TNT (
PrimedTnt.getOwner()), and anyOwnableEntity(vanilla tamables and modded summons). Wolves, snow golems, and ignited TNT are now correctly gated by Combat Toggle. (REVIEW 1.2, 1.10) - Server-side timers migrated from wall-clock to game ticks.
combat_tag_until_ms,last_toggle_ms, andlast_pvp_msbecame*_tickfields driven bylevel.getGameTime()— monotonic, persistent across server restarts, and immune to NTP steps or admin clock changes. The HUD packet still carries millisecond remainders for client-side display. (REVIEW 1.3) - Admin
/set <player> peacenow respectsforceCombatWhileTagged. Previously the command silently flipped a tagged player to Peace even though the next PvP hit would rubber-band them back. Now refuses with a clear error unlessbypass=trueis supplied. (REVIEW 1.4) /combattoggle statusno longer reports a misleading cooldown for Peace-mode players. Asks the cooldown question in the direction of the player's next possible toggle, not always TO_PEACE. (REVIEW 1.5)- Client state is reset on disconnect / reconnect.
ClientCombatStatezeros itself onClientPlayerNetworkEvent.LoggingInandLoggingOutso the HUD never carries stale tag/cooldown state across servers. (REVIEW 1.6) /combattoggle tag <player> 0rejected at the parser. Brigadier now usesinteger(1, 3600); the no-args form surfaces a clearer error (tag_disabled_in_config) when the server has tagging disabled. (REVIEW 1.7)- Per-call NBT allocations eliminated for player state.
CombatToggleDatais now a Forge capability attached to everyPlayerentity.CombatToggleData.get(player)returns the same in-memory instance for the lifetime of that player — no per-call allocation, no read-modify-save footgun, no async-mutation race.save()is preserved as a no-op for source compatibility. (REVIEW 1.8, 1.13, 5.1) cooldownAppliesToPeaceOnlyboolean replaced withcooldownScopeenum (PEACE_ONLY/COMBAT_ONLY/BOTH/NONE). The boolean conflated two semantics and made the symmetric/none cases inexpressible. Boolean is dropped — operators on upgrade get thePEACE_ONLYdefault. (REVIEW 1.9, with related rename ofisCooldownActive(boolean)→isCooldownActiveForDirection(ToggleDirection), REVIEW 3.8.)/combattoggle reloadrenamed to/combattoggle resync. The actual operation is a team refresh + HUD resync — Forge auto-reloads the config on file save independently. The old/reloadliteral is preserved as an alias. (REVIEW 1.11)- Mode argument is now tab-completable.
/combattoggle set <player> <combat|peace> [bypass]uses literal subcommands; typos no longer reach the executor. (REVIEW 1.12)
New Features
/combattoggle help— permission-filtered usage listing for every subcommand. (REVIEW 3.9)- Damage-type denylist — new
blockedDamageTypesconfig (list of damage-type resource locations) lets admins forbid specific PvP vectors (e.g.minecraft:magic,minecraft:trident) without disabling PvP entirely. (REVIEW 3.1) - Public Forge event surface for mod integrations — three new events under
com.runecraft.combattoggle.api.events:CombatToggleStateChangeEvent(cancellable, fires before persist; lets safe-zone mods refuse a toggle)CombatTagAppliedEvent(fires when a tag is set or extended)CombatTagExpiredEvent(fires when a tag elapses, including on next-login if it elapsed offline)CombatLoggedOutEvent(fires on disconnect with remaining tag ticks; canonical combat-log signal for penalty mods) (REVIEW 3.2, 3.12, 3.13)
- Configurable HUD position. New client-config keys
hudAnchor(LEFT/CENTER/RIGHT),hudYOffset(pixels), andshowHudTimers(boolean) so HUD-customisation users can move or hide the indicator. (REVIEW 3.5) - Tag-expired chat ping fires after offline-elapsed tags too. A new
tag_expiry_notifiedpersisted flag ensures the notification is sent exactly once whether the tag expired live or while the player was offline. (REVIEW 3.11) - Force-combat flips notify the target. When
forceCombatWhileTaggedflips a Peace player to Combat (PvP hit or login while tagged), the player gets a chat hint explaining why and how long the tag has left. (REVIEW 3.10)
Performance
- Tick handler stops allocating once per tagged player per tick. Tag deadlines are cached in a
Map<UUID, Long>alongside the tracker — the per-tick walk is one iterator + one>comparison, no NBT reads, noCombatToggleDataallocations. (REVIEW 2.1) - HUD timer strings cached per-second. Replaces the per-frame string concat + font.width measurement with a one-render-per-second rebuild. (REVIEW 2.2)
- Sync packet shrunk from 17 bytes to ~5. Two longs replaced with two varint seconds (HUD only displays mm:ss). Packet protocol bumps to "3" — clients on 1.1.x get a clean handshake reject. (REVIEW 2.3, 4.12)
isPvpAllowedcentralised inCombatToggleData. Single source of truth used by both the API and enforcement; eliminates duplicatedrequireBothconfig reads. (REVIEW 2.4, 2.5)- Team-name pair cached at config load/reload instead of resolved on every login/respawn/toggle/admin-set. (REVIEW 2.6)
- Hot-path PvP debug logging guarded by
LOGGER.isDebugEnabled()to avoid eager arg evaluation on the per-hit path. (REVIEW 2.7)
Internals
- New
data/CombatToggleCapability.javaregisters the capability and attaches a provider to everyPlayer. The clone hook replaces the oldPlayerEvent.Clone-based persistent-data copy. - New
data/ToggleDirection.javaanddata/CooldownScope.javaenums replace boolean direction flags. - One-shot legacy NBT migration (
PlayerLifecycleEvents.migrateLegacyData) portsenabledfrom any pre-1.2.0combat_togglepersistent-data compound and discards the wall-clock timestamps (which would compare as in-the-future against the new game-tick clock). The legacy compound is removed after migration. - API method
CombatToggleAPI.isCooldownActive(ServerPlayer, boolean)deprecated for removal in favour of theToggleDirectionoverload. - The lang file gained 12 new keys (help_*, set_blocked_tagged, tag_disabled_in_config, admin_force_flipped,
pvp_blocked_damage_type, state_change_cancelled, resync) and the
reloadkey was renamed.
Skipped / Out-of-Scope
- JEI/EMI integration page (REVIEW 3.14) — would require adding compileOnly external Maven deps and a custom anchor
item to host the info page. The
/combattoggle helpcommand added in this release covers the same discoverability gap with no extra dependencies.
Projects on Modrinth are automatically available through a Maven repository for use with JVM build tools such as Gradle. To learn more about the Modrinth Maven API, click here.
Note: When available, you should use the creator's maven repo instead as it will have transitive dependency information that the Modrinth Maven API does not. You may also end up with duplicate dependencies if you use a mix of Modrinth and non-Modrinth Maven repositories for your dependencies, because the group identifier will be different when served through the Modrinth Maven API.
Maven coordinates:
Version ID:
build.gradle:
repositories {
exclusiveContent {
forRepository {
maven {
name = "Modrinth"
url = "https://api.modrinth.com/maven"
}
}
// forRepositories(fg.repository) // Uncomment when using ForgeGradle
filter {
includeGroup "maven.modrinth"
}
}
}
// Standard Gradle dependency
dependencies {
implementation "maven.modrinth:o97ryxJy:apsu4lGB"
}
// Legacy Loom dependency
dependencies {
modImplementation "maven.modrinth:o97ryxJy:apsu4lGB"
}

