Lixfel
9eefaf9e6b
Alle Prüfungen waren erfolgreich
SteamWarCI Build successful
Signed-off-by: Lixfel <agga-games@gmx.de>
562 Zeilen
19 KiB
Java
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;
|
|
}
|
|
}
|