11package com .github .squi2rel .vp .video ;
22
3+ import com .github .squi2rel .vp .ClientPacketHandler ;
34import com .github .squi2rel .vp .VideoPlayerClient ;
45import com .github .squi2rel .vp .provider .VideoInfo ;
56import io .netty .buffer .ByteBuf ;
7+ import net .minecraft .client .MinecraftClient ;
68import net .minecraft .client .render .VertexConsumerProvider ;
79import net .minecraft .client .util .math .MatrixStack ;
10+ import net .minecraft .text .Text ;
11+ import net .minecraft .util .Formatting ;
812import org .joml .Vector3f ;
913
10- import java .util .Objects ;
14+ import java .util .* ;
1115
1216public class ClientVideoScreen extends VideoScreen {
1317 public IVideoPlayer player = null ;
@@ -16,6 +20,14 @@ public class ClientVideoScreen extends VideoScreen {
1620 private long startTime = System .currentTimeMillis ();
1721 public boolean interactable = true ;
1822
23+ private long lastAutoSync ;
24+ private int syncFrames ;
25+
26+ private double srtt = -1 ;
27+ private double rttvar = -1 ;
28+ private static final double ALPHA = 0.125 ;
29+ private static final double BETA = 0.25 ;
30+
1931 public ClientVideoScreen (VideoArea area , String name , Vector3f v1 , Vector3f v2 , Vector3f v3 , Vector3f v4 , String source ) {
2032 super (area , name , v1 , v2 , v3 , v4 , source );
2133 }
@@ -54,8 +66,16 @@ public void swapTexture() {
5466 if (player != null ) player .swapTexture ();
5567 }
5668
57- public void updateTexture () {
69+ public void update () {
5870 if (player != null ) player .updateTexture ();
71+
72+ if (player instanceof VideoPlayer vp && !vp .isPaused ()) {
73+ long syncTime = 150L * Math .max (syncFrames , 1 );
74+ if (meta .getOrDefault ("autoSync" , 0 ) != 0 && System .currentTimeMillis () - lastAutoSync >= syncTime ) {
75+ lastAutoSync = System .currentTimeMillis ();
76+ ClientPacketHandler .autoSync (this , System .currentTimeMillis ());
77+ }
78+ }
5979 }
6080
6181 public ClientVideoScreen getTrackingScreen () {
@@ -73,6 +93,7 @@ public void load() {
7393 }
7494
7595 public void play (VideoInfo info ) {
96+ syncFrames = 0 ;
7697 if (source .isEmpty ()) {
7798 IVideoPlayer old = player ;
7899 player = VideoPlayers .from (info , this , player );
@@ -107,10 +128,75 @@ public long getStartTime() {
107128 }
108129
109130 public void setProgress (long progress ) {
131+ syncFrames = 0 ;
110132 player .setProgress (progress );
111133 startTime = System .currentTimeMillis () - progress ;
112134 }
113135
136+ public void autoSync (int clientDelay , long syncProgress ) {
137+ if (srtt < 0 ) {
138+ srtt = clientDelay ;
139+ rttvar = clientDelay / 2.0 ;
140+ } else {
141+ double delta = Math .abs (clientDelay - srtt );
142+ if (delta > 1000 ) return ;
143+ rttvar = (1 - BETA ) * rttvar + BETA * delta ;
144+ srtt = (1 - ALPHA ) * srtt + ALPHA * clientDelay ;
145+ }
146+
147+ int rtt = (int ) Math .round (srtt );
148+ syncProgress += rtt / 2 ;
149+
150+ if (player instanceof VideoPlayer vp && !vp .isPaused ()) {
151+ if (syncProgress <= 0 ) return ;
152+ long progress = vp .getProgress ();
153+ if (progress <= 0 ) return ;
154+
155+ long delta = syncProgress - progress ;
156+ if (delta > -25 && delta <= 25 ) {
157+ syncFrames ++;
158+ } else {
159+ syncFrames --;
160+ }
161+ syncFrames = Math .clamp (syncFrames , 0 , 7 );
162+
163+ if (syncFrames < 5 ) {
164+ if (delta > 10000 ) {
165+ if (vp .getRate () != 3f ) vp .setRate (3f );
166+ } else if (delta > 5000 ) {
167+ if (vp .getRate () != 2f ) vp .setRate (2f );
168+ } else if (delta > 3000 ) {
169+ if (vp .getRate () != 1.5f ) vp .setRate (1.5f );
170+ } else if (delta > 1500 ) {
171+ if (vp .getRate () != 1.4f ) vp .setRate (1.4f );
172+ } else if (delta > 500 ) {
173+ if (vp .getRate () != 1.3f ) vp .setRate (1.3f );
174+ } else if (delta > 100 ) {
175+ if (vp .getRate () != 1.2f ) vp .setRate (1.2f );
176+ } else if (delta > 25 ) {
177+ if (vp .getRate () != 1.1f ) vp .setRate (1.1f );
178+ } else if (delta > -25 ) {
179+ if (vp .getRate () != 1f ) vp .setRate (1f );
180+ } else if (delta > -1000 ) {
181+ if (vp .getRate () != 0.9f ) vp .setRate (0.9f );
182+ } else if (delta > -5000 ) {
183+ if (vp .getRate () != 0.8f ) vp .setRate (0.8f );
184+ } else if (delta > -10000 ) {
185+ vp .stop ();
186+ MinecraftClient .getInstance ().inGameHud .setOverlayMessage (Text .literal ("提前太多,失去同步" ).formatted (Formatting .RED ), false );
187+ }
188+ }
189+
190+ if (meta .getOrDefault ("debug" , 0 ) != 0 ) {
191+ MinecraftClient .getInstance ().inGameHud .setOverlayMessage (Text .literal (
192+ "local: %s, server: %s, rtt: %s, delta: %s, sync: %s/7, rate: %.2f" .formatted (
193+ progress , syncProgress , rtt , delta , syncFrames , vp .getRate ()
194+ )
195+ ).formatted (Formatting .GREEN ), false );
196+ }
197+ }
198+ }
199+
114200 public void unload () {
115201 VideoPlayerClient .screens .remove (this );
116202 if (player != null ) player .cleanup ();
0 commit comments