Uploaded image for project: 'Minecraft: Java Edition'
  1. Minecraft: Java Edition
  2. MC-238249

Redundant checks in explosion code

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Unresolved
    • None
    • 1.17.1, 1.18 Pre-release 1, 22w11a, 1.19 Pre-release 5, 1.19, 1.20.2
    • None
    • Confirmed
    • Performance
    • Low
    • Platform

      When an explosion is created, it casts a lot of rays (1352, to be precise). The issue is, the block and liquid blast resistance at the origin point of the explosion is checked for every single ray, even though for each of them, the result will be exactly the same, so only checking once would be needed. Calls to getBlockState and getFluidState are quite expensive, and having a lot of these to be unnecessary can really hurt the performance.

       

      Code Analysis of current latest version (1.17.1) (using mojang mappings and CFR decompiler) :

      if (i != 0 && i != 15 && n2 != 0 && n2 != 15 && n != 0 && n != 15) continue;
                          double d = (float)i / 15.0f * 2.0f - 1.0f;
                          double d2 = (float)n2 / 15.0f * 2.0f - 1.0f;
                          double d3 = (float)n / 15.0f * 2.0f - 1.0f;
                          double d4 = Math.sqrt(d * d + d2 * d2 + d3 * d3);
                          d /= d4;
                          d2 /= d4;
                          d3 /= d4;
      
                          // this sets the starting position of the ray at the explosion point
                          double d5 = this.x;
                          double d6 = this.y;
                          double d7 = this.z;
                          float f = 0.3f;
                          for (float f2 = this.radius * (0.7f + this.level.random.nextFloat() * 0.6f); f2 > 0.0f; f2 -= 0.22500001f) {
                              object = new BlockPos(d5, d6, d7);
      
                              // however as you can see, it checks for the blockstate and liquid state at that position, every time a new ray is made
                              BlockState blockState = this.level.getBlockState((BlockPos)object);
                              object2 = this.level.getFluidState((BlockPos)object);
                              if (!this.level.isInWorldBounds((BlockPos)object)) continue block2;
                              Optional<Float> optional = this.damageCalculator.getBlockExplosionResistance(thisthis.level, (BlockPos)object, blockState, (FluidState)object2);
                              if (optional.isPresent()) {
                                  f2 -= (optional.get().floatValue() + 0.3f) * 0.3f;
                              }
      
      

      How to fix :

      a good way to fix would be to have a boolean check if the blast resistance have already been checked at the origin position, keep the origin position as well (it's basically free skipping some calls to the world if the same ray calls multiple time the origin pos, which can happen, as jumps along the ray are only of 0.3F), and keep the blast resistance in a float.

       

      Fixing this bug would allow explosions in general to perform better, especially in case they would happen inside of a liquid or a blast proof block, since instead of 1352 * 2 calls to the world, there would only be two.

            Unassigned Unassigned
            SRAZKVT SRAZKVT
            Votes:
            75 Vote for this issue
            Watchers:
            13 Start watching this issue

              Created:
              Updated:
              CHK: