@@ -54,16 +54,23 @@ public class BlockBreakSpeed {
5454 StateTypes .ENDER_CHEST
5555 );
5656
57- private static final boolean serverUsesComponentsAndRules = PacketEvents .getAPI ().getServerManager ().getVersion ().isNewerThanOrEquals (ServerVersion .V_1_20_5 );
57+ private static final boolean SERVER_USES_COMPONENTS_AND_RULES = PacketEvents .getAPI ().getServerManager ().getVersion ().isNewerThanOrEquals (ServerVersion .V_1_20_5 );
58+
59+ record ToolSpeedData (float speedMultiplier , boolean isCorrectToolForDrop ) {
60+ }
5861
5962 public static double getBlockDamage (GrimPlayer player , WrappedBlockState block ) {
63+ ItemStack tool = player .inventory .getHeldItem ();
64+ return getBlockDamage (player , tool , block .getType ());
65+ }
66+
67+ public static double getBlockDamage (GrimPlayer player , ItemStack tool , StateType block ) {
6068 // GET destroy speed
6169 // Starts with itemstack get destroy speed
62- ItemStack tool = player .inventory .getHeldItem ();
6370 ItemType toolType = tool .getType ();
6471
6572 if (player .gamemode == GameMode .CREATIVE ) {
66- if (serverUsesComponentsAndRules && player .getClientVersion ().isNewerThanOrEquals (ClientVersion .V_1_21_5 )) {
73+ if (SERVER_USES_COMPONENTS_AND_RULES && player .getClientVersion ().isNewerThanOrEquals (ClientVersion .V_1_21_5 )) {
6774 return tool .getComponent (ComponentTypes .TOOL )
6875 .map (ItemTool ::isCanDestroyBlocksInCreative )
6976 .orElse (true ) ? 1 : 0 ;
@@ -77,137 +84,35 @@ public static double getBlockDamage(GrimPlayer player, WrappedBlockState block)
7784 }
7885 }
7986
80- float blockHardness = block .getType (). getHardness ();
87+ float blockHardness = block .getHardness ();
8188
8289 // 1.15.2 and below need this hack
83- if ((block . getType () == StateTypes .PISTON || block . getType () == StateTypes .PISTON_HEAD || block . getType () == StateTypes .STICKY_PISTON ) && player .getClientVersion ().isOlderThanOrEquals (ClientVersion .V_1_15_2 )) {
90+ if ((block == StateTypes .PISTON || block == StateTypes .PISTON_HEAD || block == StateTypes .STICKY_PISTON ) && player .getClientVersion ().isOlderThanOrEquals (ClientVersion .V_1_15_2 )) {
8491 blockHardness = 0.5f ;
8592 }
8693
8794 if (blockHardness == -1 ) return 0 ; // Unbreakable block
8895
89- boolean isCorrectToolForDrop = false ;
90- float speedMultiplier = 1.0F ;
91-
92- // TODO technically its possible to use packet level manipulation to enforce Tool rules on newer clients on older servers
93- // But I've yet to hear of anyone even trying to do such a thing rather than just update the server
94- // And we can't support this because we don't see the tool components/data before Via
95- if (serverUsesComponentsAndRules && player .getClientVersion ().isNewerThanOrEquals (ClientVersion .V_1_20_5 )) {
96- Optional <ItemTool > toolComponentOpt = tool .getComponent (ComponentTypes .TOOL );
97- if (toolComponentOpt .isPresent ()) {
98- ItemTool itemTool = toolComponentOpt .get ();
99-
100- // Initialize with final default values. These will be used if the loop doesn't find a value.
101- // isCorrectToolForDrop is already set to false, no need to set again as default
102- speedMultiplier = itemTool .getDefaultMiningSpeed ();
103-
104- boolean speedFound = false ;
105- boolean dropsFound = false ;
106-
107- for (ItemTool .Rule rule : itemTool .getRules ()) {
108- MappedEntitySet <StateType .Mapped > predicate = rule .getBlocks ();
109- ResourceLocation tagKey = predicate .getTagKey ();
110- boolean isMatch ;
111-
112- // First, determine if the current rule even applies to this block.
113- if (tagKey != null ) {
114- SyncedTag <StateType > playerTag = player .tagManager .block (tagKey );
115- isMatch = (playerTag != null && playerTag .contains (block .getType ()))
116- || BlockTags .getByName (tagKey .getKey ()).contains (block .getType ());
117- } else {
118- isMatch = predicate .getEntities ().contains (block .getType ().getMapped ());
119- }
120-
121- // If the rule matches the block, check if we still need its properties.
122- if (isMatch ) {
123- // Check for speed if we haven't found it yet.
124- if (!speedFound && rule .getSpeed () != null ) {
125- speedMultiplier = rule .getSpeed ();
126- speedFound = true ;
127- }
128-
129- // Check for drops if we haven't found it yet.
130- if (!dropsFound && rule .getCorrectForDrops () != null ) {
131- isCorrectToolForDrop = rule .getCorrectForDrops ();
132- dropsFound = true ;
133- }
134- }
135-
136- if (speedFound && dropsFound ) {
137- break ;
138- }
139- }
140- }
96+ final ToolSpeedData toolSpeedData ;
97+ if (SERVER_USES_COMPONENTS_AND_RULES && player .getClientVersion ().isNewerThanOrEquals (ClientVersion .V_1_20_5 )) {
98+ toolSpeedData = getModernToolSpeedData (player , tool , block );
14199 } else {
142- // 1.13 and below need their own huge methods to support this...
143- if (toolType .hasAttribute (ItemTypes .ItemAttribute .AXE )) {
144- isCorrectToolForDrop = player .tagManager .block (SyncedTags .MINEABLE_AXE ).contains (block .getType ());
145- } else if (toolType .hasAttribute (ItemTypes .ItemAttribute .PICKAXE )) {
146- isCorrectToolForDrop = player .tagManager .block (SyncedTags .MINEABLE_PICKAXE ).contains (block .getType ());
147- } else if (toolType .hasAttribute (ItemTypes .ItemAttribute .SHOVEL )) {
148- isCorrectToolForDrop = player .tagManager .block (SyncedTags .MINEABLE_SHOVEL ).contains (block .getType ());
149- } else if (toolType .hasAttribute (ItemTypes .ItemAttribute .HOE )) {
150- isCorrectToolForDrop = player .tagManager .block (SyncedTags .MINEABLE_HOE ).contains (block .getType ());
151- }
152-
153- if (isCorrectToolForDrop ) {
154- int tier = 0 ;
155- if (toolType .hasAttribute (ItemTypes .ItemAttribute .WOOD_TIER )) { // Tier 0
156- speedMultiplier = 2.0f ;
157- } else if (toolType .hasAttribute (ItemTypes .ItemAttribute .STONE_TIER )) { // Tier 1
158- speedMultiplier = 4.0f ;
159- tier = 1 ;
160- } else if (toolType .hasAttribute (ItemTypes .ItemAttribute .IRON_TIER )) { // Tier 2
161- speedMultiplier = 6.0f ;
162- tier = 2 ;
163- } else if (toolType .hasAttribute (ItemTypes .ItemAttribute .DIAMOND_TIER )) { // Tier 3
164- speedMultiplier = 8.0f ;
165- tier = 3 ;
166- } else if (toolType .hasAttribute (ItemTypes .ItemAttribute .GOLD_TIER )) { // Tier 0
167- speedMultiplier = 12.0f ;
168- } else if (toolType .hasAttribute (ItemTypes .ItemAttribute .NETHERITE_TIER )) { // Tier 4
169- speedMultiplier = 9.0f ;
170- tier = 4 ;
171- }
100+ toolSpeedData = getLegacyToolSpeedData (player , tool , block );
101+ }
172102
173- if (tier < 3 && player .tagManager .block (SyncedTags .NEEDS_DIAMOND_TOOL ).contains (block .getType ())) {
174- isCorrectToolForDrop = false ;
175- } else if (tier < 2 && player .tagManager .block (SyncedTags .NEEDS_IRON_TOOL ).contains (block .getType ())) {
176- isCorrectToolForDrop = false ;
177- } else if (tier < 1 && player .tagManager .block (SyncedTags .NEEDS_STONE_TOOL ).contains (block .getType ())) {
178- isCorrectToolForDrop = false ;
179- }
180- }
103+ final float speedMultiplier = getSpeedMultiplierFromToolData (player , tool , toolSpeedData );
181104
182- // Shears can mine some blocks faster
183- if (toolType == ItemTypes .SHEARS ) {
184- isCorrectToolForDrop = true ;
185-
186- if (block .getType () == StateTypes .COBWEB || Materials .isLeaves (block .getType ())) {
187- speedMultiplier = 15.0f ;
188- } else if (BlockTags .WOOL .contains (block .getType ())) {
189- speedMultiplier = 5.0f ;
190- } else if (block .getType () == StateTypes .VINE ||
191- block .getType () == StateTypes .GLOW_LICHEN ) {
192- speedMultiplier = 2.0f ;
193- } else {
194- isCorrectToolForDrop = block .getType () == StateTypes .COBWEB ||
195- block .getType () == StateTypes .REDSTONE_WIRE ||
196- block .getType () == StateTypes .TRIPWIRE ;
197- }
198- }
105+ final boolean canHarvest = !block .isRequiresCorrectTool () || toolSpeedData .isCorrectToolForDrop
106+ // temporary hardcode to workaround PE bug https://github.com/retrooper/packetevents/issues/1217; see https://github.com/GrimAnticheat/Grim/issues/2091
107+ || player .getClientVersion ().isNewerThanOrEquals (ClientVersion .V_1_21_4 ) && HARVESTABLE_TYPES_1_21_4 .contains (block );
199108
200- // Swords can also mine some blocks faster
201- if (toolType .hasAttribute (ItemTypes .ItemAttribute .SWORD )) {
202- if (block .getType () == StateTypes .COBWEB ) {
203- speedMultiplier = 15.0f ;
204- } else if (player .tagManager .block (SyncedTags .SWORD_EFFICIENT ).contains (block .getType ())) {
205- speedMultiplier = 1.5f ;
206- }
109+ float damage = speedMultiplier / blockHardness ;
110+ damage /= canHarvest ? 30F : 100F ;
111+ return damage ;
112+ }
207113
208- isCorrectToolForDrop = block .getType () == StateTypes .COBWEB ;
209- }
210- }
114+ private static float getSpeedMultiplierFromToolData (GrimPlayer player , ItemStack tool , ToolSpeedData data ) {
115+ float speedMultiplier = data .speedMultiplier ;
211116
212117 if (speedMultiplier > 1.0f ) {
213118 if (player .getClientVersion ().isNewerThanOrEquals (ClientVersion .V_1_21 ) && PacketEvents .getAPI ().getServerManager ().getVersion ().isNewerThanOrEquals (ServerVersion .V_1_21 )) {
@@ -262,13 +167,138 @@ public static double getBlockDamage(GrimPlayer player, WrappedBlockState block)
262167 speedMultiplier /= 5 ;
263168 }
264169
265- float damage = speedMultiplier / blockHardness ;
170+ return speedMultiplier ;
171+ }
266172
267- boolean canHarvest = !block .getType ().isRequiresCorrectTool () || isCorrectToolForDrop
268- // temporary hardcode to workaround PE bug https://github.com/retrooper/packetevents/issues/1217; see https://github.com/GrimAnticheat/Grim/issues/2091
269- || player .getClientVersion ().isNewerThanOrEquals (ClientVersion .V_1_21_4 ) && HARVESTABLE_TYPES_1_21_4 .contains (block .getType ());
270- damage /= canHarvest ? 30F : 100F ;
173+ // TODO technically its possible to use packet level manipulation to enforce Tool rules on newer clients on older servers
174+ // But I've yet to hear of anyone even trying to do such a thing rather than just update the server
175+ // And we can't support this because we don't see the tool components/data before Via
176+ private static ToolSpeedData getModernToolSpeedData (GrimPlayer player , ItemStack tool , StateType block ) {
177+ Optional <ItemTool > toolComponentOpt = tool .getComponent (ComponentTypes .TOOL );
178+ float speedMultiplier = 1.0f ;
179+ boolean isCorrectToolForDrop = false ;
180+ if (toolComponentOpt .isPresent ()) {
181+ ItemTool itemTool = toolComponentOpt .get ();
182+
183+ // Initialize with final default values. These will be used if the loop doesn't find a value.
184+ // isCorrectToolForDrop is already set to false, no need to set again as default
185+ speedMultiplier = itemTool .getDefaultMiningSpeed ();
186+
187+ boolean speedFound = false ;
188+ boolean dropsFound = false ;
189+
190+ for (ItemTool .Rule rule : itemTool .getRules ()) {
191+ MappedEntitySet <StateType .Mapped > predicate = rule .getBlocks ();
192+ ResourceLocation tagKey = predicate .getTagKey ();
193+ boolean isMatch ;
194+
195+ // First, determine if the current rule even applies to this block.
196+ if (tagKey != null ) {
197+ SyncedTag <StateType > playerTag = player .tagManager .block (tagKey );
198+ isMatch = (playerTag != null && playerTag .contains (block ))
199+ || BlockTags .getByName (tagKey .getKey ()).contains (block );
200+ } else {
201+ isMatch = predicate .getEntities ().contains (block .getMapped ());
202+ }
271203
272- return damage ;
204+ // If the rule matches the block, check if we still need its properties.
205+ if (isMatch ) {
206+ // Check for speed if we haven't found it yet.
207+ if (!speedFound && rule .getSpeed () != null ) {
208+ speedMultiplier = rule .getSpeed ();
209+ speedFound = true ;
210+ }
211+
212+ // Check for drops if we haven't found it yet.
213+ if (!dropsFound && rule .getCorrectForDrops () != null ) {
214+ isCorrectToolForDrop = rule .getCorrectForDrops ();
215+ dropsFound = true ;
216+ }
217+ }
218+
219+ if (speedFound && dropsFound ) {
220+ break ;
221+ }
222+ }
223+ }
224+ return new ToolSpeedData (speedMultiplier , isCorrectToolForDrop );
225+ }
226+
227+ private static ToolSpeedData getLegacyToolSpeedData (GrimPlayer player , ItemStack tool , StateType block ) {
228+ ItemType toolType = tool .getType ();
229+ float speedMultiplier = 1.0f ;
230+ boolean isCorrectToolForDrop = false ;
231+ // 1.13 and below need their own huge methods to support this...
232+ if (toolType .hasAttribute (ItemTypes .ItemAttribute .AXE )) {
233+ isCorrectToolForDrop = player .tagManager .block (SyncedTags .MINEABLE_AXE ).contains (block );
234+ } else if (toolType .hasAttribute (ItemTypes .ItemAttribute .PICKAXE )) {
235+ isCorrectToolForDrop = player .tagManager .block (SyncedTags .MINEABLE_PICKAXE ).contains (block );
236+ } else if (toolType .hasAttribute (ItemTypes .ItemAttribute .SHOVEL )) {
237+ isCorrectToolForDrop = player .tagManager .block (SyncedTags .MINEABLE_SHOVEL ).contains (block );
238+ } else if (toolType .hasAttribute (ItemTypes .ItemAttribute .HOE )) {
239+ isCorrectToolForDrop = player .tagManager .block (SyncedTags .MINEABLE_HOE ).contains (block );
240+ }
241+
242+ if (isCorrectToolForDrop ) {
243+ int tier = 0 ;
244+ if (toolType .hasAttribute (ItemTypes .ItemAttribute .WOOD_TIER )) { // Tier 0
245+ speedMultiplier = 2.0f ;
246+ } else if (toolType .hasAttribute (ItemTypes .ItemAttribute .STONE_TIER )) { // Tier 1
247+ speedMultiplier = 4.0f ;
248+ tier = 1 ;
249+ } else if (toolType .hasAttribute (ItemTypes .ItemAttribute .IRON_TIER )) { // Tier 2
250+ speedMultiplier = 6.0f ;
251+ tier = 2 ;
252+ } else if (toolType .hasAttribute (ItemTypes .ItemAttribute .DIAMOND_TIER )) { // Tier 3
253+ speedMultiplier = 8.0f ;
254+ tier = 3 ;
255+ } else if (toolType .hasAttribute (ItemTypes .ItemAttribute .GOLD_TIER )) { // Tier 0
256+ speedMultiplier = 12.0f ;
257+ } else if (toolType .hasAttribute (ItemTypes .ItemAttribute .NETHERITE_TIER )) { // Tier 4
258+ speedMultiplier = 9.0f ;
259+ tier = 4 ;
260+ }
261+
262+ if (tier < 3 && player .tagManager .block (SyncedTags .NEEDS_DIAMOND_TOOL ).contains (block )) {
263+ isCorrectToolForDrop = false ;
264+ } else if (tier < 2 && player .tagManager .block (SyncedTags .NEEDS_IRON_TOOL ).contains (block )) {
265+ isCorrectToolForDrop = false ;
266+ } else if (tier < 1 && player .tagManager .block (SyncedTags .NEEDS_STONE_TOOL ).contains (block )) {
267+ isCorrectToolForDrop = false ;
268+ }
269+ }
270+
271+ // Shears can mine some blocks faster
272+ if (toolType == ItemTypes .SHEARS ) {
273+ isCorrectToolForDrop = true ;
274+
275+ if (block == StateTypes .COBWEB || Materials .isLeaves (block )) {
276+ speedMultiplier = 15.0f ;
277+ } else if (BlockTags .WOOL .contains (block )) {
278+ speedMultiplier = 5.0f ;
279+ } else if (block == StateTypes .VINE ||
280+ block == StateTypes .GLOW_LICHEN ) {
281+ speedMultiplier = 2.0f ;
282+ } else {
283+ isCorrectToolForDrop = block == StateTypes .COBWEB ||
284+ block == StateTypes .REDSTONE_WIRE ||
285+ block == StateTypes .TRIPWIRE ;
286+ }
287+ }
288+
289+ // Swords can also mine some blocks faster
290+ if (toolType .hasAttribute (ItemTypes .ItemAttribute .SWORD )) {
291+ if (block == StateTypes .COBWEB ) {
292+ speedMultiplier = 15.0f ;
293+ } else if (player .tagManager .block (SyncedTags .SWORD_EFFICIENT ).contains (block )) {
294+ speedMultiplier = 1.5f ;
295+ }
296+
297+ isCorrectToolForDrop = block == StateTypes .COBWEB ;
298+ }
299+ //
300+ return new ToolSpeedData (speedMultiplier , isCorrectToolForDrop );
273301 }
302+
303+
274304}
0 commit comments