Open tterrag1098 opened 6 years ago
The affected method is BufferBuilder.normal
public BufferBuilder func_181663_c(float p_181663_1_, float p_181663_2_, float p_181663_3_) {
int i = this.field_178997_d * this.field_179011_q.func_177338_f() + this.field_179011_q.func_181720_d(this.field_181678_g);
switch(this.field_181677_f.func_177367_b()) {
case FLOAT:
this.field_179001_a.putFloat(i, p_181663_1_);
this.field_179001_a.putFloat(i + 4, p_181663_2_);
this.field_179001_a.putFloat(i + 8, p_181663_3_);
break;
case UINT:
case INT:
this.field_179001_a.putInt(i, (int)p_181663_1_);
this.field_179001_a.putInt(i + 4, (int)p_181663_2_);
this.field_179001_a.putInt(i + 8, (int)p_181663_3_);
break;
case USHORT:
case SHORT:
this.field_179001_a.putShort(i, (short)((int)p_181663_1_ * 32767 & '\uffff'));
this.field_179001_a.putShort(i + 2, (short)((int)p_181663_2_ * 32767 & '\uffff'));
this.field_179001_a.putShort(i + 4, (short)((int)p_181663_3_ * 32767 & '\uffff'));
break;
case UBYTE:
case BYTE:
this.field_179001_a.put(i, (byte)((int)p_181663_1_ * 127 & 255));
this.field_179001_a.put(i + 1, (byte)((int)p_181663_2_ * 127 & 255));
this.field_179001_a.put(i + 2, (byte)((int)p_181663_3_ * 127 & 255));
}
this.func_181667_k();
return this;
}
public net.minecraft.client.renderer.BufferBuilder func_181663_c(float, float, float); descriptor: (FFF)Lnet/minecraft/client/renderer/BufferBuilder; flags: ACC_PUBLIC Code: stack=4, locals=5, args_size=4 0: aload_0 1: getfield #99 // Field field_178997_d:I 4: aload_0 5: getfield #101 // Field field_179011_q:Lnet/minecraft/client/renderer/vertex/VertexFormat; 8: invokevirtual #106 // Method net/minecraft/client/renderer/vertex/VertexFormat.func_177338_f:()I 11: imul 12: aload_0 13: getfield #101 // Field field_179011_q:Lnet/minecraft/client/renderer/vertex/VertexFormat; 16: aload_0 17: getfield #300 // Field field_181678_g:I 20: invokevirtual #329 // Method net/minecraft/client/renderer/vertex/VertexFormat.func_181720_d:(I)I 23: iadd 24: istore 4 26: getstatic #332 // Field net/minecraft/client/renderer/BufferBuilder$1.field_210254_a:[I 29: aload_0 30: getfield #298 // Field field_181677_f:Lnet/minecraft/client/renderer/vertex/VertexFormatElement; 33: invokevirtual #336 // Method net/minecraft/client/renderer/vertex/VertexFormatElement.func_177367_b:()Lnet/minecraft/client/renderer/vertex/VertexFormatElement$EnumType; 36: invokevirtual #339 // Method net/minecraft/client/renderer/vertex/VertexFormatElement$EnumType.ordinal:()I 39: iaload 40: tableswitch { // 1 to 7 1: 84 2: 125 3: 125 4: 169 5: 169 6: 239 7: 239 default: 303 } 84: aload_0 85: getfield #61 // Field field_179001_a:Ljava/nio/ByteBuffer; 88: iload 4 90: fload_1 91: invokevirtual #343 // Method java/nio/ByteBuffer.putFloat:(IF)Ljava/nio/ByteBuffer; 94: pop 95: aload_0 96: getfield #61 // Field field_179001_a:Ljava/nio/ByteBuffer; 99: iload 4 101: iconst_4 102: iadd 103: fload_2 104: invokevirtual #343 // Method java/nio/ByteBuffer.putFloat:(IF)Ljava/nio/ByteBuffer; 107: pop 108: aload_0 109: getfield #61 // Field field_179001_a:Ljava/nio/ByteBuffer; 112: iload 4 114: bipush 8 116: iadd 117: fload_3 118: invokevirtual #343 // Method java/nio/ByteBuffer.putFloat:(IF)Ljava/nio/ByteBuffer; 121: pop 122: goto 303 125: aload_0 126: getfield #61 // Field field_179001_a:Ljava/nio/ByteBuffer; 129: iload 4 131: fload_1 132: f2i 133: invokevirtual #347 // Method java/nio/ByteBuffer.putInt:(II)Ljava/nio/ByteBuffer; 136: pop 137: aload_0 138: getfield #61 // Field field_179001_a:Ljava/nio/ByteBuffer; 141: iload 4 143: iconst_4 144: iadd 145: fload_2 146: f2i 147: invokevirtual #347 // Method java/nio/ByteBuffer.putInt:(II)Ljava/nio/ByteBuffer; 150: pop 151: aload_0 152: getfield #61 // Field field_179001_a:Ljava/nio/ByteBuffer; 155: iload 4 157: bipush 8 159: iadd 160: fload_3 161: f2i 162: invokevirtual #347 // Method java/nio/ByteBuffer.putInt:(II)Ljava/nio/ByteBuffer; 165: pop 166: goto 303 169: aload_0 170: getfield #61 // Field field_179001_a:Ljava/nio/ByteBuffer; 173: iload 4 175: fload_1 176: f2i 177: sipush 32767 180: imul 181: ldc_w #484 // int 65535 184: iand 185: i2s 186: invokevirtual #351 // Method java/nio/ByteBuffer.putShort:(IS)Ljava/nio/ByteBuffer; 189: pop 190: aload_0 191: getfield #61 // Field field_179001_a:Ljava/nio/ByteBuffer; 194: iload 4 196: iconst_2 197: iadd 198: fload_2 199: f2i 200: sipush 32767 203: imul 204: ldc_w #484 // int 65535 207: iand 208: i2s 209: invokevirtual #351 // Method java/nio/ByteBuffer.putShort:(IS)Ljava/nio/ByteBuffer; 212: pop 213: aload_0 214: getfield #61 // Field field_179001_a:Ljava/nio/ByteBuffer; 217: iload 4 219: iconst_4 220: iadd 221: fload_3 222: f2i 223: sipush 32767 226: imul 227: ldc_w #484 // int 65535 230: iand 231: i2s 232: invokevirtual #351 // Method java/nio/ByteBuffer.putShort:(IS)Ljava/nio/ByteBuffer; 235: pop 236: goto 303 239: aload_0 240: getfield #61 // Field field_179001_a:Ljava/nio/ByteBuffer; 243: iload 4 245: fload_1 246: f2i 247: bipush 127 249: imul 250: sipush 255 253: iand 254: i2b 255: invokevirtual #354 // Method java/nio/ByteBuffer.put:(IB)Ljava/nio/ByteBuffer; 258: pop 259: aload_0 260: getfield #61 // Field field_179001_a:Ljava/nio/ByteBuffer; 263: iload 4 265: iconst_1 266: iadd 267: fload_2 268: f2i 269: bipush 127 271: imul 272: sipush 255 275: iand 276: i2b 277: invokevirtual #354 // Method java/nio/ByteBuffer.put:(IB)Ljava/nio/ByteBuffer; 280: pop 281: aload_0 282: getfield #61 // Field field_179001_a:Ljava/nio/ByteBuffer; 285: iload 4 287: iconst_2 288: iadd 289: fload_3 290: f2i 291: bipush 127 293: imul 294: sipush 255 297: iand 298: i2b 299: invokevirtual #354 // Method java/nio/ByteBuffer.put:(IB)Ljava/nio/ByteBuffer; 302: pop 303: aload_0 304: invokespecial #357 // Method func_181667_k:()V 307: aload_0 308: areturn StackMapTable: number_of_entries = 5 frame_type = 252 /* append */ offset_delta = 84 locals = [ int ] frame_type = 40 /* same */ frame_type = 43 /* same */ frame_type = 251 /* same_frame_extended */ offset_delta = 69 frame_type = 255 /* full_frame */ offset_delta = 63 locals = [ class net/minecraft/client/renderer/BufferBuilder ] stack = [] LineNumberTable: line 464: 0 line 465: 26 line 467: 84 line 468: 95 line 469: 108 line 470: 122 line 473: 125 line 474: 137 line 475: 151 line 476: 166 line 479: 169 line 480: 190 line 481: 213 line 482: 236 line 485: 239 line 486: 259 line 487: 281 line 490: 303 line 491: 307 LocalVariableTable: Start Length Slot Name Signature 0 309 0 this Lnet/minecraft/client/renderer/BufferBuilder; 0 309 1 p_181663_1_ F 0 309 2 p_181663_2_ F 0 309 3 p_181663_3_ F 26 283 4 lvt_4_1_ I
Since this is a lot of text, I'll focus just on just the BYTE
and UBYTE
path.
public net.minecraft.client.renderer.BufferBuilder func_181663_c(float, float, float); Code: // Computing i - snip // switch 40: tableswitch { // 1 to 7 // snip cases we don't care about 6: 239 // for UBYTE jump to 239 7: 239 // for BYTE jump to 239 default: 303 } // snip code for cases we don't care about 239: aload_0 240: getfield #61 // Field field_179001_a:Ljava/nio/ByteBuffer; 243: iload 4 245: fload_1 246: f2i 247: bipush 127 249: imul 250: sipush 255 253: iand 254: i2b 255: invokevirtual #354 // Method java/nio/ByteBuffer.put:(IB)Ljava/nio/ByteBuffer; 258: pop 259: aload_0 260: getfield #61 // Field field_179001_a:Ljava/nio/ByteBuffer; 263: iload 4 265: iconst_1 266: iadd 267: fload_2 268: f2i 269: bipush 127 271: imul 272: sipush 255 275: iand 276: i2b 277: invokevirtual #354 // Method java/nio/ByteBuffer.put:(IB)Ljava/nio/ByteBuffer; 280: pop 281: aload_0 282: getfield #61 // Field field_179001_a:Ljava/nio/ByteBuffer; 285: iload 4 287: iconst_2 288: iadd 289: fload_3 290: f2i 291: bipush 127 293: imul 294: sipush 255 297: iand 298: i2b 299: invokevirtual #354 // Method java/nio/ByteBuffer.put:(IB)Ljava/nio/ByteBuffer; 302: pop // Exiting the method 303: aload_0 304: invokespecial #357 // Method func_181667_k:()V 307: aload_0 308: areturn
And now to dissect a tiny section of that specifically -- one call to put
:
; Put `this` onto the stack
; Stack: [this]
239: aload_0
; Remove `this` from the stack and put `this.byteBuffer` onto it
; Stack: [this.byteBuffer]
240: getfield #61 // Field field_179001_a:Ljava/nio/ByteBuffer;
; Load local variable 4 (which is i, or alternatively lvt_4_1_), and put it onto the stack
; Stack: [this.byteBuffer, i]
243: iload 4
; Load local variable 1 (which is x, or alternatively p_181663_1_), and put it onto the stack.
; Stack: [this.byteBuffer, i, x]
245: fload_1
; Convert the top of the stack from a float to an int and put it into the stack
; Stack: [this.byteBuffer, i, ((int)x)]
246: f2i
; Put the number 127 onto the stack
; Stack: [this.byteBuffer, i, ((int)x), 127]
247: bipush 127
; Take the top two values from the stack and perform an integer multiplication
; and then put that onto the stack
; Stack: [this.byteBuffer, i, (((int)x) * 127)]
249: imul
; Take the number 255 and put it onto the stack
; Stack: [this.byteBuffer, i, (((int)x) * 127), 255]
250: sipush 255
; And the two top values together and put the result onto the stack
; Stack: [this.byteBuffer, i, ((((int)x) * 127) & 255)]
253: iand
; Convert the top of the stack from an int into a byte and put it onto the stack
; Stack: [this.byteBuffer, i, ((byte)((((int)x) * 127) & 255))]
254: i2b
; Call `this.byteBuffer.put`. Two arguments are popped off
; and then the object to call it on.
; The resultant call is `this.byteBuffer.put(i, ((byte)((((int)x) * 127) & 255)))`
; `ByteBuffer.put` puts the result back onto the stack, so:
; Stack: [this.byteBuffer]
255: invokevirtual #354 // Method java/nio/ByteBuffer.put:(IB)Ljava/nio/ByteBuffer;
; Discard the return value of put
; Stack: []
280: pop
This shows that the cast in the bytecode happens before the multiplication, and the original code actually does have it. So it's a mistake on Mojang's end, not a bug with FernFlower.
I'm mostly ignorant on the actual rendering code, so I need to ask: how would this manifest itself ingame? Is there any way that it could empirically be confirmed that this is a vanilla issue?
There's an image here: https://github.com/MinecraftForge/MinecraftForge/pull/2437
Could it be FernFlower causing this bug? https://github.com/MinecraftForge/MinecraftForge/issues/2321
The
(int)
cast needs to be applied to the entirep_181663_1_ * 127
expression, but the parentheses are left out so that it only castsp_181663_1_
, changing the calculation.