diff --git a/archive/src/main/kotlin/org/openrs2/archive/cache/CacheDownloader.kt b/archive/src/main/kotlin/org/openrs2/archive/cache/CacheDownloader.kt index 964a93f4..6ccb63fb 100644 --- a/archive/src/main/kotlin/org/openrs2/archive/cache/CacheDownloader.kt +++ b/archive/src/main/kotlin/org/openrs2/archive/cache/CacheDownloader.kt @@ -54,6 +54,7 @@ public class CacheDownloader @Inject constructor( ) ) } + "runescape" -> { val buildMinor = game.buildMinor ?: throw Exception("Current minor build not set") @@ -82,6 +83,7 @@ public class CacheDownloader @Inject constructor( ) ) } + else -> throw UnsupportedOperationException() } diff --git a/archive/src/main/kotlin/org/openrs2/archive/cache/nxt/Js5RequestEncoder.kt b/archive/src/main/kotlin/org/openrs2/archive/cache/nxt/Js5RequestEncoder.kt index 993d2268..0f8e5dfb 100644 --- a/archive/src/main/kotlin/org/openrs2/archive/cache/nxt/Js5RequestEncoder.kt +++ b/archive/src/main/kotlin/org/openrs2/archive/cache/nxt/Js5RequestEncoder.kt @@ -16,6 +16,7 @@ public object Js5RequestEncoder : MessageToByteEncoder(Js5Request::c out.writeShort(msg.build) out.writeShort(0) } + is Js5Request.Connected -> { out.writeByte(6) out.writeMedium(5) diff --git a/archive/src/main/kotlin/org/openrs2/archive/jav/JavConfig.kt b/archive/src/main/kotlin/org/openrs2/archive/jav/JavConfig.kt index e4361827..8ac9671a 100644 --- a/archive/src/main/kotlin/org/openrs2/archive/jav/JavConfig.kt +++ b/archive/src/main/kotlin/org/openrs2/archive/jav/JavConfig.kt @@ -47,12 +47,14 @@ public data class JavConfig( messages[parts[0]] = parts[1] } } + line.startsWith("param=") -> { val parts = line.substring("param=".length).split("=", limit = 2) if (parts.size == 2) { params[parts[0]] = parts[1] } } + else -> { val parts = line.split("=", limit = 2) if (parts.size == 2) { diff --git a/archive/src/main/kotlin/org/openrs2/archive/key/JsonKeyReader.kt b/archive/src/main/kotlin/org/openrs2/archive/key/JsonKeyReader.kt index 374b4c7f..4b0e724d 100644 --- a/archive/src/main/kotlin/org/openrs2/archive/key/JsonKeyReader.kt +++ b/archive/src/main/kotlin/org/openrs2/archive/key/JsonKeyReader.kt @@ -24,11 +24,13 @@ public class JsonKeyReader @Inject constructor( keys += mapper.treeToValue(key) ?: throw IOException("Key must be non-null") } } + root.isObject -> { for (entry in root.fields()) { keys += mapper.treeToValue(entry.value) ?: throw IOException("Key must be non-null") } } + else -> throw IOException("Root element must be an array or object") } diff --git a/asm/src/main/kotlin/org/openrs2/asm/ClassNodeRemapper.kt b/asm/src/main/kotlin/org/openrs2/asm/ClassNodeRemapper.kt index f13f921a..685c109a 100644 --- a/asm/src/main/kotlin/org/openrs2/asm/ClassNodeRemapper.kt +++ b/asm/src/main/kotlin/org/openrs2/asm/ClassNodeRemapper.kt @@ -109,12 +109,14 @@ public fun AbstractInsnNode.remap(remapper: ExtendedRemapper) { name = remapper.mapFieldName(originalOwner, name, desc) desc = remapper.mapDesc(desc) } + is MethodInsnNode -> { val originalOwner = owner owner = remapper.mapMethodOwner(originalOwner, name, desc) name = remapper.mapMethodName(originalOwner, name, desc) desc = remapper.mapDesc(desc) } + is InvokeDynamicInsnNode -> throw UnsupportedOperationException() is TypeInsnNode -> desc = remapper.mapType(desc) is LdcInsnNode -> cst = remapper.mapValue(cst) diff --git a/asm/src/main/kotlin/org/openrs2/asm/InsnNodeUtils.kt b/asm/src/main/kotlin/org/openrs2/asm/InsnNodeUtils.kt index 25ccae25..1751eeb8 100644 --- a/asm/src/main/kotlin/org/openrs2/asm/InsnNodeUtils.kt +++ b/asm/src/main/kotlin/org/openrs2/asm/InsnNodeUtils.kt @@ -245,6 +245,7 @@ public val AbstractInsnNode.intConstant: Int? null } } + is LdcInsnNode -> { val cst = cst if (cst is Int) { @@ -253,6 +254,7 @@ public val AbstractInsnNode.intConstant: Int? null } } + else -> when (opcode) { Opcodes.ICONST_M1 -> -1 Opcodes.ICONST_0 -> 0 diff --git a/asm/src/main/kotlin/org/openrs2/asm/MethodNodeUtils.kt b/asm/src/main/kotlin/org/openrs2/asm/MethodNodeUtils.kt index 2a1ebbd7..1733b051 100644 --- a/asm/src/main/kotlin/org/openrs2/asm/MethodNodeUtils.kt +++ b/asm/src/main/kotlin/org/openrs2/asm/MethodNodeUtils.kt @@ -99,6 +99,7 @@ public fun MethodNode.removeArgument(argIndex: Int) { newLocalIndexUsed = true } } + is IincInsnNode -> { insn.`var` = remap(insn.`var`, argType, localIndex, newLocalIndex) @@ -106,6 +107,7 @@ public fun MethodNode.removeArgument(argIndex: Int) { newLocalIndexUsed = true } } + is FrameNode -> throw UnsupportedOperationException("SKIP_FRAMES and COMPUTE_FRAMES must be used") } } diff --git a/asm/src/main/kotlin/org/openrs2/asm/StackMetadata.kt b/asm/src/main/kotlin/org/openrs2/asm/StackMetadata.kt index 94b5f551..a6690281 100644 --- a/asm/src/main/kotlin/org/openrs2/asm/StackMetadata.kt +++ b/asm/src/main/kotlin/org/openrs2/asm/StackMetadata.kt @@ -188,6 +188,7 @@ public val AbstractInsnNode.stackMetadata: StackMetadata } else { PUSH1 } + is FieldInsnNode -> { val fieldSize = Type.getType(desc).size var pushes = 0 @@ -202,6 +203,7 @@ public val AbstractInsnNode.stackMetadata: StackMetadata } StackMetadata(pops, pushes) } + is MethodInsnNode -> { val argumentsAndReturnSizes = Type.getArgumentsAndReturnSizes(desc) val pushes = argumentsAndReturnSizes and 0x3 @@ -211,6 +213,7 @@ public val AbstractInsnNode.stackMetadata: StackMetadata } StackMetadata(pops, pushes) } + is InvokeDynamicInsnNode -> throw UnsupportedOperationException() is MultiANewArrayInsnNode -> StackMetadata(dims, 1) else -> SIMPLE_OPCODES[opcode] ?: throw IllegalArgumentException() diff --git a/asm/src/main/kotlin/org/openrs2/asm/filter/Glob.kt b/asm/src/main/kotlin/org/openrs2/asm/filter/Glob.kt index 168e60fa..1721e96a 100644 --- a/asm/src/main/kotlin/org/openrs2/asm/filter/Glob.kt +++ b/asm/src/main/kotlin/org/openrs2/asm/filter/Glob.kt @@ -35,6 +35,7 @@ public object Glob { } else { regex.append(".*") } + else -> regex.append(Regex.escape(ch.toString())) } } diff --git a/asm/src/main/kotlin/org/openrs2/asm/packclass/ConstantPool.kt b/asm/src/main/kotlin/org/openrs2/asm/packclass/ConstantPool.kt index c9f2b49f..af3d4f06 100644 --- a/asm/src/main/kotlin/org/openrs2/asm/packclass/ConstantPool.kt +++ b/asm/src/main/kotlin/org/openrs2/asm/packclass/ConstantPool.kt @@ -94,6 +94,7 @@ public class ConstantPool private constructor( addMethodRef(methodRef) } } + is FieldInsnNode -> addFieldRef(MemberRef(insn.owner, insn.name, insn.desc)) is TypeInsnNode -> strings += insn.desc } @@ -155,6 +156,7 @@ public class ConstantPool private constructor( throw IllegalArgumentException("Unsupported constant type: ${value.sort}") } } + else -> throw IllegalArgumentException("Unsupported constant type: ${value.javaClass.name}") } } diff --git a/asm/src/main/kotlin/org/openrs2/asm/packclass/PackClass.kt b/asm/src/main/kotlin/org/openrs2/asm/packclass/PackClass.kt index 756158a3..6d170fb7 100644 --- a/asm/src/main/kotlin/org/openrs2/asm/packclass/PackClass.kt +++ b/asm/src/main/kotlin/org/openrs2/asm/packclass/PackClass.kt @@ -503,11 +503,13 @@ public object PackClass { branchLen += (cases + 2) * 4 sipushAndSwitchLen += 4 } + Opcodes.LOOKUPSWITCH -> { val cases = buf.readVarInt() branchLen += (cases + 1) * 4 sipushAndSwitchLen += cases * 4 } + Opcodes.INVOKEINTERFACE -> interfaceMethodRefLen += 2 Opcodes.NEWARRAY -> newArrayLen++ Opcodes.MULTIANEWARRAY -> multiNewArrayLen++ @@ -1155,10 +1157,12 @@ public object PackClass { ) } } + insn.`var` < 256 -> { buf.writeByte(insn.opcode) localVarBuf.writeByte(insn.`var`) } + else -> { buf.writeByte(WIDE) buf.writeByte(insn.opcode) @@ -1166,28 +1170,34 @@ public object PackClass { } } } + is LdcInsnNode -> { when (val value = insn.cst) { is Int -> { buf.writeByte(LDC_INT) constantPool.writeInt(constantBuf, value) } + is Long -> { buf.writeByte(LDC_LONG) constantPool.writeLong(wideConstantBuf, value) } + is Float -> { buf.writeByte(LDC_FLOAT) constantPool.writeFloat(constantBuf, value) } + is Double -> { buf.writeByte(LDC_DOUBLE) constantPool.writeDouble(wideConstantBuf, value) } + is String -> { buf.writeByte(LDC_STRING) constantPool.writeString(constantBuf, value) } + is Type -> { if (value.sort == Type.OBJECT) { buf.writeByte(LDC_CLASS) @@ -1198,19 +1208,23 @@ public object PackClass { ) } } + else -> throw IllegalArgumentException( "Unsupported constant type: ${value.javaClass.name}" ) } } + is TypeInsnNode -> { buf.writeByte(insn.opcode) constantPool.writeString(classBuf, insn.desc) } + is FieldInsnNode -> { buf.writeByte(insn.opcode) constantPool.writeFieldRef(fieldRefBuf, MemberRef(insn.owner, insn.name, insn.desc)) } + is MethodInsnNode -> { buf.writeByte(insn.opcode) @@ -1221,6 +1235,7 @@ public object PackClass { constantPool.writeMethodRef(methodRefBuf, methodRef) } } + is JumpInsnNode -> { val targetPc = insns[i].indexOf(insn.label.nextReal) val delta = targetPc - pc @@ -1239,6 +1254,7 @@ public object PackClass { branchBuf.writeInt(delta) } } + is IntInsnNode -> { buf.writeByte(insn.opcode) @@ -1249,6 +1265,7 @@ public object PackClass { else -> throw IllegalArgumentException("Unsupported IntInsnNode opcode: ${insn.opcode}") } } + is IincInsnNode -> { if (insn.`var` < 256 && (insn.incr >= -128 && insn.incr <= 127)) { buf.writeByte(insn.opcode) @@ -1261,6 +1278,7 @@ public object PackClass { wideIincBuf.writeShort(insn.incr) } } + is TableSwitchInsnNode -> { buf.writeByte(insn.opcode) @@ -1275,6 +1293,7 @@ public object PackClass { branchBuf.writeInt(targetPc - pc) } } + is LookupSwitchInsnNode -> { buf.writeByte(insn.opcode) @@ -1295,11 +1314,13 @@ public object PackClass { branchBuf.writeInt(targetPc - pc) } } + is MultiANewArrayInsnNode -> { buf.writeByte(insn.opcode) constantPool.writeString(classBuf, insn.desc) multiNewArrayBuf.writeByte(insn.dims) } + is InsnNode -> buf.writeByte(insn.opcode) else -> throw IllegalArgumentException("Unsupported instruction type: ${insn.javaClass.name}") } @@ -1552,6 +1573,7 @@ public object PackClass { throw IllegalArgumentException("Unsupported constant type: ${value.sort}") } } + else -> throw IllegalArgumentException("Unsupported constant type: ${value.javaClass.name}") } } diff --git a/buffer-generator/src/main/kotlin/org/openrs2/buffer/generator/ByteOrder.kt b/buffer-generator/src/main/kotlin/org/openrs2/buffer/generator/ByteOrder.kt index 2680c0ac..cd094386 100644 --- a/buffer-generator/src/main/kotlin/org/openrs2/buffer/generator/ByteOrder.kt +++ b/buffer-generator/src/main/kotlin/org/openrs2/buffer/generator/ByteOrder.kt @@ -19,6 +19,7 @@ public enum class ByteOrder(public val suffix: String) { else -> 8 } } + ALT3_REVERSE -> { require(width == 4) when (i) { diff --git a/cache-550/src/main/kotlin/org/openrs2/cache/config/enum/EnumType.kt b/cache-550/src/main/kotlin/org/openrs2/cache/config/enum/EnumType.kt index d6c4c882..846f3705 100644 --- a/cache-550/src/main/kotlin/org/openrs2/cache/config/enum/EnumType.kt +++ b/cache-550/src/main/kotlin/org/openrs2/cache/config/enum/EnumType.kt @@ -37,6 +37,7 @@ public class EnumType(id: Int) : ConfigType(id) { this.strings = strings } + 6 -> { val size = buf.readUnsignedShort() val ints = Int2IntOpenHashMap() @@ -48,6 +49,7 @@ public class EnumType(id: Int) : ConfigType(id) { this.ints = ints } + else -> throw IllegalArgumentException("Unsupported config code: $code") } } diff --git a/cache-550/src/main/kotlin/org/openrs2/cache/config/struct/StructType.kt b/cache-550/src/main/kotlin/org/openrs2/cache/config/struct/StructType.kt index cdc550eb..6ffb54a2 100644 --- a/cache-550/src/main/kotlin/org/openrs2/cache/config/struct/StructType.kt +++ b/cache-550/src/main/kotlin/org/openrs2/cache/config/struct/StructType.kt @@ -26,6 +26,7 @@ public class StructType(id: Int) : ConfigType(id) { } } } + else -> throw IllegalArgumentException("Unsupported config code: $code") } } @@ -42,11 +43,13 @@ public class StructType(id: Int) : ConfigType(id) { buf.writeMedium(id) buf.writeString(value) } + is Int -> { buf.writeBoolean(false) buf.writeMedium(id) buf.writeInt(value) } + else -> throw IllegalStateException() } } diff --git a/cache-550/src/main/kotlin/org/openrs2/cache/config/varbit/VarbitType.kt b/cache-550/src/main/kotlin/org/openrs2/cache/config/varbit/VarbitType.kt index e60d7ed8..626fc23c 100644 --- a/cache-550/src/main/kotlin/org/openrs2/cache/config/varbit/VarbitType.kt +++ b/cache-550/src/main/kotlin/org/openrs2/cache/config/varbit/VarbitType.kt @@ -15,6 +15,7 @@ public class VarbitType(id: Int) : ConfigType(id) { startBit = buf.readUnsignedByte().toInt() endBit = buf.readUnsignedByte().toInt() } + else -> throw IllegalArgumentException("Unsupported config code: $code") } } diff --git a/cache-550/src/main/kotlin/org/openrs2/cache/midi/Song.kt b/cache-550/src/main/kotlin/org/openrs2/cache/midi/Song.kt index 9968008f..33f16128 100644 --- a/cache-550/src/main/kotlin/org/openrs2/cache/midi/Song.kt +++ b/cache-550/src/main/kotlin/org/openrs2/cache/midi/Song.kt @@ -196,11 +196,13 @@ public object Song { onVelocity = (onVelocity + onVelocityBuf.readUnsignedByte().toInt()) and 0x7F ShortMessage(ShortMessage.NOTE_ON, channel, key, onVelocity) } + NOTE_OFF -> { key = (key + keyBuf.readUnsignedByte().toInt()) and 0x7F offVelocity = (offVelocity + offVelocityBuf.readUnsignedByte().toInt()) and 0x7F ShortMessage(ShortMessage.NOTE_OFF, channel, key, offVelocity) } + CONTROL_CHANGE -> { controller = (controller + controllerBuf.readUnsignedByte()) and 0x7F @@ -218,6 +220,7 @@ public object Song { REGISTERED_LSB -> registeredLsbBuf.readUnsignedByte().toInt() DAMPER, PORTAMENTO, ALL_SOUND_OFF, RESET_CONTROLLERS, ALL_NOTES_OFF -> otherKnownControllerBuf.readUnsignedByte().toInt() + else -> unknownControllerBuf.readUnsignedByte().toInt() } @@ -225,25 +228,30 @@ public object Song { values[controller] = value ShortMessage(ShortMessage.CONTROL_CHANGE, channel, controller, value and 0x7F) } + PITCH_WHEEL_CHANGE -> { pitchWheel += pitchWheelLsbBuf.readUnsignedByte().toInt() pitchWheel += (pitchWheelMsbBuf.readUnsignedByte().toInt() shl 7) pitchWheel = pitchWheel and 0x3FFF ShortMessage(ShortMessage.PITCH_BEND, channel, pitchWheel and 0x7F, pitchWheel shr 7) } + CHANNEL_PRESSURE_CHANGE -> { channelPressure = (channelPressure + channelPressureBuf.readUnsignedByte().toInt()) and 0x7F ShortMessage(ShortMessage.CHANNEL_PRESSURE, channel, channelPressure, 0) } + KEY_PRESSURE_CHANGE -> { key = (key + keyBuf.readUnsignedByte().toInt()) and 0x7F keyPressure = (keyPressure + keyPressureBuf.readUnsignedByte().toInt()) and 0x7F ShortMessage(ShortMessage.POLY_PRESSURE, channel, key, keyPressure) } + PROGRAM_CHANGE -> { val bankSelect = bankSelectBuf.readUnsignedByte().toInt() ShortMessage(ShortMessage.PROGRAM_CHANGE, channel, bankSelect, 0) } + else -> throw IllegalStateException() } @@ -317,9 +325,11 @@ public object Song { require(message.data.size == 3) tempoBuf.writeBytes(message.data) } + else -> throw IllegalArgumentException("Unsupported meta type: $type") } } + is ShortMessage -> { val command = message.status and 0xF0 val channel = message.status and 0xF @@ -354,11 +364,13 @@ public object Song { onVelocityBuf.writeByte((onVelocity - prevOnVelocity) and 0x7F) prevOnVelocity = onVelocity } + ShortMessage.NOTE_OFF -> { val offVelocity = message.data2 offVelocityBuf.writeByte((offVelocity - prevOffVelocity) and 0x7F) prevOffVelocity = offVelocity } + ShortMessage.CONTROL_CHANGE -> { val controller = message.data1 controllerBuf.writeByte((controller - prevController) and 0x7F) @@ -381,11 +393,13 @@ public object Song { REGISTERED_LSB -> registeredLsbBuf.writeByte(valueDelta) DAMPER, PORTAMENTO, ALL_SOUND_OFF, RESET_CONTROLLERS, ALL_NOTES_OFF -> otherKnownControllerBuf.writeByte(valueDelta) + else -> unknownControllerBuf.writeByte(valueDelta) } prevValues[controller] = value } + ShortMessage.PITCH_BEND -> { val pitchWheel = message.data1 or (message.data2 shl 7) val pitchWheelDelta = (pitchWheel - prevPitchWheel) and 0x3FFF @@ -393,22 +407,27 @@ public object Song { pitchWheelMsbBuf.writeByte(pitchWheelDelta shr 7) prevPitchWheel = pitchWheel } + ShortMessage.CHANNEL_PRESSURE -> { val channelPressure = message.data1 channelPressureBuf.writeByte((channelPressure - prevChannelPressure) and 0x7F) prevChannelPressure = channelPressure } + ShortMessage.POLY_PRESSURE -> { val keyPressure = message.data2 keyPressureBuf.writeByte((keyPressure - prevKeyPressure) and 0x7F) prevKeyPressure = keyPressure } + ShortMessage.PROGRAM_CHANGE -> { bankSelectBuf.writeByte(message.data1) } + else -> throw IllegalStateException() } } + else -> throw IllegalArgumentException("Unsupported message type: ${message.javaClass.name}") } } diff --git a/cache/src/main/kotlin/org/openrs2/cache/Js5Compression.kt b/cache/src/main/kotlin/org/openrs2/cache/Js5Compression.kt index bc4a8fc1..f2c2643e 100644 --- a/cache/src/main/kotlin/org/openrs2/cache/Js5Compression.kt +++ b/cache/src/main/kotlin/org/openrs2/cache/Js5Compression.kt @@ -255,6 +255,7 @@ public object Js5Compression { return null } } + Js5CompressionType.GZIP -> { val magic = plaintext.readUnsignedShort() if (magic != GZIP_MAGIC) { @@ -269,6 +270,7 @@ public object Js5Compression { return null } } + Js5CompressionType.LZMA -> { val properties = plaintext.readUnsignedByte() diff --git a/cache/src/main/kotlin/org/openrs2/cache/Js5MasterIndex.kt b/cache/src/main/kotlin/org/openrs2/cache/Js5MasterIndex.kt index 51df61cd..50fa4534 100644 --- a/cache/src/main/kotlin/org/openrs2/cache/Js5MasterIndex.kt +++ b/cache/src/main/kotlin/org/openrs2/cache/Js5MasterIndex.kt @@ -210,12 +210,14 @@ public data class Js5MasterIndex( } len / 4 } + MasterIndexFormat.VERSIONED -> { require(len % 8 == 0) { "Length is not a multiple of 8 bytes" } len / 8 } + else -> { buf.readUnsignedByte().toInt() } diff --git a/cache/src/main/kotlin/org/openrs2/cache/MutableNamedEntryCollection.kt b/cache/src/main/kotlin/org/openrs2/cache/MutableNamedEntryCollection.kt index fac6db68..7f4fd90d 100644 --- a/cache/src/main/kotlin/org/openrs2/cache/MutableNamedEntryCollection.kt +++ b/cache/src/main/kotlin/org/openrs2/cache/MutableNamedEntryCollection.kt @@ -251,6 +251,7 @@ public abstract class MutableNamedEntryCollection( newSet.add(id) nameHashTable[newNameHash] = newSet } + else -> set.add(id) } diff --git a/compress/src/main/kotlin/org/openrs2/compress/gzip/GzipLaxInputStream.kt b/compress/src/main/kotlin/org/openrs2/compress/gzip/GzipLaxInputStream.kt index 68b324a1..97a07c5a 100644 --- a/compress/src/main/kotlin/org/openrs2/compress/gzip/GzipLaxInputStream.kt +++ b/compress/src/main/kotlin/org/openrs2/compress/gzip/GzipLaxInputStream.kt @@ -65,6 +65,7 @@ public class GzipLaxInputStream( checkTrailer() return -1 } + inflater.needsInput() -> fill() inflater.needsDictionary() -> throw IOException("Dictionaries not supported") } diff --git a/deob-ast/src/main/kotlin/org/openrs2/deob/ast/transform/AddSubTransformer.kt b/deob-ast/src/main/kotlin/org/openrs2/deob/ast/transform/AddSubTransformer.kt index 84a0a174..6fc74366 100644 --- a/deob-ast/src/main/kotlin/org/openrs2/deob/ast/transform/AddSubTransformer.kt +++ b/deob-ast/src/main/kotlin/org/openrs2/deob/ast/transform/AddSubTransformer.kt @@ -80,18 +80,22 @@ public class AddSubTransformer : Transformer() { negate -> terms += expr.negate() else -> terms += expr } + expr is BinaryExpr -> when { expr.operator == BinaryExpr.Operator.PLUS -> { addTerms(terms, expr.left, negate) addTerms(terms, expr.right, negate) } + expr.operator == BinaryExpr.Operator.MINUS -> { addTerms(terms, expr.left, negate) addTerms(terms, expr.right, !negate) } + negate -> terms += expr.negate() else -> terms += expr } + negate -> terms += expr.negate() else -> terms += expr } @@ -105,11 +109,13 @@ public class AddSubTransformer : Transformer() { is Int -> n < 0 else -> error("Invalid IntegerLiteralExpr type") } + is LongLiteralExpr -> when (val n = asNumber()) { LongLiteralExpr.MAX_63_BIT_UNSIGNED_VALUE_AS_BIG_INTEGER -> false is Long -> n < 0 else -> error("Invalid LongLiteralExpr type") } + else -> false } } diff --git a/deob-ast/src/main/kotlin/org/openrs2/deob/ast/transform/BitMaskTransformer.kt b/deob-ast/src/main/kotlin/org/openrs2/deob/ast/transform/BitMaskTransformer.kt index 01fdf49f..2cf52619 100644 --- a/deob-ast/src/main/kotlin/org/openrs2/deob/ast/transform/BitMaskTransformer.kt +++ b/deob-ast/src/main/kotlin/org/openrs2/deob/ast/transform/BitMaskTransformer.kt @@ -62,6 +62,7 @@ public class BitMaskTransformer : Transformer() { maskExpr = IntegerLiteralExpr(mask.toString()) } + is LongLiteralExpr -> { var mask = maskExpr.checkedAsLong() @@ -73,6 +74,7 @@ public class BitMaskTransformer : Transformer() { maskExpr = mask.toLongLiteralExpr() } + else -> return@walk } @@ -124,6 +126,7 @@ public class BitMaskTransformer : Transformer() { mask = mask ushr shamt IntegerLiteralExpr(mask.toString()) } + is LongLiteralExpr -> { var mask = maskExpr.checkedAsLong() if (shamt > java.lang.Long.numberOfTrailingZeros(mask)) { @@ -133,6 +136,7 @@ public class BitMaskTransformer : Transformer() { mask = mask ushr shamt mask.toLongLiteralExpr() } + else -> return@walk } diff --git a/deob-ast/src/main/kotlin/org/openrs2/deob/ast/transform/EncloseTransformer.kt b/deob-ast/src/main/kotlin/org/openrs2/deob/ast/transform/EncloseTransformer.kt index e88c5a96..433e8be4 100644 --- a/deob-ast/src/main/kotlin/org/openrs2/deob/ast/transform/EncloseTransformer.kt +++ b/deob-ast/src/main/kotlin/org/openrs2/deob/ast/transform/EncloseTransformer.kt @@ -76,6 +76,7 @@ public class EncloseTransformer : Transformer() { BinaryExpr.Operator.OR -> LOGICAL_OR else -> null } + is InstanceOfExpr -> RELATIONAL is ConditionalExpr -> TERNARY is AssignExpr -> ASSIGNMENT @@ -95,6 +96,7 @@ public class EncloseTransformer : Transformer() { encloseLeft(expr, scope) } } + is UnaryExpr -> encloseRight(expr, expr.expression) is CastExpr -> encloseRight(expr, expr.expression) is ObjectCreationExpr -> { @@ -102,16 +104,19 @@ public class EncloseTransformer : Transformer() { encloseLeft(expr, scope) } } + is BinaryExpr -> { encloseLeft(expr, expr.left) encloseRight(expr, expr.right) } + is InstanceOfExpr -> encloseLeft(expr, expr.expression) is ConditionalExpr -> { encloseLeft(expr, expr.condition) encloseLeft(expr, expr.thenExpr) encloseRight(expr, expr.elseExpr) } + is AssignExpr -> { encloseLeft(expr, expr.target) encloseRight(expr, expr.value) @@ -131,6 +136,7 @@ public class EncloseTransformer : Transformer() { parent.replace(child, EnclosedExpr(child.clone())) } } + Associativity.NONE, Associativity.RIGHT -> { if (childOp.isPrecedenceLessEqual(parentOp)) { parent.replace(child, EnclosedExpr(child.clone())) @@ -149,6 +155,7 @@ public class EncloseTransformer : Transformer() { parent.replace(child, EnclosedExpr(child.clone())) } } + Associativity.RIGHT -> { if (childOp.isPrecedenceLess(parentOp)) { parent.replace(child, EnclosedExpr(child.clone())) diff --git a/deob-ast/src/main/kotlin/org/openrs2/deob/ast/transform/ForLoopConditionTransformer.kt b/deob-ast/src/main/kotlin/org/openrs2/deob/ast/transform/ForLoopConditionTransformer.kt index 2abd8139..0b47909b 100644 --- a/deob-ast/src/main/kotlin/org/openrs2/deob/ast/transform/ForLoopConditionTransformer.kt +++ b/deob-ast/src/main/kotlin/org/openrs2/deob/ast/transform/ForLoopConditionTransformer.kt @@ -45,6 +45,7 @@ public class ForLoopConditionTransformer : Transformer() { PREFIX_INCREMENT, PREFIX_DECREMENT, POSTFIX_INCREMENT, POSTFIX_DECREMENT -> expression else -> null } + is AssignExpr -> target else -> null } diff --git a/deob-ast/src/main/kotlin/org/openrs2/deob/ast/transform/GlTransformer.kt b/deob-ast/src/main/kotlin/org/openrs2/deob/ast/transform/GlTransformer.kt index 6530672f..5c494742 100644 --- a/deob-ast/src/main/kotlin/org/openrs2/deob/ast/transform/GlTransformer.kt +++ b/deob-ast/src/main/kotlin/org/openrs2/deob/ast/transform/GlTransformer.kt @@ -244,10 +244,12 @@ public class GlTransformer @Inject constructor(private val registry: GlRegistry) transformExpr(unit, command, parameter, expr.left) transformExpr(unit, command, parameter, expr.right) } + is ConditionalExpr -> { transformExpr(unit, command, parameter, expr.thenExpr) transformExpr(unit, command, parameter, expr.elseExpr) } + is IntegerLiteralExpr -> { transformIntegerLiteralExpr(unit, command, parameter, expr) } diff --git a/deob-ast/src/main/kotlin/org/openrs2/deob/ast/transform/IdentityTransformer.kt b/deob-ast/src/main/kotlin/org/openrs2/deob/ast/transform/IdentityTransformer.kt index d8612974..c5134198 100644 --- a/deob-ast/src/main/kotlin/org/openrs2/deob/ast/transform/IdentityTransformer.kt +++ b/deob-ast/src/main/kotlin/org/openrs2/deob/ast/transform/IdentityTransformer.kt @@ -27,6 +27,7 @@ public class IdentityTransformer : Transformer() { expr.replace(expr.left) } } + BinaryExpr.Operator.MINUS -> { if (expr.left.isZero()) { // 0 - x => -x @@ -36,6 +37,7 @@ public class IdentityTransformer : Transformer() { expr.replace(expr.left) } } + BinaryExpr.Operator.MULTIPLY -> { if (expr.left.isOne()) { // 1 * x => x @@ -45,12 +47,14 @@ public class IdentityTransformer : Transformer() { expr.replace(expr.left) } } + BinaryExpr.Operator.DIVIDE -> { if (expr.right.isOne()) { // x / 1 => x expr.replace(expr.left) } } + else -> Unit } } diff --git a/deob-ast/src/main/kotlin/org/openrs2/deob/ast/transform/IfElseTransformer.kt b/deob-ast/src/main/kotlin/org/openrs2/deob/ast/transform/IfElseTransformer.kt index 49271b06..2e3ac081 100644 --- a/deob-ast/src/main/kotlin/org/openrs2/deob/ast/transform/IfElseTransformer.kt +++ b/deob-ast/src/main/kotlin/org/openrs2/deob/ast/transform/IfElseTransformer.kt @@ -458,6 +458,7 @@ public class IfElseTransformer : Transformer() { null } } + else -> null } } @@ -477,6 +478,7 @@ public class IfElseTransformer : Transformer() { val tail = statements.lastOrNull() tail is ThrowStmt || tail is ReturnStmt } + else -> false } } diff --git a/deob-ast/src/main/kotlin/org/openrs2/deob/ast/util/ExprUtils.kt b/deob-ast/src/main/kotlin/org/openrs2/deob/ast/util/ExprUtils.kt index 4ca07ffe..1ed31a23 100644 --- a/deob-ast/src/main/kotlin/org/openrs2/deob/ast/util/ExprUtils.kt +++ b/deob-ast/src/main/kotlin/org/openrs2/deob/ast/util/ExprUtils.kt @@ -51,16 +51,19 @@ public fun Expression.negate(): Expression { UnaryExpr.Operator.MINUS -> expression.clone() else -> UnaryExpr(clone(), UnaryExpr.Operator.MINUS) } + is IntegerLiteralExpr -> when (val n = asNumber()) { IntegerLiteralExpr.MAX_31_BIT_UNSIGNED_VALUE_AS_LONG -> IntegerLiteralExpr(Integer.MIN_VALUE.toString()) is Int -> IntegerLiteralExpr((-n.toInt()).toString()) else -> error("Invalid IntegerLiteralExpr type") } + is LongLiteralExpr -> when (val n = asNumber()) { LongLiteralExpr.MAX_63_BIT_UNSIGNED_VALUE_AS_BIG_INTEGER -> Long.MIN_VALUE.toLongLiteralExpr() is Long -> (-n).toLongLiteralExpr() else -> error("Invalid LongLiteralExpr type") } + else -> UnaryExpr(clone(), UnaryExpr.Operator.MINUS) } } @@ -72,27 +75,37 @@ public fun Expression.not(): Expression { return expression.clone() } } + is BinaryExpr -> { when (operator) { BinaryExpr.Operator.EQUALS -> return BinaryExpr(left.clone(), right.clone(), BinaryExpr.Operator.NOT_EQUALS) + BinaryExpr.Operator.NOT_EQUALS -> return BinaryExpr(left.clone(), right.clone(), BinaryExpr.Operator.EQUALS) + BinaryExpr.Operator.GREATER -> return BinaryExpr(left.clone(), right.clone(), BinaryExpr.Operator.LESS_EQUALS) + BinaryExpr.Operator.GREATER_EQUALS -> return BinaryExpr(left.clone(), right.clone(), BinaryExpr.Operator.LESS) + BinaryExpr.Operator.LESS -> return BinaryExpr(left.clone(), right.clone(), BinaryExpr.Operator.GREATER_EQUALS) + BinaryExpr.Operator.LESS_EQUALS -> return BinaryExpr(left.clone(), right.clone(), BinaryExpr.Operator.GREATER) + BinaryExpr.Operator.AND -> return BinaryExpr(left.not(), right.not(), BinaryExpr.Operator.OR) + BinaryExpr.Operator.OR -> return BinaryExpr(left.not(), right.not(), BinaryExpr.Operator.AND) + else -> Unit } } + is BooleanLiteralExpr -> return BooleanLiteralExpr(!value) } diff --git a/deob-bytecode/src/main/kotlin/org/openrs2/deob/bytecode/analysis/CopyPropagationAnalyzer.kt b/deob-bytecode/src/main/kotlin/org/openrs2/deob/bytecode/analysis/CopyPropagationAnalyzer.kt index 63df506c..4c480997 100644 --- a/deob-bytecode/src/main/kotlin/org/openrs2/deob/bytecode/analysis/CopyPropagationAnalyzer.kt +++ b/deob-bytecode/src/main/kotlin/org/openrs2/deob/bytecode/analysis/CopyPropagationAnalyzer.kt @@ -51,6 +51,7 @@ public class CopyPropagationAnalyzer(owner: String, method: MethodNode) : newSet } } + insn is IincInsnNode -> set.minusKilledByAssignmentTo(insn.`var`) else -> set } diff --git a/deob-bytecode/src/main/kotlin/org/openrs2/deob/bytecode/analysis/IntInterpreter.kt b/deob-bytecode/src/main/kotlin/org/openrs2/deob/bytecode/analysis/IntInterpreter.kt index 32f1b736..a2675509 100644 --- a/deob-bytecode/src/main/kotlin/org/openrs2/deob/bytecode/analysis/IntInterpreter.kt +++ b/deob-bytecode/src/main/kotlin/org/openrs2/deob/bytecode/analysis/IntInterpreter.kt @@ -84,12 +84,14 @@ public class IntInterpreter(private val args: Array) : Interpreter< } v1 / v2 } + Opcodes.IREM -> { if (v2 == 0) { return IntValue(basicValue) } v1 % v2 } + Opcodes.ISHL -> v1 shl v2 Opcodes.ISHR -> v1 shr v2 Opcodes.IUSHR -> v1 ushr v2 diff --git a/deob-bytecode/src/main/kotlin/org/openrs2/deob/bytecode/analysis/LiveVariableAnalyzer.kt b/deob-bytecode/src/main/kotlin/org/openrs2/deob/bytecode/analysis/LiveVariableAnalyzer.kt index 31a5cc95..daff7578 100644 --- a/deob-bytecode/src/main/kotlin/org/openrs2/deob/bytecode/analysis/LiveVariableAnalyzer.kt +++ b/deob-bytecode/src/main/kotlin/org/openrs2/deob/bytecode/analysis/LiveVariableAnalyzer.kt @@ -27,6 +27,7 @@ public class LiveVariableAnalyzer(owner: String, method: MethodNode) : Opcodes.ISTORE, Opcodes.LSTORE, Opcodes.FSTORE, Opcodes.DSTORE, Opcodes.ASTORE -> set.minus(insn.`var`) else -> set } + is IincInsnNode -> set.plus(insn.`var`) else -> set } diff --git a/deob-bytecode/src/main/kotlin/org/openrs2/deob/bytecode/remap/FieldMappingGenerator.kt b/deob-bytecode/src/main/kotlin/org/openrs2/deob/bytecode/remap/FieldMappingGenerator.kt index fbf56dcf..70b519ff 100644 --- a/deob-bytecode/src/main/kotlin/org/openrs2/deob/bytecode/remap/FieldMappingGenerator.kt +++ b/deob-bytecode/src/main/kotlin/org/openrs2/deob/bytecode/remap/FieldMappingGenerator.kt @@ -60,10 +60,12 @@ public class FieldMappingGenerator( Type.BOOLEAN, Type.BYTE, Type.CHAR, Type.SHORT, Type.INT, Type.LONG, Type.FLOAT, Type.DOUBLE -> { elementType.className + dimensions } + Type.OBJECT -> { val className = classMapping.getOrDefault(elementType.internalName, elementType.internalName) className.getClassName() + dimensions } + else -> throw IllegalArgumentException("Unknown field type $elementType") } diff --git a/deob-bytecode/src/main/kotlin/org/openrs2/deob/bytecode/transform/ConstantArgTransformer.kt b/deob-bytecode/src/main/kotlin/org/openrs2/deob/bytecode/transform/ConstantArgTransformer.kt index 9d4c89b1..736ba6c3 100644 --- a/deob-bytecode/src/main/kotlin/org/openrs2/deob/bytecode/transform/ConstantArgTransformer.kt +++ b/deob-bytecode/src/main/kotlin/org/openrs2/deob/bytecode/transform/ConstantArgTransformer.kt @@ -212,6 +212,7 @@ public class ConstantArgTransformer @Inject constructor(private val profile: Pro else -> Unit } } + IF_ICMPEQ, IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE -> { val value1 = frame.getStack(frame.stackSize - 2) val value2 = frame.getStack(frame.stackSize - 1) diff --git a/deob-bytecode/src/main/kotlin/org/openrs2/deob/bytecode/transform/EmptyClassTransformer.kt b/deob-bytecode/src/main/kotlin/org/openrs2/deob/bytecode/transform/EmptyClassTransformer.kt index 06832365..19d6ce3f 100644 --- a/deob-bytecode/src/main/kotlin/org/openrs2/deob/bytecode/transform/EmptyClassTransformer.kt +++ b/deob-bytecode/src/main/kotlin/org/openrs2/deob/bytecode/transform/EmptyClassTransformer.kt @@ -79,6 +79,7 @@ public class EmptyClassTransformer : Transformer() { addTypeReference(cst) } } + is TypeInsnNode -> referencedClasses.add(insn.desc) } } diff --git a/deob-bytecode/src/main/kotlin/org/openrs2/deob/bytecode/transform/OpaquePredicateTransformer.kt b/deob-bytecode/src/main/kotlin/org/openrs2/deob/bytecode/transform/OpaquePredicateTransformer.kt index 1c2a043f..2907ac19 100644 --- a/deob-bytecode/src/main/kotlin/org/openrs2/deob/bytecode/transform/OpaquePredicateTransformer.kt +++ b/deob-bytecode/src/main/kotlin/org/openrs2/deob/bytecode/transform/OpaquePredicateTransformer.kt @@ -111,10 +111,12 @@ public class OpaquePredicateTransformer : Transformer() { method.instructions.remove(match[0]) branch.opcode = Opcodes.GOTO } + Opcodes.IFNE -> { // branch is never taken match.forEach(method.instructions::remove) } + else -> error("Invalid opcode") } diff --git a/deob-bytecode/src/main/kotlin/org/openrs2/deob/bytecode/transform/UnusedArgTransformer.kt b/deob-bytecode/src/main/kotlin/org/openrs2/deob/bytecode/transform/UnusedArgTransformer.kt index fa32e5e4..35800bc1 100644 --- a/deob-bytecode/src/main/kotlin/org/openrs2/deob/bytecode/transform/UnusedArgTransformer.kt +++ b/deob-bytecode/src/main/kotlin/org/openrs2/deob/bytecode/transform/UnusedArgTransformer.kt @@ -85,6 +85,7 @@ public class UnusedArgTransformer @Inject constructor(private val profile: Profi retainArg(partition, localToArgMap, frame, insn.`var`) } } + is IincInsnNode -> retainArg(partition, localToArgMap, frame, insn.`var`) is MethodInsnNode -> { val invokePartition = inheritedMethodSets[MemberRef(insn)] diff --git a/deob-processor/src/main/kotlin/org/openrs2/deob/processor/NameMapProcessor.kt b/deob-processor/src/main/kotlin/org/openrs2/deob/processor/NameMapProcessor.kt index 73315469..3c2f74eb 100644 --- a/deob-processor/src/main/kotlin/org/openrs2/deob/processor/NameMapProcessor.kt +++ b/deob-processor/src/main/kotlin/org/openrs2/deob/processor/NameMapProcessor.kt @@ -101,6 +101,7 @@ public class NameMapProcessor : AbstractProcessor() { map.methods[ref] = Method(owner, name, arguments, locals) } + else -> error("Unexpected element type") } } diff --git a/http/src/main/kotlin/org/openrs2/http/NetrcReader.kt b/http/src/main/kotlin/org/openrs2/http/NetrcReader.kt index c73cd1b1..f3a00565 100644 --- a/http/src/main/kotlin/org/openrs2/http/NetrcReader.kt +++ b/http/src/main/kotlin/org/openrs2/http/NetrcReader.kt @@ -49,10 +49,12 @@ public class NetrcReader(private val scanner: Scanner) { state = State.READ_MACHINE host = scanner.next() } + "default" -> { state = State.READ_MACHINE host = null } + "login", "password", "account" -> { if (state != State.READ_MACHINE) { throw IOException("Unexpected token '$token'") @@ -66,6 +68,7 @@ public class NetrcReader(private val scanner: Scanner) { password = scanner.next() } } + "macdef" -> skipMacro() } } diff --git a/patcher/src/main/kotlin/org/openrs2/patcher/transform/CachePathTransformer.kt b/patcher/src/main/kotlin/org/openrs2/patcher/transform/CachePathTransformer.kt index 10cde788..eb537c8c 100644 --- a/patcher/src/main/kotlin/org/openrs2/patcher/transform/CachePathTransformer.kt +++ b/patcher/src/main/kotlin/org/openrs2/patcher/transform/CachePathTransformer.kt @@ -32,10 +32,12 @@ public class CachePathTransformer @Inject constructor( insn.cst = ".${config.internalOperator}_cache_" paths++ } + "jagex_" -> { insn.cst = ".${config.internalOperator}_" paths++ } + "runescape" -> { insn.cst = config.internalGame paths++ diff --git a/patcher/src/main/kotlin/org/openrs2/patcher/transform/HighDpiTransformer.kt b/patcher/src/main/kotlin/org/openrs2/patcher/transform/HighDpiTransformer.kt index 6763dfdd..3799ff16 100644 --- a/patcher/src/main/kotlin/org/openrs2/patcher/transform/HighDpiTransformer.kt +++ b/patcher/src/main/kotlin/org/openrs2/patcher/transform/HighDpiTransformer.kt @@ -63,10 +63,12 @@ public class HighDpiTransformer : Transformer() { addCanvasScaleField(clazz) newMembers++ } + in GL_INTERFACES -> { addPixelZoomMethod(clazz, Opcodes.ACC_ABSTRACT) newMembers++ } + in GL_IMPLS -> { addPixelZoomMethod(clazz, Opcodes.ACC_FINAL or Opcodes.ACC_NATIVE) newMembers++ diff --git a/patcher/src/main/kotlin/org/openrs2/patcher/transform/PublicKeyTransformer.kt b/patcher/src/main/kotlin/org/openrs2/patcher/transform/PublicKeyTransformer.kt index a22a0748..ce31bdd8 100644 --- a/patcher/src/main/kotlin/org/openrs2/patcher/transform/PublicKeyTransformer.kt +++ b/patcher/src/main/kotlin/org/openrs2/patcher/transform/PublicKeyTransformer.kt @@ -32,6 +32,7 @@ public class PublicKeyTransformer @Inject constructor(private val key: RSAPrivat insn.cst = key.publicExponent.toString() exponents++ } + JAGEX_MODULUS -> { insn.cst = key.modulus.toString() moduli++ diff --git a/protocol/src/main/kotlin/org/openrs2/protocol/js5/upstream/Js5RequestEncoder.kt b/protocol/src/main/kotlin/org/openrs2/protocol/js5/upstream/Js5RequestEncoder.kt index ec18916f..3c660a9f 100644 --- a/protocol/src/main/kotlin/org/openrs2/protocol/js5/upstream/Js5RequestEncoder.kt +++ b/protocol/src/main/kotlin/org/openrs2/protocol/js5/upstream/Js5RequestEncoder.kt @@ -14,17 +14,20 @@ public object Js5RequestEncoder : MessageToByteEncoder(Js5Request::c out.writeByte(msg.archive) out.writeShort(msg.group) } + is Js5Request.Rekey -> { out.writeByte(4) out.writeByte(msg.key) out.writeZero(2) } + is Js5Request.LoggedIn -> encodeSimple(out, 2) is Js5Request.LoggedOut -> encodeSimple(out, 3) is Js5Request.Connected -> { out.writeByte(6) out.writeMedium(3) } + is Js5Request.Disconnect -> encodeSimple(out, 7) } } diff --git a/protocol/src/main/kotlin/org/openrs2/protocol/login/upstream/LoginRequest.kt b/protocol/src/main/kotlin/org/openrs2/protocol/login/upstream/LoginRequest.kt index 900da460..214bde3e 100644 --- a/protocol/src/main/kotlin/org/openrs2/protocol/login/upstream/LoginRequest.kt +++ b/protocol/src/main/kotlin/org/openrs2/protocol/login/upstream/LoginRequest.kt @@ -12,6 +12,7 @@ public sealed class LoginRequest : Packet { public val day: Int, public val country: Int ) : LoginRequest() + public data class CreateCheckName(public val username: String) : LoginRequest() public data class CreateAccount( public val build: Int, @@ -27,11 +28,13 @@ public sealed class LoginRequest : Packet { public val country: Int, public val email: String ) : LoginRequest() + public data class RequestWorldList(public val checksum: Int) : LoginRequest() public data class CheckWorldSuitability( public val build: Int, public val username: String, public val password: String ) : LoginRequest() + public object InitCrossDomainConnection : LoginRequest() } diff --git a/util/src/main/kotlin/org/openrs2/util/charset/ModifiedUtf8Charset.kt b/util/src/main/kotlin/org/openrs2/util/charset/ModifiedUtf8Charset.kt index 9feab981..ec03925f 100644 --- a/util/src/main/kotlin/org/openrs2/util/charset/ModifiedUtf8Charset.kt +++ b/util/src/main/kotlin/org/openrs2/util/charset/ModifiedUtf8Charset.kt @@ -37,6 +37,7 @@ public object ModifiedUtf8Charset : Charset("ModifiedUtf8", null) { output.put((0xC0 or ((char.code shr 6) and 0x1F)).toByte()) output.put((0x80 or (char.code and 0x3F)).toByte()) } + else -> { output.put((0xE0 or ((char.code shr 12) and 0x1F)).toByte()) output.put((0x80 or ((char.code shr 6) and 0x1F)).toByte()) diff --git a/util/src/main/kotlin/org/openrs2/util/collect/ForestDisjointSet.kt b/util/src/main/kotlin/org/openrs2/util/collect/ForestDisjointSet.kt index 6df81421..36f5fbde 100644 --- a/util/src/main/kotlin/org/openrs2/util/collect/ForestDisjointSet.kt +++ b/util/src/main/kotlin/org/openrs2/util/collect/ForestDisjointSet.kt @@ -105,9 +105,11 @@ public class ForestDisjointSet : DisjointSet { xRoot.rank < yRoot.rank -> { xRoot.parent = yRoot } + xRoot.rank > yRoot.rank -> { yRoot.parent = xRoot } + else -> { yRoot.parent = xRoot xRoot.rank++