2020-06-17 00:03:28 +00:00
/ *
2021-01-01 15:10:36 +00:00
* Copyright ( c ) 2019 - 2021 GeyserMC . http : //geysermc.org
2020-06-17 00:03:28 +00:00
*
2020-07-30 20:10:15 +00:00
* Permission is hereby granted , free of charge , to any person obtaining a copy
* of this software and associated documentation files ( the " Software " ) , to deal
* in the Software without restriction , including without limitation the rights
* to use , copy , modify , merge , publish , distribute , sublicense , and / or sell
* copies of the Software , and to permit persons to whom the Software is
* furnished to do so , subject to the following conditions :
2020-06-17 00:03:28 +00:00
*
2020-07-30 20:10:15 +00:00
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software .
2020-06-17 00:03:28 +00:00
*
2020-07-30 20:10:15 +00:00
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
* IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER
* LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM ,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE .
2020-06-17 00:03:28 +00:00
*
2020-07-30 20:10:15 +00:00
* @author GeyserMC
* @link https : //github.com/GeyserMC/Geyser
2020-06-17 00:03:28 +00:00
* /
2021-11-20 23:29:46 +00:00
package org.geysermc.geyser.util ;
2020-06-17 00:03:28 +00:00
import com.nukkitx.protocol.bedrock.packet.SetTitlePacket ;
2021-04-01 04:06:01 +00:00
import lombok.Getter ;
2021-11-21 18:36:42 +00:00
import org.geysermc.geyser.session.GeyserSessionImpl ;
2021-11-20 23:29:46 +00:00
import org.geysermc.geyser.session.cache.PreferencesCache ;
2020-06-17 00:03:28 +00:00
import java.util.concurrent.TimeUnit ;
/ * *
* Manages the sending of a cooldown indicator to the Bedrock player as there is no cooldown indicator in Bedrock .
* Much of the work here is from the wonderful folks from ViaRewind : https : //github.com/ViaVersion/ViaRewind
* /
public class CooldownUtils {
2021-05-15 02:48:34 +00:00
private static CooldownType DEFAULT_SHOW_COOLDOWN ;
2020-06-17 00:03:28 +00:00
2021-05-15 02:48:34 +00:00
public static void setDefaultShowCooldown ( String showCooldown ) {
DEFAULT_SHOW_COOLDOWN = CooldownType . getByName ( showCooldown ) ;
}
public static CooldownType getDefaultShowCooldown ( ) {
return DEFAULT_SHOW_COOLDOWN ;
2020-06-17 00:03:28 +00:00
}
/ * *
2021-05-15 03:12:37 +00:00
* Starts sending the fake cooldown to the Bedrock client . If the cooldown is not disabled , the sent type is the cooldownPreference in { @link PreferencesCache }
2020-06-17 00:03:28 +00:00
* @param session GeyserSession
* /
2021-11-21 18:36:42 +00:00
public static void sendCooldown ( GeyserSessionImpl session ) {
2021-05-15 02:48:34 +00:00
if ( DEFAULT_SHOW_COOLDOWN = = CooldownType . DISABLED ) return ;
CooldownType sessionPreference = session . getPreferencesCache ( ) . getCooldownPreference ( ) ;
if ( sessionPreference = = CooldownType . DISABLED ) return ;
2020-06-17 00:03:28 +00:00
if ( session . getAttackSpeed ( ) = = 0 . 0 | | session . getAttackSpeed ( ) > 20 ) return ; // 0.0 usually happens on login and causes issues with visuals; anything above 20 means a plugin like OldCombatMechanics is being used
// Needs to be sent or no subtitle packet is recognized by the client
SetTitlePacket titlePacket = new SetTitlePacket ( ) ;
2020-06-23 00:11:09 +00:00
titlePacket . setType ( SetTitlePacket . Type . TITLE ) ;
2020-06-17 00:03:28 +00:00
titlePacket . setText ( " " ) ;
2021-07-13 01:19:40 +00:00
titlePacket . setXuid ( " " ) ;
titlePacket . setPlatformOnlineId ( " " ) ;
2020-06-17 00:03:28 +00:00
session . sendUpstreamPacket ( titlePacket ) ;
session . setLastHitTime ( System . currentTimeMillis ( ) ) ;
long lastHitTime = session . getLastHitTime ( ) ; // Used later to prevent multiple scheduled cooldown threads
2021-05-15 02:48:34 +00:00
computeCooldown ( session , sessionPreference , lastHitTime ) ;
2020-06-17 00:03:28 +00:00
}
/ * *
* Keeps updating the cooldown until the bar is complete .
* @param session GeyserSession
2021-05-15 02:48:34 +00:00
* @param sessionPreference The type of cooldown the client prefers
2020-06-17 00:03:28 +00:00
* @param lastHitTime The time of the last hit . Used to gauge how long the cooldown is taking .
* /
2021-11-21 18:36:42 +00:00
private static void computeCooldown ( GeyserSessionImpl session , CooldownType sessionPreference , long lastHitTime ) {
2020-06-17 00:03:28 +00:00
if ( session . isClosed ( ) ) return ; // Don't run scheduled tasks if the client left
if ( lastHitTime ! = session . getLastHitTime ( ) ) return ; // Means another cooldown has started so there's no need to continue this one
SetTitlePacket titlePacket = new SetTitlePacket ( ) ;
2021-05-15 02:48:34 +00:00
if ( sessionPreference = = CooldownType . ACTIONBAR ) {
2021-04-01 04:06:01 +00:00
titlePacket . setType ( SetTitlePacket . Type . ACTIONBAR ) ;
} else {
titlePacket . setType ( SetTitlePacket . Type . SUBTITLE ) ;
}
2020-06-17 00:03:28 +00:00
titlePacket . setText ( getTitle ( session ) ) ;
titlePacket . setFadeInTime ( 0 ) ;
titlePacket . setFadeOutTime ( 5 ) ;
titlePacket . setStayTime ( 2 ) ;
2021-07-13 01:19:40 +00:00
titlePacket . setXuid ( " " ) ;
titlePacket . setPlatformOnlineId ( " " ) ;
2020-06-17 00:03:28 +00:00
session . sendUpstreamPacket ( titlePacket ) ;
if ( hasCooldown ( session ) ) {
2021-11-13 16:03:55 +00:00
session . scheduleInEventLoop ( ( ) - >
computeCooldown ( session , sessionPreference , lastHitTime ) , 50 , TimeUnit . MILLISECONDS ) ; // Updated per tick. 1000 divided by 20 ticks equals 50
2020-06-17 00:03:28 +00:00
} else {
SetTitlePacket removeTitlePacket = new SetTitlePacket ( ) ;
2021-05-15 02:48:34 +00:00
if ( sessionPreference = = CooldownType . ACTIONBAR ) {
2021-04-01 04:06:01 +00:00
removeTitlePacket . setType ( SetTitlePacket . Type . ACTIONBAR ) ;
} else {
removeTitlePacket . setType ( SetTitlePacket . Type . SUBTITLE ) ;
}
2020-06-17 00:03:28 +00:00
removeTitlePacket . setText ( " " ) ;
2021-07-13 01:19:40 +00:00
removeTitlePacket . setXuid ( " " ) ;
removeTitlePacket . setPlatformOnlineId ( " " ) ;
2020-06-17 00:03:28 +00:00
session . sendUpstreamPacket ( removeTitlePacket ) ;
}
}
2021-11-21 18:36:42 +00:00
private static boolean hasCooldown ( GeyserSessionImpl session ) {
2020-06-17 00:03:28 +00:00
long time = System . currentTimeMillis ( ) - session . getLastHitTime ( ) ;
double cooldown = restrain ( ( ( double ) time ) * session . getAttackSpeed ( ) / 1000d , 1 . 5 ) ;
return cooldown < 1 . 1 ;
}
private static double restrain ( double x , double max ) {
if ( x < 0d )
return 0d ;
return Math . min ( x , max ) ;
}
2021-11-21 18:36:42 +00:00
private static String getTitle ( GeyserSessionImpl session ) {
2020-06-17 00:03:28 +00:00
long time = System . currentTimeMillis ( ) - session . getLastHitTime ( ) ;
double cooldown = restrain ( ( ( double ) time ) * session . getAttackSpeed ( ) / 1000d , 1 ) ;
int darkGrey = ( int ) Math . floor ( 10d * cooldown ) ;
int grey = 10 - darkGrey ;
StringBuilder builder = new StringBuilder ( " §8 " ) ;
while ( darkGrey > 0 ) {
builder . append ( " ˙ " ) ;
darkGrey - - ;
}
builder . append ( " §7 " ) ;
while ( grey > 0 ) {
builder . append ( " ˙ " ) ;
grey - - ;
}
return builder . toString ( ) ;
}
2021-04-01 04:06:01 +00:00
@Getter
public enum CooldownType {
TITLE ,
ACTIONBAR ,
DISABLED ;
public static final CooldownType [ ] VALUES = values ( ) ;
/ * *
2021-05-15 02:48:34 +00:00
* Convert the CooldownType string ( from config ) to the enum , DISABLED on fail
2021-04-01 04:06:01 +00:00
*
* @param name CooldownType string
*
* @return The converted CooldownType
* /
public static CooldownType getByName ( String name ) {
if ( name . equalsIgnoreCase ( " true " ) ) { // Backwards config compatibility
return CooldownType . TITLE ;
}
for ( CooldownType type : VALUES ) {
if ( type . name ( ) . equalsIgnoreCase ( name ) ) {
return type ;
}
}
return DISABLED ;
}
}
2020-06-17 00:03:28 +00:00
}