<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.dragonminez.com/index.php?action=history&amp;feed=atom&amp;title=Implementation_and_Events</id>
	<title>Implementation and Events - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.dragonminez.com/index.php?action=history&amp;feed=atom&amp;title=Implementation_and_Events"/>
	<link rel="alternate" type="text/html" href="https://wiki.dragonminez.com/index.php?title=Implementation_and_Events&amp;action=history"/>
	<updated>2026-10-25T10:25:08Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.43.11</generator>
	<entry>
		<id>https://wiki.dragonminez.com/index.php?title=Implementation_and_Events&amp;diff=210&amp;oldid=prev</id>
		<title>Neb: Sync from dragonminez-wiki repository</title>
		<link rel="alternate" type="text/html" href="https://wiki.dragonminez.com/index.php?title=Implementation_and_Events&amp;diff=210&amp;oldid=prev"/>
		<updated>2026-10-13T04:17:26Z</updated>

		<summary type="html">&lt;p&gt;Sync from dragonminez-wiki repository&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;&amp;lt;translate&amp;gt;&lt;br /&gt;
&amp;lt;!--T:1--&amp;gt;&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Implementation and Events&amp;#039;&amp;#039;&amp;#039; describes the hook surface DragonMineZ offers to add-ons: its events, how to read player state, the extension registries, and where to plug in your own networking and registries. Read it once your add-on builds against DMZ (see [[Special:MyLanguage/Add-on Getting Started|Add-on Getting Started]]).&lt;br /&gt;
&amp;lt;/translate&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;translate&amp;gt;&lt;br /&gt;
== Listening to a DMZ event == &amp;lt;!--T:2--&amp;gt;&lt;br /&gt;
&amp;lt;/translate&amp;gt;&lt;br /&gt;
&amp;lt;translate&amp;gt;&lt;br /&gt;
&amp;lt;!--T:3--&amp;gt;&lt;br /&gt;
All server and common events are nested static classes of &amp;lt;code&amp;gt;com.dragonminez.common.events.DMZEvent&amp;lt;/code&amp;gt;, posted to the standard Forge event bus (&amp;lt;code&amp;gt;MinecraftForge.EVENT_BUS&amp;lt;/code&amp;gt;). Each nested class extends Forge&amp;#039;s &amp;lt;code&amp;gt;Event&amp;lt;/code&amp;gt; directly (&amp;lt;code&amp;gt;DMZEvent&amp;lt;/code&amp;gt; itself is only the container), so subscribe to the specific nested class:&lt;br /&gt;
&amp;lt;/translate&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
@Mod.EventBusSubscriber(modid = &amp;quot;your_addon_modid&amp;quot;, bus = Mod.EventBusSubscriber.Bus.FORGE)&lt;br /&gt;
public class DmzHooks {&lt;br /&gt;
    @SubscribeEvent&lt;br /&gt;
    public static void onTpGain(DMZEvent.TPGainEvent event) {&lt;br /&gt;
        int boosted = Math.round(event.getTpGain() * 1.10f);&lt;br /&gt;
        event.setTpGain(boosted);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    @SubscribeEvent&lt;br /&gt;
    public static void onFormChange(DMZEvent.FormChangeEvent event) {&lt;br /&gt;
        if (event.isTransform()) {&lt;br /&gt;
            // player transformed into event.getNewGroup() / event.getNewForm()&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;translate&amp;gt;&lt;br /&gt;
&amp;lt;!--T:4--&amp;gt;&lt;br /&gt;
Events marked &amp;#039;&amp;#039;&amp;#039;cancelable&amp;#039;&amp;#039;&amp;#039; below carry Forge&amp;#039;s &amp;lt;code&amp;gt;@Cancelable&amp;lt;/code&amp;gt; annotation: &amp;lt;code&amp;gt;event.setCanceled(true)&amp;lt;/code&amp;gt; blocks the underlying action. Fields marked &amp;#039;&amp;#039;settable&amp;#039;&amp;#039; have a setter (&amp;lt;code&amp;gt;setTpGain&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;setAmount&amp;lt;/code&amp;gt;, ...), and DMZ uses the value after all listeners ran. All getters follow the field names (&amp;lt;code&amp;gt;getPlayer()&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;getOldValue()&amp;lt;/code&amp;gt;, ...); boolean fields use &amp;lt;code&amp;gt;is...&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;isParry()&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;isBlocked()&amp;lt;/code&amp;gt;).&lt;br /&gt;
&amp;lt;/translate&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;translate&amp;gt;&lt;br /&gt;
== Event list == &amp;lt;!--T:5--&amp;gt;&lt;br /&gt;
&amp;lt;/translate&amp;gt;&lt;br /&gt;
&amp;lt;translate&amp;gt;&lt;br /&gt;
&amp;lt;!--T:6--&amp;gt;&lt;br /&gt;
Source: &amp;lt;code&amp;gt;src/main/java/com/dragonminez/common/events/DMZEvent.java&amp;lt;/code&amp;gt;.&lt;br /&gt;
&amp;lt;/translate&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;translate&amp;gt;&lt;br /&gt;
=== Stats, resources and progression === &amp;lt;!--T:7--&amp;gt;&lt;br /&gt;
&amp;lt;/translate&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! &amp;lt;translate&amp;gt;&amp;lt;!--T:8--&amp;gt; Event&amp;lt;/translate&amp;gt; !! &amp;lt;translate&amp;gt;&amp;lt;!--T:9--&amp;gt; Cancelable&amp;lt;/translate&amp;gt; !! &amp;lt;translate&amp;gt;&amp;lt;!--T:10--&amp;gt; Fires when&amp;lt;/translate&amp;gt; !! &amp;lt;translate&amp;gt;&amp;lt;!--T:11--&amp;gt; Key fields&amp;lt;/translate&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;StatChangeEvent&amp;lt;/code&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:12--&amp;gt; Yes&amp;lt;/translate&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:13--&amp;gt; A stat (STR, SKP, RES, VIT, PWR or ENE) changes through a &amp;lt;code&amp;gt;Stats.set*()&amp;lt;/code&amp;gt; call: commands, items, menus, and also when stats are loaded or copied (on both server and client).&amp;lt;/translate&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:14--&amp;gt; &amp;lt;code&amp;gt;player&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;stat&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;STRENGTH&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;STRIKE_POWER&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;RESISTANCE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;VITALITY&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;KI_POWER&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;ENERGY&amp;lt;/code&amp;gt;), &amp;lt;code&amp;gt;oldValue&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;newValue&amp;lt;/code&amp;gt;&amp;lt;/translate&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;TPGainEvent&amp;lt;/code&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:15--&amp;gt; Yes&amp;lt;/translate&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:16--&amp;gt; Before a positive amount of training points is added (&amp;lt;code&amp;gt;Resources.addTrainingPoints&amp;lt;/code&amp;gt;).&amp;lt;/translate&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:17--&amp;gt; &amp;lt;code&amp;gt;player&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;oldValue&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;tpGain&amp;lt;/code&amp;gt; (settable), &amp;lt;code&amp;gt;shareWithParty&amp;lt;/code&amp;gt; (settable); helper &amp;lt;code&amp;gt;getNewTpsValue()&amp;lt;/code&amp;gt;&amp;lt;/translate&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;KiChargeEvent&amp;lt;/code&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:18--&amp;gt; Yes&amp;lt;/translate&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:19--&amp;gt; Once per second while the player is actively charging ki. Cancel it to stop that second&amp;#039;s ki gain.&amp;lt;/translate&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:20--&amp;gt; &amp;lt;code&amp;gt;player&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;currentEnergy&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;maxEnergy&amp;lt;/code&amp;gt;; helper &amp;lt;code&amp;gt;isEnergyFull()&amp;lt;/code&amp;gt;&amp;lt;/translate&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;HealthRegenEvent&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;EnergyRegenEvent&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;StaminaRegenEvent&amp;lt;/code&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:21--&amp;gt; Yes&amp;lt;/translate&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:22--&amp;gt; Before the per-second regeneration of health, ki or stamina is applied. They share the &amp;lt;code&amp;gt;ResourceRegenEvent&amp;lt;/code&amp;gt; base.&amp;lt;/translate&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:23--&amp;gt; &amp;lt;code&amp;gt;player&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;statsData&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;amount&amp;lt;/code&amp;gt; (settable)&amp;lt;/translate&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;FormChangeEvent&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;StackFormChangeEvent&amp;lt;/code&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:24--&amp;gt; No&amp;lt;/translate&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:25--&amp;gt; After the player&amp;#039;s race form or stack form changes (server side).&amp;lt;/translate&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:26--&amp;gt; &amp;lt;code&amp;gt;player&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;oldGroup&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;oldForm&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;newGroup&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;newForm&amp;lt;/code&amp;gt;; helpers &amp;lt;code&amp;gt;isTransform()&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;isUntransform()&amp;lt;/code&amp;gt;&amp;lt;/translate&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PlayerDataSaveEvent&amp;lt;/code&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:27--&amp;gt; No&amp;lt;/translate&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:28--&amp;gt; Player data is about to be written to the &amp;lt;code&amp;gt;JSON&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;DATABASE&amp;lt;/code&amp;gt; storage backend. You may add your own keys to &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;.&amp;lt;/translate&amp;gt; || &amp;lt;code&amp;gt;player&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PlayerDataLoadEvent&amp;lt;/code&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:29--&amp;gt; No&amp;lt;/translate&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:30--&amp;gt; Player data was read from the &amp;lt;code&amp;gt;JSON&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;DATABASE&amp;lt;/code&amp;gt; backend, right before it is applied to the player.&amp;lt;/translate&amp;gt; || &amp;lt;code&amp;gt;player&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{{Note|title=&amp;lt;translate&amp;gt;&amp;lt;!--T:31--&amp;gt; StatChangeEvent and loading&amp;lt;/translate&amp;gt;|text=&amp;lt;translate&amp;gt;&amp;lt;!--T:32--&amp;gt; &amp;lt;code&amp;gt;StatChangeEvent&amp;lt;/code&amp;gt; also fires while DMZ loads saved data and applies client syncs. If you cancel it, check &amp;lt;code&amp;gt;event.getPlayer().level().isClientSide()&amp;lt;/code&amp;gt; and your own conditions first, or you can block a player&amp;#039;s saved stats from loading.&amp;lt;/translate&amp;gt;}}&lt;br /&gt;
&lt;br /&gt;
{{Note|title=&amp;lt;translate&amp;gt;&amp;lt;!--T:33--&amp;gt; Storage backends&amp;lt;/translate&amp;gt;|text=&amp;lt;translate&amp;gt;&amp;lt;!--T:34--&amp;gt; &amp;lt;code&amp;gt;PlayerDataSaveEvent&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;PlayerDataLoadEvent&amp;lt;/code&amp;gt; do not fire with the default &amp;lt;code&amp;gt;NBT&amp;lt;/code&amp;gt; backend, where DMZ data is saved by vanilla with the player file. See [[Special:MyLanguage/General Server Config|General Server Config]] for the &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; settings.&amp;lt;/translate&amp;gt;}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;translate&amp;gt;&lt;br /&gt;
=== Combat === &amp;lt;!--T:35--&amp;gt;&lt;br /&gt;
&amp;lt;/translate&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! &amp;lt;translate&amp;gt;&amp;lt;!--T:36--&amp;gt; Event&amp;lt;/translate&amp;gt; !! &amp;lt;translate&amp;gt;&amp;lt;!--T:37--&amp;gt; Cancelable&amp;lt;/translate&amp;gt; !! &amp;lt;translate&amp;gt;&amp;lt;!--T:38--&amp;gt; Fires when&amp;lt;/translate&amp;gt; !! &amp;lt;translate&amp;gt;&amp;lt;!--T:39--&amp;gt; Key fields&amp;lt;/translate&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DamageModifyEvent&amp;lt;/code&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:40--&amp;gt; Yes&amp;lt;/translate&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:41--&amp;gt; Damage calculation before mitigation, for a hit dealt by a player (melee hits and strike attacks). Cancel it to deal no DMZ damage.&amp;lt;/translate&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:42--&amp;gt; &amp;lt;code&amp;gt;attacker&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;victim&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;amount&amp;lt;/code&amp;gt; (settable), &amp;lt;code&amp;gt;defensePenetration&amp;lt;/code&amp;gt; (settable), &amp;lt;code&amp;gt;sourceType&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;MELEE&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;STRIKE&amp;lt;/code&amp;gt;)&amp;lt;/translate&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DamageDealtEvent&amp;lt;/code&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:43--&amp;gt; No&amp;lt;/translate&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:44--&amp;gt; After blocking is resolved for a player&amp;#039;s melee hit (amount before mitigation).&amp;lt;/translate&amp;gt; || &amp;lt;code&amp;gt;attacker&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;victim&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;amount&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;blocked&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;parried&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;sourceType&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PlayerDamageMitigatedEvent&amp;lt;/code&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:45--&amp;gt; No&amp;lt;/translate&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:46--&amp;gt; After DMZ has finished mitigating a hit taken by a player. Read-only: do not change damage here.&amp;lt;/translate&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:47--&amp;gt; &amp;lt;code&amp;gt;victim&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;source&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;DamageSource&amp;lt;/code&amp;gt;), &amp;lt;code&amp;gt;rawDamage&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;defenseMitigated&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;blockMitigated&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;finalDamage&amp;lt;/code&amp;gt;&amp;lt;/translate&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PlayerBlockEvent&amp;lt;/code&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:48--&amp;gt; Yes&amp;lt;/translate&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:49--&amp;gt; The player successfully blocks or parries an attack. Cancel it and the player takes the full hit.&amp;lt;/translate&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:50--&amp;gt; &amp;lt;code&amp;gt;victim&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;attacker&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;originalDamage&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;finalDamage&amp;lt;/code&amp;gt; (settable), &amp;lt;code&amp;gt;isParry&amp;lt;/code&amp;gt; (settable), &amp;lt;code&amp;gt;poiseDamage&amp;lt;/code&amp;gt; (settable)&amp;lt;/translate&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;BarrierAbsorbEvent&amp;lt;/code&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:51--&amp;gt; No&amp;lt;/translate&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:52--&amp;gt; A ki barrier (the barrier technique or the Android barrier) absorbs a hit before it reaches the protected entity.&amp;lt;/translate&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:53--&amp;gt; &amp;lt;code&amp;gt;owner&amp;lt;/code&amp;gt; (the barrier&amp;#039;s creator), &amp;lt;code&amp;gt;protectedEntity&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;attacker&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;amount&amp;lt;/code&amp;gt;&amp;lt;/translate&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PlayerDashEvent&amp;lt;/code&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:54--&amp;gt; Yes&amp;lt;/translate&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:55--&amp;gt; Before a dash executes.&amp;lt;/translate&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:56--&amp;gt; &amp;lt;code&amp;gt;player&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;dashType&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;NORMAL&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;DOUBLE&amp;lt;/code&amp;gt;), &amp;lt;code&amp;gt;distance&amp;lt;/code&amp;gt; (settable), &amp;lt;code&amp;gt;kiCost&amp;lt;/code&amp;gt; (settable)&amp;lt;/translate&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PlayerEvasionEvent&amp;lt;/code&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:57--&amp;gt; Yes&amp;lt;/translate&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:58--&amp;gt; Before an evasion triggers.&amp;lt;/translate&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:59--&amp;gt; &amp;lt;code&amp;gt;player&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;attacker&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;originalDamage&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;kiCost&amp;lt;/code&amp;gt; (settable)&amp;lt;/translate&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;CritChanceEvent&amp;lt;/code&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:60--&amp;gt; No&amp;lt;/translate&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:61--&amp;gt; While a player&amp;#039;s critical chance is being resolved.&amp;lt;/translate&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:62--&amp;gt; &amp;lt;code&amp;gt;player&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;chance&amp;lt;/code&amp;gt; (settable, 0 to 1)&amp;lt;/translate&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;KiAttackCastEvent&amp;lt;/code&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:63--&amp;gt; No&amp;lt;/translate&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:64--&amp;gt; A player starts charging (casts) a ki attack.&amp;lt;/translate&amp;gt; || &amp;lt;code&amp;gt;player&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;statsData&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;kiAttack&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;KiAttackFireEvent&amp;lt;/code&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:65--&amp;gt; No&amp;lt;/translate&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:66--&amp;gt; A charged ki attack is released.&amp;lt;/translate&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:67--&amp;gt; &amp;lt;code&amp;gt;player&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;statsData&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;kiAttack&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;chargeMultiplier&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;cooldownTicks&amp;lt;/code&amp;gt; (settable, minimum 1)&amp;lt;/translate&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;StrikeAttackCastEvent&amp;lt;/code&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:68--&amp;gt; No&amp;lt;/translate&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:69--&amp;gt; A player starts a strike attack.&amp;lt;/translate&amp;gt; || &amp;lt;code&amp;gt;player&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;statsData&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;strike&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;StrikeAttackFireEvent&amp;lt;/code&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:70--&amp;gt; No&amp;lt;/translate&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:71--&amp;gt; A strike attack connects and starts on a target.&amp;lt;/translate&amp;gt; || &amp;lt;code&amp;gt;player&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;statsData&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;strike&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;target&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;translate&amp;gt;&lt;br /&gt;
&amp;lt;!--T:72--&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;DamageSourceType&amp;lt;/code&amp;gt; also contains a &amp;lt;code&amp;gt;KI&amp;lt;/code&amp;gt; value; in v2.2, ki attacks do not post &amp;lt;code&amp;gt;DamageModifyEvent&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;DamageDealtEvent&amp;lt;/code&amp;gt;.&lt;br /&gt;
&amp;lt;/translate&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;translate&amp;gt;&lt;br /&gt;
=== Fusions and dragons === &amp;lt;!--T:73--&amp;gt;&lt;br /&gt;
&amp;lt;/translate&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! &amp;lt;translate&amp;gt;&amp;lt;!--T:74--&amp;gt; Event&amp;lt;/translate&amp;gt; !! &amp;lt;translate&amp;gt;&amp;lt;!--T:75--&amp;gt; Cancelable&amp;lt;/translate&amp;gt; !! &amp;lt;translate&amp;gt;&amp;lt;!--T:76--&amp;gt; Fires when&amp;lt;/translate&amp;gt; !! &amp;lt;translate&amp;gt;&amp;lt;!--T:77--&amp;gt; Key fields&amp;lt;/translate&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;FusionEvent&amp;lt;/code&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:78--&amp;gt; Yes&amp;lt;/translate&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:79--&amp;gt; Before a fusion attempt. DMZ posts it for &amp;lt;code&amp;gt;METAMORU&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;POTHALA&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;BEETLE&amp;lt;/code&amp;gt; (Medi-Bug Beetle) fusions; the enum also contains &amp;lt;code&amp;gt;ABSORPTION&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;ASSIMILATION&amp;lt;/code&amp;gt;.&amp;lt;/translate&amp;gt; || &amp;lt;code&amp;gt;initiator&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;target&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;type&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DragonSummonedEvent&amp;lt;/code&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:80--&amp;gt; No&amp;lt;/translate&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:81--&amp;gt; After a dragon is summoned from a completed ball set.&amp;lt;/translate&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:82--&amp;gt; &amp;lt;code&amp;gt;player&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;level&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;position&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;dragonDefinition&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ballSetDefinition&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;consumedPositions&amp;lt;/code&amp;gt;; helpers &amp;lt;code&amp;gt;getDragonId()&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;getBallSetId()&amp;lt;/code&amp;gt;&amp;lt;/translate&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;translate&amp;gt;&lt;br /&gt;
&amp;lt;!--T:83--&amp;gt;&lt;br /&gt;
See [[Special:MyLanguage/Fusions|Fusions]] and [[Special:MyLanguage/Dragons and Wishes|Dragons and Wishes]] for the gameplay side.&lt;br /&gt;
&amp;lt;/translate&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;translate&amp;gt;&lt;br /&gt;
=== Quests === &amp;lt;!--T:84--&amp;gt;&lt;br /&gt;
&amp;lt;/translate&amp;gt;&lt;br /&gt;
&amp;lt;translate&amp;gt;&lt;br /&gt;
&amp;lt;!--T:85--&amp;gt;&lt;br /&gt;
All quest events extend &amp;lt;code&amp;gt;QuestLifecycleEvent&amp;lt;/code&amp;gt; and share its fields: &amp;lt;code&amp;gt;player&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;questKey&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;sagaId:questId&amp;lt;/code&amp;gt; for saga quests, the string id for side quests), &amp;lt;code&amp;gt;saga&amp;lt;/code&amp;gt; (null for side quests), &amp;lt;code&amp;gt;quest&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;partyMembers&amp;lt;/code&amp;gt;.&lt;br /&gt;
&amp;lt;/translate&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! &amp;lt;translate&amp;gt;&amp;lt;!--T:86--&amp;gt; Event&amp;lt;/translate&amp;gt; !! &amp;lt;translate&amp;gt;&amp;lt;!--T:87--&amp;gt; Cancelable&amp;lt;/translate&amp;gt; !! &amp;lt;translate&amp;gt;&amp;lt;!--T:88--&amp;gt; Fires when&amp;lt;/translate&amp;gt; !! &amp;lt;translate&amp;gt;&amp;lt;!--T:89--&amp;gt; Extra fields&amp;lt;/translate&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;QuestStartEvent&amp;lt;/code&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:90--&amp;gt; Yes&amp;lt;/translate&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:91--&amp;gt; Before a quest is accepted.&amp;lt;/translate&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:92--&amp;gt; &amp;lt;code&amp;gt;difficulty&amp;lt;/code&amp;gt; (settable)&amp;lt;/translate&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;QuestObjectiveProgressEvent&amp;lt;/code&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:93--&amp;gt; Yes&amp;lt;/translate&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:94--&amp;gt; Before objective progress is stored.&amp;lt;/translate&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:95--&amp;gt; &amp;lt;code&amp;gt;objectiveIndex&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;oldProgress&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;newProgress&amp;lt;/code&amp;gt; (settable), &amp;lt;code&amp;gt;objectiveRequired&amp;lt;/code&amp;gt;&amp;lt;/translate&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;QuestFailEvent&amp;lt;/code&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:96--&amp;gt; Yes&amp;lt;/translate&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:97--&amp;gt; Before a quest is marked as failed.&amp;lt;/translate&amp;gt; || &amp;lt;code&amp;gt;reason&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;PLAYER_DEATH&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;FORCED_RESET&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;SCRIPT&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;TIME_EXPIRED&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ESCORT_FAILED&amp;lt;/code&amp;gt;)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;QuestTurnInEvent&amp;lt;/code&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:98--&amp;gt; Yes&amp;lt;/translate&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:99--&amp;gt; Before a quest turn-in is applied.&amp;lt;/translate&amp;gt; || &amp;lt;code&amp;gt;npcId&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;QuestRewardClaimEvent&amp;lt;/code&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:100--&amp;gt; Yes&amp;lt;/translate&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:101--&amp;gt; Before an individual reward is claimed.&amp;lt;/translate&amp;gt; || &amp;lt;code&amp;gt;rewardIndex&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;QuestCompletedEvent&amp;lt;/code&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:102--&amp;gt; No&amp;lt;/translate&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:103--&amp;gt; When a quest completes.&amp;lt;/translate&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:104--&amp;gt; Shared fields only&amp;lt;/translate&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;translate&amp;gt;&lt;br /&gt;
=== Client events === &amp;lt;!--T:105--&amp;gt;&lt;br /&gt;
&amp;lt;/translate&amp;gt;&lt;br /&gt;
&amp;lt;translate&amp;gt;&lt;br /&gt;
&amp;lt;!--T:106--&amp;gt;&lt;br /&gt;
Client-only events live on &amp;lt;code&amp;gt;com.dragonminez.client.events.DMZClientEvent&amp;lt;/code&amp;gt; and are posted on the Forge bus of the physical client. Register these listeners with &amp;lt;code&amp;gt;value = Dist.CLIENT&amp;lt;/code&amp;gt;. None of them is cancelable, and they are informational: the server still decides what actually happens.&lt;br /&gt;
&amp;lt;/translate&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! &amp;lt;translate&amp;gt;&amp;lt;!--T:107--&amp;gt; Event&amp;lt;/translate&amp;gt; !! &amp;lt;translate&amp;gt;&amp;lt;!--T:108--&amp;gt; Fires when&amp;lt;/translate&amp;gt; !! &amp;lt;translate&amp;gt;&amp;lt;!--T:109--&amp;gt; Key fields&amp;lt;/translate&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PlayerAttackStart&amp;lt;/code&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:110--&amp;gt; The local player starts the attack windup.&amp;lt;/translate&amp;gt; || &amp;lt;code&amp;gt;player&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;attackHand&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PlayerAttackHit&amp;lt;/code&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:111--&amp;gt; The local player&amp;#039;s attack resolves its targets (zero or more).&amp;lt;/translate&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:112--&amp;gt; &amp;lt;code&amp;gt;player&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;attackHand&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;targets&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;cursorTarget&amp;lt;/code&amp;gt; (nullable)&amp;lt;/translate&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;KiAttackCast&amp;lt;/code&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:113--&amp;gt; The local player starts charging the ki attack in a slot.&amp;lt;/translate&amp;gt; || &amp;lt;code&amp;gt;player&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;slot&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;KiAttackRelease&amp;lt;/code&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:114--&amp;gt; The local player releases a charged ki attack.&amp;lt;/translate&amp;gt; || &amp;lt;code&amp;gt;player&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;StrikeAttack&amp;lt;/code&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:115--&amp;gt; The local player starts a strike attack.&amp;lt;/translate&amp;gt; || &amp;lt;code&amp;gt;player&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;targetId&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;translate&amp;gt;&lt;br /&gt;
== Reading player state == &amp;lt;!--T:116--&amp;gt;&lt;br /&gt;
&amp;lt;/translate&amp;gt;&lt;br /&gt;
&amp;lt;translate&amp;gt;&lt;br /&gt;
&amp;lt;!--T:117--&amp;gt;&lt;br /&gt;
Get the capability from any &amp;lt;code&amp;gt;Player&amp;lt;/code&amp;gt; (a server player, or the local player on the client; DMZ keeps the client copy in sync):&lt;br /&gt;
&amp;lt;/translate&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
StatsProvider.get(StatsCapability.INSTANCE, player).ifPresent(data -&amp;gt; {&lt;br /&gt;
    String race = data.getCharacter().getRaceName();&lt;br /&gt;
    String activeForm = data.getCharacter().getActiveForm();&lt;br /&gt;
    float currentKi = data.getResources().getCurrentEnergy();&lt;br /&gt;
    float maxKi = data.getMaxEnergy();&lt;br /&gt;
    int level = data.getLevel();&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;translate&amp;gt;&lt;br /&gt;
&amp;lt;!--T:118--&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;StatsProvider.get(cap, entity)&amp;lt;/code&amp;gt; is a shortcut for &amp;lt;code&amp;gt;player.getCapability(StatsCapability.INSTANCE)&amp;lt;/code&amp;gt;; both return a &amp;lt;code&amp;gt;LazyOptional&amp;lt;StatsData&amp;gt;&amp;lt;/code&amp;gt;. DMZ&amp;#039;s getters are generated by Lombok at compile time, so you don&amp;#039;t need Lombok in your add-on to call them.&lt;br /&gt;
&amp;lt;/translate&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;translate&amp;gt;&lt;br /&gt;
&amp;lt;!--T:119--&amp;gt;&lt;br /&gt;
Useful reads on &amp;lt;code&amp;gt;StatsData&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;/translate&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! &amp;lt;translate&amp;gt;&amp;lt;!--T:120--&amp;gt; Getter&amp;lt;/translate&amp;gt; !! &amp;lt;translate&amp;gt;&amp;lt;!--T:121--&amp;gt; Returns&amp;lt;/translate&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;getCharacter().getRaceName() / getCharacterClass() / getGender()&amp;lt;/code&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:122--&amp;gt; Race, class and gender&amp;lt;/translate&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;getCharacter().getActiveForm() / getActiveFormGroup()&amp;lt;/code&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:123--&amp;gt; Current race form (an empty string in base form)&amp;lt;/translate&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;getCharacter().getActiveStackForm() / getActiveStackFormGroup()&amp;lt;/code&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:124--&amp;gt; Current stack form (for example the Kaioken tier)&amp;lt;/translate&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;getStats().getStrength() / getStrikePower() / getResistance() / getVitality() / getKiPower() / getEnergy()&amp;lt;/code&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:125--&amp;gt; Base stat values&amp;lt;/translate&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;getResources().getCurrentEnergy() / getCurrentStamina() / getCurrentPoise() / getAlignment()&amp;lt;/code&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:126--&amp;gt; Current resource pools and alignment&amp;lt;/translate&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;getMaxHealth() / getMaxEnergy() / getMaxStamina() / getMaxPoise()&amp;lt;/code&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:127--&amp;gt; Calculated resource caps&amp;lt;/translate&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;getBattlePower() / getMeleeDamage() / getStrikeDamage() / getKiDamage() / getDefense()&amp;lt;/code&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:128--&amp;gt; Calculated combat stats&amp;lt;/translate&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;getLevel()&amp;lt;/code&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:129--&amp;gt; Computed player level&amp;lt;/translate&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;getPlayerQuestData()&amp;lt;/code&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:130--&amp;gt; Quest progress (&amp;lt;code&amp;gt;getQuestStatus(questKey)&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;isQuestAccepted(questKey)&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;isQuestCompleted(questKey)&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;isSagaLocked(sagaId)&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;getTrackedQuestId()&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;getDifficulty()&amp;lt;/code&amp;gt;)&amp;lt;/translate&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;getSkills()&amp;lt;/code&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:131--&amp;gt; Skill levels (&amp;lt;code&amp;gt;hasSkill(name)&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;getSkillLevel(name)&amp;lt;/code&amp;gt;)&amp;lt;/translate&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;getStatus()&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;getEffects()&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;getTechniques()&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;getBonusStats()&amp;lt;/code&amp;gt; || &amp;lt;translate&amp;gt;&amp;lt;!--T:132--&amp;gt; Status flags, active effects, ki and strike techniques, bonus stat modifiers&amp;lt;/translate&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;translate&amp;gt;&lt;br /&gt;
&amp;lt;!--T:133--&amp;gt;&lt;br /&gt;
Race, form and stat math reads the live config every time, so values always reflect the current server config (including after &amp;lt;code&amp;gt;/dmzreload&amp;lt;/code&amp;gt;).&lt;br /&gt;
&amp;lt;/translate&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;translate&amp;gt;&lt;br /&gt;
== Changing state safely == &amp;lt;!--T:134--&amp;gt;&lt;br /&gt;
&amp;lt;/translate&amp;gt;&lt;br /&gt;
&amp;lt;translate&amp;gt;&lt;br /&gt;
&amp;lt;!--T:135--&amp;gt;&lt;br /&gt;
DMZ&amp;#039;s own stat setters (for example &amp;lt;code&amp;gt;Stats.setStrength()&amp;lt;/code&amp;gt;) post a cancelable event first and only apply the change if it isn&amp;#039;t cancelled:&lt;br /&gt;
&amp;lt;/translate&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
DMZEvent.StatChangeEvent event = new DMZEvent.StatChangeEvent(player, StatType.STRENGTH, oldValue, newValue);&lt;br /&gt;
if (!MinecraftForge.EVENT_BUS.post(event)) {&lt;br /&gt;
    // apply the change&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;translate&amp;gt;&lt;br /&gt;
&amp;lt;!--T:136--&amp;gt;&lt;br /&gt;
In your add-on, prefer &amp;#039;&amp;#039;&amp;#039;reacting to&amp;#039;&amp;#039;&amp;#039; events (changing their settable fields, or cancelling them) over calling DMZ setters directly. Not every setter validates or posts an event (most &amp;lt;code&amp;gt;Resources&amp;lt;/code&amp;gt; setters, for example, just clamp and apply with no event), so going through the event path is the one integration point guaranteed to stay stable.&lt;br /&gt;
&amp;lt;/translate&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;translate&amp;gt;&lt;br /&gt;
&amp;lt;!--T:137--&amp;gt;&lt;br /&gt;
If you do change DMZ data from the server, do it on the server thread and send the client a fresh copy afterwards, the same way DMZ does:&lt;br /&gt;
&amp;lt;/translate&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
NetworkHandler.sendToTrackingEntityAndSelf(new StatsSyncS2C(serverPlayer), serverPlayer);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;translate&amp;gt;&lt;br /&gt;
&amp;lt;!--T:138--&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;StatsSyncS2C&amp;lt;/code&amp;gt; sends the full player data; DMZ also uses &amp;lt;code&amp;gt;ProgressionSyncS2C&amp;lt;/code&amp;gt; (stats, bonus stats, skills, techniques, quest data) and &amp;lt;code&amp;gt;ResourceSyncS2C&amp;lt;/code&amp;gt; (resources and status) for smaller updates.&lt;br /&gt;
&amp;lt;/translate&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;translate&amp;gt;&lt;br /&gt;
== Custom quest objectives and rewards == &amp;lt;!--T:139--&amp;gt;&lt;br /&gt;
&amp;lt;/translate&amp;gt;&lt;br /&gt;
{{See also|Custom Quests}}&lt;br /&gt;
&amp;lt;translate&amp;gt;&lt;br /&gt;
&amp;lt;!--T:140--&amp;gt;&lt;br /&gt;
Add-ons can add new quest objective and reward &amp;#039;&amp;#039;&amp;#039;types&amp;#039;&amp;#039;&amp;#039; that quest JSON files can then use, without touching DMZ&amp;#039;s parser. Register them during mod setup (for example in &amp;lt;code&amp;gt;FMLCommonSetupEvent&amp;lt;/code&amp;gt;) on &amp;#039;&amp;#039;&amp;#039;both&amp;#039;&amp;#039;&amp;#039; sides: the client rebuilds quests from the synced registry with the same factories.&lt;br /&gt;
&amp;lt;/translate&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
QuestObjectiveRegistry.register(&amp;quot;MEDITATE&amp;quot;,&lt;br /&gt;
    json -&amp;gt; new MeditateObjective(json.get(&amp;quot;seconds&amp;quot;).getAsInt()),                                 // parse quest JSON&lt;br /&gt;
    (objective, out) -&amp;gt; out.addProperty(&amp;quot;seconds&amp;quot;, ((MeditateObjective) objective).getSeconds()),  // client sync fields&lt;br /&gt;
    objective -&amp;gt; Component.translatable(&amp;quot;myaddon.quest.meditate.obj&amp;quot;));                            // HUD/journal text&lt;br /&gt;
&lt;br /&gt;
QuestRewardRegistry.register(&amp;quot;MY_CURRENCY&amp;quot;,&lt;br /&gt;
    json -&amp;gt; new MyCurrencyReward(json.get(&amp;quot;amount&amp;quot;).getAsInt()),&lt;br /&gt;
    (reward, out) -&amp;gt; out.addProperty(&amp;quot;amount&amp;quot;, ((MyCurrencyReward) reward).getAmount()));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;translate&amp;gt;&lt;br /&gt;
&amp;lt;!--T:141--&amp;gt;&lt;br /&gt;
The contract:&lt;br /&gt;
&amp;lt;/translate&amp;gt;&lt;br /&gt;
&amp;lt;translate&amp;gt;&lt;br /&gt;
&amp;lt;!--T:142--&amp;gt;&lt;br /&gt;
* Objective classes extend &amp;lt;code&amp;gt;QuestObjective&amp;lt;/code&amp;gt; and call the &amp;lt;code&amp;gt;QuestObjective(String customType, int required)&amp;lt;/code&amp;gt; constructor; reward classes extend &amp;lt;code&amp;gt;QuestReward&amp;lt;/code&amp;gt;, call &amp;lt;code&amp;gt;QuestReward(String customType)&amp;lt;/code&amp;gt; and implement &amp;lt;code&amp;gt;giveReward(ServerPlayer)&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;getDescription()&amp;lt;/code&amp;gt;. Objectives must also implement &amp;lt;code&amp;gt;checkProgress(Object... params)&amp;lt;/code&amp;gt;.&lt;br /&gt;
* In quest JSON, use your key as the &amp;lt;code&amp;gt;&amp;quot;type&amp;quot;&amp;lt;/code&amp;gt; (for example &amp;lt;code&amp;gt;{&amp;quot;type&amp;quot;: &amp;quot;MEDITATE&amp;quot;, &amp;quot;seconds&amp;quot;: 60}&amp;lt;/code&amp;gt;). Type keys are case-insensitive (stored in upper case). Treat them like registry names: don&amp;#039;t rename them once quests use them.&lt;br /&gt;
* The sync writer must write every field your factory reads, because the client parses the synced JSON again with your factory.&lt;br /&gt;
* Unknown types are reported in the JSON load report (see [[Special:MyLanguage/Developer Scope and Prerequisites#Finding JSON mistakes|Finding JSON mistakes]]) and the objective or reward is skipped.&lt;br /&gt;
* Progress is server-authoritative and event-driven: listen to your own game events on the server and store progress with &amp;lt;code&amp;gt;PlayerQuestData.setObjectiveProgress(questKey, objectiveIndex, progress)&amp;lt;/code&amp;gt;, then sync with &amp;lt;code&amp;gt;ProgressionSyncS2C&amp;lt;/code&amp;gt;. Use &amp;lt;code&amp;gt;DMZEvent.QuestObjectiveProgressEvent&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;QuestCompletedEvent&amp;lt;/code&amp;gt; to react to built-in quests.&lt;br /&gt;
&amp;lt;/translate&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;translate&amp;gt;&lt;br /&gt;
&amp;lt;!--T:143--&amp;gt;&lt;br /&gt;
See [[Special:MyLanguage/Custom Quests|Custom Quests]] for the quest JSON format.&lt;br /&gt;
&amp;lt;/translate&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;translate&amp;gt;&lt;br /&gt;
== Custom text placeholders == &amp;lt;!--T:144--&amp;gt;&lt;br /&gt;
&amp;lt;/translate&amp;gt;&lt;br /&gt;
&amp;lt;translate&amp;gt;&lt;br /&gt;
&amp;lt;!--T:145--&amp;gt;&lt;br /&gt;
Quest, dialogue and NPC text supports &amp;lt;code&amp;gt;%placeholders%&amp;lt;/code&amp;gt; such as &amp;lt;code&amp;gt;%player%&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;%race%&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;%class%&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;%level%&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;%alignment%&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;%deaths%&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;%form%&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;%dimension%&amp;lt;/code&amp;gt;. Add your own during mod setup:&lt;br /&gt;
&amp;lt;/translate&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
DMZTextPlaceholders.register(&amp;quot;zeni&amp;quot;, (player, data) -&amp;gt; String.valueOf(MyAddon.getZeni(player)));&lt;br /&gt;
// &amp;quot;%zeni%&amp;quot; in quest/dialogue text now resolves to your value&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;translate&amp;gt;&lt;br /&gt;
&amp;lt;!--T:146--&amp;gt;&lt;br /&gt;
Keys are case-insensitive. The resolver runs on whichever side renders the text (usually the client), and it must handle a &amp;lt;code&amp;gt;null&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;StatsData&amp;lt;/code&amp;gt;.&lt;br /&gt;
&amp;lt;/translate&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;translate&amp;gt;&lt;br /&gt;
== Utility menu buttons == &amp;lt;!--T:147--&amp;gt;&lt;br /&gt;
&amp;lt;/translate&amp;gt;&lt;br /&gt;
&amp;lt;translate&amp;gt;&lt;br /&gt;
&amp;lt;!--T:148--&amp;gt;&lt;br /&gt;
The utility (radial) menu on the client has two free slots, on the left and right of the wheel, reserved for add-ons. Add a button from client setup:&lt;br /&gt;
&amp;lt;/translate&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
UtilityMenuScreen.addMenuSlot(new IUtilityMenuSlot() {&lt;br /&gt;
    @Override&lt;br /&gt;
    public ButtonInfo render(StatsData statsData) {&lt;br /&gt;
        return new ButtonInfo(Component.literal(&amp;quot;My Addon&amp;quot;), Component.literal(&amp;quot;Open&amp;quot;));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    @Override&lt;br /&gt;
    public void handle(StatsData statsData, boolean rightClick) {&lt;br /&gt;
        // client side: open your screen or send your own packet to the server&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;translate&amp;gt;&lt;br /&gt;
&amp;lt;!--T:149--&amp;gt;&lt;br /&gt;
Slots are filled in registration order; registrations beyond the two free slots are not shown. Override &amp;lt;code&amp;gt;hasRightClickAction&amp;lt;/code&amp;gt; to return &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt; if your button also reacts to right-click. &amp;lt;code&amp;gt;IUtilityMenuSlot&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;ButtonInfo&amp;lt;/code&amp;gt; live in &amp;lt;code&amp;gt;com.dragonminez.client.gui.utilitymenu&amp;lt;/code&amp;gt;.&lt;br /&gt;
&amp;lt;/translate&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;translate&amp;gt;&lt;br /&gt;
== Armor and render layers == &amp;lt;!--T:150--&amp;gt;&lt;br /&gt;
&amp;lt;/translate&amp;gt;&lt;br /&gt;
&amp;lt;translate&amp;gt;&lt;br /&gt;
&amp;lt;!--T:151--&amp;gt;&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Armor from your add-on:&amp;#039;&amp;#039;&amp;#039; DMZ&amp;#039;s armor item class &amp;lt;code&amp;gt;DbzArmorItem&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;common/init/armor&amp;lt;/code&amp;gt;) has a constructor &amp;lt;code&amp;gt;DbzArmorItem(material, type, properties, modId, itemId)&amp;lt;/code&amp;gt;. Pass your own &amp;lt;code&amp;gt;modId&amp;lt;/code&amp;gt; and the textures are read from your own namespace: &amp;lt;code&amp;gt;assets/&amp;lt;modId&amp;gt;/textures/armor/&amp;lt;itemId&amp;gt;_layer1.png&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;_layer2&amp;lt;/code&amp;gt; for leggings), plus the optional &amp;lt;code&amp;gt;&amp;lt;itemId&amp;gt;_damaged_layer1.png&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;_damaged_layer2.png&amp;lt;/code&amp;gt;, used once the item has lost more than half of its durability.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Other armor:&amp;#039;&amp;#039;&amp;#039; regular &amp;lt;code&amp;gt;ArmorItem&amp;lt;/code&amp;gt;s from other mods are drawn on DMZ&amp;#039;s player model with their normal armor texture.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Third-party render layers:&amp;#039;&amp;#039;&amp;#039; render layers that other mods add to the vanilla player renderer are forwarded onto DMZ&amp;#039;s player model. Vanilla layers and cosmetic armor layers are skipped, and nothing is forwarded while the player is an Oozaru.&lt;br /&gt;
&amp;lt;/translate&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;translate&amp;gt;&lt;br /&gt;
== Networking == &amp;lt;!--T:152--&amp;gt;&lt;br /&gt;
&amp;lt;/translate&amp;gt;&lt;br /&gt;
&amp;lt;translate&amp;gt;&lt;br /&gt;
&amp;lt;!--T:153--&amp;gt;&lt;br /&gt;
DMZ&amp;#039;s channel is &amp;lt;code&amp;gt;NetworkHandler.INSTANCE&amp;lt;/code&amp;gt; (a Forge &amp;lt;code&amp;gt;SimpleChannel&amp;lt;/code&amp;gt; at &amp;lt;code&amp;gt;dragonminez:network&amp;lt;/code&amp;gt;). Don&amp;#039;t register your own packets on it: DMZ assigns packet ids by registration order, so anything you add would shift or collide with DMZ&amp;#039;s ids. Register your own &amp;lt;code&amp;gt;SimpleChannel&amp;lt;/code&amp;gt; in your add-on instead, and use DMZ&amp;#039;s as a reference for the pattern (&amp;lt;code&amp;gt;messageBuilder&amp;lt;/code&amp;gt;, encoder, decoder and handler, with an explicit direction).&lt;br /&gt;
&amp;lt;/translate&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;translate&amp;gt;&lt;br /&gt;
&amp;lt;!--T:154--&amp;gt;&lt;br /&gt;
You can use DMZ&amp;#039;s send helpers (&amp;lt;code&amp;gt;sendToPlayer&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;sendToTrackingEntityAndSelf&amp;lt;/code&amp;gt;, ...) to send DMZ&amp;#039;s own sync packets, as shown above.&lt;br /&gt;
&amp;lt;/translate&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;translate&amp;gt;&lt;br /&gt;
&amp;lt;!--T:155--&amp;gt;&lt;br /&gt;
Never trust the client in your own packets either: validate on the server anything that affects stats, unlocks, quests, wishes or progression.&lt;br /&gt;
&amp;lt;/translate&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;translate&amp;gt;&lt;br /&gt;
&amp;lt;!--T:156--&amp;gt;&lt;br /&gt;
There is no client-side &amp;quot;data synced&amp;quot; event. On the client, read the capability when you need it (for example while rendering) instead of trying to intercept DMZ packets.&lt;br /&gt;
&amp;lt;/translate&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;translate&amp;gt;&lt;br /&gt;
== Using DMZ&amp;#039;s registries == &amp;lt;!--T:157--&amp;gt;&lt;br /&gt;
&amp;lt;/translate&amp;gt;&lt;br /&gt;
&amp;lt;translate&amp;gt;&lt;br /&gt;
&amp;lt;!--T:158--&amp;gt;&lt;br /&gt;
Import the &amp;lt;code&amp;gt;Main*&amp;lt;/code&amp;gt; registry holders directly instead of hardcoding resource locations:&lt;br /&gt;
&amp;lt;/translate&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
import com.dragonminez.common.init.MainItems;&lt;br /&gt;
import com.dragonminez.common.init.MainAttributes;&lt;br /&gt;
&lt;br /&gt;
Item redCapsule = MainItems.RED_CAPSULE.get();&lt;br /&gt;
Attribute strength = MainAttributes.STRENGTH.get();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;translate&amp;gt;&lt;br /&gt;
&amp;lt;!--T:159--&amp;gt;&lt;br /&gt;
Available under &amp;lt;code&amp;gt;common/init/&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;MainItems&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MainBlocks&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MainBlockEntities&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MainEntities&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MainAttributes&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MainEffects&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MainEnchants&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MainPotions&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MainSounds&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MainParticles&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MainFluids&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MainMenus&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MainRecipes&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MainTabs&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MainTags&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MainVillagers&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MainDamageTypes&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MainGameRules&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MainLootModifiers&amp;lt;/code&amp;gt;.&lt;br /&gt;
&amp;lt;/translate&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;translate&amp;gt;&lt;br /&gt;
== Optional dependency pattern == &amp;lt;!--T:160--&amp;gt;&lt;br /&gt;
&amp;lt;/translate&amp;gt;&lt;br /&gt;
&amp;lt;translate&amp;gt;&lt;br /&gt;
&amp;lt;!--T:161--&amp;gt;&lt;br /&gt;
If your add-on should work with or without DMZ installed, follow DMZ&amp;#039;s own pattern for optional integrations (&amp;lt;code&amp;gt;common/compat/WeaponLevelingCompat.java&amp;lt;/code&amp;gt;):&lt;br /&gt;
&amp;lt;/translate&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public final class DmzCompat {&lt;br /&gt;
    private static Boolean loaded;&lt;br /&gt;
&lt;br /&gt;
    public static boolean isLoaded() {&lt;br /&gt;
        if (loaded == null) loaded = ModList.get().isLoaded(&amp;quot;dragonminez&amp;quot;);&lt;br /&gt;
        return loaded;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public static int getLevel(Player player) {&lt;br /&gt;
        if (!isLoaded()) return 0;   // safe fallback without DMZ&lt;br /&gt;
        return Impl.getLevel(player);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Only this nested class imports DMZ classes, so it is never loaded without DMZ.&lt;br /&gt;
    private static final class Impl {&lt;br /&gt;
        static int getLevel(Player player) {&lt;br /&gt;
            return StatsProvider.get(StatsCapability.INSTANCE, player).map(StatsData::getLevel).orElse(0);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;translate&amp;gt;&lt;br /&gt;
&amp;lt;!--T:162--&amp;gt;&lt;br /&gt;
# Check &amp;lt;code&amp;gt;ModList.get().isLoaded(&amp;quot;dragonminez&amp;quot;)&amp;lt;/code&amp;gt; once and cache the result.&lt;br /&gt;
# Keep every DMZ import inside classes that are only touched after that check (event listeners for DMZ events included: register them manually, and only when DMZ is loaded).&lt;br /&gt;
# Guard every call that touches DMZ behind that flag, with a safe fallback or default when it is &amp;lt;code&amp;gt;false&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Log a clear info or warning message either way, so server owners can tell at a glance whether the integration is active.&lt;br /&gt;
&amp;lt;/translate&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;translate&amp;gt;&lt;br /&gt;
== Next step == &amp;lt;!--T:163--&amp;gt;&lt;br /&gt;
&amp;lt;/translate&amp;gt;&lt;br /&gt;
&amp;lt;translate&amp;gt;&lt;br /&gt;
&amp;lt;!--T:164--&amp;gt;&lt;br /&gt;
See [[Special:MyLanguage/Creating a DMZ Addon|Creating a DMZ Addon]] for the full Gradle project setup and the &amp;lt;code&amp;gt;mods.toml&amp;lt;/code&amp;gt; dependency declaration.&lt;br /&gt;
&amp;lt;/translate&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{Navbox Add-ons}}&lt;/div&gt;</summary>
		<author><name>Neb</name></author>
	</entry>
</feed>