diff --git a/Data/Sys/GameSettings/GALE01r2.ini b/Data/Sys/GameSettings/GALE01r2.ini index 6b4f9af5e5..6ee26b6288 100644 --- a/Data/Sys/GameSettings/GALE01r2.ini +++ b/Data/Sys/GameSettings/GALE01r2.ini @@ -9,7 +9,7 @@ FastDiscSpeed = True [Gecko_Enabled] $Required: General Codes $Required: Slippi Recording -$Required: Slippi Online +$Required: Slippi Online (Subframe rollback) $Recommended: Normal Lag Reduction $Recommended: Apply Delay to all In-Game Scenes @@ -1190,7 +1190,7 @@ C216EBAC 0000000C #Common/CSS KO Stars/Asign KO Stars Upon Exiting Dairantou.asm 8001001C 83E10014 60000000 00000000 -$Required: Slippi Online [Fizzi, UnclePunch] +$Required: Slippi Online (Subframe rollback) [Fizzi, UnclePunch] *Adds online mode, Slippi device must be in Slot B. *Change settings in Config > GameCube C206A880 00000018 #Online/Core/BrawlOffscreenDamage.asm @@ -1292,10 +1292,10 @@ C216E748 00000070 #Online/Core/InitOnlinePlay.asm 38600012 3D808037 618CF1E4 7D8903A6 4E800421 907B00D1 -3860010A 3D808037 +3860012E 3D808037 618CF1E4 7D8903A6 4E800421 907B00D5 -7C7A1B78 3880010A +7C7A1B78 3880012E 3D808000 618CC160 7D8903A6 4E800421 38600021 3D808037 @@ -1311,7 +1311,7 @@ C216E748 00000070 #Online/Core/InitOnlinePlay.asm 38800007 98830001 93790005 386007BC 90790009 9359000D -3860010A 90790011 +3860012E 90790011 807B024E 90790015 3860009E 90790019 38600000 9079001D @@ -1665,18 +1665,18 @@ C0570010 3D80803A 4E800421 BA810008 800100B4 382100B0 7C0803A6 00000000 -C2376A28 000000DD #Online/Core/TriggerSendInput.asm +C2376A28 000002A0 # Alpha subframe rollback with pad prediction logs | Online/Core/TriggerSendInput.asm 7C0802A6 90010004 9421FF50 BE810008 3C608048 80639D30 5463443E 2C030208 -408206B0 3C608047 +408214C8 3C608047 60639D64 80630000 -2C030000 4082069C +2C030000 408214B4 836DB61C 833B00D1 831B00D5 82FB024A 835B0003 887B00D9 -2C030001 418205F8 +2C030001 41821320 887B001B 38800054 7C632050 2C1A0003 4080001C 386100DC @@ -1685,189 +1685,610 @@ C2376A28 000000DD #Online/Core/TriggerSendInput.asm 4E800421 889B0002 1C84000C 386400E6 7C6118AE 7C630774 -2C03FFFD 40820024 -386400DC 7C611A14 -389B000F 38A0000C -3D808000 618C31F4 -7D8903A6 4E800421 +2C03FFFD 40820040 +39400000 899B001B +7F4BD378 7D6B6214 +398400DC 7D816214 +48001349 386400DC +7C611A14 389B000F +38A0000C 3D808000 +618C31F4 7D8903A6 +4E800421 889B0002 +1C84000C 388400DC +387B000F 7C812214 +38A0000C 3D808000 +618C31F4 7D8903A6 +4E800421 386000B0 +98790000 93590001 +887B001B 98790005 889B0002 1C84000C -388400DC 387B000F +388400DC 38790006 7C812214 38A0000C 3D808000 618C31F4 7D8903A6 4E800421 -386000B0 98790000 -93590001 887B001B -98790005 889B0002 +39400001 899B001B +7F4BD378 7D6B6214 +39990006 480012AD +7F23CB78 38800012 +38A00001 3D808000 +618C55F0 7D8903A6 +4E800421 38780000 +3880012E 38A00000 +3D808000 618C55F0 +7D8903A6 4E800421 +88780000 2C030002 +4182001C 2C030003 +41820008 48000030 +38600001 987B000D +48000024 BA810008 +800100B4 382100B0 +7C0803A6 3D808037 +618C6CEC 7D8903A6 +4E800420 889B001C +1C84000C 3884001D +887B0000 1C63000C +386300DC 7C611A14 +7C9B2214 38A0000C +3D808000 618C31F4 +7D8903A6 4E800421 +887B00DF 1C63000C +386300E0 889B0000 1C84000C 388400DC -38790006 7C812214 +39400003 7F4BD378 +7D812214 480011D5 +7C7B1A14 7C812214 38A0000C 3D808000 618C31F4 7D8903A6 -4E800421 7F23CB78 -38800012 38A00001 +4E800421 887B00DF +38630001 2C030007 +41800008 38600000 +987B00DF 887B001C +1C63000C 3863001D +39400002 899B001B +7F4BD378 7D6B6214 +39990006 4800117D +7C7B1A14 38990006 +38A0000C 3D808000 +618C31F4 7D8903A6 +4E800421 889B001B +887B001C 38630001 +7C032000 41800008 +38600000 987B001C +887B0236 2C030000 +40820018 38600000 +987B0247 987B0248 +987B0249 48000948 +3A800000 38D40247 +7C66D8AE 2C030001 +408203D8 1CD40004 +38C60002 7C66C02E +1CD40004 38C6023B +7C86D82E 7C641851 +418003B8 7C761B78 +38D40134 7C66D8AE +38D40137 7C86D8AE +48000044 4E800021 +506C6179 65722025 +645B2564 5D20722F +7720696E 64657865 +73207768 656E2072 +65616469 6E67206E +65787420 696E7075 +743A2025 642F2564 +00000000 7C0802A6 +90010004 9421FF00 +BC610008 7E85A378 +7EC6B378 7C671B78 +7C882378 60000000 +806DAFC4 38630003 +4BFFFF95 7C8802A6 +4CC63242 3D808032 +618C3CF4 7D8903A6 +4E800421 806DAFC4 +388000D0 98830000 +38800000 98830001 +38800003 98830002 +38800080 38A00001 3D808000 618C55F0 7D8903A6 4E800421 -38780000 3880010A -38A00000 3D808000 -618C55F0 7D8903A6 -4E800421 88780000 -2C030002 4182001C -2C030003 41820008 -48000030 38600001 -987B000D 48000024 +B8610008 80010104 +38210100 7C0803A6 +7EC3B378 1C63000C +3863000E 1CD40054 +7C633214 38D40134 +7C86D8AE 1C84000C +3884013A 1CB40054 +7C842A14 7CD81A14 +7CFB2214 88660000 +88870000 546306FE +548406FE 7C032000 +4082017C 88660001 +88870001 5463067E +5484067E 7C032000 +40820164 80660002 +80870002 7C032000 +40820154 38A00005 +38A50001 2C050008 +40800028 7C6530AE +7C8538AE 2C03002A +4181000C 2C04002A +4081FFE0 7C032000 +40820124 4BFFFFD4 +1CD40004 38C6023B +7C66D82E 38630001 +7C66D92E 38D40134 +7C66D8AE 38630001 +2C030007 41800008 +3863FFF9 7C66D9AE +38D40134 7C66D8AE +38D40137 7C86D8AE +48000034 4E800021 +506C6179 65722025 +6420722F 7720696E +64657865 73206166 +74657220 72656164 +696E673A 2025642F +25640000 7C0802A6 +90010004 9421FF00 +BC610008 7E85A378 +7C661B78 7C872378 +60000000 60000000 +806DAFC4 38630003 +4BFFFFA5 7C8802A6 +4CC63242 3D808032 +618C3CF4 7D8903A6 +4E800421 806DAFC4 +388000D0 98830000 +38800000 98830001 +38800003 98830002 +38800080 38A00001 +3D808000 618C55F0 +7D8903A6 4E800421 +B8610008 80010104 +38210100 7C0803A6 +38D40134 7C66D8AE +38D40137 7C86D8AE +7C041800 4082FD30 +48000110 1CD40004 +38C6023B 7C66D82E +48000044 4E800021 +54726967 67657269 +6E672072 6F6C6C62 +61636B20 66726F6D +20706C61 79657220 +25642069 6E707574 +206F6E20 70617374 +20667261 6D652025 +64000000 7C0802A6 +90010004 9421FF00 +BC610008 7E85A378 +7C661B78 60000000 +60000000 60000000 +806DAFC4 38630003 +4BFFFF95 7C8802A6 +4CC63242 3D808032 +618C3CF4 7D8903A6 +4E800421 806DAFC4 +388000D0 98830000 +38800000 98830001 +38800003 98830002 +38800080 38A00001 +3D808000 618C55F0 +7D8903A6 4E800421 +B8610008 80010104 +38210100 7C0803A6 +38600001 987B00D9 +987B00DA 935B00DB BA810008 800100B4 382100B0 7C0803A6 3D808037 618C6CEC 7D8903A6 4E800420 -889B001C 1C84000C -3884001D 887B0000 -1C63000C 386300DC -7C611A14 7C9B2214 -38A0000C 3D808000 -618C31F4 7D8903A6 -4E800421 887B00DF -1C63000C 386300E0 -889B0000 1C84000C -388400DC 7C7B1A14 -7C812214 38A0000C -3D808000 618C31F4 -7D8903A6 4E800421 -887B00DF 38630001 -2C030007 41800008 -38600000 987B00DF -887B001C 1C63000C -3863001D 7C7B1A14 -38990006 38A0000C -3D808000 618C31F4 +3A940001 2C140003 +4180FC14 3AA00000 +3A800000 807B0237 +7C761B78 48000038 +4E800021 41747465 +6D707469 6E672074 +6F206164 76616E63 +65207361 76657374 +61746520 6672616D +65207061 73742025 +64000000 7C0802A6 +90010004 9421FF00 +BC610008 7C651B78 +60000000 60000000 +60000000 60000000 +806DAFC4 38630003 +4BFFFFA1 7C8802A6 +4CC63242 3D808032 +618C3CF4 7D8903A6 +4E800421 806DAFC4 +388000D0 98830000 +38800000 98830001 +38800003 98830002 +38800080 38A00001 +3D808000 618C55F0 7D8903A6 4E800421 -889B001B 887B001C -38630001 7C032000 -41800008 38600000 -987B001C 887B0236 -2C030000 40820018 -38600000 987B0247 -987B0248 987B0249 -48000284 3A800000 -38D40247 7C66D8AE -2C030001 40820178 -1CD40004 38C60002 -7C66C02E 1CD40004 -38C6023B 7C86D82E -7C641851 41800158 -7C761B78 38D40134 -7C66D8AE 38D40137 -7C86D8AE 7EC3B378 -1C63000C 3863000E -1CD40054 7C633214 -38D40134 7C86D8AE -1C84000C 3884013A -1CB40054 7C842A14 -7CD81A14 7CFB2214 -88660000 88870000 -546306FE 548406FE -7C032000 408200BC -88660001 88870001 -5463067E 5484067E -7C032000 408200A4 -80660002 80870002 -7C032000 40820094 -38A00005 38A50001 -2C050008 40800028 -7C6530AE 7C8538AE -2C03002A 4181000C -2C04002A 4081FFE0 -7C032000 40820064 -4BFFFFD4 1CD40004 -38C6023B 7C66D82E -38630001 7C66D92E -38D40134 7C66D8AE -38630001 2C030007 -41800008 3863FFF9 -7C66D9AE 38D40134 -7C66D8AE 38D40137 -7C86D8AE 38D40134 -7C66D8AE 38D40137 -7C86D8AE 7C041800 -4082FEC0 48000040 -1CD40004 38C6023B -7C66D82E 38600001 -987B00D9 987B00DA -935B00DB BA810008 -800100B4 382100B0 -7C0803A6 3D808037 -618C6CEC 7D8903A6 -4E800420 3A940001 -2C140003 4180FE74 -3AA00000 3A800000 -807B0237 7C761B78 +B8610008 80010104 +38210100 7C0803A6 7EC3B378 38D40247 7C86D8AE 7C761B78 -7EC3B378 38D40247 -7C86D8AE 2C040001 -40820030 1CD40004 -38C6023B 7C86D82E -2C150000 4182000C -7C041800 40800014 -7C832378 7C761B78 -7EC3B378 3AA00001 -3A940001 2C140003 -4180FFAC 907B0237 +48000028 4E800021 +506C6179 65722025 +64207361 76657374 +61746520 666C6167 +3A202564 00000000 +7C0802A6 90010004 +9421FF00 BC610008 +7E85A378 7C862378 +60000000 60000000 +60000000 806DAFC4 +38630003 4BFFFFB1 +7C8802A6 4CC63242 +3D808032 618C3CF4 +7D8903A6 4E800421 +806DAFC4 388000D0 +98830000 38800000 +98830001 38800003 +98830002 38800080 +38A00001 3D808000 +618C55F0 7D8903A6 +4E800421 B8610008 +80010104 38210100 +7C0803A6 7EC3B378 +38D40247 7C86D8AE +2C040001 408200E8 +1CD40004 38C6023B +7C86D82E 2C150000 +4182000C 7C041800 +408000CC 7C832378 +7C761B78 4800002C +4E800021 506C6179 +65722025 64207365 +74207361 76657374 +61746520 6672616D +65202564 00000000 +7C0802A6 90010004 +9421FF00 BC610008 +7E85A378 7C862378 +60000000 60000000 +60000000 806DAFC4 +38630003 4BFFFFAD +7C8802A6 4CC63242 +3D808032 618C3CF4 +7D8903A6 4E800421 +806DAFC4 388000D0 +98830000 38800000 +98830001 38800003 +98830002 38800080 +38A00001 3D808000 +618C55F0 7D8903A6 +4E800421 B8610008 +80010104 38210100 +7C0803A6 7EC3B378 +3AA00001 3A940001 +2C140003 4180FE40 +907B0237 48000034 +4E800021 53657420 +73617665 73746174 +65206672 616D6520 +746F2025 642C2067 +616D6520 6672616D +653A2025 64000000 +7C0802A6 90010004 +9421FF00 BC610008 +7C651B78 3CC08048 +80C69D60 60000000 +60000000 60000000 +806DAFC4 38630003 +4BFFFFA1 7C8802A6 +4CC63242 3D808032 +618C3CF4 7D8903A6 +4E800421 806DAFC4 +388000D0 98830000 +38800000 98830001 +38800003 98830002 +38800080 38A00001 +3D808000 618C55F0 +7D8903A6 4E800421 +B8610008 80010104 +38210100 7C0803A6 3A800000 38D40247 7C86D8AE 2C040001 -40820038 38D40134 +408200F8 38D40134 7C66D8AE 38D40137 -7C86D8AE 38D40134 +7C86D8AE 48000034 +4E800021 506C6179 +65722025 6420722F +7720696E 64657865 +73206475 72696E67 +20726573 65743A20 +25642F25 64000000 +7C0802A6 90010004 +9421FF00 BC610008 +7E85A378 7C661B78 +7C872378 60000000 +60000000 806DAFC4 +38630003 4BFFFFA5 +7C8802A6 4CC63242 +3D808032 618C3CF4 +7D8903A6 4E800421 +806DAFC4 388000D0 +98830000 38800000 +98830001 38800003 +98830002 38800080 +38A00001 3D808000 +618C55F0 7D8903A6 +4E800421 B8610008 +80010104 38210100 +7C0803A6 38D40134 7C66D8AE 38D40137 7C86D8AE 7C041800 40820010 38600000 38D40247 7C66D9AE 3A940001 2C140003 -4180FFB4 3A800000 +4180FEF4 3A800000 38D40247 7C86D8AE -2C040001 41820018 +2C040001 418200C8 3A940001 2C140003 4180FFE8 38600000 -987B0236 3A800000 +987B0236 48000024 +4E800021 52657365 +74207361 76657374 +61746520 666C6167 +7320746F 20300000 +7C0802A6 90010004 +9421FF00 BC610008 +60000000 60000000 +60000000 60000000 +60000000 806DAFC4 +38630003 4BFFFFB5 +7C8802A6 4CC63242 +3D808032 618C3CF4 +7D8903A6 4E800421 +806DAFC4 388000D0 +98830000 38800000 +98830001 38800003 +98830002 38800080 +38A00001 3D808000 +618C55F0 7D8903A6 +4E800421 B8610008 +80010104 38210100 +7C0803A6 3A800000 3AA00000 887B0000 7C151800 40820008 3AB50001 1CD40004 38C60002 7C66C02E 7C7A1850 2C030000 -408000D4 887B001B +40800548 887B001B 38800054 7C632050 -7C1A1800 418000BC +7C1A1800 41800478 887B000C 2C030001 -418200B0 38D40137 +4182046C 38D40137 7EC6D8AE 1C76000C 3863013A 1CB40054 -7C632A14 1CD40054 -38C6000E 7C7B1A14 -7C983214 38A0000C -3D808000 618C31F4 +7C632A14 38A0010A +1CD4000C 7CC53214 +7C7B1A14 7C983214 +38A0000C 3D808000 +618C31F4 7D8903A6 +4E800421 38760001 +2C030007 41800008 +3863FFF9 38D40137 +7C66D9AE 38D40134 +7C66D8AE 38D40137 +7C86D8AE 48000038 +4E800021 506C6179 +65722025 6420722F +7720696E 64657865 +73206166 74657220 +77726974 65207570 +64617465 3A202564 +2F256400 7C0802A6 +90010004 9421FF00 +BC610008 7E85A378 +7C661B78 7C872378 +60000000 60000000 +806DAFC4 38630003 +4BFFFFA1 7C8802A6 +4CC63242 3D808032 +618C3CF4 7D8903A6 +4E800421 806DAFC4 +388000D0 98830000 +38800000 98830001 +38800003 98830002 +38800080 38A00001 +3D808000 618C55F0 7D8903A6 4E800421 -38760001 2C030007 -41800008 3863FFF9 -38D40137 7C66D9AE -38D40134 7C66D8AE -38D40137 7C86D8AE +B8610008 80010104 +38210100 7C0803A6 38D40247 7C66D8AE -2C030001 4182003C +2C030001 41820330 1CD40004 38C6023B -7F46D92E 38600001 +7F46D92E 48000034 +4E800021 53657474 +696E6720 73617665 +73746174 65206672 +616D6520 666F7220 +706C6179 65722025 +6420746F 20256400 +7C0802A6 90010004 +9421FF00 BC610008 +7E85A378 7F46D378 +60000000 60000000 +60000000 806DAFC4 +38630003 4BFFFFA5 +7C8802A6 4CC63242 +3D808032 618C3CF4 +7D8903A6 4E800421 +806DAFC4 388000D0 +98830000 38800000 +98830001 38800003 +98830002 38800080 +38A00001 3D808000 +618C55F0 7D8903A6 +4E800421 B8610008 +80010104 38210100 +7C0803A6 38600001 38D40247 7C66D9AE +48000034 4E800021 +53657474 696E6720 +73617665 73746174 +6520666C 61672074 +6F203120 666F7220 +706C6179 65722025 +64000000 7C0802A6 +90010004 9421FF00 +BC610008 7E85A378 +60000000 60000000 +60000000 60000000 +806DAFC4 38630003 +4BFFFFA5 7C8802A6 +4CC63242 3D808032 +618C3CF4 7D8903A6 +4E800421 806DAFC4 +388000D0 98830000 +38800000 98830001 +38800003 98830002 +38800080 38A00001 +3D808000 618C55F0 +7D8903A6 4E800421 +B8610008 80010104 +38210100 7C0803A6 38D40134 7EC6D9AE 887B0236 2C030001 -41820010 935B0237 -38600001 987B0236 -38600000 1C63000C -38A3000E 1CD40054 -7CA53214 1C75000C -386300DC 7C611A14 -7C982A14 38A0000C -3D808000 618C31F4 +41820184 935B0237 +48000030 4E800021 +53657474 696E6720 +676C6F62 616C2073 +61766573 74617465 +20667261 6D652074 +6F202564 00000000 +7C0802A6 90010004 +9421FF00 BC610008 +7F45D378 60000000 +60000000 60000000 +60000000 806DAFC4 +38630003 4BFFFFA9 +7C8802A6 4CC63242 +3D808032 618C3CF4 +7D8903A6 4E800421 +806DAFC4 388000D0 +98830000 38800000 +98830001 38800003 +98830002 38800080 +38A00001 3D808000 +618C55F0 7D8903A6 +4E800421 B8610008 +80010104 38210100 +7C0803A6 38600001 +987B0236 4800002C +4E800021 53657474 +696E6720 676C6F62 +616C2073 61766573 +74617465 20666C61 +6720746F 20310000 +7C0802A6 90010004 +9421FF00 BC610008 +60000000 60000000 +60000000 60000000 +60000000 806DAFC4 +38630003 4BFFFFAD +7C8802A6 4CC63242 +3D808032 618C3CF4 +7D8903A6 4E800421 +806DAFC4 388000D0 +98830000 38800000 +98830001 38800003 +98830002 38800080 +38A00001 3D808000 +618C55F0 7D8903A6 +4E800421 B8610008 +80010104 38210100 +7C0803A6 48000020 +4E800021 50726564 +69637465 6420696E +70757420 6272616E +63680000 7C0802A6 +90010004 9421FF00 +BC610008 60000000 +60000000 60000000 +60000000 60000000 +806DAFC4 38630003 +4BFFFFB9 7C8802A6 +4CC63242 3D808032 +618C3CF4 7D8903A6 +4E800421 806DAFC4 +388000D0 98830000 +38800000 98830001 +38800003 98830002 +38800080 38A00001 +3D808000 618C55F0 +7D8903A6 4E800421 +B8610008 80010104 +38210100 7C0803A6 +38A0010A 1CD4000C +7CA53214 480000BC +4800001C 4E800021 +4B6E6F77 6E20696E +70757420 6272616E +63680000 7C0802A6 +90010004 9421FF00 +BC610008 60000000 +60000000 60000000 +60000000 60000000 +806DAFC4 38630003 +4BFFFFBD 7C8802A6 +4CC63242 3D808032 +618C3CF4 7D8903A6 +4E800421 806DAFC4 +388000D0 98830000 +38800000 98830001 +38800003 98830002 +38800080 38A00001 +3D808000 618C55F0 7D8903A6 4E800421 +B8610008 80010104 +38210100 7C0803A6 +1C63000C 38A3000E +1CD40054 7CA53214 +1C75000C 386300DC +7C611A14 7C982A14 +38A0000C 3D808000 +618C31F4 7D8903A6 +4E800421 2C140000 +408200E8 1C75000C +386300DC 7C811A14 +80E40000 7CE83B78 +54E7843E 7108FFFF +81240004 7D2A4B78 +5529843E 714AFFFF +4800002C 4E800021 +4672616D 65202564 +20706C61 79657220 +25642058 20256420 +25642025 64202564 +00000000 7C0802A6 +90010004 9421FF00 +BC610008 7F45D378 +7E86A378 60000000 +60000000 60000000 +806DAFC4 38630003 +4BFFFFAD 7C8802A6 +4CC63242 3D808032 +618C3CF4 7D8903A6 +4E800421 806DAFC4 +388000D0 98830000 +38800000 98830001 +38800003 98830002 +38800080 38A00001 +3D808000 618C55F0 +7D8903A6 4E800421 +B8610008 80010104 +38210100 7C0803A6 3A940001 3AB50001 -2C140003 4180FEC8 -48000080 807B00DB +2C140003 4180F8C0 +48000170 807B00DB 7C1A1800 40810024 BA810008 800100B4 382100B0 7C0803A6 @@ -1879,10 +2300,40 @@ BA810008 800100B4 38630007 1C63000C 388300E0 887B0000 1C63000C 386300DC +39400004 7F4BD378 +7D9B2214 48000025 7C611A14 7C9B2214 38A0000C 3D808000 618C31F4 7D8903A6 -4E800421 4BFFFE40 +4E800421 4BFFF828 +7C0802A6 90010004 +9421FF00 BC610008 +7D7F5B78 7D9E6378 +7D5C5378 480000A1 +7FA802A6 887B001B +38630001 7C1F1800 +4181002C 38600040 +3D808037 618CF1E4 +7D8903A6 4E800421 +907D0000 388000D0 +98830000 38800000 +98830001 807D0000 +38630002 389D0004 +7FE5FB78 7F86E378 +80FE0000 811E0004 +813E0008 3D808032 +618C3CF4 7D8903A6 +4E800421 807D0000 +38800040 38A00001 +3D808000 618C55F0 +7D8903A6 4E800421 +B8610008 80010104 +38210100 7C0803A6 +4E800020 4E800021 +00000000 5B25645D +20282564 29202530 +38582025 30385820 +25303858 00000000 3B5A0001 935B0003 BA810008 800100B4 382100B0 7C0803A6 @@ -4064,19 +4515,20 @@ C222B044 00000006 #Online/Menus/TitleMenu/AllowSwapToSameSubmenu.asm 7D8903A6 4E800420 38600000 986DAFA2 60000000 00000000 -C22299F0 00000019 #Online/Menus/TitleMenu/HandleOnlineLockedOptions.asm -2C030008 408200B8 +C22299F0 0000001A #Online/Menus/TitleMenu/HandleOnlineLockedOptions.asm +2C030008 408200C0 886DAFA1 2C030000 41820014 2C030001 41820040 2C030002 -41820054 2C040000 -41820080 2C040001 -41820078 2C040002 -41820070 2C040003 -41820068 2C040005 -41820060 2C040006 -41820058 48000068 -2C040000 4182004C +4182005C 2C040000 +41820088 2C040001 +41820080 2C040002 +41820078 2C040003 +41820070 2C040005 +41820068 2C040006 +41820060 48000070 +2C040000 41820054 +2C040001 4182004C 2C040004 41820044 2C040006 4182003C 4800004C 2C040000 @@ -5381,7 +5833,37 @@ BE810008 4BFFFCA9 800100B4 382100B0 7C0803A6 4E800020 60000000 00000000 -043775B8 A0190000 #Online/Logging/LogInputOnCopy.asm +C23775B8 0000001E #Online/Logging/LogInputOnCopy.asm +48000024 4E800021 +00000000 5B25645D +20502564 20253038 +58202530 38582025 +30385800 3C608048 +80639D30 5463443E +2C030208 408200B4 +7C0802A6 90010004 +9421FF50 BE810008 +4BFFFFBD 7FE802A6 +3C608048 80639D60 +2C030001 4181002C +38600040 3D808037 +618CF1E4 7D8903A6 +4E800421 907F0000 +388000D0 98830000 +38800000 98830001 +807F0000 38630002 +389F0004 3CA08048 +80A59D60 7F06C378 +80F90000 81190004 +81390008 3D808032 +618C3CF4 7D8903A6 +4E800421 807F0000 +38800040 38A00001 +3D808000 618C55F0 +7D8903A6 4E800421 +BA810008 800100B4 +382100B0 7C0803A6 +A0190000 00000000 041A4C24 C0429A7C #Polling Drift Fix + VB [tauKhan] 0401985C 3C60804C 04019860 91231F5C diff --git a/Data/Sys/GameSettings/GALJ01r2.ini b/Data/Sys/GameSettings/GALJ01r2.ini index b5131634bc..789d6bd9b5 100644 --- a/Data/Sys/GameSettings/GALJ01r2.ini +++ b/Data/Sys/GameSettings/GALJ01r2.ini @@ -9,7 +9,7 @@ FastDiscSpeed = True [Gecko_Enabled] $Required: General Codes $Required: Slippi Recording -$Required: Slippi Online +$Required: Slippi Online (Subframe rollback) $Recommended: Normal Lag Reduction $Recommended: Apply Delay to all In-Game Scenes @@ -1190,7 +1190,7 @@ C216EBAC 0000000C #Common/CSS KO Stars/Asign KO Stars Upon Exiting Dairantou.asm 8001001C 83E10014 60000000 00000000 -$Required: Slippi Online [Fizzi, UnclePunch] +$Required: Slippi Online (Subframe rollback) [Fizzi, UnclePunch] *Adds online mode, Slippi device must be in Slot B. *Change settings in Config > GameCube C206A880 00000018 #Online/Core/BrawlOffscreenDamage.asm @@ -1292,10 +1292,10 @@ C216E748 00000070 #Online/Core/InitOnlinePlay.asm 38600012 3D808037 618CF1E4 7D8903A6 4E800421 907B00D1 -3860010A 3D808037 +3860012E 3D808037 618CF1E4 7D8903A6 4E800421 907B00D5 -7C7A1B78 3880010A +7C7A1B78 3880012E 3D808000 618CC160 7D8903A6 4E800421 38600021 3D808037 @@ -1311,7 +1311,7 @@ C216E748 00000070 #Online/Core/InitOnlinePlay.asm 38800007 98830001 93790005 386007BC 90790009 9359000D -3860010A 90790011 +3860012E 90790011 807B024E 90790015 3860009E 90790019 38600000 9079001D @@ -1665,18 +1665,18 @@ C0570010 3D80803A 4E800421 BA810008 800100B4 382100B0 7C0803A6 00000000 -C2376A28 000000DD #Online/Core/TriggerSendInput.asm +C2376A28 000002A0 # Alpha subframe rollback with pad prediction logs | Online/Core/TriggerSendInput.asm 7C0802A6 90010004 9421FF50 BE810008 3C608048 80639D30 5463443E 2C030208 -408206B0 3C608047 +408214C8 3C608047 60639D64 80630000 -2C030000 4082069C +2C030000 408214B4 836DB61C 833B00D1 831B00D5 82FB024A 835B0003 887B00D9 -2C030001 418205F8 +2C030001 41821320 887B001B 38800054 7C632050 2C1A0003 4080001C 386100DC @@ -1685,189 +1685,610 @@ C2376A28 000000DD #Online/Core/TriggerSendInput.asm 4E800421 889B0002 1C84000C 386400E6 7C6118AE 7C630774 -2C03FFFD 40820024 -386400DC 7C611A14 -389B000F 38A0000C -3D808000 618C31F4 -7D8903A6 4E800421 +2C03FFFD 40820040 +39400000 899B001B +7F4BD378 7D6B6214 +398400DC 7D816214 +48001349 386400DC +7C611A14 389B000F +38A0000C 3D808000 +618C31F4 7D8903A6 +4E800421 889B0002 +1C84000C 388400DC +387B000F 7C812214 +38A0000C 3D808000 +618C31F4 7D8903A6 +4E800421 386000B0 +98790000 93590001 +887B001B 98790005 889B0002 1C84000C -388400DC 387B000F +388400DC 38790006 7C812214 38A0000C 3D808000 618C31F4 7D8903A6 4E800421 -386000B0 98790000 -93590001 887B001B -98790005 889B0002 +39400001 899B001B +7F4BD378 7D6B6214 +39990006 480012AD +7F23CB78 38800012 +38A00001 3D808000 +618C55F0 7D8903A6 +4E800421 38780000 +3880012E 38A00000 +3D808000 618C55F0 +7D8903A6 4E800421 +88780000 2C030002 +4182001C 2C030003 +41820008 48000030 +38600001 987B000D +48000024 BA810008 +800100B4 382100B0 +7C0803A6 3D808037 +618C6CEC 7D8903A6 +4E800420 889B001C +1C84000C 3884001D +887B0000 1C63000C +386300DC 7C611A14 +7C9B2214 38A0000C +3D808000 618C31F4 +7D8903A6 4E800421 +887B00DF 1C63000C +386300E0 889B0000 1C84000C 388400DC -38790006 7C812214 +39400003 7F4BD378 +7D812214 480011D5 +7C7B1A14 7C812214 38A0000C 3D808000 618C31F4 7D8903A6 -4E800421 7F23CB78 -38800012 38A00001 +4E800421 887B00DF +38630001 2C030007 +41800008 38600000 +987B00DF 887B001C +1C63000C 3863001D +39400002 899B001B +7F4BD378 7D6B6214 +39990006 4800117D +7C7B1A14 38990006 +38A0000C 3D808000 +618C31F4 7D8903A6 +4E800421 889B001B +887B001C 38630001 +7C032000 41800008 +38600000 987B001C +887B0236 2C030000 +40820018 38600000 +987B0247 987B0248 +987B0249 48000948 +3A800000 38D40247 +7C66D8AE 2C030001 +408203D8 1CD40004 +38C60002 7C66C02E +1CD40004 38C6023B +7C86D82E 7C641851 +418003B8 7C761B78 +38D40134 7C66D8AE +38D40137 7C86D8AE +48000044 4E800021 +506C6179 65722025 +645B2564 5D20722F +7720696E 64657865 +73207768 656E2072 +65616469 6E67206E +65787420 696E7075 +743A2025 642F2564 +00000000 7C0802A6 +90010004 9421FF00 +BC610008 7E85A378 +7EC6B378 7C671B78 +7C882378 60000000 +806DAFC4 38630003 +4BFFFF95 7C8802A6 +4CC63242 3D808032 +618C3CF4 7D8903A6 +4E800421 806DAFC4 +388000D0 98830000 +38800000 98830001 +38800003 98830002 +38800080 38A00001 3D808000 618C55F0 7D8903A6 4E800421 -38780000 3880010A -38A00000 3D808000 -618C55F0 7D8903A6 -4E800421 88780000 -2C030002 4182001C -2C030003 41820008 -48000030 38600001 -987B000D 48000024 +B8610008 80010104 +38210100 7C0803A6 +7EC3B378 1C63000C +3863000E 1CD40054 +7C633214 38D40134 +7C86D8AE 1C84000C +3884013A 1CB40054 +7C842A14 7CD81A14 +7CFB2214 88660000 +88870000 546306FE +548406FE 7C032000 +4082017C 88660001 +88870001 5463067E +5484067E 7C032000 +40820164 80660002 +80870002 7C032000 +40820154 38A00005 +38A50001 2C050008 +40800028 7C6530AE +7C8538AE 2C03002A +4181000C 2C04002A +4081FFE0 7C032000 +40820124 4BFFFFD4 +1CD40004 38C6023B +7C66D82E 38630001 +7C66D92E 38D40134 +7C66D8AE 38630001 +2C030007 41800008 +3863FFF9 7C66D9AE +38D40134 7C66D8AE +38D40137 7C86D8AE +48000034 4E800021 +506C6179 65722025 +6420722F 7720696E +64657865 73206166 +74657220 72656164 +696E673A 2025642F +25640000 7C0802A6 +90010004 9421FF00 +BC610008 7E85A378 +7C661B78 7C872378 +60000000 60000000 +806DAFC4 38630003 +4BFFFFA5 7C8802A6 +4CC63242 3D808032 +618C3CF4 7D8903A6 +4E800421 806DAFC4 +388000D0 98830000 +38800000 98830001 +38800003 98830002 +38800080 38A00001 +3D808000 618C55F0 +7D8903A6 4E800421 +B8610008 80010104 +38210100 7C0803A6 +38D40134 7C66D8AE +38D40137 7C86D8AE +7C041800 4082FD30 +48000110 1CD40004 +38C6023B 7C66D82E +48000044 4E800021 +54726967 67657269 +6E672072 6F6C6C62 +61636B20 66726F6D +20706C61 79657220 +25642069 6E707574 +206F6E20 70617374 +20667261 6D652025 +64000000 7C0802A6 +90010004 9421FF00 +BC610008 7E85A378 +7C661B78 60000000 +60000000 60000000 +806DAFC4 38630003 +4BFFFF95 7C8802A6 +4CC63242 3D808032 +618C3CF4 7D8903A6 +4E800421 806DAFC4 +388000D0 98830000 +38800000 98830001 +38800003 98830002 +38800080 38A00001 +3D808000 618C55F0 +7D8903A6 4E800421 +B8610008 80010104 +38210100 7C0803A6 +38600001 987B00D9 +987B00DA 935B00DB BA810008 800100B4 382100B0 7C0803A6 3D808037 618C6CEC 7D8903A6 4E800420 -889B001C 1C84000C -3884001D 887B0000 -1C63000C 386300DC -7C611A14 7C9B2214 -38A0000C 3D808000 -618C31F4 7D8903A6 -4E800421 887B00DF -1C63000C 386300E0 -889B0000 1C84000C -388400DC 7C7B1A14 -7C812214 38A0000C -3D808000 618C31F4 -7D8903A6 4E800421 -887B00DF 38630001 -2C030007 41800008 -38600000 987B00DF -887B001C 1C63000C -3863001D 7C7B1A14 -38990006 38A0000C -3D808000 618C31F4 +3A940001 2C140003 +4180FC14 3AA00000 +3A800000 807B0237 +7C761B78 48000038 +4E800021 41747465 +6D707469 6E672074 +6F206164 76616E63 +65207361 76657374 +61746520 6672616D +65207061 73742025 +64000000 7C0802A6 +90010004 9421FF00 +BC610008 7C651B78 +60000000 60000000 +60000000 60000000 +806DAFC4 38630003 +4BFFFFA1 7C8802A6 +4CC63242 3D808032 +618C3CF4 7D8903A6 +4E800421 806DAFC4 +388000D0 98830000 +38800000 98830001 +38800003 98830002 +38800080 38A00001 +3D808000 618C55F0 7D8903A6 4E800421 -889B001B 887B001C -38630001 7C032000 -41800008 38600000 -987B001C 887B0236 -2C030000 40820018 -38600000 987B0247 -987B0248 987B0249 -48000284 3A800000 -38D40247 7C66D8AE -2C030001 40820178 -1CD40004 38C60002 -7C66C02E 1CD40004 -38C6023B 7C86D82E -7C641851 41800158 -7C761B78 38D40134 -7C66D8AE 38D40137 -7C86D8AE 7EC3B378 -1C63000C 3863000E -1CD40054 7C633214 -38D40134 7C86D8AE -1C84000C 3884013A -1CB40054 7C842A14 -7CD81A14 7CFB2214 -88660000 88870000 -546306FE 548406FE -7C032000 408200BC -88660001 88870001 -5463067E 5484067E -7C032000 408200A4 -80660002 80870002 -7C032000 40820094 -38A00005 38A50001 -2C050008 40800028 -7C6530AE 7C8538AE -2C03002A 4181000C -2C04002A 4081FFE0 -7C032000 40820064 -4BFFFFD4 1CD40004 -38C6023B 7C66D82E -38630001 7C66D92E -38D40134 7C66D8AE -38630001 2C030007 -41800008 3863FFF9 -7C66D9AE 38D40134 -7C66D8AE 38D40137 -7C86D8AE 38D40134 -7C66D8AE 38D40137 -7C86D8AE 7C041800 -4082FEC0 48000040 -1CD40004 38C6023B -7C66D82E 38600001 -987B00D9 987B00DA -935B00DB BA810008 -800100B4 382100B0 -7C0803A6 3D808037 -618C6CEC 7D8903A6 -4E800420 3A940001 -2C140003 4180FE74 -3AA00000 3A800000 -807B0237 7C761B78 +B8610008 80010104 +38210100 7C0803A6 7EC3B378 38D40247 7C86D8AE 7C761B78 -7EC3B378 38D40247 -7C86D8AE 2C040001 -40820030 1CD40004 -38C6023B 7C86D82E -2C150000 4182000C -7C041800 40800014 -7C832378 7C761B78 -7EC3B378 3AA00001 -3A940001 2C140003 -4180FFAC 907B0237 +48000028 4E800021 +506C6179 65722025 +64207361 76657374 +61746520 666C6167 +3A202564 00000000 +7C0802A6 90010004 +9421FF00 BC610008 +7E85A378 7C862378 +60000000 60000000 +60000000 806DAFC4 +38630003 4BFFFFB1 +7C8802A6 4CC63242 +3D808032 618C3CF4 +7D8903A6 4E800421 +806DAFC4 388000D0 +98830000 38800000 +98830001 38800003 +98830002 38800080 +38A00001 3D808000 +618C55F0 7D8903A6 +4E800421 B8610008 +80010104 38210100 +7C0803A6 7EC3B378 +38D40247 7C86D8AE +2C040001 408200E8 +1CD40004 38C6023B +7C86D82E 2C150000 +4182000C 7C041800 +408000CC 7C832378 +7C761B78 4800002C +4E800021 506C6179 +65722025 64207365 +74207361 76657374 +61746520 6672616D +65202564 00000000 +7C0802A6 90010004 +9421FF00 BC610008 +7E85A378 7C862378 +60000000 60000000 +60000000 806DAFC4 +38630003 4BFFFFAD +7C8802A6 4CC63242 +3D808032 618C3CF4 +7D8903A6 4E800421 +806DAFC4 388000D0 +98830000 38800000 +98830001 38800003 +98830002 38800080 +38A00001 3D808000 +618C55F0 7D8903A6 +4E800421 B8610008 +80010104 38210100 +7C0803A6 7EC3B378 +3AA00001 3A940001 +2C140003 4180FE40 +907B0237 48000034 +4E800021 53657420 +73617665 73746174 +65206672 616D6520 +746F2025 642C2067 +616D6520 6672616D +653A2025 64000000 +7C0802A6 90010004 +9421FF00 BC610008 +7C651B78 3CC08048 +80C69D60 60000000 +60000000 60000000 +806DAFC4 38630003 +4BFFFFA1 7C8802A6 +4CC63242 3D808032 +618C3CF4 7D8903A6 +4E800421 806DAFC4 +388000D0 98830000 +38800000 98830001 +38800003 98830002 +38800080 38A00001 +3D808000 618C55F0 +7D8903A6 4E800421 +B8610008 80010104 +38210100 7C0803A6 3A800000 38D40247 7C86D8AE 2C040001 -40820038 38D40134 +408200F8 38D40134 7C66D8AE 38D40137 -7C86D8AE 38D40134 +7C86D8AE 48000034 +4E800021 506C6179 +65722025 6420722F +7720696E 64657865 +73206475 72696E67 +20726573 65743A20 +25642F25 64000000 +7C0802A6 90010004 +9421FF00 BC610008 +7E85A378 7C661B78 +7C872378 60000000 +60000000 806DAFC4 +38630003 4BFFFFA5 +7C8802A6 4CC63242 +3D808032 618C3CF4 +7D8903A6 4E800421 +806DAFC4 388000D0 +98830000 38800000 +98830001 38800003 +98830002 38800080 +38A00001 3D808000 +618C55F0 7D8903A6 +4E800421 B8610008 +80010104 38210100 +7C0803A6 38D40134 7C66D8AE 38D40137 7C86D8AE 7C041800 40820010 38600000 38D40247 7C66D9AE 3A940001 2C140003 -4180FFB4 3A800000 +4180FEF4 3A800000 38D40247 7C86D8AE -2C040001 41820018 +2C040001 418200C8 3A940001 2C140003 4180FFE8 38600000 -987B0236 3A800000 +987B0236 48000024 +4E800021 52657365 +74207361 76657374 +61746520 666C6167 +7320746F 20300000 +7C0802A6 90010004 +9421FF00 BC610008 +60000000 60000000 +60000000 60000000 +60000000 806DAFC4 +38630003 4BFFFFB5 +7C8802A6 4CC63242 +3D808032 618C3CF4 +7D8903A6 4E800421 +806DAFC4 388000D0 +98830000 38800000 +98830001 38800003 +98830002 38800080 +38A00001 3D808000 +618C55F0 7D8903A6 +4E800421 B8610008 +80010104 38210100 +7C0803A6 3A800000 3AA00000 887B0000 7C151800 40820008 3AB50001 1CD40004 38C60002 7C66C02E 7C7A1850 2C030000 -408000D4 887B001B +40800548 887B001B 38800054 7C632050 -7C1A1800 418000BC +7C1A1800 41800478 887B000C 2C030001 -418200B0 38D40137 +4182046C 38D40137 7EC6D8AE 1C76000C 3863013A 1CB40054 -7C632A14 1CD40054 -38C6000E 7C7B1A14 -7C983214 38A0000C -3D808000 618C31F4 +7C632A14 38A0010A +1CD4000C 7CC53214 +7C7B1A14 7C983214 +38A0000C 3D808000 +618C31F4 7D8903A6 +4E800421 38760001 +2C030007 41800008 +3863FFF9 38D40137 +7C66D9AE 38D40134 +7C66D8AE 38D40137 +7C86D8AE 48000038 +4E800021 506C6179 +65722025 6420722F +7720696E 64657865 +73206166 74657220 +77726974 65207570 +64617465 3A202564 +2F256400 7C0802A6 +90010004 9421FF00 +BC610008 7E85A378 +7C661B78 7C872378 +60000000 60000000 +806DAFC4 38630003 +4BFFFFA1 7C8802A6 +4CC63242 3D808032 +618C3CF4 7D8903A6 +4E800421 806DAFC4 +388000D0 98830000 +38800000 98830001 +38800003 98830002 +38800080 38A00001 +3D808000 618C55F0 7D8903A6 4E800421 -38760001 2C030007 -41800008 3863FFF9 -38D40137 7C66D9AE -38D40134 7C66D8AE -38D40137 7C86D8AE +B8610008 80010104 +38210100 7C0803A6 38D40247 7C66D8AE -2C030001 4182003C +2C030001 41820330 1CD40004 38C6023B -7F46D92E 38600001 +7F46D92E 48000034 +4E800021 53657474 +696E6720 73617665 +73746174 65206672 +616D6520 666F7220 +706C6179 65722025 +6420746F 20256400 +7C0802A6 90010004 +9421FF00 BC610008 +7E85A378 7F46D378 +60000000 60000000 +60000000 806DAFC4 +38630003 4BFFFFA5 +7C8802A6 4CC63242 +3D808032 618C3CF4 +7D8903A6 4E800421 +806DAFC4 388000D0 +98830000 38800000 +98830001 38800003 +98830002 38800080 +38A00001 3D808000 +618C55F0 7D8903A6 +4E800421 B8610008 +80010104 38210100 +7C0803A6 38600001 38D40247 7C66D9AE +48000034 4E800021 +53657474 696E6720 +73617665 73746174 +6520666C 61672074 +6F203120 666F7220 +706C6179 65722025 +64000000 7C0802A6 +90010004 9421FF00 +BC610008 7E85A378 +60000000 60000000 +60000000 60000000 +806DAFC4 38630003 +4BFFFFA5 7C8802A6 +4CC63242 3D808032 +618C3CF4 7D8903A6 +4E800421 806DAFC4 +388000D0 98830000 +38800000 98830001 +38800003 98830002 +38800080 38A00001 +3D808000 618C55F0 +7D8903A6 4E800421 +B8610008 80010104 +38210100 7C0803A6 38D40134 7EC6D9AE 887B0236 2C030001 -41820010 935B0237 -38600001 987B0236 -38600000 1C63000C -38A3000E 1CD40054 -7CA53214 1C75000C -386300DC 7C611A14 -7C982A14 38A0000C -3D808000 618C31F4 +41820184 935B0237 +48000030 4E800021 +53657474 696E6720 +676C6F62 616C2073 +61766573 74617465 +20667261 6D652074 +6F202564 00000000 +7C0802A6 90010004 +9421FF00 BC610008 +7F45D378 60000000 +60000000 60000000 +60000000 806DAFC4 +38630003 4BFFFFA9 +7C8802A6 4CC63242 +3D808032 618C3CF4 +7D8903A6 4E800421 +806DAFC4 388000D0 +98830000 38800000 +98830001 38800003 +98830002 38800080 +38A00001 3D808000 +618C55F0 7D8903A6 +4E800421 B8610008 +80010104 38210100 +7C0803A6 38600001 +987B0236 4800002C +4E800021 53657474 +696E6720 676C6F62 +616C2073 61766573 +74617465 20666C61 +6720746F 20310000 +7C0802A6 90010004 +9421FF00 BC610008 +60000000 60000000 +60000000 60000000 +60000000 806DAFC4 +38630003 4BFFFFAD +7C8802A6 4CC63242 +3D808032 618C3CF4 +7D8903A6 4E800421 +806DAFC4 388000D0 +98830000 38800000 +98830001 38800003 +98830002 38800080 +38A00001 3D808000 +618C55F0 7D8903A6 +4E800421 B8610008 +80010104 38210100 +7C0803A6 48000020 +4E800021 50726564 +69637465 6420696E +70757420 6272616E +63680000 7C0802A6 +90010004 9421FF00 +BC610008 60000000 +60000000 60000000 +60000000 60000000 +806DAFC4 38630003 +4BFFFFB9 7C8802A6 +4CC63242 3D808032 +618C3CF4 7D8903A6 +4E800421 806DAFC4 +388000D0 98830000 +38800000 98830001 +38800003 98830002 +38800080 38A00001 +3D808000 618C55F0 +7D8903A6 4E800421 +B8610008 80010104 +38210100 7C0803A6 +38A0010A 1CD4000C +7CA53214 480000BC +4800001C 4E800021 +4B6E6F77 6E20696E +70757420 6272616E +63680000 7C0802A6 +90010004 9421FF00 +BC610008 60000000 +60000000 60000000 +60000000 60000000 +806DAFC4 38630003 +4BFFFFBD 7C8802A6 +4CC63242 3D808032 +618C3CF4 7D8903A6 +4E800421 806DAFC4 +388000D0 98830000 +38800000 98830001 +38800003 98830002 +38800080 38A00001 +3D808000 618C55F0 7D8903A6 4E800421 +B8610008 80010104 +38210100 7C0803A6 +1C63000C 38A3000E +1CD40054 7CA53214 +1C75000C 386300DC +7C611A14 7C982A14 +38A0000C 3D808000 +618C31F4 7D8903A6 +4E800421 2C140000 +408200E8 1C75000C +386300DC 7C811A14 +80E40000 7CE83B78 +54E7843E 7108FFFF +81240004 7D2A4B78 +5529843E 714AFFFF +4800002C 4E800021 +4672616D 65202564 +20706C61 79657220 +25642058 20256420 +25642025 64202564 +00000000 7C0802A6 +90010004 9421FF00 +BC610008 7F45D378 +7E86A378 60000000 +60000000 60000000 +806DAFC4 38630003 +4BFFFFAD 7C8802A6 +4CC63242 3D808032 +618C3CF4 7D8903A6 +4E800421 806DAFC4 +388000D0 98830000 +38800000 98830001 +38800003 98830002 +38800080 38A00001 +3D808000 618C55F0 +7D8903A6 4E800421 +B8610008 80010104 +38210100 7C0803A6 3A940001 3AB50001 -2C140003 4180FEC8 -48000080 807B00DB +2C140003 4180F8C0 +48000170 807B00DB 7C1A1800 40810024 BA810008 800100B4 382100B0 7C0803A6 @@ -1879,10 +2300,40 @@ BA810008 800100B4 38630007 1C63000C 388300E0 887B0000 1C63000C 386300DC +39400004 7F4BD378 +7D9B2214 48000025 7C611A14 7C9B2214 38A0000C 3D808000 618C31F4 7D8903A6 -4E800421 4BFFFE40 +4E800421 4BFFF828 +7C0802A6 90010004 +9421FF00 BC610008 +7D7F5B78 7D9E6378 +7D5C5378 480000A1 +7FA802A6 887B001B +38630001 7C1F1800 +4181002C 38600040 +3D808037 618CF1E4 +7D8903A6 4E800421 +907D0000 388000D0 +98830000 38800000 +98830001 807D0000 +38630002 389D0004 +7FE5FB78 7F86E378 +80FE0000 811E0004 +813E0008 3D808032 +618C3CF4 7D8903A6 +4E800421 807D0000 +38800040 38A00001 +3D808000 618C55F0 +7D8903A6 4E800421 +B8610008 80010104 +38210100 7C0803A6 +4E800020 4E800021 +00000000 5B25645D +20282564 29202530 +38582025 30385820 +25303858 00000000 3B5A0001 935B0003 BA810008 800100B4 382100B0 7C0803A6 @@ -4064,19 +4515,20 @@ C222B044 00000006 #Online/Menus/TitleMenu/AllowSwapToSameSubmenu.asm 7D8903A6 4E800420 38600000 986DAFA2 60000000 00000000 -C22299F0 00000019 #Online/Menus/TitleMenu/HandleOnlineLockedOptions.asm -2C030008 408200B8 +C22299F0 0000001A #Online/Menus/TitleMenu/HandleOnlineLockedOptions.asm +2C030008 408200C0 886DAFA1 2C030000 41820014 2C030001 41820040 2C030002 -41820054 2C040000 -41820080 2C040001 -41820078 2C040002 -41820070 2C040003 -41820068 2C040005 -41820060 2C040006 -41820058 48000068 -2C040000 4182004C +4182005C 2C040000 +41820088 2C040001 +41820080 2C040002 +41820078 2C040003 +41820070 2C040005 +41820068 2C040006 +41820060 48000070 +2C040000 41820054 +2C040001 4182004C 2C040004 41820044 2C040006 4182003C 4800004C 2C040000 @@ -5381,7 +5833,37 @@ BE810008 4BFFFCA9 800100B4 382100B0 7C0803A6 4E800020 60000000 00000000 -043775B8 A0190000 #Online/Logging/LogInputOnCopy.asm +C23775B8 0000001E #Online/Logging/LogInputOnCopy.asm +48000024 4E800021 +00000000 5B25645D +20502564 20253038 +58202530 38582025 +30385800 3C608048 +80639D30 5463443E +2C030208 408200B4 +7C0802A6 90010004 +9421FF50 BE810008 +4BFFFFBD 7FE802A6 +3C608048 80639D60 +2C030001 4181002C +38600040 3D808037 +618CF1E4 7D8903A6 +4E800421 907F0000 +388000D0 98830000 +38800000 98830001 +807F0000 38630002 +389F0004 3CA08048 +80A59D60 7F06C378 +80F90000 81190004 +81390008 3D808032 +618C3CF4 7D8903A6 +4E800421 807F0000 +38800040 38A00001 +3D808000 618C55F0 +7D8903A6 4E800421 +BA810008 800100B4 +382100B0 7C0803A6 +A0190000 00000000 041A4C24 C0429A7C #Polling Drift Fix + VB [tauKhan] 0401985C 3C60804C 04019860 91231F5C diff --git a/Source/Core/Common/Logging/Log.h b/Source/Core/Common/Logging/Log.h index 5c0f1a4242..7c37a3c257 100644 --- a/Source/Core/Common/Logging/Log.h +++ b/Source/Core/Common/Logging/Log.h @@ -40,6 +40,7 @@ enum LOG_TYPE SERIALINTERFACE, SLIPPI, SLIPPI_ONLINE, + KRISTAL, SP1, VIDEO, VIDEOINTERFACE, diff --git a/Source/Core/Common/Logging/LogManager.cpp b/Source/Core/Common/Logging/LogManager.cpp index 80fc9a99cc..dc00778ef8 100644 --- a/Source/Core/Common/Logging/LogManager.cpp +++ b/Source/Core/Common/Logging/LogManager.cpp @@ -70,7 +70,8 @@ LogManager::LogManager() m_Log[LogTypes::DYNA_REC] = new LogContainer("JIT", "Dynamic Recompiler"); m_Log[LogTypes::EXPANSIONINTERFACE] = new LogContainer("EXI", "Expansion Interface"); m_Log[LogTypes::SLIPPI] = new LogContainer("SLIPPI", "Slippi"); - m_Log[LogTypes::SLIPPI_ONLINE] = new LogContainer("SLIPPI_ONLINE", "Slippi Online"); + m_Log[LogTypes::SLIPPI_ONLINE] = new LogContainer("SLIPPI_ONLINE", "Slippi Online"); + m_Log[LogTypes::KRISTAL] = new LogContainer("KRISTAL", "Kristal"); m_Log[LogTypes::FILEMON] = new LogContainer("FileMon", "File Monitor"); m_Log[LogTypes::GDB_STUB] = new LogContainer("GDB_STUB", "GDB Stub"); m_Log[LogTypes::GPFIFO] = new LogContainer("GP", "GPFifo"); diff --git a/Source/Core/Common/Version.cpp b/Source/Core/Common/Version.cpp index 96669438b0..5614848674 100644 --- a/Source/Core/Common/Version.cpp +++ b/Source/Core/Common/Version.cpp @@ -23,7 +23,9 @@ //#else //" " BUILD_TYPE_STR " " SCM_DESC_STR; //#endif -#define SLIPPI_REV_STR "2.3.1" + +#define SLIPPI_REV_STR "3.0.0" + #ifdef IS_PLAYBACK const std::string scm_rev_str = "Faster Melee - Slippi (" SLIPPI_REV_STR ") - Playback"; #else diff --git a/Source/Core/Core/ConfigManager.cpp b/Source/Core/Core/ConfigManager.cpp index 23eb2e0a3e..13426932be 100644 --- a/Source/Core/Core/ConfigManager.cpp +++ b/Source/Core/Core/ConfigManager.cpp @@ -617,7 +617,7 @@ void SConfig::LoadCoreSettings(IniFile &ini) core->Get("TimeStretching", &bTimeStretching, false); core->Get("RSHACK", &bRSHACK, false); core->Get("Latency", &iLatency, 0); - core->Get("ReduceTimingDispersion", &bReduceTimingDispersion, false); + core->Get("ReduceTimingDispersion", &bReduceTimingDispersion, true); core->Get("SlippiEnableSpectator", &m_enableSpectator, true); core->Get("SlippiSpectatorLocalPort", &m_spectator_local_port, 51441); core->Get("SlippiOnlineDelay", &m_slippiOnlineDelay, 2); diff --git a/Source/Core/Core/ConfigManager.h b/Source/Core/Core/ConfigManager.h index 478dd8a1d0..51e780ac84 100644 --- a/Source/Core/Core/ConfigManager.h +++ b/Source/Core/Core/ConfigManager.h @@ -134,7 +134,7 @@ struct SConfig : NonCopyable bool bQoSEnabled = true; bool bAdapterWarning = true; - bool bReduceTimingDispersion = false; + bool bReduceTimingDispersion = true; MeleeLagReductionCode iLagReductionCode = MELEE_LAG_REDUCTION_CODE_UNSET; bool bHasShownLagReductionWarning = false; diff --git a/Source/Core/Core/HW/EXI_DeviceSlippi.cpp b/Source/Core/Core/HW/EXI_DeviceSlippi.cpp index 724a526abc..4e7d3d564c 100644 --- a/Source/Core/Core/HW/EXI_DeviceSlippi.cpp +++ b/Source/Core/Core/HW/EXI_DeviceSlippi.cpp @@ -1545,6 +1545,15 @@ void CEXISlippi::handleOnlineInputs(u8 *payload) m_read_queue.clear(); int32_t frame = payload[0] << 24 | payload[1] << 16 | payload[2] << 8 | payload[3]; + u8 delay = payload[4]; + + { + std::ostringstream oss; + oss << "In frame " << frame << " delay " << (int)delay << " pad "; + for (int i = 0; i < SLIPPI_PAD_FULL_SIZE; i++) + oss << (int)payload[5 + i] << " "; + INFO_LOG(KRISTAL, oss.str().c_str()); + } if (frame == 1) { @@ -1564,7 +1573,7 @@ void CEXISlippi::handleOnlineInputs(u8 *payload) // Reset character selections as they are no longer needed localSelections.Reset(); if (slippi_netplay) - slippi_netplay->StartSlippiGame(); + slippi_netplay->StartSlippiGame(delay); } if (isDisconnected()) @@ -1577,12 +1586,39 @@ void CEXISlippi::handleOnlineInputs(u8 *payload) { // Send inputs that have not yet been acked slippi_netplay->SendSlippiPad(nullptr); + // Tell the input stabilizers not to take the last poll into account + slippi_netplay->DecrementInputStabilizerFrameCounts(); m_read_queue.push_back(2); return; } + // calls SendSlippiPad handleSendInputs(payload); prepareOpponentInputs(payload); + + { + std::ostringstream oss; + oss << "Out result " << (int)m_read_queue[0] << " count " << (int)m_read_queue[1]; + oss << " frame " + << ((((int)m_read_queue[2]) << 24) + (((int)m_read_queue[3]) << 16) + (((int)m_read_queue[4]) << 8) + + ((int)m_read_queue[5])); + oss << " Kristal [ "; + for (int i = 0; i < SLIPPI_PAD_FULL_SIZE; i++) + oss << (int)m_read_queue[2 + 12 + 7*(int)SLIPPI_PAD_FULL_SIZE*3 + i] << " "; + oss << "] Slippi "; + + for (int j = 0; j < 7; j++) + { + oss << "[ "; + for (int i = 0; i < SLIPPI_PAD_FULL_SIZE; i++) + { + oss << (int)m_read_queue[2 + 12 + j * SLIPPI_PAD_FULL_SIZE + i] << " "; + } + oss << "] "; + } + + INFO_LOG(KRISTAL, oss.str().c_str()); + } } bool CEXISlippi::shouldSkipOnlineFrame(s32 frame) @@ -1708,6 +1744,8 @@ void CEXISlippi::prepareOpponentInputs(u8 *payload) int32_t latestFrameRead[SLIPPI_REMOTE_PLAYER_MAX]{}; + int32_t latestFrameSent[SLIPPI_REMOTE_PLAYER_MAX] {}; + // Get pad data for each remote player and write each of their latest frame nums to the buf for (int i = 0; i < remotePlayerCount; i++) { @@ -1724,6 +1762,14 @@ void CEXISlippi::prepareOpponentInputs(u8 *payload) latestFrameRead[i] = latestFrame; appendWordToBuffer(&m_read_queue, *(u32 *)&latestFrame); // INFO_LOG(SLIPPI_ONLINE, "Sending frame num %d for pIdx %d (offset: %d)", latestFrame, i, offset[i]); + + // DEBUG + if (results[i]->data[offset[i]] & 4) + { + std::ostringstream oss; + oss << "X pressed for frame " << latestFrame; + WARN_LOG(KRISTAL, oss.str().c_str()); + } } // Send the current frame for any unused player slots. for (int i = remotePlayerCount; i < SLIPPI_REMOTE_PLAYER_MAX; i++) @@ -1742,21 +1788,77 @@ void CEXISlippi::prepareOpponentInputs(u8 *payload) { auto txStart = results[i]->data.begin() + offset[i]; auto txEnd = results[i]->data.end(); - tx.insert(tx.end(), txStart, txEnd); + tx.insert(tx.end(), txStart, txEnd); //* Inversion de sens ? } tx.resize(SLIPPI_PAD_FULL_SIZE * ROLLBACK_MAX_FRAMES, 0); m_read_queue.insert(m_read_queue.end(), tx.begin(), tx.end()); + + // TODO log + /*ERROR_LOG(SLIPPI_ONLINE, "EXI: [%d] %X %X %X %X %X %X %X %X", results[i]->latestFrame, m_read_queue[5], + m_read_queue[6], + m_read_queue[7], m_read_queue[8], m_read_queue[9], m_read_queue[10], m_read_queue[11], + m_read_queue[12]);*/ + } + + for (int i = 0; i < SLIPPI_REMOTE_PLAYER_MAX; i++) + { + if (i < remotePlayerCount) + { + // Add Kristal input + std::pair kristalPad = + slippi_netplay->GetKristalInput(frame, i); // No more than the current frame + + if (kristalPad.first) + { + if (kristalPad.second.subframe > + (float)results[i]->latestFrame) // No less than the latest frame for which we have inputs + { + // More recent, use the Kristal input + + auto slippiPad = results[i]->data.begin() + offset[i]; + + m_read_queue.insert(m_read_queue.end(), kristalPad.second.pad, + kristalPad.second.pad + SLIPPI_PAD_DATA_SIZE); + m_read_queue.insert(m_read_queue.end(), SLIPPI_PAD_FULL_SIZE - SLIPPI_PAD_DATA_SIZE, 0); + + std::ostringstream oss; + oss << std::fixed << std::setprecision(2) << "Kristal input was used for frame " << frame + << " subframe " << kristalPad.second.subframe << " latest known frame " + << results[i]->latestFrame; + ERROR_LOG(KRISTAL, oss.str().c_str()); + oss.str(""); + oss << "Kristal " << (int)kristalPad.second.pad[0] << " " << (int)kristalPad.second.pad[1] << " " + << (int)kristalPad.second.pad[2] << " " << (int)kristalPad.second.pad[3] << " " + << (int)kristalPad.second.pad[4] << " " << (int)kristalPad.second.pad[5] << " " + << (int)kristalPad.second.pad[6] << " " << (int)kristalPad.second.pad[7] << " "; + ERROR_LOG(KRISTAL, oss.str().c_str()); + oss.str(""); + oss << "Slippi " << (int)slippiPad[0] << " " << (int)slippiPad[1] << " " << (int)slippiPad[2] << " " + << (int)slippiPad[3] << " " << (int)slippiPad[4] << " " << (int)slippiPad[5] << " " + << (int)slippiPad[6] << " " << (int)slippiPad[7]; + ERROR_LOG(KRISTAL, oss.str().c_str()); + } + else + kristalPad.first = false; + } + if (!kristalPad.first) + { + m_read_queue.insert(m_read_queue.end(), results[i]->data.begin(), + results[i]->data.begin() + SLIPPI_PAD_FULL_SIZE); + } + } + else + { + m_read_queue.insert(m_read_queue.end(), SLIPPI_PAD_FULL_SIZE, 0); + } } // the latest read frame instead of the current frame must be passed to avoid nuking inputs // that are > latest read frame < current frame and arrived during this function int32_t minFrameRead = *std::min_element(latestFrameRead, latestFrameRead + SLIPPI_REMOTE_PLAYER_MAX); slippi_netplay->DropOldRemoteInputs(minFrameRead); - - // ERROR_LOG(SLIPPI_ONLINE, "EXI: [%d] %X %X %X %X %X %X %X %X", latestFrame, m_read_queue[5], m_read_queue[6], - // m_read_queue[7], m_read_queue[8], m_read_queue[9], m_read_queue[10], m_read_queue[11], m_read_queue[12]); } void CEXISlippi::handleCaptureSavestate(u8 *payload) @@ -2236,6 +2338,15 @@ void CEXISlippi::prepareOnlineMatchState() if (localPlayerReady && remotePlayersReady) { + auto status = slippi_netplay->GetSlippiConnectStatus(); + bool isConnected = status == SlippiNetplayClient::SlippiConnectStatus::NET_CONNECT_STATUS_CONNECTED; + if (!isConnected) + { + handleConnectionCleanup(); + prepareOnlineMatchState(); // run again with new state + return; + } + auto isDecider = slippi_netplay->IsDecider(); u8 remotePlayerCount = matchmaking->RemotePlayerCount(); auto matchInfo = slippi_netplay->GetMatchInfo(); @@ -2961,6 +3072,7 @@ void CEXISlippi::DMAWrite(u32 _uAddr, u32 _uSize) while (bufLoc < _uSize) { byte = memPtr[bufLoc]; + //INFO_LOG(SLIPPI, "EXI SLIPPI: Loc: %d, Size: %d, Cmd: 0x%x", bufLoc, _uSize, byte); if (!payloadSizes.count(byte)) { @@ -2977,6 +3089,11 @@ void CEXISlippi::DMAWrite(u32 _uAddr, u32 _uSize) m_slippiserver->write(&memPtr[bufLoc], payloadLen + 1); m_slippiserver->endGame(); break; + case CMD_FRAME_BOOKEND: + g_needInputForFrame = true; + writeToFileAsync(&memPtr[bufLoc], payloadLen + 1, ""); + m_slippiserver->write(&memPtr[bufLoc], payloadLen + 1); + break; case CMD_PREPARE_REPLAY: // log.open("log.txt"); prepareGameInfo(&memPtr[bufLoc + 1]); @@ -2984,17 +3101,12 @@ void CEXISlippi::DMAWrite(u32 _uAddr, u32 _uSize) case CMD_READ_FRAME: prepareFrameData(&memPtr[bufLoc + 1]); break; - case CMD_FRAME_BOOKEND: - g_needInputForFrame = true; - writeToFileAsync(&memPtr[bufLoc], payloadLen + 1, ""); - m_slippiserver->write(&memPtr[bufLoc], payloadLen + 1); + case CMD_IS_FILE_READY: + prepareIsFileReady(); break; case CMD_IS_STOCK_STEAL: prepareIsStockSteal(&memPtr[bufLoc + 1]); break; - case CMD_IS_FILE_READY: - prepareIsFileReady(); - break; case CMD_GET_GECKO_CODES: m_read_queue.clear(); m_read_queue.insert(m_read_queue.begin(), geckoList.begin(), geckoList.end()); diff --git a/Source/Core/Core/HW/EXI_DeviceSlippi.h b/Source/Core/Core/HW/EXI_DeviceSlippi.h index d7ea201c00..ebc0ee7e13 100644 --- a/Source/Core/Core/HW/EXI_DeviceSlippi.h +++ b/Source/Core/Core/HW/EXI_DeviceSlippi.h @@ -34,7 +34,7 @@ class CEXISlippi : public IEXIDevice void DMAWrite(u32 _uAddr, u32 _uSize) override; void DMARead(u32 addr, u32 size) override; - + bool IsPresent() const override; private: @@ -179,6 +179,7 @@ class CEXISlippi : public IEXIDevice void handleOnlineInputs(u8 *payload); void prepareOpponentInputs(u8 *payload); void handleSendInputs(u8 *payload); + void handleCaptureSavestate(u8 *payload); void handleLoadSavestate(u8 *payload); void handleNameEntryAutoComplete(u8 *payload); @@ -232,7 +233,8 @@ class CEXISlippi : public IEXIDevice std::vector playbackSavestatePayload; std::vector geckoList; - u32 stallFrameCount = 0; + u32 stallFrameCount = 0; + bool isConnectionStalled = false; std::vector m_read_queue; diff --git a/Source/Core/Core/HW/SI.cpp b/Source/Core/Core/HW/SI.cpp index dd10892f18..bda74e1916 100644 --- a/Source/Core/Core/HW/SI.cpp +++ b/Source/Core/Core/HW/SI.cpp @@ -25,12 +25,12 @@ #include "InputCommon/ControllerInterface/ControllerInterface.h" #include "InputCommon/GCAdapter.h" #include "InputCommon/GCPadStatus.h" -#include "InputCommon/InputStabilizer.h" - -static std::vector stabilizers(MAX_SI_CHANNELS, InputStabilizer()); namespace SerialInterface { + +std::vector stabilizers(MAX_SI_CHANNELS, InputStabilizer()); + static CoreTiming::EventType* changeDevice; static CoreTiming::EventType* et_transfer_pending; static CoreTiming::EventType* et_send_netplay_inputs; diff --git a/Source/Core/Core/HW/SI.h b/Source/Core/Core/HW/SI.h index 5a055f9959..e9e019b64f 100644 --- a/Source/Core/Core/HW/SI.h +++ b/Source/Core/Core/HW/SI.h @@ -7,6 +7,7 @@ #include #include "Common/CommonTypes.h" #include +#include "InputCommon/InputStabilizer.h" class PointerWrap; class ISIDevice; @@ -45,4 +46,6 @@ u32 GetPollXLines(); extern std::chrono::time_point last_si_read; +extern std::vector stabilizers; + } // end of namespace SerialInterface diff --git a/Source/Core/Core/HW/SI_DeviceGCController.cpp b/Source/Core/Core/HW/SI_DeviceGCController.cpp index 3a3ea11074..d916150b3e 100644 --- a/Source/Core/Core/HW/SI_DeviceGCController.cpp +++ b/Source/Core/Core/HW/SI_DeviceGCController.cpp @@ -15,6 +15,7 @@ #include "Core/Movie.h" #include "Core/NetPlayProto.h" #include "InputCommon/GCPadStatus.h" +#include "InputCommon/GCAdapter.h" // --- standard GameCube controller --- CSIDevice_GCController::CSIDevice_GCController(SIDevices device, int _iDeviceNumber) @@ -322,6 +323,7 @@ void CSIDevice_GCController::SendCommand(u32 _Cmd, u8 _Poll) { m_Mode = command.Parameter2; INFO_LOG(SERIALINTERFACE, "PAD %i set to mode %i", ISIDevice::m_iDeviceNumber, m_Mode); + GCAdapter::InformPadModeSet(ISIDevice::m_iDeviceNumber); } } break; diff --git a/Source/Core/Core/NetPlayProto.h b/Source/Core/Core/NetPlayProto.h index 213a3787c9..cf389d328e 100644 --- a/Source/Core/Core/NetPlayProto.h +++ b/Source/Core/Core/NetPlayProto.h @@ -62,6 +62,7 @@ enum NP_MSG_SLIPPI_MATCH_SELECTIONS = 0x82, NP_MSG_SLIPPI_CONN_SELECTED = 0x83, NP_MSG_SLIPPI_CHAT_MESSAGE = 0x84, + NP_MSG_KRISTAL_PAD = 0x8E, NP_MSG_START_GAME = 0xA0, NP_MSG_CHANGE_GAME = 0xA1, diff --git a/Source/Core/Core/Slippi/SlippiNetplay.cpp b/Source/Core/Core/Slippi/SlippiNetplay.cpp index e9211138ae..a4de8a9b80 100644 --- a/Source/Core/Core/Slippi/SlippiNetplay.cpp +++ b/Source/Core/Core/Slippi/SlippiNetplay.cpp @@ -12,6 +12,9 @@ #include "SlippiPremadeText.h" #include "VideoCommon/OnScreenDisplay.h" #include "VideoCommon/VideoConfig.h" +#include "Core/HW/SI.h" +#include "InputCommon/InputStabilizer.h" + #include #include #include @@ -59,6 +62,13 @@ SlippiNetplayClient::~SlippiNetplayClient() m_client = nullptr; } + for (auto &stabilizer : SerialInterface::stabilizers) + { + stabilizer.endFrameCount(); + } + + GCAdapter::ClearKristalInputCallback(); + SLIPPI_NETPLAY = nullptr; WARN_LOG(SLIPPI_ONLINE, "Netplay client cleanup complete"); @@ -74,6 +84,7 @@ SlippiNetplayClient::SlippiNetplayClient(std::vector addrs, std::ve { WARN_LOG(SLIPPI_ONLINE, "Initializing Slippi Netplay for port: %d, with host: %s, player idx: %d", localPort, isDecider ? "true" : "false", playerIdx); + this->isDecider = isDecider; this->m_remotePlayerCount = remotePlayerCount; this->playerIdx = playerIdx; @@ -382,6 +393,62 @@ unsigned int SlippiNetplayClient::OnData(sf::Packet &packet, ENetPeer *peer) } break; + case NP_MSG_KRISTAL_PAD: + { + float subframe; + if (!(packet >> subframe)) + { + ERROR_LOG(KRISTAL, "Kristal packet too small to read subframe"); + break; + } + u8 version; + if (!(packet >> version)) + { + ERROR_LOG(KRISTAL, "Kristal packet too small to read version"); + break; + } + u8 packetPlayerPort; + if (!(packet >> packetPlayerPort)) + { + ERROR_LOG(KRISTAL, "Kristal packet too small to read player index"); + break; + } + u8 pIdx = PlayerIdxFromPort(packetPlayerPort); + if (pIdx >= m_remotePlayerCount) + { + ERROR_LOG(KRISTAL, "Got Kristal packet with invalid player idx %d", pIdx); + break; + } + + auto packetData = (u8 *)packet.getData(); + // Check that the packet actually contains the data it claims to + if ((7 + SLIPPI_PAD_DATA_SIZE) > (int)packet.getDataSize()) + { + ERROR_LOG(KRISTAL, "Kristal packet too small to read pad. Size: %d, MinSize: %d", + (int)packet.getDataSize(), 7 + SLIPPI_PAD_DATA_SIZE); + break; + } + + KristalPad kpad; + kpad.subframe = subframe; + kpad.version = version; + memcpy(kpad.pad, packetData + 7, SLIPPI_PAD_DATA_SIZE); + { + std::lock_guard lk(subframePadSetLocks[pIdx]); + if (subframePadSets[pIdx].size() < 50) // Hard limit on number of pad stored max + subframePadSets[pIdx].insert({kpad}); + } + std::ostringstream oss; + auto tp = std::chrono::high_resolution_clock::now(); + auto eval = + SerialInterface::stabilizers[m_last_adapter_chan_used_in_kristal_callback].evaluateTiming(tp); + oss << std::fixed << std::setprecision(2) << "Received Kristal input. Received: " + << eval.first << " v" << (int)eval.second << " Content: "<< kpad.subframe + << " v" << (int)kpad.version; + WARN_LOG(KRISTAL, oss.str().c_str()); + } + break; + case NP_MSG_SLIPPI_MATCH_SELECTIONS: { auto s = readSelectionsFromPacket(packet); @@ -395,6 +462,28 @@ unsigned int SlippiNetplayClient::OnData(sf::Packet &packet, ENetPeer *peer) // Reset remote pad queue such that next inputs that we get are not compared to inputs from last game remotePadQueue[idx].clear(); + + if (!kristalVersionWasReceived) + { + KRISTAL_CROSSPLAY_DEBUG_MESSAGE = + "You won't connect because your opponent isn't using Kristal. Crossplay with Slippi is not supported.\n"; + Disconnect(); + } + else if (kristalVersionReceived < minimumRequiredKristalVersion) + { + KRISTAL_CROSSPLAY_DEBUG_MESSAGE = + "You won't connect because your opponent is using an older Kristal version, " + "which yours isn't retro-compatible with.\n"; + Disconnect(); + } + else if (localKristalVersion < minimumKristalVersionSupportedReceived) + { + KRISTAL_CROSSPLAY_DEBUG_MESSAGE = + "You won't connect because your opponent is on a more recent Kristal version than you and has " + "indicated that they are not retro-compatible with your version.\n" + "Please update.\n"; + Disconnect(); + } } break; @@ -443,6 +532,8 @@ void SlippiNetplayClient::writeToPacket(sf::Packet &packet, SlippiPlayerSelectio packet << s.stageId << s.isStageSelected; packet << s.rngOffset; packet << s.teamId; + packet << localKristalVersion; + packet << minimumRequiredKristalVersion; } void SlippiNetplayClient::WriteChatMessageToPacket(sf::Packet &packet, int messageId, u8 playerIdx) @@ -478,6 +569,13 @@ std::unique_ptr SlippiNetplayClient::readSelectionsFromP packet >> s->rngOffset; packet >> s->teamId; + KRISTAL_CROSSPLAY_DEBUG_MESSAGE = ""; // TODO An awful solution when it comes to Teams but at this point I am very done with this + + if ((packet >> kristalVersionReceived) && (packet >> minimumKristalVersionSupportedReceived)) + { + kristalVersionWasReceived = true; + } + return std::move(s); } @@ -507,6 +605,7 @@ void SlippiNetplayClient::Disconnect() { ENetEvent netEvent; slippiConnectStatus = SlippiConnectStatus::NET_CONNECT_STATUS_DISCONNECTED; + kristalVersionWasReceived = false; if (activeConnections.empty()) { return; @@ -892,7 +991,7 @@ std::vector SlippiNetplayClient::GetFailedConnections() return failedConnections; } -void SlippiNetplayClient::StartSlippiGame() +void SlippiNetplayClient::StartSlippiGame(u8 delay) // called when frame is 1 { // Reset variables to start a new game hasGameStarted = false; @@ -913,6 +1012,24 @@ void SlippiNetplayClient::StartSlippiGame() // Reset match info for next game matchInfo.Reset(); + + // Initialize the frame count of InputStabilizers + // (all of them because we're unsure which one to use at that point) + for (auto &stabilizer : SerialInterface::stabilizers) + { + stabilizer.startFrameCount(1+delay); // 1 for frame 1 + our delay + } + + for (auto &subframePadSet : subframePadSets) + { + std::lock_guard lock(GCAdapter::kristal_callback_mutex); + subframePadSet.clear(); + } + GCAdapter::SetKristalInputCallback([this](const GCPadStatus &pad, std::chrono::high_resolution_clock::time_point tp, int chan) -> void + { + std::lock_guard lock(GCAdapter::kristal_callback_mutex); + this->KristalInputCallback(pad, tp, chan); + }); } void SlippiNetplayClient::SendConnectionSelected() @@ -1050,9 +1167,13 @@ u8 SlippiNetplayClient::GetSlippiRemoteSentChatMessage() return copiedMessageId; } +std::mutex &SlippiNetplayClient::padMutex() { + return pad_mutex; +} + std::unique_ptr SlippiNetplayClient::GetSlippiRemotePad(int32_t curFrame, int index) { - std::lock_guard lk(pad_mutex); // TODO: Is this the correct lock? + std::lock_guard lk(pad_mutex); std::unique_ptr padOutput = std::make_unique(); @@ -1188,3 +1309,99 @@ s32 SlippiNetplayClient::CalcTimeOffsetUs() // INFO_LOG(SLIPPI_ONLINE, "Time offsets, [0]: %d, [1]: %d, [2]: %d", offsets[0], offsets[1], offsets[2]); return maxOffset; } + +void SlippiNetplayClient::DecrementInputStabilizerFrameCounts() { + for (auto &stabilizer : SerialInterface::stabilizers) + { + stabilizer.decrementFrameCount(); + } +} + +std::array convertToInGamePadData(const GCPadStatus &pad) +{ + std::array ingamePadData = {}; + ingamePadData[0] = + ((!!(pad.button & PAD_BUTTON_A)) << 0) + + ((!!(pad.button & PAD_BUTTON_B)) << 1) + + ((!!(pad.button & PAD_BUTTON_X)) << 2) + + ((!!(pad.button & PAD_BUTTON_Y)) << 3) + + ((!!(pad.button & PAD_BUTTON_START)) << 4); + ingamePadData[1] = + ((!!(pad.button & PAD_BUTTON_LEFT)) << 0) + + ((!!(pad.button & PAD_BUTTON_RIGHT)) << 1) + + ((!!(pad.button & PAD_BUTTON_DOWN)) << 2) + + ((!!(pad.button & PAD_BUTTON_UP)) << 3) + + ((!!(pad.button & PAD_TRIGGER_Z)) << 4) + + ((!!(pad.button & PAD_TRIGGER_R)) << 5) + + ((!!(pad.button & PAD_TRIGGER_L)) << 6); + ingamePadData[2] = pad.stickX - 0x80; + ingamePadData[3] = pad.stickY - 0x80; + ingamePadData[4] = pad.substickX - 0x80; + ingamePadData[5] = pad.substickY - 0x80; + ingamePadData[6] = pad.triggerLeft; + ingamePadData[7] = pad.triggerRight; + + return ingamePadData; +} + +void SlippiNetplayClient::KristalInputCallback(const GCPadStatus &pad, + std::chrono::high_resolution_clock::time_point tp, int chan) +{ + + m_last_adapter_chan_used_in_kristal_callback = chan; + + auto status = slippiConnectStatus; + bool connectionFailed = status == SlippiNetplayClient::SlippiConnectStatus::NET_CONNECT_STATUS_FAILED; + bool connectionDisconnected = status == SlippiNetplayClient::SlippiConnectStatus::NET_CONNECT_STATUS_DISCONNECTED; + if (connectionFailed || connectionDisconnected) + { + return; + } + + std::pair timingAndVersion = SerialInterface::stabilizers[chan].evaluateTiming(tp); + + auto spac = std::make_unique(); + *spac << static_cast(NP_MSG_KRISTAL_PAD); + *spac << timingAndVersion.first; // subframe, 4 bytes + *spac << timingAndVersion.second; // version, 1 byte + *spac << this->playerIdx; // player index, 1 byte + + std::array ingamePadData = convertToInGamePadData(pad); + + spac->append(&ingamePadData, SLIPPI_PAD_DATA_SIZE); // first 8 bytes of pad + + std::pair timingAndVersionNow = SerialInterface::stabilizers[chan].evaluateTiming(std::chrono::high_resolution_clock::now()); + + // Log + std::ostringstream oss; + oss << std::fixed << std::setprecision(2) << "Sending Kristal input timing " << timingAndVersion.first + << " v" << (int)timingAndVersion.second << " on " << timingAndVersionNow.first << " v" + << (int)timingAndVersionNow.second; + WARN_LOG(KRISTAL, oss.str().c_str()); + + SendAsync(std::move(spac)); +} + +std::pair SlippiNetplayClient::GetKristalInput(u32 frame, u8 playerIdx) +{ + auto &subframePadSet = subframePadSets[playerIdx]; + if (subframePadSet.size()==0) + return std::pair(false, KristalPad()); + auto it = std::lower_bound(subframePadSet.begin(), subframePadSet.end(), frame, + [](KristalPad pad, u32 frame) { return pad.subframe < (float)frame; }); // Get first pad in the future + if (it == subframePadSet.begin()) // No pad in the past + return std::pair(false, KristalPad()); // The latest SlippiPad should be used as prediction + it--; // Last pad before future + // Otherwise, clean elements strictly older than this pad before returning + KristalPad pad = *it; + subframePadSet.erase(subframePadSet.begin(), it); + // It's left to the caller to check that he's better off with that subframe than with the last known Slippi pad + return std::pair(true, pad); +} + +/*std::string SlippiNetplayClient::getKristalCrossplayDebugMessage() +{ + return kristalCrossplayDebugMessage; +}*/ + +extern std::string KRISTAL_CROSSPLAY_DEBUG_MESSAGE = ""; \ No newline at end of file diff --git a/Source/Core/Core/Slippi/SlippiNetplay.h b/Source/Core/Core/Slippi/SlippiNetplay.h index 67222243f0..4651abefb5 100644 --- a/Source/Core/Core/Slippi/SlippiNetplay.h +++ b/Source/Core/Core/Slippi/SlippiNetplay.h @@ -11,10 +11,12 @@ #include "Common/TraversalClient.h" #include "Core/NetPlayProto.h" #include "Core/Slippi/SlippiPad.h" +#include "InputCommon/GCAdapter.h" #include "InputCommon/GCPadStatus.h" #include #include #include +#include #include #include #include @@ -130,10 +132,11 @@ class SlippiNetplayClient u8 LocalPlayerPort(); SlippiConnectStatus GetSlippiConnectStatus(); std::vector GetFailedConnections(); - void StartSlippiGame(); + void StartSlippiGame(u8 delay); void SendConnectionSelected(); void SendSlippiPad(std::unique_ptr pad); void SetMatchSelections(SlippiPlayerSelections &s); + std::unique_ptr GetSlippiRemotePad(int32_t curFrame, int index); void DropOldRemoteInputs(int32_t minFrameRead); SlippiMatchInfo *GetMatchInfo(); @@ -149,6 +152,36 @@ class SlippiNetplayClient nullptr; // most recent chat message player selection (message + player index) u8 remoteSentChatMessageId = 0; // most recent chat message id that current player sent + void DecrementInputStabilizerFrameCounts(); + + void KristalInputCallback(const GCPadStatus &pad, std::chrono::high_resolution_clock::time_point tp, int chan); + // TODO Check whether we can't just use the first InputStabilizer since we only want timing information + // Will have to handle that for HID controller support + + // TODO Extract to own class + struct KristalPad + { + float subframe; + u8 version; + u8 pad[SLIPPI_PAD_DATA_SIZE]; + + // Latest pad in back of set i.e superior + bool operator<(const KristalPad &rhs) const + { + if ((int)subframe != (int)rhs.subframe) // If not from the same frame + return subframe < rhs.subframe; // Check higher frame + if (version != rhs.version) // If from the same frame and not same version + return version < rhs.version; // Check higher version + return subframe < rhs.subframe; // If same frame, same version, check higher subframe + } + }; + + std::pair GetKristalInput(u32 frame, u8 playerIdx); + + std::mutex& padMutex(); + + // std::string getKristalCrossplayDebugMessage(); + protected: struct { @@ -210,6 +243,11 @@ class SlippiNetplayClient bool m_is_recording = false; + bool shouldInitializeInputStabilizers = false; + + std::set subframePadSets[SLIPPI_REMOTE_PLAYER_MAX]; + std::mutex subframePadSetLocks[SLIPPI_REMOTE_PLAYER_MAX]; + void writeToPacket(sf::Packet &packet, SlippiPlayerSelections &s); std::unique_ptr readSelectionsFromPacket(sf::Packet &packet); @@ -220,6 +258,11 @@ class SlippiNetplayClient void Disconnect(); bool m_is_connected = false; + bool kristalVersionWasReceived = false; + u8 kristalVersionReceived = 0; + u8 minimumKristalVersionSupportedReceived = 0; + static const u8 localKristalVersion = 0; + static const u8 minimumRequiredKristalVersion = 0; #ifdef _WIN32 HANDLE m_qos_handle; @@ -227,9 +270,14 @@ class SlippiNetplayClient #endif u32 m_timebase_frame = 0; + + u8 m_last_adapter_chan_used_in_kristal_callback = 0; }; + extern SlippiNetplayClient *SLIPPI_NETPLAY; // singleton static pointer +extern std::string KRISTAL_CROSSPLAY_DEBUG_MESSAGE; + static bool IsOnline() { return SLIPPI_NETPLAY != nullptr; diff --git a/Source/Core/DolphinWX/Config/SlippiConfigPane.cpp b/Source/Core/DolphinWX/Config/SlippiConfigPane.cpp index 6c87783341..29df7c60c9 100644 --- a/Source/Core/DolphinWX/Config/SlippiConfigPane.cpp +++ b/Source/Core/DolphinWX/Config/SlippiConfigPane.cpp @@ -187,6 +187,7 @@ void SlippiNetplayConfigPane::LoadGUIValues() } m_reduce_timing_dispersion_checkbox->SetValue(startup_params.bReduceTimingDispersion); + m_reduce_timing_dispersion_checkbox->Disable(); } void SlippiNetplayConfigPane::BindEvents() diff --git a/Source/Core/InputCommon/CMakeLists.txt b/Source/Core/InputCommon/CMakeLists.txt index 06aae8d08b..06290b0231 100644 --- a/Source/Core/InputCommon/CMakeLists.txt +++ b/Source/Core/InputCommon/CMakeLists.txt @@ -1,6 +1,7 @@ set(SRCS ControllerEmu.cpp InputConfig.cpp InputStabilizer.cpp + KristalInputJudge.cpp ControllerInterface/ControllerInterface.cpp ControllerInterface/Device.cpp ControllerInterface/ExpressionParser.cpp) diff --git a/Source/Core/InputCommon/GCAdapter.cpp b/Source/Core/InputCommon/GCAdapter.cpp index 6b17f1c81c..21c570bbc1 100644 --- a/Source/Core/InputCommon/GCAdapter.cpp +++ b/Source/Core/InputCommon/GCAdapter.cpp @@ -23,6 +23,8 @@ #include "Core/HW/SystemTimers.h" #include "Core/NetPlayProto.h" +#include "InputCommon/KristalInputJudge.h" + #include "InputCommon/GCAdapter.h" #include "InputCommon/GCPadStatus.h" @@ -135,6 +137,137 @@ void judgeEILVOptimsApplicability() { } } +std::pair origins[4] = {}; // pls gib C++17 + +uint8_t applyStickOrigin(uint8_t applyOn, uint8_t origin) +{ + int offset = 0x80 - (int)origin; + int result = ((int)applyOn) + offset; + int limitedResult = std::min(255, std::max(0, result)); + return (uint8_t)limitedResult; +} + +uint8_t applyTriggerOrigin(uint8_t applyOn, uint8_t origin) +{ + int result = ((int)applyOn) - (int)origin; + int limitedResult = std::max(0, result); + return (uint8_t)limitedResult; +} + +GCPadStatus makePadFrom8ByteArray(uint8_t *byteArray, bool get_origin, bool applyOrigin, int chan) +{ + GCPadStatus pad = {}; + + u8 b1 = byteArray[0]; + u8 b2 = byteArray[1]; + + if (b1 & (1 << 0)) + pad.button |= PAD_BUTTON_A; + if (b1 & (1 << 1)) + pad.button |= PAD_BUTTON_B; + if (b1 & (1 << 2)) + pad.button |= PAD_BUTTON_X; + if (b1 & (1 << 3)) + pad.button |= PAD_BUTTON_Y; + + if (b1 & (1 << 4)) + pad.button |= PAD_BUTTON_LEFT; + if (b1 & (1 << 5)) + pad.button |= PAD_BUTTON_RIGHT; + if (b1 & (1 << 6)) + pad.button |= PAD_BUTTON_DOWN; + if (b1 & (1 << 7)) + pad.button |= PAD_BUTTON_UP; + + if (b2 & (1 << 0)) + pad.button |= PAD_BUTTON_START; + if (b2 & (1 << 1)) + pad.button |= PAD_TRIGGER_Z; + if (b2 & (1 << 2)) + pad.button |= PAD_TRIGGER_R; + if (b2 & (1 << 3)) + pad.button |= PAD_TRIGGER_L; + + if (get_origin) + pad.button |= PAD_GET_ORIGIN; + + // Correct by origin + + if (applyOrigin && origins[chan].second) + { + pad.stickX = applyStickOrigin(byteArray[2], origins[chan].first.stickX); + pad.stickY = applyStickOrigin(byteArray[3], origins[chan].first.stickY); + pad.substickX = applyStickOrigin(byteArray[4], origins[chan].first.substickX); + pad.substickY = applyStickOrigin(byteArray[5], origins[chan].first.substickY); + pad.triggerLeft = applyTriggerOrigin(byteArray[6], origins[chan].first.triggerLeft); + pad.triggerRight = applyTriggerOrigin(byteArray[7], origins[chan].first.triggerRight); + } + else + { + pad.stickX = byteArray[2]; + pad.stickY = byteArray[3]; + pad.substickX = byteArray[4]; + pad.substickY = byteArray[5]; + pad.triggerLeft = byteArray[6]; + pad.triggerRight = byteArray[7]; + } + + return pad; +} + +/* +* 0 : no start press +* 1-4 : chan 0-3 start press (lower takes prio) +*/ +static u8 FindUsedController(u8 *controller_payload) +{ + return + ((controller_payload[1 + 2 + 0*9] & 1) ? 1 : + ((controller_payload[1 + 2 + 1*9] & 1) ? 2 : + ((controller_payload[1 + 2 + 2*9] & 1) ? 3 : + ((controller_payload[1 + 2 + 3*9] & 1) ? 4 : 0)))); +} + + + +std::function kristalInputCallback = + [](const GCPadStatus &, std::chrono::high_resolution_clock::time_point, int) -> void {}; + +void SetKristalInputCallback( + std::function callback) +{ + std::lock_guard lock(kristal_callback_mutex); + kristalInputCallback = callback; +} + +void ClearKristalInputCallback() +{ + std::lock_guard lock(kristal_callback_mutex); + // Called from a destructor + // Termination if throws there. //TODO ? + kristalInputCallback = [](const GCPadStatus &, std::chrono::high_resolution_clock::time_point, int) -> void {}; +} + +volatile u8 usedControllerChan = 0; // P1 default +GCPadStatus previousPad{}; + +static void HandleKristalFunctions(u8 *controller_payload, const std::chrono::high_resolution_clock::time_point &tp) +{ + u8 volatile usedControllerInfo = FindUsedController(controller_payload); + if (usedControllerInfo != 0 && usedControllerChan != usedControllerInfo - 1) + { + usedControllerChan = usedControllerInfo - 1; + ERROR_LOG(KRISTAL, "Found used controller %d", usedControllerInfo); + } + GCPadStatus pad = makePadFrom8ByteArray(controller_payload + 2 + 9 * usedControllerChan, false, true, usedControllerChan); + if (isKristalInput(pad, previousPad)) + { + INFO_LOG(KRISTAL, "Perceived Kristal Input"); + kristalInputCallback(pad, tp, usedControllerChan); + } + previousPad = pad; +} + static void Feed(std::chrono::high_resolution_clock::time_point tp, u8 *controller_payload) { const SConfig &sconfig = SConfig::GetInstance(); @@ -306,6 +439,17 @@ static void Feed(std::chrono::high_resolution_clock::time_point tp, u8 *controll if (controller_payload_entries.size() > controller_payload_limit) controller_payload_entries.pop_back(); + + // Makes sense to *add* delays because if they're put further in the future by them, they're also at higher subframe + auto kristalTp = newEntry.estimated_timing; //TODO Incorporate these delays in the estimated_timing directly ? + if (sconfig.bReduceTimingDispersion && beenUsingTR()) + kristalTp += std::chrono::nanoseconds(800'000) + std::chrono::nanoseconds(usbPollingStabilizationDelay); + else if (sconfig.bReduceTimingDispersion) + kristalTp += std::chrono::nanoseconds(usbPollingStabilizationDelay); + else + kristalTp = newEntry.raw_timing; + HandleKristalFunctions(controller_payload, + kristalTp); // TODO Perhaps shouldn't be in USB polling thread ? Performance concerns ? } const u8 *Fetch(std::chrono::high_resolution_clock::time_point *tp) @@ -774,7 +918,8 @@ GCPadStatus Input(int chan, std::chrono::high_resolution_clock::time_point *tp) payload_size = s_controller_payload_size.load(); } - GCPadStatus pad = {}; + GCPadStatus pad{}; + if (payload_size != sizeof(controller_payload_copy) || controller_payload_copy[0] != LIBUSB_DT_HID) { @@ -798,45 +943,7 @@ GCPadStatus Input(int chan, std::chrono::high_resolution_clock::time_point *tp) if (s_controller_type[chan] != ControllerTypes::CONTROLLER_NONE) { - u8 b1 = controller_payload_copy[1 + (9 * chan) + 1]; - u8 b2 = controller_payload_copy[1 + (9 * chan) + 2]; - - if (b1 & (1 << 0)) - pad.button |= PAD_BUTTON_A; - if (b1 & (1 << 1)) - pad.button |= PAD_BUTTON_B; - if (b1 & (1 << 2)) - pad.button |= PAD_BUTTON_X; - if (b1 & (1 << 3)) - pad.button |= PAD_BUTTON_Y; - - if (b1 & (1 << 4)) - pad.button |= PAD_BUTTON_LEFT; - if (b1 & (1 << 5)) - pad.button |= PAD_BUTTON_RIGHT; - if (b1 & (1 << 6)) - pad.button |= PAD_BUTTON_DOWN; - if (b1 & (1 << 7)) - pad.button |= PAD_BUTTON_UP; - - if (b2 & (1 << 0)) - pad.button |= PAD_BUTTON_START; - if (b2 & (1 << 1)) - pad.button |= PAD_TRIGGER_Z; - if (b2 & (1 << 2)) - pad.button |= PAD_TRIGGER_R; - if (b2 & (1 << 3)) - pad.button |= PAD_TRIGGER_L; - - if (get_origin) - pad.button |= PAD_GET_ORIGIN; - - pad.stickX = controller_payload_copy[1 + (9 * chan) + 3]; - pad.stickY = controller_payload_copy[1 + (9 * chan) + 4]; - pad.substickX = controller_payload_copy[1 + (9 * chan) + 5]; - pad.substickY = controller_payload_copy[1 + (9 * chan) + 6]; - pad.triggerLeft = controller_payload_copy[1 + (9 * chan) + 7]; - pad.triggerRight = controller_payload_copy[1 + (9 * chan) + 8]; + pad = makePadFrom8ByteArray(controller_payload_copy + 2 + (9 * chan), get_origin, false, chan); } else { @@ -911,4 +1018,32 @@ bool IsDriverDetected() return !s_libusb_driver_not_supported; } +void InformPadModeSet(int chan) { + if (controller_payload_entries.size() > 0) + { + origins[chan].first = + makePadFrom8ByteArray(controller_payload_entries.front().controller_payload + 2 + chan * 9, false, false, chan); + origins[chan].second = true; + + std::ostringstream oss; + oss << "New origin for port "; + oss << (int)(chan + 1); + oss << ": "; + for (int i = 0; i < 8; i++) + { + oss << (int)((u8 *)(origins + chan))[i] << " "; + } + ERROR_LOG(KRISTAL, oss.str().c_str()); + } + else + { + std::ostringstream oss; + oss << "Origin registration for port "; + oss << (int)(chan + 1); + oss << " failed because no pad data was known yet."; + ERROR_LOG(KRISTAL, oss.str().c_str()); + } + +} + } // end of namespace GCAdapter diff --git a/Source/Core/InputCommon/GCAdapter.h b/Source/Core/InputCommon/GCAdapter.h index a14a27e3d3..d0599ab5ca 100644 --- a/Source/Core/InputCommon/GCAdapter.h +++ b/Source/Core/InputCommon/GCAdapter.h @@ -5,6 +5,7 @@ #pragma once #include +#include #include "Common/CommonTypes.h" @@ -12,6 +13,7 @@ struct GCPadStatus; namespace GCAdapter { + enum ControllerTypes { CONTROLLER_NONE = 0, @@ -35,4 +37,11 @@ bool IsDriverDetected(); bool DeviceConnected(int chan); bool UseAdapter(); +static std::mutex kristal_callback_mutex; +void SetKristalInputCallback( + std::function callback); +void ClearKristalInputCallback(); + +void InformPadModeSet(int chan); + } // end of namespace GCAdapter diff --git a/Source/Core/InputCommon/InputCommon.vcxproj b/Source/Core/InputCommon/InputCommon.vcxproj index eade5f9b64..277b548194 100644 --- a/Source/Core/InputCommon/InputCommon.vcxproj +++ b/Source/Core/InputCommon/InputCommon.vcxproj @@ -76,6 +76,7 @@ + @@ -94,6 +95,7 @@ + diff --git a/Source/Core/InputCommon/InputCommon.vcxproj.filters b/Source/Core/InputCommon/InputCommon.vcxproj.filters index ac85e3deba..252cd06f87 100644 --- a/Source/Core/InputCommon/InputCommon.vcxproj.filters +++ b/Source/Core/InputCommon/InputCommon.vcxproj.filters @@ -22,7 +22,8 @@ - + + ControllerInterface\DInput @@ -57,8 +58,9 @@ - - + + + ControllerInterface\DInput diff --git a/Source/Core/InputCommon/InputStabilizer.cpp b/Source/Core/InputCommon/InputStabilizer.cpp index 97f7f30a52..b743cdb041 100644 --- a/Source/Core/InputCommon/InputStabilizer.cpp +++ b/Source/Core/InputCommon/InputStabilizer.cpp @@ -70,6 +70,16 @@ InputStabilizer::InputStabilizer(const InputStabilizer& target) void InputStabilizer::feedPollTiming(std::chrono::high_resolution_clock::time_point tp) { + std::lock_guard lock(mutex); + + { // Kristal stuff + frameCount++; + if (isNewFrameCounter != 0) + isNewFrameCounter--; + if (isNewFrameCounter == 0) + version = 1; + } + const SConfig& sconfig = SConfig::GetInstance(); double period = 1'000'000'000 / 59.94; @@ -104,12 +114,12 @@ void InputStabilizer::feedPollTiming(std::chrono::high_resolution_clock::time_po if (pollTimings.size() == sizeLimit) // Initialize steady state algorithm { incrementsSinceOrigin = 0; - steadyStateOrigin = computeNextPollTiming(true) + std::chrono::nanoseconds(delay); + steadyStateOrigin = computeNextPollTimingInternal(true) + std::chrono::nanoseconds(delay); // The origin is compared to real time points and therefore doesn't contain the delay } } -time_point InputStabilizer::computeNextPollTiming(bool init) +time_point InputStabilizer::computeNextPollTimingInternal(bool init, bool alter) //TODO Why the fuck is there a state change in the read method what was I thinking { const SConfig& sconfig = SConfig::GetInstance(); double period = 1'000'000'000 / 59.94; @@ -122,7 +132,7 @@ time_point InputStabilizer::computeNextPollTiming(bool init) if ((!init) && (size == sizeLimit)) { auto result = steadyStateOrigin + std::chrono::nanoseconds((int64_t)(incrementsSinceOrigin * period - delay)); - incrementsSinceOrigin++; + if (alter) incrementsSinceOrigin++; return result; } @@ -130,4 +140,67 @@ time_point InputStabilizer::computeNextPollTiming(bool init) int64_t actualization = (int64_t)((size) * (size - 1) / 2 * period); int64_t actualizedOffsetsMean = (offsetsSum + actualization) / (int64_t)size; return ref + std::chrono::nanoseconds(actualizedOffsetsMean - delay); +} + +time_point InputStabilizer::computeNextPollTiming() +{ + std::lock_guard lock(mutex); + return computeNextPollTimingInternal(false, false); +} + +void InputStabilizer::startFrameCount(int32_t initialValue) +{ + frameCount = initialValue; + isCountingFrames = true; +} + +void InputStabilizer::endFrameCount() { + frameCount = 0; + isCountingFrames = false; +} + +void InputStabilizer::decrementFrameCount() { + frameCount--; + isNewFrameCounter = 2; +} + +std::pair InputStabilizer::evaluateTiming(const time_point& tp) { + std::lock_guard lock(mutex); + + const SConfig &sconfig = SConfig::GetInstance(); + double period = (int64_t)1'000'000'000 / 59.94; + + // It is assumed the last provided timing matches the frame number we currently have + + // What we're looking here is when tp is relatively to the stabilizer timings + // The stabilizer timings are natively offset by the delay + // But the parameter isn't + // the time point returned by computeNextPollTiming isn't the "real" timing for the integer that is frameCount + // We must compensate the delay by adding it again + time_point previousPoll = computeNextPollTimingInternal() + std::chrono::nanoseconds(delay); + + long long diff = (tp - previousPoll).count(); + + int inputVersion = 1; + double timing = frameCount + (diff / period); + if (timing >= frameOfHigherVersion && timing < frameOfHigherVersion + 1) + inputVersion = version; + + // DEBUG + auto now = std::chrono::high_resolution_clock::now(); + long long diffDebug = (now - previousPoll).count(); + int inputVersionDebug = 1; + double timingDebug = frameCount + (diffDebug / period); + if (timingDebug >= frameOfHigherVersion && timingDebug < frameOfHigherVersion + 1) + inputVersionDebug = version; + // /DEBUG + + + std::ostringstream oss; + oss << std::fixed << std::setprecision(2) << "Evaluated tp " << tp.time_since_epoch().count() << " to " << (float)timing << " v" << inputVersion << " on " + << now.time_since_epoch().count() << " " << (float)timingDebug << " v" << inputVersionDebug; + + INFO_LOG(KRISTAL, oss.str().c_str()); + + return std::pair((float)timing, (u8)inputVersion); } \ No newline at end of file diff --git a/Source/Core/InputCommon/InputStabilizer.h b/Source/Core/InputCommon/InputStabilizer.h index ed35a06d92..adeaa372fe 100644 --- a/Source/Core/InputCommon/InputStabilizer.h +++ b/Source/Core/InputCommon/InputStabilizer.h @@ -10,18 +10,44 @@ class InputStabilizer using time_point = std::chrono::high_resolution_clock::time_point; private: - std::list pollTimings; - int64_t offsetsSum; + // Parameters const size_t sizeLimit; const int64_t delay; const int64_t leniency; + + // Transition state + std::list pollTimings; + int64_t offsetsSum; // period used to be an input but is now dynamically controlled by the 59.94/60Hz switch + + // Steady state time_point steadyStateOrigin; int64_t incrementsSinceOrigin=0; + // Kristal + int32_t frameCount = 0; + bool isCountingFrames = false; + std::mutex mutex; + // An instance can be used from both the polling thread that computing a Kristal input's + // timestamp, and the main thread doing normal pacing stuff - this warrants synchronizing + // accesses to pollTimings + int version = 1; + int frameOfHigherVersion = -10; + int isNewFrameCounter = 0; + // to account for stall inputs, we send a timing, and a "version" - receiving an input for + // timing n=42.5 version 2 makes it more recent than anything in [42,43[ version 1 + // version is incremented when frame count is decremented + public: InputStabilizer(size_t sizeLimit=100, int64_t delay=1'400'000, int64_t leniency=3'333'333); InputStabilizer(const InputStabilizer &); void feedPollTiming(time_point tp); - time_point computeNextPollTiming(bool init=false); + time_point computeNextPollTiming(); + + // Kristal + time_point computeNextPollTimingInternal(bool init = false, bool alter = true); + void startFrameCount(int32_t initialValue=0); + void endFrameCount(); + void decrementFrameCount(); + std::pair evaluateTiming(const time_point &); }; \ No newline at end of file diff --git a/Source/Core/InputCommon/KristalInputJudge.cpp b/Source/Core/InputCommon/KristalInputJudge.cpp new file mode 100644 index 0000000000..dc67d077cc --- /dev/null +++ b/Source/Core/InputCommon/KristalInputJudge.cpp @@ -0,0 +1,65 @@ +#include "KristalInputJudge.h" +#include "GCPadStatus.h" + +#define coord(x) ((u8)(128 + 80*x + 0.5)) + +bool isKristalInput(const GCPadStatus& newPad, const GCPadStatus& oldPad) +{ + return + // Digital (!A -> A, !B -> B, !other <-> other) + ((newPad.button & PAD_BUTTON_A) && !(oldPad.button & PAD_BUTTON_A)) || + ((newPad.button & PAD_BUTTON_B) && !(oldPad.button & PAD_BUTTON_B)) || + ((newPad.button & PAD_BUTTON_X) && !(oldPad.button & PAD_BUTTON_X)) || + ((oldPad.button & PAD_BUTTON_X) && !(newPad.button & PAD_BUTTON_X)) || + ((newPad.button & PAD_BUTTON_Y) && !(oldPad.button & PAD_BUTTON_Y)) || + ((oldPad.button & PAD_BUTTON_Y) && !(newPad.button & PAD_BUTTON_Y)) || + ((newPad.button & PAD_TRIGGER_L) && !(oldPad.button & PAD_TRIGGER_L)) || + ((oldPad.button & PAD_TRIGGER_L) && !(newPad.button & PAD_TRIGGER_L)) || + ((newPad.button & PAD_TRIGGER_R) && !(oldPad.button & PAD_TRIGGER_R)) || + ((oldPad.button & PAD_TRIGGER_R) && !(newPad.button & PAD_TRIGGER_R)) || + ((newPad.button & PAD_TRIGGER_Z) && !(oldPad.button & PAD_TRIGGER_Z)) || + ((oldPad.button & PAD_TRIGGER_Z) && !(newPad.button & PAD_TRIGGER_Z)) || + ((newPad.button & PAD_BUTTON_START) && !(oldPad.button & PAD_BUTTON_START)) || + + // Stick (|X|>=.2875, |X|>=0.8, |Y|>=.2875, Y>=0.6625, Y<-0.7) + ((oldPad.stickX < coord(0.2875)) && (newPad.stickX >= coord(0.2875))) || // Right + ((oldPad.stickX < coord(0.8)) && (newPad.stickX >= coord(0.8))) || // Dash right + ((oldPad.stickX > coord(-0.2875)) && (newPad.stickX <= coord(-0.2875))) || // Left + ((oldPad.stickX > coord(-0.8)) && (newPad.stickX <= coord(-0.8))) || // Dash left + ((oldPad.stickY < coord(0.2875)) && (newPad.stickY >= coord(0.2875))) || // Up + ((oldPad.stickY < coord(0.6625)) && (newPad.stickY >= coord(0.6625))) || // Jump + ((oldPad.stickY > coord(-0.2875)) && (newPad.stickY <= coord(-0.2875))) || // Down + ((oldPad.stickY > coord(-0.7)) && (newPad.stickY <= coord(-0.7))) || // Crouch + + // C Stick + ((oldPad.substickX < coord(0.2875)) && (newPad.substickX >= coord(0.2875))) || // Right air + ((oldPad.substickX < coord(0.8)) && (newPad.substickX >= coord(0.8))) || // Right smash + ((oldPad.substickX > coord(-0.2875)) && (newPad.substickX <= coord(-0.2875))) || // Left air + ((oldPad.substickX > coord(-0.8)) && (newPad.substickX <= coord(-0.8))) || // Left smash + ((oldPad.substickY < coord(0.2875)) && (newPad.substickY >= coord(0.2875))) || // Up air + ((oldPad.substickY < coord(0.6625)) && (newPad.substickY >= coord(0.6625))) || // Up smash + ((oldPad.substickY > coord(-0.2875)) && (newPad.substickY <= coord(-0.2875))) || // Down air + ((oldPad.substickY > coord(-0.6625)) && (newPad.substickY <= coord(-0.6625))) || // Down smash + + // Triggers (no shield <-> minimum shield check for both triggers) + ((oldPad.triggerLeft < 43) && (newPad.triggerLeft >= 43)) || + ((oldPad.triggerRight < 43) && (newPad.triggerRight >= 43)) || + ((oldPad.triggerLeft >= 43) && (newPad.triggerLeft < 43)) || + ((oldPad.triggerRight >= 43) && (newPad.triggerRight < 43)) || + + // Dpad (none) + + /* Advanced checks */ + + // Tap jump from dash + ( (oldPad.stickX >= coord(0.8) || oldPad.stickX <= coord(-0.8)) && oldPad.stickY < coord(0.6625) && newPad.stickY >= coord(0.6625) ) || + + // Shield drop + ( + ((newPad.button & (PAD_TRIGGER_L | PAD_TRIGGER_R | PAD_TRIGGER_Z)) || + (newPad.triggerLeft >= 43) || + (newPad.triggerRight >= 43)) // New pad may be shielding + && (oldPad.stickY > coord(-0.6625)) // Old pad above shield drop + && (newPad.stickY <= coord(-0.6625)) // New pad below shield drop + ); +} \ No newline at end of file diff --git a/Source/Core/InputCommon/KristalInputJudge.h b/Source/Core/InputCommon/KristalInputJudge.h new file mode 100644 index 0000000000..4f01455236 --- /dev/null +++ b/Source/Core/InputCommon/KristalInputJudge.h @@ -0,0 +1,5 @@ +#pragma once + +#include "GCAdapter.h" + +bool isKristalInput(const GCPadStatus &newPad, const GCPadStatus &oldPad); \ No newline at end of file diff --git a/Source/Core/VideoCommon/RenderBase.cpp b/Source/Core/VideoCommon/RenderBase.cpp index 6bea386f88..cffd712514 100644 --- a/Source/Core/VideoCommon/RenderBase.cpp +++ b/Source/Core/VideoCommon/RenderBase.cpp @@ -45,7 +45,7 @@ #include "Core/NetPlayProto.h" #include "Core/NetPlayClient.h" #include "Core/HW/SI.h" - +#include "Core/Slippi/SlippiNetplay.h" #include "InputCommon/GCAdapter.h" #include "VideoCommon/AVIDump.h" @@ -509,6 +509,8 @@ void Renderer::DrawDebugText() "Under \"Troubleshooting\", uncheck \"Show a message when inputs are being read at a reduced rate\"."; } + final_yellow += KRISTAL_CROSSPLAY_DEBUG_MESSAGE; // Haha I hate this + // and then the text RenderText(final_cyan, 20, 20, 0xFF00FFFF); RenderText(final_yellow, 20, 20, 0xFFFFFF00);