11package net .swofty .type .skyblockgeneric .event .actions .player ;
22
33import net .kyori .adventure .key .Key ;
4+ import net .swofty .commons .StringUtility ;
45import org .tinylog .Logger ;
56import net .kyori .adventure .sound .Sound ;
6- import org .tinylog .Logger ;
77import net .minestom .server .coordinate .Pos ;
8- import org .tinylog .Logger ;
98import net .minestom .server .coordinate .Vec ;
10- import org .tinylog .Logger ;
119import net .minestom .server .entity .EntityType ;
12- import org .tinylog .Logger ;
1310import net .minestom .server .entity .LivingEntity ;
14- import org .tinylog .Logger ;
1511import net .minestom .server .event .player .PlayerMoveEvent ;
16- import org .tinylog .Logger ;
1712import net .minestom .server .network .packet .server .play .ParticlePacket ;
18- import org .tinylog .Logger ;
1913import net .minestom .server .particle .Particle ;
20- import org .tinylog .Logger ;
14+ import net .swofty .commons .ServerType ;
15+ import net .swofty .proxyapi .ProxyInformation ;
2116import net .swofty .type .generic .event .EventNodes ;
22- import org .tinylog .Logger ;
2317import net .swofty .type .generic .event .HypixelEvent ;
24- import org .tinylog .Logger ;
2518import net .swofty .type .generic .event .HypixelEventClass ;
26- import org .tinylog .Logger ;
2719import net .swofty .type .generic .utility .MathUtility ;
28- import org .tinylog .Logger ;
2920import net .swofty .type .skyblockgeneric .user .SkyBlockPlayer ;
30- import org .tinylog .Logger ;
3121import net .swofty .type .skyblockgeneric .utility .LaunchPads ;
32- import org .tinylog .Logger ;
3322
3423import java .util .List ;
24+ import java .util .Set ;
25+ import java .util .UUID ;
26+ import java .util .concurrent .ConcurrentHashMap ;
3527import java .util .concurrent .Executors ;
3628import java .util .concurrent .ScheduledExecutorService ;
3729import java .util .concurrent .ScheduledFuture ;
4133public class ActionPlayerLaunchPads implements HypixelEventClass {
4234 private static final int SEGMENTS = 30 ;
4335 private static final ScheduledExecutorService scheduler = Executors .newScheduledThreadPool (1 );
36+ private static final Set <UUID > notifiedPlayers = ConcurrentHashMap .newKeySet ();
4437
4538
4639 @ HypixelEvent (node = EventNodes .PLAYER , requireDataLoaded = true , isAsync = true )
@@ -53,7 +46,12 @@ public void run(PlayerMoveEvent event) {
5346 } catch (ExceptionInInitializerError err ) {
5447 return ;
5548 }
56- if (pad == null ) return ;
49+
50+ if (pad == null ) {
51+ notifiedPlayers .remove (player .getUuid ());
52+ return ;
53+ }
54+
5755 if (player .isInLaunchpad ()) return ;
5856 player .setInLaunchpad (true );
5957
@@ -84,37 +82,78 @@ public void run(PlayerMoveEvent event) {
8482 player .setInLaunchpad (false );
8583 return ;
8684 }
87- player .playSound (Sound .sound (Key .key ("entity.firework_rocket.launch" ), Sound .Source .PLAYER , 1 , 1 ));
88-
89- LivingEntity armorStand = new LivingEntity (EntityType .ARMOR_STAND );
90- armorStand .getEntityMeta ().setInvisible (true );
91- armorStand .getEntityMeta ().setHasNoGravity (true );
92- armorStand .setInstance (player .getInstance (), player .getPosition ());
93- armorStand .addPassenger (player );
94-
95- List <Pos > curve = MathUtility .bezierCurve (player .getPosition (), pad .getDestination (), SEGMENTS );
96- long timeToSleep = 3000 / SEGMENTS ;
97-
98- // Use ScheduledExecutorService to run the launch trajectory with delays
99- AtomicInteger index = new AtomicInteger (0 );
100- ScheduledFuture <?>[] taskHolder = new ScheduledFuture <?>[1 ];
101- taskHolder [0 ] = scheduler .scheduleAtFixedRate (() -> {
102- int currentIndex = index .getAndIncrement ();
103- if (currentIndex >= curve .size ()) {
104- // Cancel the task
105- if (taskHolder [0 ] != null ) {
106- taskHolder [0 ].cancel (false );
85+
86+ // Check server availability before starting animation
87+ ServerType targetServerType = pad .getTargetServerType ();
88+ ProxyInformation proxyInfo = new ProxyInformation ();
89+ proxyInfo .getServerInformation (targetServerType ).thenAccept (servers -> {
90+ if (servers == null || servers .isEmpty ()) {
91+ player .setInLaunchpad (false );
92+ if (!notifiedPlayers .contains (player .getUuid ())) {
93+ notifiedPlayers .add (player .getUuid ());
94+ player .sendMessage ("§cThere are no " + StringUtility .toNormalCase (targetServerType .name ()) + " servers available at the moment. Please try again later." );
10795 }
108- // Execute the after finished callback
109- player .sendMessage ("Done" );
110- pad .getAfterFinished ().accept (player );
11196 return ;
11297 }
11398
114- Pos pos = curve .get (currentIndex );
115- Vec toGoTo = pos .asVec ();
116- Vec direction = toGoTo .sub (player .getPosition ().asVec ()).normalize ();
117- armorStand .setVelocity (direction .mul (50 , 5 , 50 ));
118- }, 0 , timeToSleep , TimeUnit .MILLISECONDS );
99+ notifiedPlayers .remove (player .getUuid ());
100+
101+ Pos originalPosition = player .getPosition ();
102+ player .playSound (Sound .sound (Key .key ("entity.firework_rocket.launch" ), Sound .Source .PLAYER , 1 , 1 ));
103+
104+ LivingEntity armorStand = new LivingEntity (EntityType .ARMOR_STAND );
105+ armorStand .getEntityMeta ().setInvisible (true );
106+ armorStand .getEntityMeta ().setHasNoGravity (true );
107+ armorStand .setInstance (player .getInstance (), player .getPosition ());
108+ armorStand .addPassenger (player );
109+
110+ List <Pos > curve = MathUtility .bezierCurve (player .getPosition (), pad .getDestination (), SEGMENTS );
111+ long timeToSleep = 3000 / SEGMENTS ;
112+
113+ // Use ScheduledExecutorService to run the launch trajectory with delays
114+ AtomicInteger index = new AtomicInteger (0 );
115+ ScheduledFuture <?>[] taskHolder = new ScheduledFuture <?>[1 ];
116+ taskHolder [0 ] = scheduler .scheduleAtFixedRate (() -> {
117+ int currentIndex = index .getAndIncrement ();
118+ if (currentIndex >= curve .size ()) {
119+ // Cancel the task
120+ if (taskHolder [0 ] != null ) {
121+ taskHolder [0 ].cancel (false );
122+ }
123+
124+ player .setInLaunchpad (false );
125+ notifiedPlayers .remove (player .getUuid ());
126+
127+ // Execute the after finished callback
128+ player .sendMessage ("Done" );
129+ pad .getAfterFinished ().accept (player );
130+
131+ // Check after a delay if player is still on this server (transfer failed)
132+ scheduler .schedule (() -> {
133+ // If player is still on the same server and instance, teleport them back
134+ if (player .getInstance () != null && player .getInstance ().equals (armorStand .getInstance ())) {
135+ player .teleport (originalPosition );
136+ player .sendMessage ("§cFailed to connect to the server. You have been teleported back." );
137+ }
138+ try {
139+ armorStand .remove ();
140+ } catch (Exception e ) {
141+ }
142+ }, 2 , TimeUnit .SECONDS );
143+
144+ return ;
145+ }
146+
147+ Pos pos = curve .get (currentIndex );
148+ Vec toGoTo = pos .asVec ();
149+ Vec direction = toGoTo .sub (player .getPosition ().asVec ()).normalize ();
150+ armorStand .setVelocity (direction .mul (50 , 5 , 50 ));
151+ }, 0 , timeToSleep , TimeUnit .MILLISECONDS );
152+ }).exceptionally (ex -> {
153+ Logger .error (ex , "Error checking server availability for launch pad" );
154+ player .setInLaunchpad (false );
155+ player .sendMessage ("§cAn error occurred while checking server availability. Please try again later." );
156+ return null ;
157+ });
119158 }
120159}
0 commit comments