SteamWar/FightSystem
Archiviert
13
1
Dieses Repository wurde am 2024-08-05 archiviert. Du kannst Dateien ansehen und es klonen, aber nicht pushen oder Issues/Pull-Requests öffnen.
FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/record/PacketProcessor.java
Lixfel 9eefaf9e6b
Alle Prüfungen waren erfolgreich
SteamWarCI Build successful
Full multiling
Signed-off-by: Lixfel <agga-games@gmx.de>
2021-10-24 15:04:12 +02:00

562 Zeilen
19 KiB
Java

/*
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/>.
*/
package de.steamwar.fightsystem.record;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
import de.steamwar.core.Core;
import de.steamwar.fightsystem.ArenaMode;
import de.steamwar.fightsystem.Config;
import de.steamwar.fightsystem.FightSystem;
import de.steamwar.fightsystem.countdown.Countdown;
import de.steamwar.fightsystem.countdown.EventSpectateCountdown;
import de.steamwar.fightsystem.fight.Fight;
import de.steamwar.fightsystem.fight.FightTeam;
import de.steamwar.fightsystem.fight.FreezeWorld;
import de.steamwar.fightsystem.listener.FightScoreboard;
import de.steamwar.fightsystem.states.FightState;
import de.steamwar.fightsystem.utils.*;
import de.steamwar.sql.Schematic;
import de.steamwar.sql.Team;
import net.md_5.bungee.api.ChatMessageType;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.chat.TextComponent;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Sound;
import org.bukkit.World;
import org.bukkit.entity.EntityType;
import org.bukkit.scheduler.BukkitTask;
import java.io.EOFException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
public class PacketProcessor {
static boolean replaying = false;
public static boolean isReplaying(){
return replaying;
}
private static final World world = Bukkit.getWorlds().get(0);
private final PacketParser[] packetDecoder = new PacketParser[256];
private final PacketSource source;
private final BukkitTask task;
private final LinkedList<Runnable> syncList = new LinkedList<>();
private final Set<Integer> hiddenBlockIds = BlockIdWrapper.impl.getHiddenBlockIds();
private final int obfuscateWith = BlockIdWrapper.impl.getObfuscateWith();
private final FreezeWorld freezer = new FreezeWorld();
private boolean rotateZ = false;
private int arenaMinX = Config.ArenaRegion.getMinX();
private int arenaMinY = Config.BluePasteRegion.getMinY();
private int arenaMinZ = Config.ArenaRegion.getMinZ();
private boolean tickFinished = false;
public PacketProcessor(PacketSource source){
this.source = source;
replaying = true;
packetDecoder[0x00] = this::playerJoins;
packetDecoder[0x01] = this::entityMoves;
packetDecoder[0x02] = this::entityDespawns;
packetDecoder[0x03] = this::entitySneak;
packetDecoder[0x04] = this::entityAnimation;
packetDecoder[0x05] = this::tntSpawn;
packetDecoder[0x06] = this::entityVelocity;
packetDecoder[0x07] = this::playerItem;
packetDecoder[0x08] = this::arrowSpawn;
packetDecoder[0x09] = this::fireballSpawn;
packetDecoder[0x0a] = this::bow;
packetDecoder[0x0b] = this::damage;
packetDecoder[0x0c] = this::fireTick;
packetDecoder[0x20] = this::arenaInfo;
packetDecoder[0x30] = this::block;
packetDecoder[0x31] = this::particle;
packetDecoder[0x32] = this::sound;
packetDecoder[0x33] = this::shortBlock;
packetDecoder[0x34] = this::soundAtPlayer;
packetDecoder[0x35] = this::shortRelativeBlock;
packetDecoder[0xa0] = () -> send(ChatMessageType.CHAT);
packetDecoder[0xa1] = () -> send(ChatMessageType.ACTION_BAR);
packetDecoder[0xa2] = () -> send(ChatMessageType.SYSTEM);
packetDecoder[0xa3] = this::countdown;
packetDecoder[0xa4] = this::chat;
packetDecoder[0xa5] = this::system;
packetDecoder[0xb0] = () -> pasteSchem(Fight.getBlueTeam());
packetDecoder[0xb1] = () -> pasteSchem(Fight.getRedTeam());
packetDecoder[0xb2] = this::teams;
packetDecoder[0xb3] = () -> pasteEmbeddedSchem(Fight.getBlueTeam());
packetDecoder[0xb4] = () -> pasteEmbeddedSchem(Fight.getRedTeam());
packetDecoder[0xc0] = this::scoreboardTitle;
packetDecoder[0xc1] = this::scoreboardData;
packetDecoder[0xc2] = this::bossBar;
packetDecoder[0xc3] = this::subtitle;
packetDecoder[0xc4] = this::printWin;
packetDecoder[0xc5] = this::messageSubtitle;
packetDecoder[0xc6] = this::winMessage;
packetDecoder[0xc7] = this::bossBarMessage;
packetDecoder[0xef] = source::readUTF;
packetDecoder[0xff] = this::tick;
if(source.async()) {
Bukkit.getScheduler().runTaskAsynchronously(FightSystem.getPlugin(), this::process);
task = Bukkit.getScheduler().runTaskTimer(FightSystem.getPlugin(), this::runSync, 1, 1);
}else
task = Bukkit.getScheduler().runTaskTimer(FightSystem.getPlugin(), this::process, 1, 1);
}
private void winMessage() throws IOException {
byte team = source.readByte();
Message message = readMessage();
execSync(() -> {
FightTeam winner = null;
if(team == 0x01)
winner = Fight.getBlueTeam();
else if(team == 0x02)
winner = Fight.getRedTeam();
if(Config.replayserver() || ArenaMode.AntiReplay.contains(Config.mode)) {
FightSystem.setSpectateState(winner, "Replay ends", message.getMsg(), message.getParams());
}else{
FightUI.printWin(winner, message.getMsg(), message.getParams());
new EventSpectateCountdown().enable();
}
});
}
private void system() throws IOException {
Message message = readMessage();
FightSystem.getMessage().broadcast(message.getMsg(), message.getParams());
}
private void messageSubtitle() throws IOException {
Message message = readMessage();
FightUI.addSubtitle(message.getMsg(), message.getParams());
}
private void chat() throws IOException {
Message message = readMessage();
FightSystem.getMessage().chat(message.getMsg(), message.getParams());
}
private void runSync() {
synchronized (syncList) {
for(Runnable runnable : syncList) {
try{
runnable.run();
}catch (Exception e) {
Bukkit.getLogger().log(Level.WARNING, "Failed to execute packet", e);
}
}
syncList.clear();
}
}
private void execSync(Runnable runnable){
if (!source.async()) {
runnable.run();
return;
}
synchronized (syncList) {
syncList.add(runnable);
}
}
private void playerJoins() throws IOException {
int entityId = source.readInt();
int userId = source.readInt();
execSync(() -> new REntity(entityId, userId));
}
private void entityMoves() throws IOException {
int entityId = source.readInt();
double locX = source.readDouble() - arenaMinX + Config.ArenaRegion.getMinX();
double locY = source.readDouble() - arenaMinY + Config.BluePasteRegion.getMinY();
double z = source.readDouble() - arenaMinZ;
if(rotateZ)
z = Config.ArenaRegion.getSizeZ() - z;
double locZ = z + Config.ArenaRegion.getMinZ();
float pitch = source.readFloat();
float yaw = source.readFloat() + (rotateZ ? 360 : 0);
byte headYaw = (byte)((source.readByte() + (rotateZ ? 128 : 0)) % 256);
execSync(() -> REntity.getEntity(entityId).move(locX, locY, locZ, pitch, yaw, headYaw));
}
private void entityDespawns() throws IOException {
int entityId = source.readInt();
execSync(() -> REntity.getEntity(entityId).die());
}
private void entitySneak() throws IOException {
int entityId = source.readInt();
boolean sneaking = source.readBoolean();
execSync(() -> REntity.getEntity(entityId).sneak(sneaking));
}
private void entityAnimation() throws IOException {
int entityId = source.readInt();
byte animation = source.readByte();
execSync(() -> REntity.getEntity(entityId).animation(animation));
}
private void tntSpawn() throws IOException {
int entityId = source.readInt();
execSync(() -> new REntity(entityId, EntityType.PRIMED_TNT));
}
private void entityVelocity() throws IOException {
int entityId = source.readInt();
double dX = source.readDouble();
double dY = source.readDouble();
double dZ = rotateZ ? -source.readDouble() : source.readDouble();
execSync(() -> {
REntity entity = REntity.getEntity(entityId);
if(entity != null)
entity.setVelocity(dX, dY, dZ);
});
}
private void playerItem() throws IOException {
int entityId = source.readInt();
String item = source.readUTF();
boolean enchanted = source.readBoolean();
String slot = source.readUTF();
execSync(() -> REntity.getEntity(entityId).setItem(item, enchanted, slot));
}
private void arrowSpawn() throws IOException {
int entityId = source.readInt();
execSync(() -> new REntity(entityId, EntityType.ARROW));
}
private void fireballSpawn() throws IOException {
int entityId = source.readInt();
execSync(() -> new REntity(entityId, EntityType.FIREBALL));
}
private void send(ChatMessageType type) throws IOException {
String message = source.readUTF();
BaseComponent[] text = TextComponent.fromLegacyText(message);
Bukkit.getOnlinePlayers().forEach(p -> de.steamwar.core.BountifulWrapper.impl.sendMessage(p, type, text));
}
private void countdown() throws IOException {
String message = source.readUTF();
int displaytime = source.readInt();
Message appendix = readMessage();
Bukkit.getOnlinePlayers().forEach(p -> Countdown.sendCountdownMessage(p, message, displaytime, appendix));
}
private void arenaInfo() throws IOException {
rotateZ = source.readBoolean() != Config.blueNegZ();
arenaMinY = Byte.toUnsignedInt(source.readByte());
arenaMinX = source.readInt();
arenaMinZ = source.readInt();
}
private void shortBlock() throws IOException {
int x = Byte.toUnsignedInt(source.readByte()) + Config.ArenaRegion.getMinX();
int y = Byte.toUnsignedInt(source.readByte());
int z = Byte.toUnsignedInt(source.readByte()) + Config.ArenaRegion.getMinZ();
int blockState = source.readShort();
setBlock(x, y, z, blockState);
}
private void shortRelativeBlock() throws IOException {
int x = Byte.toUnsignedInt(source.readByte());
int y = Byte.toUnsignedInt(source.readByte());
int z = Byte.toUnsignedInt(source.readByte());
int blockState = source.readShort();
if(rotateZ)
z = Config.ArenaRegion.getSizeZ() - z;
setBlock(x + Config.ArenaRegion.getMinX(), y + Config.BluePasteRegion.getMinY(), z + Config.ArenaRegion.getMinZ(), blockState);
}
private void block() throws IOException {
int x = source.readInt() - arenaMinX;
int y = Byte.toUnsignedInt(source.readByte()) - arenaMinY;
int z = source.readInt() - arenaMinZ;
int blockState = source.readInt();
if(rotateZ)
z = Config.ArenaRegion.getSizeZ() - z;
setBlock(x + Config.ArenaRegion.getMinX(), y + Config.BluePasteRegion.getMinY(), z + Config.ArenaRegion.getMinZ(), blockState);
}
private void setBlock(int x, int y, int z, int blockState){
if(!Config.ArenaRegion.in2dRegion(x, z))
return; //Outside of the arena
execSync(() -> BlockIdWrapper.impl.setBlock(world, x, y, z, TechHider.ENABLED && hiddenBlockIds.contains(blockState) ? obfuscateWith : blockState));
}
private void particle() throws IOException {
double x = source.readDouble();
double y = source.readDouble();
double z = source.readDouble();
String particleName = source.readUTF();
execSync(() -> BountifulWrapper.impl.spawnParticle(world, particleName, x, y, z));
}
private void sound() throws IOException {
int x = source.readInt();
int y = source.readInt();
int z = source.readInt();
String soundName = source.readUTF();
String soundCategory = source.readUTF();
float volume = source.readFloat();
float pitch = source.readFloat();
Sound sound = Sound.valueOf(soundName);
execSync(() -> WorldOfColorWrapper.impl.playSound(new Location(world, x, y, z), sound, soundCategory, volume, pitch));
}
private void soundAtPlayer() throws IOException {
String soundName = source.readUTF();
float volume = source.readFloat();
float pitch = source.readFloat();
Sound sound = Sound.valueOf(soundName);
execSync(() -> Fight.playSound(sound, volume, pitch));
}
private void pasteSchem(FightTeam team) throws IOException {
int schemId = source.readInt();
execSync(() -> team.pasteSchem(Schematic.getSchemFromDB(schemId)));
}
private void pasteEmbeddedSchem(FightTeam team) throws IOException {
int schemId = source.readInt();
Clipboard clipboard = Schematic.clipboardFromStream(source, Core.getVersion() > 12);
execSync(() -> team.pasteSchem(schemId, clipboard));
}
private void teams() throws IOException {
int blueId = source.readInt();
int redId = source.readInt();
execSync(() -> {
pasteForTeam(blueId, Fight.getBlueTeam());
pasteForTeam(redId, Fight.getRedTeam());
});
}
private void pasteForTeam(int teamId, FightTeam fightTeam){
Team team = Team.get(teamId);
fightTeam.setPrefixAndName("§" + team.getTeamColor(), team.getTeamKuerzel());
fightTeam.pasteTeamName();
}
private void scoreboardTitle() throws IOException {
String title = source.readUTF();
FightScoreboard.getScoreboard().setTitle(title);
}
private void scoreboardData() throws IOException {
String key = source.readUTF();
int value = source.readInt();
FightScoreboard.getScoreboard().addScore(key, value);
}
private void bossBar() throws IOException {
double leftBlueProgress = source.readDouble();
double leftRedProgress = source.readDouble();
String leftBlueText = source.readUTF();
String leftRedText = source.readUTF();
FightUI.getInstance().setBossbar(leftBlueProgress, leftRedProgress, leftBlueText, leftRedText);
}
private void bossBarMessage() throws IOException {
double leftBlueProgress = source.readDouble();
double leftRedProgress = source.readDouble();
Message leftBlueText = readMessage();
Message leftRedText = readMessage();
FightUI.getInstance().setBossbar(leftBlueProgress, leftRedProgress, leftBlueText, leftRedText);
}
private void subtitle() throws IOException {
String subtitle = source.readUTF();
FightUI.addSubtitle("OLD_STRING", subtitle);
}
private void printWin() throws IOException {
String title = source.readUTF();
String subtitle = source.readUTF();
Bukkit.getOnlinePlayers().forEach(p -> {
p.resetTitle();
WorldOfColorWrapper.impl.sendTitle(p, title, subtitle, 5, 40, 5);
});
if(Config.replayserver() || ArenaMode.AntiReplay.contains(Config.mode)) {
FightState.setFightState(FightState.SPECTATE);
}else{
new EventSpectateCountdown().enable();
}
}
private void endReplay() {
REntity.dieAll();
freezer.disable();
FightSystem.getMessage().broadcast("REPLAY_ENDS");
replaying = false;
}
private void bow() throws IOException {
int entityId = source.readInt();
boolean drawn = source.readBoolean();
boolean offHand = source.readBoolean();
execSync(() -> REntity.getEntity(entityId).setBowDrawn(drawn, offHand));
}
private void damage() throws IOException {
int entityId = source.readInt();
execSync(() -> REntity.getEntity(entityId).damage());
}
private void fireTick() throws IOException {
int entityId = source.readInt();
boolean perma = source.readBoolean();
execSync(() -> REntity.getEntity(entityId).setOnFire(perma));
}
private void tick(){
execSync(REntity::tickFire);
if(!source.async())
tickFinished = true;
}
private void process(){
tickFinished = false;
try{
while(!source.isClosed() && !tickFinished){
int packetType = Byte.toUnsignedInt(source.readByte());
PacketParser parser = packetDecoder[packetType];
if(parser != null){
parser.process();
}else{
Bukkit.getLogger().log(Level.SEVERE, "Unknown packet " + packetType + " recieved, closing.");
source.close();
}
}
} catch (EOFException e) {
Bukkit.getLogger().log(Level.INFO, "The FightServer is offline");
source.close();
} catch(IOException e) {
Bukkit.getLogger().log(Level.WARNING, "Could not recieve packet", e);
source.close();
}
if(source.isClosed()){
Bukkit.getScheduler().runTask(FightSystem.getPlugin(), this::endReplay);
task.cancel();
}
}
private Message readMessage() throws IOException {
String msg = source.readUTF();
List<Object> params = new ArrayList<>();
int type;
do {
type = Byte.toUnsignedInt(source.readByte());
switch(type) {
case 0x00:
break;
case 0x01:
params.add(source.readBoolean());
break;
case 0x02:
params.add(source.readByte());
break;
case 0x03:
params.add(source.readShort());
break;
case 0x04:
params.add(source.readInt());
break;
case 0x05:
params.add(source.readFloat());
break;
case 0x06:
params.add(source.readDouble());
break;
case 0x07:
params.add(source.readUTF());
break;
case 0x08:
params.add(readMessage());
break;
default:
throw new IOException("Unknown message param type " + type);
}
} while(type != 0x00);
return new Message(msg, params.toArray());
}
private interface PacketParser{
void process() throws IOException;
}
}