2020-11-15 13:42:19 +01:00
/ *
This file is a part of the SteamWar software .
Copyright ( C ) 2020 SteamWar . de - Serverteam
This program is free software : you can redistribute it and / or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation , either version 3 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU Affero General Public License for more details .
You should have received a copy of the GNU Affero General Public License
along with this program . If not , see < https : //www.gnu.org/licenses/>.
* /
2020-11-15 13:12:52 +01:00
package de.steamwar.bausystem.commands ;
2020-11-15 21:54:06 +01:00
import com.comphenix.protocol.PacketType ;
import com.comphenix.protocol.ProtocolLibrary ;
import com.comphenix.protocol.events.PacketAdapter ;
import com.comphenix.protocol.events.PacketEvent ;
import com.comphenix.protocol.reflect.StructureModifier ;
import com.comphenix.protocol.wrappers.WrappedWatchableObject ;
2020-11-15 13:12:52 +01:00
import de.steamwar.bausystem.BauSystem ;
2020-11-15 14:10:11 +01:00
import de.steamwar.bausystem.Permission ;
import de.steamwar.bausystem.world.Welt ;
2020-11-15 13:12:52 +01:00
import net.md_5.bungee.api.ChatMessageType ;
import net.md_5.bungee.api.chat.TextComponent ;
2020-11-15 19:35:32 +01:00
import net.minecraft.server.v1_15_R1.* ;
2020-11-15 13:12:52 +01:00
import org.bukkit.Bukkit ;
import org.bukkit.World ;
import org.bukkit.command.Command ;
import org.bukkit.command.CommandExecutor ;
import org.bukkit.command.CommandSender ;
2020-11-15 19:35:32 +01:00
import org.bukkit.craftbukkit.v1_15_R1.entity.CraftEntity ;
import org.bukkit.craftbukkit.v1_15_R1.entity.CraftPlayer ;
2020-11-15 21:54:06 +01:00
import org.bukkit.craftbukkit.v1_15_R1.entity.CraftTNTPrimed ;
2020-11-15 13:42:19 +01:00
import org.bukkit.entity.Entity ;
2020-11-15 13:12:52 +01:00
import org.bukkit.entity.Player ;
2020-11-16 13:39:29 +01:00
import org.bukkit.entity.TNTPrimed ;
2020-11-15 13:42:19 +01:00
import org.bukkit.scheduler.BukkitTask ;
2020-11-15 13:12:52 +01:00
2020-11-16 13:39:29 +01:00
import java.util.HashSet ;
2020-11-15 21:54:06 +01:00
import java.util.List ;
2020-11-16 13:39:29 +01:00
import java.util.Set ;
2020-11-15 21:54:06 +01:00
2020-11-15 13:12:52 +01:00
public class CommandTPSLimiter implements CommandExecutor {
private static int currentTPSLimit = 20 ;
private static World world = Bukkit . getWorlds ( ) . get ( 0 ) ;
2020-11-15 13:42:19 +01:00
private long lastTime = System . nanoTime ( ) ;
private long currentTime = System . nanoTime ( ) ;
2020-11-15 13:12:52 +01:00
2020-11-15 13:42:19 +01:00
private BukkitTask tpsLimiter = null ;
2020-11-15 13:12:52 +01:00
2020-11-15 13:42:19 +01:00
public CommandTPSLimiter ( ) {
2020-11-15 21:54:06 +01:00
ProtocolLibrary . getProtocolManager ( ) . addPacketListener ( new PacketAdapter ( BauSystem . getPlugin ( ) , PacketType . Play . Server . ENTITY_METADATA ) {
@Override
public void onPacketSending ( PacketEvent event ) {
2020-11-16 13:39:29 +01:00
if ( true ) return ;
2020-11-15 21:54:06 +01:00
// if (tpsLimiterNotActive()) return;
if ( event . getPacket ( ) . getEntityModifier ( world ) . read ( 0 ) = = null ) return ;
if ( ! ( event . getPacket ( ) . getEntityModifier ( world ) . read ( 0 ) instanceof CraftTNTPrimed ) ) return ;
2020-11-16 07:28:49 +01:00
System . out . println ( " ENTITY_METADATA: " + event . getPacket ( ) . getIntegers ( ) . read ( 0 ) ) ;
2020-11-15 21:54:06 +01:00
List < WrappedWatchableObject > dataWatcherObjectList = event . getPacket ( ) . getWatchableCollectionModifier ( ) . read ( 0 ) ;
2020-11-16 07:28:49 +01:00
// getByIndex(dataWatcherObjectList, 5).setValue(true);
2020-11-15 21:54:06 +01:00
getByIndex ( dataWatcherObjectList , 7 ) . setValue ( ( int ) ( ( 20 . 0 / currentTPSLimit ) * 80 ) ) ;
2020-11-16 07:28:49 +01:00
// System.out.println(dataWatcherObjectList);
2020-11-15 21:54:06 +01:00
event . getPacket ( ) . getWatchableCollectionModifier ( ) . write ( 0 , dataWatcherObjectList ) ;
}
} ) ;
ProtocolLibrary . getProtocolManager ( ) . addPacketListener ( new PacketAdapter ( BauSystem . getPlugin ( ) , PacketType . Play . Server . REL_ENTITY_MOVE ) {
@Override
public void onPacketSending ( PacketEvent event ) {
2020-11-16 13:39:29 +01:00
if ( true ) return ;
2020-11-15 21:54:06 +01:00
if ( tpsLimiterNotActive ( ) ) return ;
if ( event . getPacket ( ) . getEntityModifier ( world ) . read ( 0 ) = = null ) return ;
if ( ! ( event . getPacket ( ) . getEntityModifier ( world ) . read ( 0 ) instanceof CraftTNTPrimed ) ) return ;
2020-11-16 07:28:49 +01:00
System . out . println ( " REL_ENTITY_MOVE: " + event . getPacket ( ) . getIntegers ( ) . read ( 0 ) ) ;
2020-11-15 21:54:06 +01:00
StructureModifier < Integer > structureModifier = event . getPacket ( ) . getIntegers ( ) ;
// structureModifier.write(1, 0);
// structureModifier.write(2, 0);
// structureModifier.write(3, 0);
Entity entity = event . getPacket ( ) . getEntityModifier ( world ) . read ( 0 ) ;
2020-11-16 07:28:49 +01:00
// System.out.println(entity.getLocation());
2020-11-15 21:54:06 +01:00
net . minecraft . server . v1_15_R1 . Entity serverEntity = ( ( CraftEntity ) entity ) . getHandle ( ) ;
PacketPlayOutEntityTeleport packetPlayOutEntityTeleport = new PacketPlayOutEntityTeleport ( serverEntity ) ;
sendPlayers ( packetPlayOutEntityTeleport ) ;
PacketPlayOutEntityMetadata packetPlayOutEntityMetadata = new PacketPlayOutEntityMetadata ( serverEntity . getId ( ) , serverEntity . getDataWatcher ( ) , true ) ;
sendPlayers ( packetPlayOutEntityMetadata ) ;
Vec3D vec3D = serverEntity . getMot ( ) ;
2020-11-16 13:39:29 +01:00
/ * PacketPlayOutEntityVelocity packetPlayOutEntityVelocity = new PacketPlayOutEntityVelocity ( serverEntity . getId ( ) , new Vec3D ( vec3D . x / ( 20 . 0 / currentTPSLimit ) , vec3D . y / ( 20 . 0 / currentTPSLimit ) , vec3D . z / ( 20 . 0 / currentTPSLimit ) ) ) ;
sendPlayers ( packetPlayOutEntityVelocity ) ; * /
2020-11-15 21:54:06 +01:00
}
} ) ;
ProtocolLibrary . getProtocolManager ( ) . addPacketListener ( new PacketAdapter ( BauSystem . getPlugin ( ) , PacketType . Play . Server . ENTITY_VELOCITY ) {
2020-11-16 13:39:29 +01:00
private Set < Entity > entitySet = new HashSet < > ( ) ;
2020-11-15 21:54:06 +01:00
@Override
public void onPacketSending ( PacketEvent event ) {
2020-11-16 13:39:29 +01:00
if ( true ) return ;
if ( tpsLimiterNotActive ( ) ) return ;
if ( event . getPacket ( ) . getEntityModifier ( world ) . read ( 0 ) = = null ) return ;
if ( ! ( event . getPacket ( ) . getEntityModifier ( world ) . read ( 0 ) instanceof CraftTNTPrimed ) ) return ;
System . out . println ( " ENTITY_VELOCITY: " + event . getPacket ( ) . getIntegers ( ) . read ( 0 ) ) ;
2020-11-15 21:54:06 +01:00
2020-11-16 13:39:29 +01:00
System . out . println ( event . getPacket ( ) . getIntegers ( ) . getValues ( ) ) ;
// event.setCancelled(true);
Entity entity = event . getPacket ( ) . getEntityModifier ( world ) . read ( 0 ) ;
if ( entitySet . contains ( entity ) ) {
entitySet . remove ( entity ) ;
} else {
entitySet . add ( entity ) ;
event . setCancelled ( true ) ;
net . minecraft . server . v1_15_R1 . Entity serverEntity = ( ( CraftEntity ) entity ) . getHandle ( ) ;
Vec3D vec3D = serverEntity . getMot ( ) ;
PacketPlayOutEntityVelocity packetPlayOutEntityVelocity = new PacketPlayOutEntityVelocity ( serverEntity . getId ( ) , new Vec3D ( vec3D . x / ( 20 . 0 / currentTPSLimit ) , vec3D . y / ( 20 . 0 / currentTPSLimit ) , vec3D . z / ( 20 . 0 / currentTPSLimit ) ) ) ;
sendPlayers ( packetPlayOutEntityVelocity ) ;
}
// PacketContainer packetContainer = ProtocolLibrary.getProtocolManager().createPacket(PacketType.Play.Server.ENTITY_VELOCITY);
// StructureModifier<Integer> structureModifier = packetContainer.getIntegers();
// structureModifier.write(0, entity.getEntityId());
// structureModifier.write(1, (int) (serverEntity.getMot().x / (20.0 / currentTPSLimit) * 8000));
// structureModifier.write(2, (int) (serverEntity.getMot().y / (20.0 / currentTPSLimit) * 8000));
// structureModifier.write(3, (int) (serverEntity.getMot().z / (20.0 / currentTPSLimit) * 8000));
// event.setPacket(packetContainer);
// System.out.println(event.getPacket().getIntegers());
2020-11-15 15:55:34 +01:00
}
2020-11-15 21:54:06 +01:00
} ) ;
}
private boolean tpsLimiterNotActive ( ) {
return currentTPSLimit = = 20 ;
}
private void sendPlayers ( Packet < ? > packet ) {
Bukkit . getOnlinePlayers ( ) . forEach ( player - > {
PlayerConnection connection = ( ( CraftPlayer ) player ) . getHandle ( ) . playerConnection ;
connection . sendPacket ( packet ) ;
} ) ;
}
2020-11-16 13:39:29 +01:00
private void sendPlayers ( Set < ? extends Packet < ? > > packets ) {
Bukkit . getOnlinePlayers ( ) . forEach ( player - > {
PlayerConnection connection = ( ( CraftPlayer ) player ) . getHandle ( ) . playerConnection ;
for ( Packet < ? > p : packets ) {
connection . sendPacket ( p ) ;
}
} ) ;
}
2020-11-15 21:54:06 +01:00
private WrappedWatchableObject getByIndex ( List < WrappedWatchableObject > wrappedWatchableObjects , int index ) {
for ( WrappedWatchableObject wrappedWatchableObject : wrappedWatchableObjects ) {
if ( wrappedWatchableObject . getIndex ( ) = = index ) return wrappedWatchableObject ;
}
return null ;
2020-11-15 13:12:52 +01:00
}
2020-11-15 14:10:11 +01:00
private boolean permissionCheck ( Player player ) {
2020-11-15 15:55:34 +01:00
if ( Welt . noPermission ( player , Permission . world ) ) {
2020-11-15 14:10:11 +01:00
player . sendMessage ( BauSystem . PREFIX + " §cDu darfst hier nicht den TPS-Limiter nutzen " ) ;
return false ;
}
return true ;
}
2020-11-15 13:12:52 +01:00
@Override
public boolean onCommand ( CommandSender sender , Command command , String label , String [ ] args ) {
if ( ! ( sender instanceof Player ) ) {
return false ;
} else if ( args . length = = 0 ) {
sender . sendMessage ( BauSystem . PREFIX + " Jetziges TPS limit: " + currentTPSLimit ) ;
sender . sendMessage ( BauSystem . PREFIX + " Ändere das TPS limit mit: §8/§etpslimit §8[§7TPS§8|§edefault§8] " ) ;
return false ;
}
Player player = ( Player ) sender ;
2020-11-15 14:10:11 +01:00
// TODO: Remove on final push
// if (permissionCheck(player)) return false;
2020-11-15 13:12:52 +01:00
String tpsLimit = args [ 0 ] ;
if ( tpsLimit . equals ( " default " ) ) {
currentTPSLimit = 20 ;
2020-11-15 13:42:19 +01:00
sendNewTPSLimitMessage ( ) ;
tpsLimiter ( ) ;
2020-11-15 13:12:52 +01:00
return false ;
}
try {
int tpsLimitInt = Integer . parseInt ( tpsLimit ) ;
if ( tpsLimitInt < 1 | | tpsLimitInt > 20 ) {
sendInvalidArgumentMessage ( player ) ;
return false ;
}
currentTPSLimit = tpsLimitInt ;
2020-11-15 13:42:19 +01:00
sendNewTPSLimitMessage ( ) ;
tpsLimiter ( ) ;
2020-11-15 13:12:52 +01:00
} catch ( NumberFormatException e ) {
sendInvalidArgumentMessage ( player ) ;
}
return false ;
}
2020-11-15 13:42:19 +01:00
private void sendNewTPSLimitMessage ( ) {
2020-11-15 13:12:52 +01:00
Bukkit . getOnlinePlayers ( ) . forEach ( p - > p . spigot ( ) . sendMessage ( ChatMessageType . ACTION_BAR , TextComponent . fromLegacyText ( " §eTPS limit auf " + currentTPSLimit + " gesetzt. " ) ) ) ;
}
private void sendInvalidArgumentMessage ( Player player ) {
2020-11-15 13:42:19 +01:00
player . sendMessage ( BauSystem . PREFIX + " §cNur Zahlen zwischen 1 und 20, und 'default' erlaubt. " ) ;
}
private void tpsLimiter ( ) {
if ( currentTPSLimit = = 20 ) {
if ( tpsLimiter = = null ) return ;
tpsLimiter . cancel ( ) ;
tpsLimiter = null ;
} else {
if ( tpsLimiter ! = null ) return ;
tpsLimiter = Bukkit . getScheduler ( ) . runTaskTimer ( BauSystem . getPlugin ( ) , ( ) - > {
2020-11-16 13:39:29 +01:00
sendTntMetaData ( ) ;
2020-11-15 13:42:19 +01:00
2020-11-16 13:39:29 +01:00
for ( int i = 0 ; i < ( 20 / currentTPSLimit ) ; i + + ) {
sleepUntilNextTick ( ) ;
sendTntData ( ) ;
2020-11-15 13:42:19 +01:00
}
} , 0 , 1 ) ;
}
2020-11-15 13:12:52 +01:00
}
2020-11-16 13:39:29 +01:00
private void sleepUntilNextTick ( ) {
lastTime = currentTime ;
currentTime = System . nanoTime ( ) ;
long timeDelta = ( currentTime - lastTime ) / 1000000 ;
long neededDelta = 50 ;
if ( neededDelta - timeDelta < 0 ) {
return ;
}
try {
Thread . sleep ( neededDelta - timeDelta ) ;
currentTime = System . nanoTime ( ) ;
} catch ( InterruptedException e ) {
Thread . currentThread ( ) . interrupt ( ) ;
}
2020-11-15 13:12:52 +01:00
}
2020-11-16 13:39:29 +01:00
private void sendTntData ( ) {
Vec3D noMotion = new Vec3D ( 0 , 0 , 0 ) ;
Set < Packet < ? > > packets = new HashSet < > ( ) ;
2020-11-15 13:42:19 +01:00
2020-11-16 13:39:29 +01:00
world . getEntitiesByClasses ( TNTPrimed . class ) . forEach ( entity - > {
net . minecraft . server . v1_15_R1 . Entity serverEntity = ( ( CraftEntity ) entity ) . getHandle ( ) ;
packets . add ( new PacketPlayOutEntityTeleport ( serverEntity ) ) ;
packets . add ( new PacketPlayOutEntityVelocity ( serverEntity . getId ( ) , noMotion ) ) ;
} ) ;
sendPlayers ( packets ) ;
}
private void sendTntMetaData ( ) {
world . getEntitiesByClasses ( TNTPrimed . class ) . forEach ( entity - > {
net . minecraft . server . v1_15_R1 . Entity serverEntity = ( ( CraftEntity ) entity ) . getHandle ( ) ;
PacketPlayOutEntityMetadata packetPlayOutEntityMetadata = new PacketPlayOutEntityMetadata ( serverEntity . getId ( ) , serverEntity . getDataWatcher ( ) , true ) ;
sendPlayers ( packetPlayOutEntityMetadata ) ;
} ) ;
}
public static int getCurrentTPSLimit ( ) {
return currentTPSLimit ;
2020-11-15 13:42:19 +01:00
}
2020-11-15 13:12:52 +01:00
}