diff --git a/FightSystem_14/src/de/steamwar/fightsystem/fight/FightTeam_14.java b/FightSystem_14/src/de/steamwar/fightsystem/fight/FightTeam_14.java index d648d9b..38b0170 100644 --- a/FightSystem_14/src/de/steamwar/fightsystem/fight/FightTeam_14.java +++ b/FightSystem_14/src/de/steamwar/fightsystem/fight/FightTeam_14.java @@ -19,6 +19,7 @@ package de.steamwar.fightsystem.fight; +import com.sk89q.jnbt.NBTInputStream; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; @@ -27,6 +28,7 @@ import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.extent.clipboard.io.BuiltInClipboardFormat; import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter; +import com.sk89q.worldedit.extent.clipboard.io.SpongeSchematicReader; import com.sk89q.worldedit.function.operation.ForwardExtentCopy; import com.sk89q.worldedit.function.operation.Operations; import com.sk89q.worldedit.math.BlockVector3; @@ -38,7 +40,6 @@ import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockTypes; import de.steamwar.fightsystem.Config; import de.steamwar.fightsystem.utils.Region; -import de.steamwar.sql.NoClipboardException; import de.steamwar.sql.Schematic; import org.bukkit.Bukkit; import org.bukkit.ChatColor; @@ -102,7 +103,7 @@ public class FightTeam_14 { } } - static void pasteSchematic(Clipboard clipboard, Region region, boolean rotate) throws NoClipboardException { + static void pasteSchematic(Clipboard clipboard, Region region, boolean rotate) { BlockVector3 paste = BlockVector3.at(region.centerX(), region.getMinY(), region.centerZ()); World w = new BukkitWorld(Bukkit.getWorlds().get(0)); @@ -134,6 +135,23 @@ public class FightTeam_14 { e.flushSession(); } + static void pasteChar(Clipboard character, int charOffset, int length, int x, int y, int z, AffineTransform aT){ + BlockVector3 offset = character.getRegion().getMinimumPoint().subtract(character.getOrigin()); + BlockVector3 v = BlockVector3.ZERO.subtract(- charOffset + length / 2, 0, 0).subtract(offset); + v = aT.apply(v.toVector3()).toBlockPoint(); + v = v.add(x, y, z); + + EditSession e = WorldEdit.getInstance().getEditSessionFactory().getEditSession(new BukkitWorld(Bukkit.getWorlds().get(0)), -1); + ClipboardHolder ch = new ClipboardHolder(character); + ch.setTransform(aT); + Operations.completeBlindly(ch.createPaste(e).to(v).ignoreAirBlocks(true).build()); + e.flushSession(); + } + + static Clipboard loadSchem(NBTInputStream stream) throws IOException { + return new SpongeSchematicReader(stream).read(); + } + public static boolean checkPistonMoving(Block block){ return block.getType() == Material.MOVING_PISTON; } diff --git a/FightSystem_14/src/de/steamwar/fightsystem/record/RecordSystem_14.java b/FightSystem_14/src/de/steamwar/fightsystem/record/RecordSystem_14.java new file mode 100644 index 0000000..5e65cb4 --- /dev/null +++ b/FightSystem_14/src/de/steamwar/fightsystem/record/RecordSystem_14.java @@ -0,0 +1,52 @@ +/* + 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 . +*/ + +package de.steamwar.fightsystem.record; + +import net.minecraft.server.v1_14_R1.BlockPosition; +import net.minecraft.server.v1_14_R1.EntityPose; +import net.minecraft.server.v1_14_R1.IBlockData; +import net.minecraft.server.v1_14_R1.WorldServer; +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.craftbukkit.v1_14_R1.CraftWorld; +import org.bukkit.craftbukkit.v1_14_R1.block.CraftBlock; + +import java.util.Objects; + +public class RecordSystem_14 { + private RecordSystem_14(){} + + static int blockToId(Block block){ + return net.minecraft.server.v1_14_R1.Block.REGISTRY_ID.getId(((CraftBlock)block).getNMS()); + } + + static Object getPose(boolean sneaking){ + return sneaking ? EntityPose.SNEAKING : EntityPose.STANDING; + } + + static void setBlock(World world, int x, int y, int z, int blockState){ + IBlockData blockData = Objects.requireNonNull(net.minecraft.server.v1_14_R1.Block.REGISTRY_ID.fromId(blockState)); + WorldServer cworld = ((CraftWorld)world).getHandle(); + BlockPosition pos = new BlockPosition(x, y, z); + cworld.removeTileEntity(pos); + cworld.setTypeAndData(pos, blockData, 1042); + cworld.getChunkProvider().flagDirty(pos); + } +} diff --git a/FightSystem_15/src/de/steamwar/fightsystem/record/RecordSystem_15.java b/FightSystem_15/src/de/steamwar/fightsystem/record/RecordSystem_15.java index 6d1a1e3..db63363 100644 --- a/FightSystem_15/src/de/steamwar/fightsystem/record/RecordSystem_15.java +++ b/FightSystem_15/src/de/steamwar/fightsystem/record/RecordSystem_15.java @@ -19,13 +19,34 @@ package de.steamwar.fightsystem.record; +import net.minecraft.server.v1_15_R1.BlockPosition; +import net.minecraft.server.v1_15_R1.EntityPose; +import net.minecraft.server.v1_15_R1.IBlockData; +import net.minecraft.server.v1_15_R1.WorldServer; +import org.bukkit.World; import org.bukkit.block.Block; +import org.bukkit.craftbukkit.v1_15_R1.CraftWorld; import org.bukkit.craftbukkit.v1_15_R1.block.CraftBlock; +import java.util.Objects; + class RecordSystem_15 { private RecordSystem_15(){} static int blockToId(Block block){ return net.minecraft.server.v1_15_R1.Block.REGISTRY_ID.getId(((CraftBlock)block).getNMS()); } + + static Object getPose(boolean sneaking){ + return sneaking ? EntityPose.CROUCHING : EntityPose.STANDING; + } + + static void setBlock(World world, int x, int y, int z, int blockState){ + IBlockData blockData = Objects.requireNonNull(net.minecraft.server.v1_15_R1.Block.REGISTRY_ID.fromId(blockState)); + WorldServer cworld = ((CraftWorld)world).getHandle(); + BlockPosition pos = new BlockPosition(x, y, z); + cworld.removeTileEntity(pos); + cworld.setTypeAndData(pos, blockData, 1042); + cworld.getChunkProvider().flagDirty(pos); + } } diff --git a/FightSystem_8/src/de/steamwar/fightsystem/fight/FightTeam_8.java b/FightSystem_8/src/de/steamwar/fightsystem/fight/FightTeam_8.java index 2894747..f62cb60 100644 --- a/FightSystem_8/src/de/steamwar/fightsystem/fight/FightTeam_8.java +++ b/FightSystem_8/src/de/steamwar/fightsystem/fight/FightTeam_8.java @@ -19,6 +19,7 @@ package de.steamwar.fightsystem.fight; +import com.sk89q.jnbt.NBTInputStream; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.WorldEdit; @@ -29,6 +30,7 @@ import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat; import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter; +import com.sk89q.worldedit.extent.clipboard.io.SchematicReader; import com.sk89q.worldedit.function.operation.ForwardExtentCopy; import com.sk89q.worldedit.function.operation.Operations; import com.sk89q.worldedit.math.transform.AffineTransform; @@ -37,7 +39,6 @@ import com.sk89q.worldedit.session.ClipboardHolder; import com.sk89q.worldedit.world.World; import de.steamwar.fightsystem.Config; import de.steamwar.fightsystem.utils.Region; -import de.steamwar.sql.NoClipboardException; import de.steamwar.sql.Schematic; import org.bukkit.Bukkit; import org.bukkit.ChatColor; @@ -99,7 +100,7 @@ public class FightTeam_8 { } } - static void pasteSchematic(Clipboard clipboard, Region paste, boolean rotate) throws NoClipboardException { + static void pasteSchematic(Clipboard clipboard, Region paste, boolean rotate) { World w = new BukkitWorld(Bukkit.getWorlds().get(0)); Vector dimensions = clipboard.getDimensions(); Vector v = new Vector(paste.centerX(), paste.getMinY(), paste.centerZ()); @@ -129,6 +130,24 @@ public class FightTeam_8 { e.flushQueue(); } + static void pasteChar(Clipboard character, int charOffset, int length, int x, int y, int z, AffineTransform aT){ + World w = new BukkitWorld(Bukkit.getWorlds().get(0)); + Vector offset = character.getRegion().getMinimumPoint().subtract(character.getOrigin()); + Vector v = Vector.ZERO.subtract(- charOffset + length / 2, 0, 0).subtract(offset); + v = aT.apply(v).toBlockPoint(); + v = v.add(x, y, z); + + EditSession e = WorldEdit.getInstance().getEditSessionFactory().getEditSession(w, -1); + ClipboardHolder ch = new ClipboardHolder(character, w.getWorldData()); + ch.setTransform(aT); + Operations.completeBlindly(ch.createPaste(e, w.getWorldData()).to(v).build()); + e.flushQueue(); + } + + static Clipboard loadSchem(NBTInputStream stream) throws IOException { + return new SchematicReader(stream).read(new BukkitWorld(Bukkit.getWorlds().get(0)).getWorldData()); + } + public static boolean checkPistonMoving(Block block){ return block.getType() == Material.PISTON_MOVING_PIECE; } diff --git a/FightSystem_8/src/de/steamwar/fightsystem/record/RecordSystem_8.java b/FightSystem_8/src/de/steamwar/fightsystem/record/RecordSystem_8.java index 207a3fd..19dfa53 100644 --- a/FightSystem_8/src/de/steamwar/fightsystem/record/RecordSystem_8.java +++ b/FightSystem_8/src/de/steamwar/fightsystem/record/RecordSystem_8.java @@ -19,13 +19,18 @@ package de.steamwar.fightsystem.record; +import org.bukkit.World; import org.bukkit.block.Block; +@SuppressWarnings("deprecation") class RecordSystem_8 { private RecordSystem_8(){} - @SuppressWarnings("deprecation") static int blockToId(Block block){ return block.getTypeId() << 4 + block.getData(); } + + static void setBlock(World world, int x, int y, int z, int blockState){ + world.getBlockAt(x, y, z).setTypeIdAndData(blockState >> 4, (byte)(blockState & 0b1111), false); + } } diff --git a/FightSystem_API/src/de/steamwar/fightsystem/ArenaMode.java b/FightSystem_API/src/de/steamwar/fightsystem/ArenaMode.java index 70edcef..a3a5fee 100644 --- a/FightSystem_API/src/de/steamwar/fightsystem/ArenaMode.java +++ b/FightSystem_API/src/de/steamwar/fightsystem/ArenaMode.java @@ -29,7 +29,8 @@ public enum ArenaMode { EVENT, TEST, CHECK, - PREPARE; + PREPARE, + REPLAY; public static final Set All = Collections.unmodifiableSet(EnumSet.allOf(ArenaMode.class)); @@ -39,14 +40,16 @@ public enum ArenaMode { public static final Set Test = Collections.unmodifiableSet(EnumSet.of(TEST, CHECK)); public static final Set Ranked = Collections.unmodifiableSet(EnumSet.of(RANKED)); public static final Set Prepare = Collections.unmodifiableSet(EnumSet.of(PREPARE)); + public static final Set Replay = Collections.unmodifiableSet(EnumSet.of(REPLAY)); + public static final Set AntiReplay = Collections.unmodifiableSet(EnumSet.complementOf(EnumSet.of(REPLAY))); + public static final Set Replayable = Collections.unmodifiableSet(EnumSet.of(REPLAY, TEST)); public static final Set AntiTest = Collections.unmodifiableSet(EnumSet.complementOf(EnumSet.of(TEST, CHECK))); public static final Set AntiEvent = Collections.unmodifiableSet(EnumSet.complementOf(EnumSet.of(EVENT))); public static final Set AntiPrepare = Collections.unmodifiableSet(EnumSet.complementOf(EnumSet.of(PREPARE))); - public static final Set VariableTeams = Collections.unmodifiableSet(EnumSet.complementOf(EnumSet.of(RANKED, EVENT))); - public static final Set RankedEvent = Collections.unmodifiableSet(EnumSet.of(RANKED, EVENT)); - public static final Set Restartable = Collections.unmodifiableSet(EnumSet.of(NORMAL, RANKED)); - public static final Set Fight = Collections.unmodifiableSet(EnumSet.of(NORMAL, RANKED, EVENT)); + public static final Set VariableTeams = Collections.unmodifiableSet(EnumSet.complementOf(EnumSet.of(RANKED, EVENT, REPLAY))); + public static final Set RankedEvent = Collections.unmodifiableSet(EnumSet.of(RANKED, EVENT, REPLAY)); + public static final Set Restartable = Collections.unmodifiableSet(EnumSet.of(NORMAL, RANKED, REPLAY)); public static final Set SoloLeader = Collections.unmodifiableSet(EnumSet.of(TEST, CHECK, PREPARE)); - public static final Set NotOnBau = Collections.unmodifiableSet(EnumSet.complementOf(EnumSet.of(TEST, CHECK, PREPARE))); + public static final Set NotOnBau = Collections.unmodifiableSet(EnumSet.complementOf(EnumSet.of(TEST, CHECK, PREPARE, REPLAY))); } diff --git a/FightSystem_API/src/de/steamwar/fightsystem/Config.java b/FightSystem_API/src/de/steamwar/fightsystem/Config.java index 1fcf4e8..2837356 100644 --- a/FightSystem_API/src/de/steamwar/fightsystem/Config.java +++ b/FightSystem_API/src/de/steamwar/fightsystem/Config.java @@ -63,7 +63,7 @@ public class Config { private static final int BlueToRedX; private static final int BlueToRedY; - public static final int BlueToRedZ; + private static final int BlueToRedZ; public static final int PreperationArea; public static final int WaterDepth; @@ -118,7 +118,7 @@ public class Config { public static final int EventTeamRedID; public static final boolean BothTeamsPublic; public static final int MaximumTeamMembers; - public static final boolean SpectateSystem; + public static final boolean LiveReplay; //check parameter public static final int CheckSchemID; @@ -126,9 +126,10 @@ public class Config { public static final ArenaMode mode; - //live recorder parameter + //replay system parameter public static final String spectateIP = "127.0.0.1"; public static final int spectatePort = 2222; + public static final int ReplayID; static{ if(!new File(IFightSystem.getPlugin().getDataFolder(), System.getProperty("config", "config.yml")).exists()) { @@ -335,7 +336,7 @@ public class Config { OnlyPublicSchematics = event.publicSchemsOnly(); MaximumTeamMembers = event.getMaximumTeamMembers(); } - SpectateSystem = event.spectateSystem(); + LiveReplay = event.spectateSystem(); }else{ //No event TeamRedColor = config.getString("Output.TeamRedPrefix"); @@ -347,7 +348,7 @@ public class Config { EventTeamRedID = 0; BothTeamsPublic = true; MaximumTeamMembers = Integer.MAX_VALUE; - SpectateSystem = false; + LiveReplay = false; } String blueLeader = System.getProperty("blueLeader", null); @@ -364,6 +365,7 @@ public class Config { CheckSchemID = Integer.parseInt(System.getProperty("checkSchemID", "0")); PrepareSchemID = Integer.parseInt(System.getProperty("prepareSchemID", "0")); Ranked = Boolean.parseBoolean(System.getProperty("ranked", "false")); + ReplayID = Integer.parseInt(System.getProperty("replay", "0")); if(Ranked){ mode = ArenaMode.RANKED; @@ -375,6 +377,8 @@ public class Config { mode = ArenaMode.EVENT; }else if(EventKampfID == -1){ mode = ArenaMode.TEST; + }else if(ReplayID != 0){ + mode = ArenaMode.REPLAY; }else{ mode = ArenaMode.NORMAL; } @@ -383,7 +387,10 @@ public class Config { public static boolean test(){ return ArenaMode.Test.contains(mode); } - public static boolean recording(){ - return mode == ArenaMode.EVENT; + public static boolean replayserver(){ + return ReplayID == -1; + } + public static boolean blueNegZ(){ + return BlueToRedZ > 0; } } diff --git a/FightSystem_API/src/de/steamwar/fightsystem/fight/IFight.java b/FightSystem_API/src/de/steamwar/fightsystem/fight/IFight.java index dc15ff5..1c44e1a 100644 --- a/FightSystem_API/src/de/steamwar/fightsystem/fight/IFight.java +++ b/FightSystem_API/src/de/steamwar/fightsystem/fight/IFight.java @@ -27,7 +27,7 @@ public class IFight { private static IFightTeam redTeam; private static IFightTeam blueTeam; - static void init(IFightTeam redTeam, IFightTeam blueTeam){ + public static void init(IFightTeam redTeam, IFightTeam blueTeam){ IFight.redTeam = redTeam; IFight.blueTeam = blueTeam; } diff --git a/FightSystem_API/src/de/steamwar/fightsystem/utils/Region.java b/FightSystem_API/src/de/steamwar/fightsystem/utils/Region.java index a4f9953..4f38486 100644 --- a/FightSystem_API/src/de/steamwar/fightsystem/utils/Region.java +++ b/FightSystem_API/src/de/steamwar/fightsystem/utils/Region.java @@ -71,6 +71,10 @@ public class Region { return maxZ; } + public int getSizeZ() { + return maxZ - minZ; + } + public double posToChunk(int pos){ return pos / 16.0; } @@ -137,7 +141,11 @@ public class Region { } public boolean in2dRegion(Block block){ - return minX <= block.getX() && block.getX() < maxX && minZ <= block.getZ() && block.getZ() <= maxZ; + return in2dRegion(block.getX(), block.getZ()); + } + + public boolean in2dRegion(int x, int z) { + return minX <= x && x < maxX && minZ <= z && z <= maxZ; } public boolean inRegion(Block block){ diff --git a/FightSystem_Main/src/de/steamwar/fightsystem/FightSystem.java b/FightSystem_Main/src/de/steamwar/fightsystem/FightSystem.java index 481ba37..1d2b46d 100644 --- a/FightSystem_Main/src/de/steamwar/fightsystem/FightSystem.java +++ b/FightSystem_Main/src/de/steamwar/fightsystem/FightSystem.java @@ -27,10 +27,10 @@ import de.steamwar.fightsystem.event.HellsBells; import de.steamwar.fightsystem.fight.Fight; import de.steamwar.fightsystem.fight.FightTeam; import de.steamwar.fightsystem.fight.FightWorld; +import de.steamwar.fightsystem.fight.IFight; import de.steamwar.fightsystem.listener.Shutdown; import de.steamwar.fightsystem.listener.*; -import de.steamwar.fightsystem.record.RecordSystem; -import de.steamwar.fightsystem.record.Recorder; +import de.steamwar.fightsystem.record.*; import de.steamwar.fightsystem.states.FightState; import de.steamwar.fightsystem.states.OneShotStateDependent; import de.steamwar.fightsystem.utils.EnterHandler; @@ -58,8 +58,7 @@ public class FightSystem extends JavaPlugin { @Override public void onEnable() { - Fight.init(); - RecordSystem.init(); + IFight.init(Fight.getRedTeam(), Fight.getBlueTeam()); new EntityDamage(); new WaterRemover(); @@ -107,7 +106,6 @@ public class FightSystem extends JavaPlugin { new RankedPlayerLeftWincondition(); new WinconditionPercentTimeout(); - //noinspection InstantiationOfUtilityClass new HellsBells(); new NoPlayersOnlineCountdown(); @@ -127,12 +125,16 @@ public class FightSystem extends JavaPlugin { new AkCommand(); new LeaderCommand(); new LockschemCommand(); + new ReplayCommand(); new StateCommand(); new SkipCommand(); new WinCommand(); - new OneShotStateDependent(ArenaMode.All, FightState.PreRunning, () -> Bukkit.broadcastMessage(PREFIX + "§aDer Kampf beginnt!")); - new OneShotStateDependent(ArenaMode.All, FightState.Running, () -> Bukkit.broadcastMessage(PREFIX + "§aArena freigegeben!")); + new LiveRecorder(); + new FileRecorder(); + + new OneShotStateDependent(ArenaMode.AntiReplay, FightState.PreRunning, () -> Bukkit.broadcastMessage(PREFIX + "§aDer Kampf beginnt!")); + new OneShotStateDependent(ArenaMode.AntiReplay, FightState.Running, () -> Bukkit.broadcastMessage(PREFIX + "§aArena freigegeben!")); new OneShotStateDependent(ArenaMode.AntiTest, FightState.Running, FightStatistics::start); try { @@ -152,12 +154,15 @@ public class FightSystem extends JavaPlugin { }else{ Fight.getBlueTeam().setSchem(Schematic.getSchemFromDB(Config.PrepareSchemID)); } + }else if(Config.mode == ArenaMode.REPLAY) { + FightWorld.forceLoad(); + FileSource.startReplay(); } } @Override public void onDisable() { - Recorder.closeAll(); + GlobalRecorder.getInstance().close(); } public static void setPreLeaderState() { @@ -184,24 +189,26 @@ public class FightSystem extends JavaPlugin { } public static void setSpectateState(FightTeam winFightTeam, String windescription) { + if(!PacketProcessor.isReplaying()){ + if(winFightTeam != null) { + Bukkit.broadcastMessage(PREFIX + "§aDas Team " + winFightTeam.getColoredName() + " §ahat gewonnen!"); + } else { + Bukkit.broadcastMessage(PREFIX + "§aKein Team hat gewonnen!"); + } + } + FightState.setFightState(FightState.SPECTATE); - if(winFightTeam != null) { - Bukkit.broadcastMessage(PREFIX + "§aDas Team " + winFightTeam.getColoredName() + " §ahat gewonnen!"); - } else { - Bukkit.broadcastMessage(PREFIX + "§aKein Team hat gewonnen!"); - } + if(!Config.test() && !PacketProcessor.isReplaying()){ + if(Config.mode == ArenaMode.EVENT) { + if (winFightTeam == null) + getEventFight().setErgebnis(0); + else if (winFightTeam.isBlue()) + getEventFight().setErgebnis(1); + else + getEventFight().setErgebnis(2); + } - if(Config.mode == ArenaMode.EVENT) { - if (winFightTeam == null) - getEventFight().setErgebnis(0); - else if (winFightTeam.isBlue()) - getEventFight().setErgebnis(1); - else - getEventFight().setErgebnis(2); - } - - if(!Config.test()){ FightStatistics.saveStats(winFightTeam, windescription); } } diff --git a/FightSystem_Main/src/de/steamwar/fightsystem/commands/KitCommand.java b/FightSystem_Main/src/de/steamwar/fightsystem/commands/KitCommand.java index 585262b..000711d 100644 --- a/FightSystem_Main/src/de/steamwar/fightsystem/commands/KitCommand.java +++ b/FightSystem_Main/src/de/steamwar/fightsystem/commands/KitCommand.java @@ -30,7 +30,7 @@ import org.bukkit.entity.Player; public class KitCommand implements CommandExecutor { public KitCommand() { - new StateDependentCommand(ArenaMode.All, FightState.Setup, "kit", this); + new StateDependentCommand(ArenaMode.AntiReplay, FightState.Setup, "kit", this); } @Override diff --git a/FightSystem_Main/src/de/steamwar/fightsystem/commands/LeaveCommand.java b/FightSystem_Main/src/de/steamwar/fightsystem/commands/LeaveCommand.java index 7e3327e..902f779 100644 --- a/FightSystem_Main/src/de/steamwar/fightsystem/commands/LeaveCommand.java +++ b/FightSystem_Main/src/de/steamwar/fightsystem/commands/LeaveCommand.java @@ -30,7 +30,7 @@ import org.bukkit.entity.Player; public class LeaveCommand implements CommandExecutor { public LeaveCommand() { - new StateDependentCommand(ArenaMode.All, FightState.Setup, "leave", this); + new StateDependentCommand(ArenaMode.AntiReplay, FightState.Setup, "leave", this); } @Override diff --git a/FightSystem_Main/src/de/steamwar/fightsystem/commands/LockschemCommand.java b/FightSystem_Main/src/de/steamwar/fightsystem/commands/LockschemCommand.java index 6070d12..27dbb97 100644 --- a/FightSystem_Main/src/de/steamwar/fightsystem/commands/LockschemCommand.java +++ b/FightSystem_Main/src/de/steamwar/fightsystem/commands/LockschemCommand.java @@ -37,7 +37,7 @@ import org.bukkit.entity.Player; public class LockschemCommand implements CommandExecutor { public LockschemCommand() { - new StateDependentCommand(ArenaMode.All, FightState.All, "lockschem", this); + new StateDependentCommand(ArenaMode.AntiReplay, FightState.All, "lockschem", this); } @Override diff --git a/FightSystem_Main/src/de/steamwar/fightsystem/commands/ReplayCommand.java b/FightSystem_Main/src/de/steamwar/fightsystem/commands/ReplayCommand.java new file mode 100644 index 0000000..170705b --- /dev/null +++ b/FightSystem_Main/src/de/steamwar/fightsystem/commands/ReplayCommand.java @@ -0,0 +1,70 @@ +/* + 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 . +*/ + +package de.steamwar.fightsystem.commands; + +import de.steamwar.fightsystem.ArenaMode; +import de.steamwar.fightsystem.Config; +import de.steamwar.fightsystem.FightSystem; +import de.steamwar.fightsystem.record.FileRecorder; +import de.steamwar.fightsystem.record.FileSource; +import de.steamwar.fightsystem.states.FightState; +import de.steamwar.fightsystem.states.StateDependentCommand; +import de.steamwar.sql.SteamwarUser; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +import java.io.IOException; + +public class ReplayCommand implements CommandExecutor { + + public ReplayCommand() { + new StateDependentCommand(ArenaMode.Replayable, FightState.All, "replay", this); + } + + @Override + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + if(!(sender instanceof Player)) { + return false; + } + Player player = (Player) sender; + + if(!Config.test()){ + SteamwarUser user = SteamwarUser.get(player.getUniqueId()); + if(!user.getUserGroup().isTeamGroup()){ + sender.sendMessage(FightSystem.PREFIX + "§cDieser Befehl ist zu diesem Kampfzeitpunkt nicht verfügbar."); + return false; + } + } + + if(!FileRecorder.getFile().exists()){ + sender.sendMessage(FightSystem.PREFIX + "§cKein Replay vorhanden."); + return false; + } + + try { + new FileSource(FileRecorder.getFile()); + } catch (IOException e) { + sender.sendMessage(FightSystem.PREFIX + "§cDas Replay konnte nicht gestartet werden."); + } + return false; + } +} diff --git a/FightSystem_Main/src/de/steamwar/fightsystem/countdown/Countdown.java b/FightSystem_Main/src/de/steamwar/fightsystem/countdown/Countdown.java index 35ef83b..05c2a23 100644 --- a/FightSystem_Main/src/de/steamwar/fightsystem/countdown/Countdown.java +++ b/FightSystem_Main/src/de/steamwar/fightsystem/countdown/Countdown.java @@ -23,7 +23,7 @@ import de.steamwar.core.Core; import de.steamwar.fightsystem.FightSystem; import de.steamwar.fightsystem.fight.Fight; import de.steamwar.fightsystem.listener.BasicListener; -import de.steamwar.fightsystem.record.RecordSystem; +import de.steamwar.fightsystem.record.GlobalRecorder; import net.md_5.bungee.api.chat.BaseComponent; import net.md_5.bungee.api.chat.TextComponent; import org.bukkit.Bukkit; @@ -108,7 +108,7 @@ public abstract class Countdown { } private void broadcast(String message){ - RecordSystem.actionBar(message); + GlobalRecorder.getInstance().actionBar(message); BaseComponent[] msg = TextComponent.fromLegacyText(message); for(Player p : Bukkit.getOnlinePlayers()) BasicListener.toActionbar(p, msg); diff --git a/FightSystem_Main/src/de/steamwar/fightsystem/countdown/NoPlayersOnlineCountdown.java b/FightSystem_Main/src/de/steamwar/fightsystem/countdown/NoPlayersOnlineCountdown.java index fc8ed95..5ab54d7 100644 --- a/FightSystem_Main/src/de/steamwar/fightsystem/countdown/NoPlayersOnlineCountdown.java +++ b/FightSystem_Main/src/de/steamwar/fightsystem/countdown/NoPlayersOnlineCountdown.java @@ -34,8 +34,8 @@ public class NoPlayersOnlineCountdown extends Countdown implements Listener { public NoPlayersOnlineCountdown() { super(Config.NoPlayerOnlineDuration, null, false); - new StateDependentListener(ArenaMode.All, FightState.PreLeaderSetup, this); - new StateDependentCountdown(ArenaMode.All, FightState.PreLeaderSetup, this){ + new StateDependentListener(ArenaMode.AntiReplay, FightState.PreLeaderSetup, this); + new StateDependentCountdown(ArenaMode.AntiReplay, FightState.PreLeaderSetup, this){ @Override public void enable() { if(Bukkit.getOnlinePlayers().isEmpty()) diff --git a/FightSystem_Main/src/de/steamwar/fightsystem/countdown/PreRunningCountdown.java b/FightSystem_Main/src/de/steamwar/fightsystem/countdown/PreRunningCountdown.java index 4506ace..36a6b79 100644 --- a/FightSystem_Main/src/de/steamwar/fightsystem/countdown/PreRunningCountdown.java +++ b/FightSystem_Main/src/de/steamwar/fightsystem/countdown/PreRunningCountdown.java @@ -29,7 +29,7 @@ public class PreRunningCountdown extends Countdown { public PreRunningCountdown() { super(Config.PreFightDuration, SWSound.BLOCK_NOTE_PLING, true); - new StateDependentCountdown(ArenaMode.All, FightState.PreRunning, this); + new StateDependentCountdown(ArenaMode.AntiReplay, FightState.PreRunning, this); } @Override diff --git a/FightSystem_Main/src/de/steamwar/fightsystem/countdown/PreSchemCountdown.java b/FightSystem_Main/src/de/steamwar/fightsystem/countdown/PreSchemCountdown.java index e0084a4..6dbe901 100644 --- a/FightSystem_Main/src/de/steamwar/fightsystem/countdown/PreSchemCountdown.java +++ b/FightSystem_Main/src/de/steamwar/fightsystem/countdown/PreSchemCountdown.java @@ -29,7 +29,7 @@ public class PreSchemCountdown extends Countdown { public PreSchemCountdown() { super(Config.PreSchemPasteDuration, SWSound.BLOCK_NOTE_PLING, false); - new StateDependentCountdown(ArenaMode.All, FightState.PreSchemSetup, this); + new StateDependentCountdown(ArenaMode.AntiReplay, FightState.PreSchemSetup, this); } @Override diff --git a/FightSystem_Main/src/de/steamwar/fightsystem/fight/Fight.java b/FightSystem_Main/src/de/steamwar/fightsystem/fight/Fight.java index dd56cf4..7ea0ee2 100644 --- a/FightSystem_Main/src/de/steamwar/fightsystem/fight/Fight.java +++ b/FightSystem_Main/src/de/steamwar/fightsystem/fight/Fight.java @@ -28,10 +28,12 @@ import com.comphenix.protocol.wrappers.WrappedChatComponent; import com.comphenix.protocol.wrappers.WrappedGameProfile; import de.steamwar.fightsystem.ArenaMode; import de.steamwar.fightsystem.Config; -import de.steamwar.fightsystem.record.RecordSystem; import de.steamwar.fightsystem.FightSystem; +import de.steamwar.fightsystem.record.GlobalRecorder; import de.steamwar.sql.Schematic; -import org.bukkit.*; +import org.bukkit.Bukkit; +import org.bukkit.GameMode; +import org.bukkit.Sound; import org.bukkit.entity.Player; import java.lang.reflect.InvocationTargetException; @@ -45,10 +47,6 @@ public class Fight { private static final FightTeam redTeam = new FightTeam(Config.TeamRedName, Config.TeamRedColor, Config.TeamRedSpawn, Config.RedPasteRegion, Config.RedExtendRegion, Config.RedRotate, false, Config.RedLeader); private static final FightTeam blueTeam = new FightTeam(Config.TeamBlueName, Config.TeamBlueColor, Config.TeamBlueSpawn, Config.BluePasteRegion, Config.BlueExtendRegion, Config.BlueRotate, true, Config.BlueLeader); - public static void init(){ - IFight.init(redTeam, blueTeam); - } - public static FightTeam getPlayerTeam(Player player) { if(redTeam.isPlayerInTeam(player)) return redTeam; @@ -91,7 +89,7 @@ public class Fight { } public static void playSound(Sound sound, float volume, float pitch) { - RecordSystem.soundAtPlayer(sound.name(), volume, pitch); + GlobalRecorder.getInstance().soundAtPlayer(sound.name(), volume, pitch); //volume: max. 100, pitch: max. 2 Bukkit.getServer().getOnlinePlayers().forEach(player -> player.playSound(player.getLocation(), sound, volume, pitch)); } diff --git a/FightSystem_Main/src/de/steamwar/fightsystem/fight/FightSchematic.java b/FightSystem_Main/src/de/steamwar/fightsystem/fight/FightSchematic.java index 172a8b7..af1d0b1 100644 --- a/FightSystem_Main/src/de/steamwar/fightsystem/fight/FightSchematic.java +++ b/FightSystem_Main/src/de/steamwar/fightsystem/fight/FightSchematic.java @@ -19,35 +19,36 @@ package de.steamwar.fightsystem.fight; +import com.sk89q.jnbt.NBTInputStream; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.math.transform.AffineTransform; +import de.steamwar.core.VersionedCallable; import de.steamwar.core.VersionedRunnable; import de.steamwar.fightsystem.ArenaMode; import de.steamwar.fightsystem.Config; import de.steamwar.fightsystem.FightSystem; -import de.steamwar.fightsystem.IFightSystem; -import de.steamwar.fightsystem.record.RecordSystem; +import de.steamwar.fightsystem.record.GlobalRecorder; import de.steamwar.fightsystem.states.FightState; import de.steamwar.fightsystem.states.StateDependent; import de.steamwar.fightsystem.utils.ColorConverter; import de.steamwar.fightsystem.utils.Region; -import de.steamwar.sql.NoClipboardException; import de.steamwar.sql.Schematic; import org.bukkit.Bukkit; import org.bukkit.DyeColor; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Block; -import org.bukkit.event.EventHandler; import org.bukkit.event.HandlerList; -import org.bukkit.event.Listener; -import org.bukkit.event.block.*; -import org.bukkit.event.inventory.InventoryMoveItemEvent; +import java.io.File; +import java.io.FileInputStream; import java.io.IOException; +import java.util.ArrayList; import java.util.List; import java.util.Random; import java.util.logging.Level; +import java.util.zip.GZIPInputStream; public class FightSchematic extends StateDependent { @@ -80,10 +81,15 @@ public class FightSchematic extends StateDependent { clipboard = schem.load(); } catch (IOException e) { team.broadcast(FightSystem.PREFIX + "§cKonnte die Schematic nicht laden!"); - Bukkit.getLogger().log(Level.SEVERE, "Couldn't load Schematic " + schem.getSchemName(), e); + Bukkit.getLogger().log(Level.SEVERE, e, () -> "Couldn't load Schematic " + schem.getSchemName()); } } + public void setSchematic(int schemId, Clipboard clipboard) { + this.schematic = schemId; + this.clipboard = clipboard; + } + public void reset(){ schematic = 0; clipboard = null; @@ -109,50 +115,111 @@ public class FightSchematic extends StateDependent { } if(team.isBlue()) - RecordSystem.blueSchem(schematic); + GlobalRecorder.getInstance().blueSchem(schematic); else - RecordSystem.redSchem(schematic); + GlobalRecorder.getInstance().redSchem(schematic); Bukkit.getScheduler().runTask(FightSystem.getPlugin(), this::paste); } + private void replaceTeamColor(Clipboard clipboard){ + DyeColor c = ArenaMode.AntiPrepare.contains(Config.mode) ? ColorConverter.chat2dye(team.getColor()) : DyeColor.PINK; + VersionedRunnable.call(new VersionedRunnable(() -> { + try { + FightTeam_8.replaceTeamColor(clipboard, c); + } catch (WorldEditException ex) { + throw new SecurityException("Error recoloring schematic", ex); + } + }, 8), + new VersionedRunnable(() -> { + try { + FightTeam_12.replaceTeamColor(clipboard, c); + } catch (WorldEditException ex) { + throw new SecurityException("Error recoloring schematic", ex); + } + }, 12), + new VersionedRunnable(() -> { + try { + FightTeam_14.replaceTeamColor(clipboard, c); + } catch (WorldEditException ex) { + throw new SecurityException("Error recoloring schematic", ex); + } + }, 14)); + } + private void paste(){ FreezeWorld freezer = new FreezeWorld(); - DyeColor c = ArenaMode.AntiPrepare.contains(Config.mode) ? ColorConverter.chat2dye(team.getColor()) : DyeColor.PINK; try { - VersionedRunnable.call(new VersionedRunnable(() -> { - try { - FightTeam_8.replaceTeamColor(clipboard, c); - FightTeam_8.pasteSchematic(clipboard, region, rotate); - } catch (NoClipboardException | WorldEditException ex) { - throw new SecurityException("Error pasting schematic", ex); - } - }, 8), new VersionedRunnable(() -> { - try { - FightTeam_12.replaceTeamColor(clipboard, c); - FightTeam_8.pasteSchematic(clipboard, region, rotate); - } catch (NoClipboardException | WorldEditException ex) { - throw new SecurityException("Error pasting schematic", ex); - } - }, 12), new VersionedRunnable(() -> { - try { - FightTeam_14.replaceTeamColor(clipboard, c); - FightTeam_14.pasteSchematic(clipboard, region, rotate); - } catch (NoClipboardException | WorldEditException ex) { - throw new SecurityException("Error pasting schematic", ex); - } - }, 14)); + replaceTeamColor(clipboard); + VersionedRunnable.call(new VersionedRunnable(() -> FightTeam_8.pasteSchematic(clipboard, region, rotate), 8), + new VersionedRunnable(() -> FightTeam_14.pasteSchematic(clipboard, region, rotate), 14)); } catch (SecurityException securityException) { Bukkit.broadcastMessage(FightSystem.PREFIX + "§cFehler beim Pasten der Schematic"); Bukkit.getScheduler().runTask(FightSystem.getPlugin(), FightSystem::setPreSchemState); throw securityException; } - Bukkit.getScheduler().runTaskLater(FightSystem.getPlugin(), () -> HandlerList.unregisterAll(freezer), 3); + Bukkit.getScheduler().runTaskLater(FightSystem.getPlugin(), freezer::disable, 3); Bukkit.getScheduler().runTaskLater(FightSystem.getPlugin(), team::teleportToSpawn, 40); } + private Clipboard loadTextSchem(String schemName){ + return VersionedCallable.call(new VersionedCallable<>(() -> FightTeam_8.loadSchem(new NBTInputStream(new GZIPInputStream(new FileInputStream(new File(FightSystem.getPlugin().getDataFolder(), "text/" + schemName + ".schematic"))))), 8), + new VersionedCallable<>(() -> FightTeam_14.loadSchem(new NBTInputStream(new GZIPInputStream(new FileInputStream(new File(FightSystem.getPlugin().getDataFolder(), "text/" + schemName + ".schem"))))), 14)); + } + + public void pasteTeamName(){ + List characters = new ArrayList<>(); + for(char c : team.getName().toCharArray()){ + try { + try { + characters.add(loadTextSchem(c == '/' ? "slash" : String.valueOf(c))); + } catch (RuntimeException e) { + Bukkit.getLogger().log(Level.WARNING, "Could not display character {} due to missing file!", c); + characters.add(loadTextSchem("")); + } + }catch (RuntimeException e) { + throw new SecurityException("Could not load text", e); + } + } + + //Calc character sizes + int[] lengthes = new int[characters.size()]; + for(int i = 0; i < lengthes.length; i++) + lengthes[i] = characters.get(i).getDimensions().getBlockX(); + + //Calc character offsets + int[] offsets = new int[lengthes.length]; + int previousOffset = 0; + for(int i = 0; i < offsets.length; i++){ + offsets[i] = previousOffset; + previousOffset += lengthes[i] + 1; // 1 is the distance between characters + } + + int length = lengthes.length == 0 ? 0 : lengthes[lengthes.length - 1] + offsets[offsets.length - 1]; + + int z = team.getSchemRegion().centerZ(); + AffineTransform aT = new AffineTransform(); + + if(rotate){ + aT = aT.rotateY(180); + z += team.getSchemRegion().getSizeZ() / 2; + }else{ + z -= team.getSchemRegion().getSizeZ() / 2; + } + + for(int i = 0; i < characters.size(); i++){ + replaceTeamColor(characters.get(i)); + pasteChar(characters.get(i), offsets[i], length, team.getSchemRegion().centerX(), team.getExtendRegion().getMaxY(), z, aT); + } + } + + private void pasteChar(Clipboard character, int charOffset, int length, int x, int y, int z, AffineTransform aT){ + VersionedRunnable.call(new VersionedRunnable(() -> FightTeam_8.pasteChar(character, charOffset, length, x, y, z, aT), 8), + new VersionedRunnable(() -> FightTeam_14.pasteChar(character, charOffset, length, x, y, z, aT), 14)); + } + @Override public void disable() { if(!Config.ReplaceObsidianBedrock) @@ -178,45 +245,4 @@ public class FightSchematic extends StateDependent { block.setType(replacement); }); } - - private static class FreezeWorld implements Listener { - private FreezeWorld(){ - Bukkit.getPluginManager().registerEvents(this, IFightSystem.getPlugin()); - } - - @EventHandler - public void onBlockPhysicsEvent(BlockPhysicsEvent e){ - e.setCancelled(true); - } - - @EventHandler - public void onPistonExtend(BlockPistonExtendEvent e){ - e.setCancelled(true); - } - - @EventHandler - public void onPistonRetract(BlockPistonRetractEvent e){ - e.setCancelled(true); - } - - @EventHandler - public void onBlockGrow(BlockGrowEvent e){ - e.setCancelled(true); - } - - @EventHandler - public void onRedstoneEvent(BlockRedstoneEvent e){ - e.setNewCurrent(e.getOldCurrent()); - } - - @EventHandler - public void onBlockDispense(BlockDispenseEvent e){ - e.setCancelled(true); - } - - @EventHandler - public void onInventoryMoveEvent(InventoryMoveItemEvent e){ - e.setCancelled(true); - } - } } diff --git a/FightSystem_Main/src/de/steamwar/fightsystem/fight/FightTeam.java b/FightSystem_Main/src/de/steamwar/fightsystem/fight/FightTeam.java index f2a477f..92ed1af 100644 --- a/FightSystem_Main/src/de/steamwar/fightsystem/fight/FightTeam.java +++ b/FightSystem_Main/src/de/steamwar/fightsystem/fight/FightTeam.java @@ -19,6 +19,7 @@ package de.steamwar.fightsystem.fight; +import com.sk89q.worldedit.extent.clipboard.Clipboard; import de.steamwar.comms.packets.TablistNamePacket; import de.steamwar.core.VersionedRunnable; import de.steamwar.fightsystem.ArenaMode; @@ -26,10 +27,10 @@ import de.steamwar.fightsystem.Config; import de.steamwar.fightsystem.FightSystem; import de.steamwar.fightsystem.countdown.Countdown; import de.steamwar.fightsystem.listener.BasicListener; -import de.steamwar.fightsystem.listener.PersonalKitCreator; -import de.steamwar.fightsystem.record.RecordSystem; -import de.steamwar.fightsystem.states.FightState; import de.steamwar.fightsystem.listener.FightScoreboard; +import de.steamwar.fightsystem.listener.PersonalKitCreator; +import de.steamwar.fightsystem.record.GlobalRecorder; +import de.steamwar.fightsystem.states.FightState; import de.steamwar.fightsystem.states.StateDependent; import de.steamwar.fightsystem.utils.ItemBuilder; import de.steamwar.fightsystem.utils.Region; @@ -54,9 +55,9 @@ public class FightTeam implements IFightTeam{ private final Map players = new HashMap<>(); private final Set invited = new HashSet<>(); - private final String name; - private final String prefix; - private final ChatColor color; + private String name; + private String prefix; + private ChatColor color; private final FightSchematic schematic; private final Team team; private final boolean blue; @@ -72,21 +73,19 @@ public class FightTeam implements IFightTeam{ this.spawn = spawn; this.schemRegion = schemRegion; this.extendRegion = extendRegion; - this.name = name; - this.prefix = prefix; this.ready = false; this.skip = false; this.blue = blue; this.designatedLeader = designatedLeader; - this.color = ChatColor.getByChar(ChatColor.getLastColors(prefix).replace("§", "")); + setPrefixAndName(prefix, name); this.schematic = new FightSchematic(this, rotate); new KitLoader(); new SpectateHandler(); - if(FightScoreboard.getScoreboard().getTeam(name) == null) - team = FightScoreboard.getScoreboard().registerNewTeam(name); + if(FightScoreboard.getBukkit().getTeam(name) == null) + team = FightScoreboard.getBukkit().registerNewTeam(name); else - team = FightScoreboard.getScoreboard().getTeam(name); + team = FightScoreboard.getBukkit().getTeam(name); assert team != null; setTeamColor(team, color); //noinspection deprecation @@ -94,6 +93,12 @@ public class FightTeam implements IFightTeam{ team.setAllowFriendlyFire(false); } + public void setPrefixAndName(String prefix, String name){ + this.name = name; + this.prefix = prefix; + this.color = ChatColor.getByChar(ChatColor.getLastColors(prefix).replace("§", "")); + } + public UUID getDesignatedLeader(){ return designatedLeader; } @@ -166,7 +171,7 @@ public class FightTeam implements IFightTeam{ playerSet.forEach(this::addMember); - if(isLeaderless()){ + if(ArenaMode.VariableTeams.contains(Config.mode) && isLeaderless()){ for(Player player : Bukkit.getOnlinePlayers()){ if(Fight.getPlayerTeam(player) == null && canbeLeader(player)){ addMember(player); @@ -198,7 +203,7 @@ public class FightTeam implements IFightTeam{ player.getInventory().setItem(7, new ItemBuilder(Material.BEACON).removeAllAttributs().setDisplayName("§eRespawn").build()); if(ArenaMode.NotOnBau.contains(Config.mode)) Bukkit.getScheduler().runTaskLater(FightSystem.getPlugin(), () -> new TablistNamePacket(SteamwarUser.get(player.getUniqueId()).getId(), prefix + player.getName()).send(player), 5); - RecordSystem.playerJoins(player); + GlobalRecorder.getInstance().playerJoins(player); TechHider.reloadChunks(player, chunksToReload, false); if(isLeaderless()) @@ -216,7 +221,7 @@ public class FightTeam implements IFightTeam{ if(fightPlayer.equals(leader)) setLeader(null); - RecordSystem.entityDespawns(player); + GlobalRecorder.getInstance().entityDespawns(player); Fight.setPlayerGamemode(player, GameMode.SPECTATOR); player.teleport(Config.SpecSpawn); player.getInventory().clear(); @@ -295,7 +300,15 @@ public class FightTeam implements IFightTeam{ public void pasteSchem(Schematic schematic){ setSchem(schematic); + testPasteAction(); + } + public void pasteSchem(int schemId, Clipboard clipboard){ + this.schematic.setSchematic(schemId, clipboard); + testPasteAction(); + } + + private void testPasteAction(){ if(Config.test()) this.schematic.enable(); else if(Fight.getOpposite(this).hasSchematic()){ @@ -303,6 +316,10 @@ public class FightTeam implements IFightTeam{ } } + public void pasteTeamName(){ + schematic.pasteTeamName(); + } + public void setSchem(Schematic schematic){ this.schematic.setSchematic(schematic); broadcast(FightSystem.PREFIX + "§7Das §e" + Config.GameName + " " + schematic.getSchemName() + " §7wird für den Kampf verwendet!"); @@ -398,7 +415,7 @@ public class FightTeam implements IFightTeam{ private class KitLoader extends StateDependent { private KitLoader() { - super(ArenaMode.All, FightState.Ingame); + super(ArenaMode.AntiReplay, FightState.Ingame); register(); } @@ -423,7 +440,7 @@ public class FightTeam implements IFightTeam{ private class SpectateHandler extends StateDependent { private SpectateHandler() { - super(ArenaMode.All, FightState.Spectate); + super(ArenaMode.AntiReplay, FightState.Spectate); register(); } diff --git a/FightSystem_Main/src/de/steamwar/fightsystem/fight/FightWorld.java b/FightSystem_Main/src/de/steamwar/fightsystem/fight/FightWorld.java index 342f1a4..a6343fd 100644 --- a/FightSystem_Main/src/de/steamwar/fightsystem/fight/FightWorld.java +++ b/FightSystem_Main/src/de/steamwar/fightsystem/fight/FightWorld.java @@ -38,7 +38,7 @@ public class FightWorld extends StateDependent { paper = Bukkit.getVersion().contains("git-Paper"); } - private final World world = Bukkit.getWorlds().get(0); + private static final World world = Bukkit.getWorlds().get(0); public FightWorld() { super(ArenaMode.Restartable, FightState.Schem); @@ -56,6 +56,19 @@ public class FightWorld extends StateDependent { @Override public void disable() { + resetWorld(); + } + + public static void forceLoad(){ + Config.ArenaRegion.forEachChunk((cX, cZ) -> { + world.loadChunk(cX, cZ); + world.setChunkForceLoaded(cX, cZ, true); + }); + world.setSpawnLocation(Config.SpecSpawn); + world.setKeepSpawnInMemory(true); + } + + public static void resetWorld(){ for(Entity entity : world.getEntities()){ if(entity.getType() != EntityType.PLAYER){ entity.remove(); @@ -68,7 +81,7 @@ public class FightWorld extends StateDependent { Bukkit.unloadWorld(backup, false); } - private void resetChunk(World backup, int x, int z, boolean isPaper){ + private static void resetChunk(World backup, int x, int z, boolean isPaper){ VersionedRunnable.call( new VersionedRunnable(() -> FightWorld_8.resetChunk(world, backup, x, z, isPaper), 8), new VersionedRunnable(() -> FightWorld_9.resetChunk(world, backup, x, z, isPaper), 9), diff --git a/FightSystem_Main/src/de/steamwar/fightsystem/fight/FreezeWorld.java b/FightSystem_Main/src/de/steamwar/fightsystem/fight/FreezeWorld.java new file mode 100644 index 0000000..d82cbbf --- /dev/null +++ b/FightSystem_Main/src/de/steamwar/fightsystem/fight/FreezeWorld.java @@ -0,0 +1,91 @@ +/* + 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 . +*/ + +package de.steamwar.fightsystem.fight; + +import de.steamwar.fightsystem.IFightSystem; +import org.bukkit.Bukkit; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.HandlerList; +import org.bukkit.event.Listener; +import org.bukkit.event.block.*; +import org.bukkit.event.inventory.InventoryMoveItemEvent; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.player.PlayerSwapHandItemsEvent; + +public class FreezeWorld implements Listener { + public FreezeWorld(){ + Bukkit.getPluginManager().registerEvents(this, IFightSystem.getPlugin()); + } + + public void disable(){ + HandlerList.unregisterAll(this); + } + + @EventHandler + public void onBlockPhysicsEvent(BlockPhysicsEvent e){ + e.setCancelled(true); + } + + @EventHandler + public void onPistonExtend(BlockPistonExtendEvent e){ + e.setCancelled(true); + } + + @EventHandler + public void onPistonRetract(BlockPistonRetractEvent e){ + e.setCancelled(true); + } + + @EventHandler + public void onBlockGrow(BlockGrowEvent e){ + e.setCancelled(true); + } + + @EventHandler + public void onRedstoneEvent(BlockRedstoneEvent e){ + e.setNewCurrent(e.getOldCurrent()); + } + + @EventHandler + public void onBlockDispense(BlockDispenseEvent e){ + e.setCancelled(true); + } + + @EventHandler + public void onInventoryMoveEvent(InventoryMoveItemEvent e){ + e.setCancelled(true); + } + + @EventHandler + public void onBlockExplosion(BlockExplodeEvent e){ + e.setCancelled(true); + } + + @EventHandler + public void handlePlayerSwapHandItemsEvent(PlayerSwapHandItemsEvent event) { + event.setCancelled(true); + } + + @EventHandler(priority = EventPriority.LOW) + public void handlePlayerInteract(PlayerInteractEvent event) { + event.setCancelled(true); + } +} diff --git a/FightSystem_Main/src/de/steamwar/fightsystem/listener/Chat.java b/FightSystem_Main/src/de/steamwar/fightsystem/listener/Chat.java index 8e89799..973a706 100644 --- a/FightSystem_Main/src/de/steamwar/fightsystem/listener/Chat.java +++ b/FightSystem_Main/src/de/steamwar/fightsystem/listener/Chat.java @@ -24,7 +24,7 @@ import de.steamwar.fightsystem.Config; import de.steamwar.fightsystem.FightSystem; import de.steamwar.fightsystem.fight.Fight; import de.steamwar.fightsystem.fight.FightTeam; -import de.steamwar.fightsystem.record.RecordSystem; +import de.steamwar.fightsystem.record.GlobalRecorder; import de.steamwar.fightsystem.states.FightState; import de.steamwar.fightsystem.states.StateDependentListener; import net.md_5.bungee.api.chat.BaseComponent; @@ -64,7 +64,7 @@ public class Chat implements Listener { } private void broadcastChat(String message) { - RecordSystem.chat(message); + GlobalRecorder.getInstance().chat(message); BaseComponent[] msg = TextComponent.fromLegacyText(message); for(Player p : Bukkit.getOnlinePlayers()) BasicListener.toChat(p, msg); diff --git a/FightSystem_Main/src/de/steamwar/fightsystem/listener/EventJoin.java b/FightSystem_Main/src/de/steamwar/fightsystem/listener/EventJoin.java index 55195dc..dc3cca0 100644 --- a/FightSystem_Main/src/de/steamwar/fightsystem/listener/EventJoin.java +++ b/FightSystem_Main/src/de/steamwar/fightsystem/listener/EventJoin.java @@ -42,7 +42,7 @@ public class EventJoin implements Listener { @EventHandler public void playerLogin(PlayerLoginEvent event) { - if(!Config.SpectateSystem) + if(!Config.LiveReplay) return; Player player = event.getPlayer(); @@ -89,7 +89,7 @@ public class EventJoin implements Listener { FightSystem.setEventLeiter(player); return; } - if(Config.SpectateSystem) + if(Config.LiveReplay) player.kickPlayer("§cDu bist kein Kampfteilnehmer"); } diff --git a/FightSystem_Main/src/de/steamwar/fightsystem/listener/FightScoreboard.java b/FightSystem_Main/src/de/steamwar/fightsystem/listener/FightScoreboard.java index f0ceb64..c747520 100644 --- a/FightSystem_Main/src/de/steamwar/fightsystem/listener/FightScoreboard.java +++ b/FightSystem_Main/src/de/steamwar/fightsystem/listener/FightScoreboard.java @@ -24,7 +24,8 @@ import de.steamwar.fightsystem.ArenaMode; import de.steamwar.fightsystem.countdown.Countdown; import de.steamwar.fightsystem.fight.Fight; import de.steamwar.fightsystem.fight.FightTeam; -import de.steamwar.fightsystem.record.RecordSystem; +import de.steamwar.fightsystem.record.GlobalRecorder; +import de.steamwar.fightsystem.record.PacketProcessor; import de.steamwar.fightsystem.states.FightState; import de.steamwar.fightsystem.states.StateDependentListener; import de.steamwar.fightsystem.states.StateDependentTask; @@ -43,20 +44,27 @@ import java.util.*; public class FightScoreboard implements Listener, ScoreboardCallback { + public static Scoreboard getBukkit() { + return Objects.requireNonNull(Bukkit.getScoreboardManager()).getMainScoreboard(); + } + private static final Set fullScoreboard = EnumSet.of(FightState.RUNNING, FightState.SPECTATE); + private static FightScoreboard scoreboard; + + public static FightScoreboard getScoreboard(){ + return scoreboard; + } private int index = 0; private String title = ""; private final HashMap scores = new HashMap<>(); - public static Scoreboard getScoreboard() { - return Objects.requireNonNull(Bukkit.getScoreboardManager()).getMainScoreboard(); - } public FightScoreboard(){ - new StateDependentListener(ArenaMode.All, FightState.All, this); - new StateDependentTask(ArenaMode.All, FightState.All, this::updateScoreboard, 0, 20); + new StateDependentListener(ArenaMode.AntiReplay, FightState.All, this); + new StateDependentTask(ArenaMode.AntiReplay, FightState.All, this::updateScoreboard, 0, 20); + scoreboard = this; } @EventHandler @@ -105,7 +113,9 @@ public class FightScoreboard implements Listener, ScoreboardCallback { } private void updateScoreboard() { - scores.clear(); + if(PacketProcessor.isReplaying()) + return; + if ((index++ / 5) % 2 == 0) { generalScoreboard(); } else { @@ -115,14 +125,15 @@ public class FightScoreboard implements Listener, ScoreboardCallback { } } - private void setTitle(String t) { + public void setTitle(String t) { + scores.clear(); title = t; - RecordSystem.scoreboardTitle(t); + GlobalRecorder.getInstance().scoreboardTitle(t); } - private void addScore(String string, int i) { + public void addScore(String string, int i) { scores.put(string, i); - RecordSystem.scoreboardData(string, i); + GlobalRecorder.getInstance().scoreboardData(string, i); } @Override diff --git a/FightSystem_Main/src/de/steamwar/fightsystem/listener/HotbarGUI.java b/FightSystem_Main/src/de/steamwar/fightsystem/listener/HotbarGUI.java index 94ff28a..8b3b07f 100644 --- a/FightSystem_Main/src/de/steamwar/fightsystem/listener/HotbarGUI.java +++ b/FightSystem_Main/src/de/steamwar/fightsystem/listener/HotbarGUI.java @@ -35,7 +35,7 @@ import org.bukkit.inventory.meta.ItemMeta; public class HotbarGUI implements Listener { public HotbarGUI() { - new StateDependentListener(ArenaMode.All, FightState.Setup, this); + new StateDependentListener(ArenaMode.AntiReplay, FightState.Setup, this); } @EventHandler diff --git a/FightSystem_Main/src/de/steamwar/fightsystem/listener/InFightDamage.java b/FightSystem_Main/src/de/steamwar/fightsystem/listener/InFightDamage.java index d525e6c..f83f39a 100644 --- a/FightSystem_Main/src/de/steamwar/fightsystem/listener/InFightDamage.java +++ b/FightSystem_Main/src/de/steamwar/fightsystem/listener/InFightDamage.java @@ -36,7 +36,7 @@ import java.util.Objects; public class InFightDamage implements Listener { public InFightDamage() { - new StateDependentListener(ArenaMode.All, FightState.Running, this); + new StateDependentListener(ArenaMode.AntiReplay, FightState.Running, this); } @EventHandler diff --git a/FightSystem_Main/src/de/steamwar/fightsystem/listener/InFightInventory.java b/FightSystem_Main/src/de/steamwar/fightsystem/listener/InFightInventory.java index 3dd0274..d63cccf 100644 --- a/FightSystem_Main/src/de/steamwar/fightsystem/listener/InFightInventory.java +++ b/FightSystem_Main/src/de/steamwar/fightsystem/listener/InFightInventory.java @@ -40,7 +40,7 @@ import org.bukkit.inventory.ItemStack; public class InFightInventory implements Listener { public InFightInventory() { - new StateDependentListener(ArenaMode.All, FightState.Running, this); + new StateDependentListener(ArenaMode.AntiReplay, FightState.Running, this); } @EventHandler diff --git a/FightSystem_Main/src/de/steamwar/fightsystem/listener/IngameDeath.java b/FightSystem_Main/src/de/steamwar/fightsystem/listener/IngameDeath.java index 6bf1074..8c896c5 100644 --- a/FightSystem_Main/src/de/steamwar/fightsystem/listener/IngameDeath.java +++ b/FightSystem_Main/src/de/steamwar/fightsystem/listener/IngameDeath.java @@ -26,7 +26,7 @@ import de.steamwar.fightsystem.countdown.SWSound; import de.steamwar.fightsystem.fight.Fight; import de.steamwar.fightsystem.fight.FightPlayer; import de.steamwar.fightsystem.fight.FightTeam; -import de.steamwar.fightsystem.record.RecordSystem; +import de.steamwar.fightsystem.record.GlobalRecorder; import de.steamwar.fightsystem.states.FightState; import de.steamwar.fightsystem.states.StateDependentListener; import org.bukkit.Bukkit; @@ -40,7 +40,7 @@ import org.bukkit.event.player.PlayerQuitEvent; public class IngameDeath implements Listener { public IngameDeath() { - new StateDependentListener(ArenaMode.All, FightState.Ingame, this); + new StateDependentListener(ArenaMode.AntiReplay, FightState.Ingame, this); } @EventHandler(priority = EventPriority.HIGH) @@ -71,7 +71,7 @@ public class IngameDeath implements Listener { if(fightPlayer.isLiving()) { Bukkit.broadcastMessage(FightSystem.PREFIX + "§cDer Spieler " + team.getPrefix() + player.getName() + " §chat den Kampf verlassen!"); team.getFightPlayer(player).setOut(); - RecordSystem.entityDespawns(player); + GlobalRecorder.getInstance().entityDespawns(player); } } } diff --git a/FightSystem_Main/src/de/steamwar/fightsystem/listener/Permanent.java b/FightSystem_Main/src/de/steamwar/fightsystem/listener/Permanent.java index d57e883..4463317 100644 --- a/FightSystem_Main/src/de/steamwar/fightsystem/listener/Permanent.java +++ b/FightSystem_Main/src/de/steamwar/fightsystem/listener/Permanent.java @@ -25,6 +25,7 @@ import de.steamwar.fightsystem.Config; import de.steamwar.fightsystem.FightSystem; import de.steamwar.fightsystem.fight.Fight; import de.steamwar.fightsystem.fight.FightTeam; +import de.steamwar.fightsystem.record.REntity; import de.steamwar.fightsystem.states.FightState; import de.steamwar.fightsystem.states.StateDependentListener; import de.steamwar.sql.SteamwarUser; @@ -81,6 +82,8 @@ public class Permanent implements Listener { if(ArenaMode.NotOnBau.contains(Config.mode)) Bukkit.getScheduler().runTaskLater(FightSystem.getPlugin(), () -> new TablistNamePacket(SteamwarUser.get(player.getUniqueId()).getId(), "§7" + player.getName()).send(player), 5); } + + REntity.playerJoins(player); } @EventHandler diff --git a/FightSystem_Main/src/de/steamwar/fightsystem/listener/Recording.java b/FightSystem_Main/src/de/steamwar/fightsystem/listener/Recording.java index 9a414ba..bb08635 100644 --- a/FightSystem_Main/src/de/steamwar/fightsystem/listener/Recording.java +++ b/FightSystem_Main/src/de/steamwar/fightsystem/listener/Recording.java @@ -25,15 +25,16 @@ import com.comphenix.protocol.events.PacketAdapter; import com.comphenix.protocol.events.PacketContainer; import com.comphenix.protocol.events.PacketEvent; import com.comphenix.protocol.wrappers.EnumWrappers; -import de.steamwar.fightsystem.Config; +import de.steamwar.fightsystem.ArenaMode; import de.steamwar.fightsystem.FightSystem; import de.steamwar.fightsystem.fight.Fight; import de.steamwar.fightsystem.fight.FightPlayer; import de.steamwar.fightsystem.fight.FightTeam; -import de.steamwar.fightsystem.record.RecordSystem; +import de.steamwar.fightsystem.record.GlobalRecorder; import de.steamwar.fightsystem.states.FightState; import de.steamwar.fightsystem.states.StateDependent; import de.steamwar.fightsystem.states.StateDependentListener; +import de.steamwar.fightsystem.states.StateDependentTask; import org.bukkit.*; import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; @@ -55,6 +56,7 @@ public class Recording implements Listener { private static final int AIR = 0; private static final Random random = new Random(); + private static final World world = Bukkit.getWorlds().get(0); private static final PacketAdapter BOW_PACKET_PROCESSOR = new PacketAdapter(FightSystem.getPlugin(), PacketType.Play.Client.BLOCK_PLACE) { @Override public void onPacketReceiving(PacketEvent event) { @@ -66,23 +68,22 @@ public class Recording implements Listener { (hand == EnumWrappers.Hand.OFF_HAND && p.getInventory().getItemInOffHand().getType() == Material.BOW))) return; - RecordSystem.bowSpan(p, true, hand != EnumWrappers.Hand.MAIN_HAND); + GlobalRecorder.getInstance().bowSpan(p, true, hand != EnumWrappers.Hand.MAIN_HAND); } }; - private static final PacketAdapter BOW_PACKET_DEDRAW_PROCESSOR = new PacketAdapter(FightSystem.getPlugin(), PacketType.Play.Client.BLOCK_DIG) { @Override public void onPacketReceiving(PacketEvent e) { PacketContainer packetDig = e.getPacket(); if(packetDig.getPlayerDigTypes().read(0) == EnumWrappers.PlayerDigType.RELEASE_USE_ITEM) { - RecordSystem.bowSpan(e.getPlayer(), false, false); + GlobalRecorder.getInstance().bowSpan(e.getPlayer(), false, false); } } }; public Recording() { - new StateDependentListener(Config.recording(), FightState.All, this); - new StateDependent(Config.recording(), FightState.Ingame){ + new StateDependentListener(ArenaMode.AntiReplay, FightState.All, this); + new StateDependent(ArenaMode.AntiReplay, FightState.Ingame){ @Override public void enable() { Bukkit.getScheduler().runTaskLater(FightSystem.getPlugin(), () -> { @@ -98,7 +99,7 @@ public class Recording implements Listener { despawnTNT(); } }.register(); - new StateDependent(Config.recording(), FightState.Ingame) { + new StateDependent(ArenaMode.AntiReplay, FightState.Ingame) { @Override public void enable() { ProtocolLibrary.getProtocolManager().addPacketListener(BOW_PACKET_PROCESSOR); @@ -111,6 +112,17 @@ public class Recording implements Listener { ProtocolLibrary.getProtocolManager().removePacketListener(BOW_PACKET_DEDRAW_PROCESSOR); } }.register(); + new StateDependentTask(ArenaMode.AntiReplay, FightState.All, () -> { + GlobalRecorder.getInstance().tick(); + + if(FightState.getFightState() == FightState.SPECTATE || !GlobalRecorder.getInstance().recording()) + return; + + for(TNTPrimed tnt : world.getEntitiesByClass(TNTPrimed.class)){ + GlobalRecorder.getInstance().entityMoves(tnt); + GlobalRecorder.getInstance().entitySpeed(tnt); + } + }, 1, 1); } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) @@ -118,7 +130,7 @@ public class Recording implements Listener { if(isNotSent(e.getPlayer())) return; - RecordSystem.entityMoves(e.getPlayer()); + GlobalRecorder.getInstance().entityMoves(e.getPlayer()); } @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) @@ -126,12 +138,12 @@ public class Recording implements Listener { if(isNotSent(e.getEntity())) return; - RecordSystem.entityDespawns(e.getEntity()); + GlobalRecorder.getInstance().entityDespawns(e.getEntity()); } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void onBroadcast(BroadcastMessageEvent e){ - RecordSystem.systemChat(e.getMessage()); + GlobalRecorder.getInstance().systemChat(e.getMessage()); } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) @@ -139,7 +151,7 @@ public class Recording implements Listener { if(isNotSent(e.getPlayer())) return; - RecordSystem.playerSneak(e.getPlayer(), e.isSneaking()); + GlobalRecorder.getInstance().playerSneak(e.getPlayer(), e.isSneaking()); } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) @@ -148,7 +160,7 @@ public class Recording implements Listener { return; if(e.getAnimationType() == PlayerAnimationType.ARM_SWING) - RecordSystem.entityAnimation(e.getPlayer(), AIR); + GlobalRecorder.getInstance().entityAnimation(e.getPlayer(), AIR); } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) @@ -160,10 +172,10 @@ public class Recording implements Listener { if(isNotSent(p)) return; - RecordSystem.damageAnimation(p); + GlobalRecorder.getInstance().damageAnimation(p); if(e.getCause() == EntityDamageEvent.DamageCause.FIRE_TICK || e.getCause() == EntityDamageEvent.DamageCause.FIRE) - RecordSystem.setOnFire(p, false); + GlobalRecorder.getInstance().setOnFire(p, false); } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) @@ -175,22 +187,21 @@ public class Recording implements Listener { if(isNotSent(p)) return; - RecordSystem.setOnFire(p, false); + GlobalRecorder.getInstance().setOnFire(p, false); } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void onTNTSpawn(EntitySpawnEvent e){ - //TODO: Falling block if(e.getEntityType() != EntityType.PRIMED_TNT) return; - RecordSystem.tntSpawn(e.getEntity()); + GlobalRecorder.getInstance().tntSpawn(e.getEntity()); } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void onBlockPhysics(BlockPhysicsEvent e){ if(e.getBlock() == e.getSourceBlock() || e.getChangedType() == Material.AIR) - RecordSystem.blockChange(e.getBlock()); + GlobalRecorder.getInstance().blockChange(e.getBlock()); } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) @@ -199,9 +210,9 @@ public class Recording implements Listener { return; Location loc = e.getLocation(); - RecordSystem.entityDespawns(e.getEntity()); - RecordSystem.particle(loc.getX(), loc.getY(), loc.getZ(), Particle.EXPLOSION_HUGE.name()); - RecordSystem.sound(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ(), Sound.ENTITY_GENERIC_EXPLODE.name(), SoundCategory.BLOCKS.name(), 4.0F, (1.0F + (random.nextFloat() - random.nextFloat()) * 0.2F) * 0.7F); + GlobalRecorder.getInstance().entityDespawns(e.getEntity()); + GlobalRecorder.getInstance().particle(loc.getX(), loc.getY(), loc.getZ(), Particle.EXPLOSION_HUGE.name()); + GlobalRecorder.getInstance().sound(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ(), Sound.ENTITY_GENERIC_EXPLODE.name(), SoundCategory.BLOCKS.name(), 4.0F, (1.0F + (random.nextFloat() - random.nextFloat()) * 0.2F) * 0.7F); } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) @@ -209,7 +220,7 @@ public class Recording implements Listener { if(isNotSent(e.getPlayer())) return; - RecordSystem.item(e.getPlayer(), disarmNull(e.getPlayer().getInventory().getItem(e.getNewSlot())), "MAINHAND"); + GlobalRecorder.getInstance().item(e.getPlayer(), disarmNull(e.getPlayer().getInventory().getItem(e.getNewSlot())), "MAINHAND"); } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) @@ -218,16 +229,16 @@ public class Recording implements Listener { return; Player player = e.getPlayer(); - RecordSystem.item(player, disarmNull(e.getMainHandItem()), "MAINHAND"); - RecordSystem.item(player, disarmNull(e.getOffHandItem()), "OFFHAND"); + GlobalRecorder.getInstance().item(player, disarmNull(e.getMainHandItem()), "MAINHAND"); + GlobalRecorder.getInstance().item(player, disarmNull(e.getOffHandItem()), "OFFHAND"); } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void onProjectileSpawn(ProjectileLaunchEvent e){ if(e.getEntityType() == EntityType.FIREBALL) - RecordSystem.fireballSpawn(e.getEntity()); + GlobalRecorder.getInstance().fireballSpawn(e.getEntity()); else if(e.getEntityType() == EntityType.ARROW) - RecordSystem.arrowSpawn(e.getEntity()); + GlobalRecorder.getInstance().arrowSpawn(e.getEntity()); } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) @@ -241,17 +252,17 @@ public class Recording implements Listener { switch(e.getSlot()){ case 103: - RecordSystem.item(player, disarmNull(e.getCurrentItem()), "HEAD"); + GlobalRecorder.getInstance().item(player, disarmNull(e.getCurrentItem()), "HEAD"); break; case 102: - RecordSystem.item(player, disarmNull(e.getCurrentItem()), "CHEST"); + GlobalRecorder.getInstance().item(player, disarmNull(e.getCurrentItem()), "CHEST"); break; case 101: - RecordSystem.item(player, disarmNull(e.getCurrentItem()), "LEGS"); + GlobalRecorder.getInstance().item(player, disarmNull(e.getCurrentItem()), "LEGS"); break; case 100: default: - RecordSystem.item(player, disarmNull(e.getCurrentItem()), "FEET"); + GlobalRecorder.getInstance().item(player, disarmNull(e.getCurrentItem()), "FEET"); } } @@ -264,12 +275,12 @@ public class Recording implements Listener { continue; Player player = fp.getPlayer(); - RecordSystem.item(player, disarmNull(player.getInventory().getItemInMainHand()), "MAINHAND"); - RecordSystem.item(player, disarmNull(player.getInventory().getItemInOffHand()), "OFFHAND"); - RecordSystem.item(player, disarmNull(player.getInventory().getHelmet()), "HEAD"); - RecordSystem.item(player, disarmNull(player.getInventory().getChestplate()), "CHEST"); - RecordSystem.item(player, disarmNull(player.getInventory().getLeggings()), "LEGS"); - RecordSystem.item(player, disarmNull(player.getInventory().getBoots()), "FEET"); + GlobalRecorder.getInstance().item(player, disarmNull(player.getInventory().getItemInMainHand()), "MAINHAND"); + GlobalRecorder.getInstance().item(player, disarmNull(player.getInventory().getItemInOffHand()), "OFFHAND"); + GlobalRecorder.getInstance().item(player, disarmNull(player.getInventory().getHelmet()), "HEAD"); + GlobalRecorder.getInstance().item(player, disarmNull(player.getInventory().getChestplate()), "CHEST"); + GlobalRecorder.getInstance().item(player, disarmNull(player.getInventory().getLeggings()), "LEGS"); + GlobalRecorder.getInstance().item(player, disarmNull(player.getInventory().getBoots()), "FEET"); } } @@ -282,13 +293,13 @@ public class Recording implements Listener { private void despawnTeam(FightTeam team){ for(FightPlayer player : team.getPlayers()){ if(player.isLiving()) - RecordSystem.entityDespawns(player.getPlayer()); + GlobalRecorder.getInstance().entityDespawns(player.getPlayer()); } } private void despawnTNT(){ for(TNTPrimed tnt : Bukkit.getWorlds().get(0).getEntitiesByClass(TNTPrimed.class)) - RecordSystem.entityDespawns(tnt); + GlobalRecorder.getInstance().entityDespawns(tnt); } private boolean isNotSent(Player p){ diff --git a/FightSystem_Main/src/de/steamwar/fightsystem/listener/SetupQuit.java b/FightSystem_Main/src/de/steamwar/fightsystem/listener/SetupQuit.java index 3b083e7..87d4b7e 100644 --- a/FightSystem_Main/src/de/steamwar/fightsystem/listener/SetupQuit.java +++ b/FightSystem_Main/src/de/steamwar/fightsystem/listener/SetupQuit.java @@ -32,7 +32,7 @@ import org.bukkit.event.player.PlayerQuitEvent; public class SetupQuit implements Listener { public SetupQuit(){ - new StateDependentListener(ArenaMode.All, FightState.Setup, this); + new StateDependentListener(ArenaMode.AntiReplay, FightState.Setup, this); } @EventHandler diff --git a/FightSystem_Main/src/de/steamwar/fightsystem/listener/Shutdown.java b/FightSystem_Main/src/de/steamwar/fightsystem/listener/Shutdown.java index be3e243..e088314 100644 --- a/FightSystem_Main/src/de/steamwar/fightsystem/listener/Shutdown.java +++ b/FightSystem_Main/src/de/steamwar/fightsystem/listener/Shutdown.java @@ -20,6 +20,7 @@ package de.steamwar.fightsystem.listener; import de.steamwar.fightsystem.ArenaMode; +import de.steamwar.fightsystem.Config; import de.steamwar.fightsystem.states.FightState; import de.steamwar.fightsystem.states.StateDependentListener; import org.bukkit.Bukkit; @@ -36,7 +37,10 @@ public class Shutdown implements Listener { @EventHandler(priority = EventPriority.HIGH) public void handlePlayerQuit(PlayerQuitEvent event) { - //Shutdown server if nobody online and its not an event server + if(Config.replayserver()) + return; + + //Shutdown server if nobody online if(Bukkit.getOnlinePlayers().isEmpty() || (Bukkit.getOnlinePlayers().size() == 1 && Bukkit.getOnlinePlayers().contains(event.getPlayer()))) Bukkit.shutdown(); } diff --git a/FightSystem_Main/src/de/steamwar/fightsystem/listener/WaterRemover.java b/FightSystem_Main/src/de/steamwar/fightsystem/listener/WaterRemover.java index 40ae32e..d33dc58 100644 --- a/FightSystem_Main/src/de/steamwar/fightsystem/listener/WaterRemover.java +++ b/FightSystem_Main/src/de/steamwar/fightsystem/listener/WaterRemover.java @@ -35,7 +35,7 @@ public class WaterRemover implements Listener { private static final int MIN_Y = Config.BluePasteRegion.getMinY() + Config.WaterDepth; public WaterRemover() { - new StateDependentListener(ArenaMode.All, FightState.Running, this); + new StateDependentListener(ArenaMode.AntiReplay, FightState.Running, this); } @EventHandler diff --git a/FightSystem_Main/src/de/steamwar/fightsystem/record/FileRecorder.java b/FightSystem_Main/src/de/steamwar/fightsystem/record/FileRecorder.java index 42aabd1..f462a83 100644 --- a/FightSystem_Main/src/de/steamwar/fightsystem/record/FileRecorder.java +++ b/FightSystem_Main/src/de/steamwar/fightsystem/record/FileRecorder.java @@ -19,120 +19,60 @@ package de.steamwar.fightsystem.record; +import de.steamwar.fightsystem.ArenaMode; +import de.steamwar.fightsystem.states.FightState; +import de.steamwar.fightsystem.states.StateDependent; import org.bukkit.Bukkit; -import org.bukkit.World; import java.io.*; -import java.util.logging.Level; import java.util.zip.GZIPOutputStream; -public class FileRecorder extends Recorder { +public class FileRecorder extends StateDependent implements Recorder { - private final DataOutputStream outputStream; + private static final File file = new File(Bukkit.getWorlds().get(0).getWorldFolder(), "recording.recording"); + private DataOutputStream outputStream; + + public static File getFile() { + return file; + } public FileRecorder(){ - super(); - World world = Bukkit.getWorlds().get(0); - File file = new File(world.getWorldFolder(), world.getName() + ".recording"); + super(ArenaMode.AntiReplay, FightState.Recording); + register(); + } + + @Override + public DataOutputStream getStream() { + return outputStream; + } + + @Override + public void enable() { try{ - file.createNewFile(); - outputStream = new DataOutputStream(new BufferedOutputStream(new GZIPOutputStream(new FileOutputStream(file), 4096))); + outputStream = new DataOutputStream(new BufferedOutputStream(new GZIPOutputStream(new FileOutputStream(file), 4096)){ + @Override + public synchronized void flush() { + //Don't flush explicitly (performance) + } + + @Override + public void close() throws IOException { + try{ + super.flush(); + }catch(IOException e){ + //do nothing + } + super.close(); + } + }); }catch(IOException e){ throw new SecurityException("Could not open file", e); } + Recorder.super.enable(); } @Override - protected void writeBoolean(boolean b) { - try { - outputStream.writeBoolean(b); - } catch (IOException e) { - Bukkit.getLogger().log(Level.SEVERE, "Could not write", e); - close(); - } - } - - @Override - protected void writeByte(int b) { - try { - outputStream.writeByte(b); - } catch (IOException e) { - Bukkit.getLogger().log(Level.SEVERE, "Could not write", e); - close(); - } - } - - @Override - protected void writeShort(short s) { - try { - outputStream.writeShort(s); - } catch (IOException e) { - Bukkit.getLogger().log(Level.SEVERE, "Could not write", e); - close(); - } - } - - @Override - protected void writeInt(int i) { - try { - outputStream.writeInt(i); - } catch (IOException e) { - Bukkit.getLogger().log(Level.SEVERE, "Could not write", e); - close(); - } - } - - @Override - protected void writeLong(long l) { - try { - outputStream.writeLong(l); - } catch (IOException e) { - Bukkit.getLogger().log(Level.SEVERE, "Could not write", e); - close(); - } - } - - @Override - protected void writeFloat(float f) { - try { - outputStream.writeFloat(f); - } catch (IOException e) { - Bukkit.getLogger().log(Level.SEVERE, "Could not write", e); - close(); - } - } - - @Override - protected void writeDouble(double d) { - try { - outputStream.writeDouble(d); - } catch (IOException e) { - Bukkit.getLogger().log(Level.SEVERE, "Could not write", e); - close(); - } - } - - @Override - protected void writeString(String s) { - try { - outputStream.writeUTF(s); - } catch (IOException e) { - Bukkit.getLogger().log(Level.SEVERE, "Could not write", e); - close(); - } - } - - @Override - protected void doFlush() { - - } - - @Override - protected void closeRecorder() { - try { - outputStream.close(); - } catch (IOException e) { - Bukkit.getLogger().log(Level.SEVERE, "Could not close OutputStream", e); - } + public void disable() { + Recorder.super.disable(); } } diff --git a/FightSystem_Main/src/de/steamwar/fightsystem/record/FileSource.java b/FightSystem_Main/src/de/steamwar/fightsystem/record/FileSource.java new file mode 100644 index 0000000..c283504 --- /dev/null +++ b/FightSystem_Main/src/de/steamwar/fightsystem/record/FileSource.java @@ -0,0 +1,65 @@ +/* + 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 . +*/ + +package de.steamwar.fightsystem.record; + +import de.steamwar.fightsystem.Config; + +import java.io.*; +import java.nio.file.Files; +import java.nio.file.StandardCopyOption; +import java.util.zip.GZIPInputStream; + +public class FileSource extends PacketSource { + + public static void startReplay() { + if(Config.replayserver()) + return; + + InputStream input = de.steamwar.sql.Fight.getReplay(Config.ReplayID); + try { + Files.copy( + input, + FileRecorder.getFile().toPath(), + StandardCopyOption.REPLACE_EXISTING); + input.close(); + new FileSource(FileRecorder.getFile()); + } catch (IOException e) { + throw new SecurityException("Could not start replay", e); + } + } + + public FileSource(File fightFile) throws IOException { + super(new GZIPInputStream(new FileInputStream(fightFile))); + } + + @Override + boolean isClosed() { + try{ + return available() == 0; + }catch (IOException e){ + return true; + } + } + + @Override + boolean async() { + return false; + } +} diff --git a/FightSystem_Main/src/de/steamwar/fightsystem/record/GlobalRecorder.java b/FightSystem_Main/src/de/steamwar/fightsystem/record/GlobalRecorder.java new file mode 100644 index 0000000..b0e9824 --- /dev/null +++ b/FightSystem_Main/src/de/steamwar/fightsystem/record/GlobalRecorder.java @@ -0,0 +1,95 @@ +/* + 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 . +*/ + +package de.steamwar.fightsystem.record; + +import org.bukkit.Bukkit; + +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Level; + +public class GlobalRecorder extends OutputStream implements Recorder { + + private static final GlobalRecorder recorder = new GlobalRecorder(); + + public static GlobalRecorder getInstance(){ + return recorder; + } + + private final List recorders = new ArrayList<>(); + private final DataOutputStream outputStream = new DataOutputStream(this); + + public void add(Recorder recorder){ + recorders.add(recorder); + } + + public void remove(Recorder recorder){ + recorders.remove(recorder); + } + + public boolean recording(){ + return !recorders.isEmpty(); + } + + @Override + public DataOutputStream getStream() { + return outputStream; + } + + @Override + public void write(int i) { + foreach(stream -> stream.write(i)); + } + + @Override + public void write(byte[] bytes, int i, int i1) { + foreach(stream -> stream.write(bytes, i, i1)); + } + + @Override + public void flush() { + foreach(OutputStream::flush); + } + + @Override + public void close() { + foreach(OutputStream::close); + } + + private void foreach(IOThrower thrower) { + for(int i = 0; i < recorders.size(); i++) { + Recorder stream = recorders.get(i); + try{ + thrower.run(stream.getStream()); + }catch (IOException e){ + Bukkit.getLogger().log(Level.SEVERE, "Could not operate on OutputStream", e); + stream.disable(); + i--; // Recorder was removed from recorders + } + } + } + + interface IOThrower{ + void run(OutputStream stream) throws IOException; + } +} diff --git a/FightSystem_Main/src/de/steamwar/fightsystem/record/LiveRecorder.java b/FightSystem_Main/src/de/steamwar/fightsystem/record/LiveRecorder.java new file mode 100644 index 0000000..8b6c735 --- /dev/null +++ b/FightSystem_Main/src/de/steamwar/fightsystem/record/LiveRecorder.java @@ -0,0 +1,70 @@ +/* + 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 . +*/ + +package de.steamwar.fightsystem.record; + +import de.steamwar.fightsystem.Config; +import de.steamwar.fightsystem.states.FightState; +import de.steamwar.fightsystem.states.StateDependent; +import org.bukkit.Bukkit; + +import java.io.*; +import java.net.Socket; +import java.util.logging.Level; + +public class LiveRecorder extends StateDependent implements Recorder { + + private DataOutputStream outputStream; + private Socket socket; + + public LiveRecorder(){ + super(Config.LiveReplay, FightState.All); + register(); + } + + @Override + public void enable() { + try { + socket = new Socket(Config.spectateIP, Config.spectatePort); + socket.setSoTimeout(1); // Wait a maximum of 1ms on a blocking operation (flush) + socket.setSoLinger(true, 1); // Wait a maximum of 1ms on disable + socket.setTcpNoDelay(true); // Don't wait on ack + outputStream = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream(), 1024)); + } catch (IOException e) { + Bukkit.getLogger().log(Level.WARNING, "Could not init connection to spectate server", e); + disable(); + } + Recorder.super.enable(); + } + + @Override + public void disable() { + try { + socket.close(); + } catch (IOException e) { + Bukkit.getLogger().log(Level.WARNING, "IOException on socket close", e); + } + Recorder.super.disable(); + } + + @Override + public DataOutputStream getStream() { + return outputStream; + } +} diff --git a/FightSystem_Main/src/de/steamwar/fightsystem/record/LiveServer.java b/FightSystem_Main/src/de/steamwar/fightsystem/record/LiveServer.java new file mode 100644 index 0000000..b58f0fa --- /dev/null +++ b/FightSystem_Main/src/de/steamwar/fightsystem/record/LiveServer.java @@ -0,0 +1,62 @@ +/* + 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 . +*/ + +package de.steamwar.fightsystem.record; + +import de.steamwar.fightsystem.Config; +import de.steamwar.fightsystem.FightSystem; +import org.bukkit.Bukkit; + +import java.io.IOException; +import java.net.ServerSocket; +import java.net.Socket; +import java.util.logging.Level; + +public class LiveServer { + + private final ServerSocket socket; + + public LiveServer() throws IOException { + socket = new ServerSocket(Config.spectatePort); + Bukkit.getScheduler().runTaskAsynchronously(FightSystem.getPlugin(), this::acceptConnections); + } + + public void close(){ + try { + socket.close(); + } catch (IOException e) { + Bukkit.getLogger().log(Level.SEVERE, "Could not close socket", e); + } + } + + private void acceptConnections(){ + try { + while(!socket.isClosed()){ + Socket s = socket.accept(); + if(PacketProcessor.isReplaying()){ + s.close(); + }else{ + new LiveSource(s); + } + } + } catch (IOException e) { + Bukkit.getLogger().log(Level.INFO, "Stopping accepting connections", e); + } + } +} diff --git a/FightSystem_Main/src/de/steamwar/fightsystem/record/LiveSource.java b/FightSystem_Main/src/de/steamwar/fightsystem/record/LiveSource.java new file mode 100644 index 0000000..3a1fad5 --- /dev/null +++ b/FightSystem_Main/src/de/steamwar/fightsystem/record/LiveSource.java @@ -0,0 +1,55 @@ +/* + 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 . +*/ + +package de.steamwar.fightsystem.record; + +import org.bukkit.Bukkit; + +import java.io.IOException; +import java.net.Socket; +import java.util.logging.Level; + +public class LiveSource extends PacketSource { + private final Socket socket; + + protected LiveSource(Socket socket) throws IOException { + super(socket.getInputStream()); + this.socket = socket; + } + + @Override + public void close() { + super.close(); + try { + socket.close(); + } catch (IOException e) { + Bukkit.getLogger().log(Level.SEVERE, "IOException on close", e); + } + } + + @Override + boolean isClosed() { + return socket.isClosed(); + } + + @Override + boolean async() { + return true; + } +} diff --git a/FightSystem_Main/src/de/steamwar/fightsystem/record/PacketProcessor.java b/FightSystem_Main/src/de/steamwar/fightsystem/record/PacketProcessor.java new file mode 100644 index 0000000..57c53fd --- /dev/null +++ b/FightSystem_Main/src/de/steamwar/fightsystem/record/PacketProcessor.java @@ -0,0 +1,440 @@ +/* + 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 . +*/ + +package de.steamwar.fightsystem.record; + +import com.sk89q.worldedit.extent.clipboard.Clipboard; +import de.steamwar.core.Core; +import de.steamwar.core.VersionedRunnable; +import de.steamwar.fightsystem.ArenaMode; +import de.steamwar.fightsystem.Config; +import de.steamwar.fightsystem.FightSystem; +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.utils.TechHider; +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.*; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Player; +import org.bukkit.scheduler.BukkitTask; + +import java.io.EOFException; +import java.io.IOException; +import java.util.LinkedList; +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 syncList = new LinkedList<>(); + private final Set hiddenBlockIds = TechHider.getHiddenBlockIds(); + private final int obfuscateWith = TechHider.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[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[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 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 -> p.spigot().sendMessage(type, text)); + } + + 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(() -> setBlockInternal(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(() -> world.spawnParticle(Particle.valueOf(particleName), x, y, z, 1)); + } + + 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); + SoundCategory sCategory = SoundCategory.valueOf(soundCategory); + + execSync(() -> world.playSound(new Location(world, x, y, z), sound, sCategory, 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(() -> { + for(Player player : Bukkit.getOnlinePlayers()){ + player.playSound(player.getLocation(), 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 endReplay(){ + REntity.dieAll(); + freezer.disable(); + if(Config.replayserver() || ArenaMode.AntiReplay.contains(Config.mode)) { + FightSystem.setSpectateState(null, "Replay ends"); + }else{ + Bukkit.broadcastMessage(FightSystem.PREFIX + "§cReplay beendet"); + new EventSpectateCountdown().enable(); + } + 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 static void setBlockInternal(int x, int y, int z, int blockState){ + VersionedRunnable.call(new VersionedRunnable(() -> RecordSystem_8.setBlock(world, x, y, z, blockState), 8), + new VersionedRunnable(() -> RecordSystem_14.setBlock(world, x, y, z, blockState), 14), + new VersionedRunnable(() -> RecordSystem_15.setBlock(world, x, y, z, blockState), 15)); + } + + private interface PacketParser{ + void process() throws IOException; + } +} diff --git a/FightSystem_Main/src/de/steamwar/fightsystem/record/PacketSource.java b/FightSystem_Main/src/de/steamwar/fightsystem/record/PacketSource.java new file mode 100644 index 0000000..855959f --- /dev/null +++ b/FightSystem_Main/src/de/steamwar/fightsystem/record/PacketSource.java @@ -0,0 +1,47 @@ +/* + 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 . +*/ + +package de.steamwar.fightsystem.record; + +import org.bukkit.Bukkit; + +import java.io.DataInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.logging.Level; + +public abstract class PacketSource extends DataInputStream { + + protected PacketSource(InputStream inputStream){ + super(inputStream); + new PacketProcessor(this); + } + + @Override + public void close(){ + try { + super.close(); + } catch (IOException e) { + Bukkit.getLogger().log(Level.SEVERE, "IOException on disable", e); + } + } + + abstract boolean isClosed(); + abstract boolean async(); +} diff --git a/FightSystem_Main/src/de/steamwar/fightsystem/record/REntity.java b/FightSystem_Main/src/de/steamwar/fightsystem/record/REntity.java new file mode 100644 index 0000000..6e2d067 --- /dev/null +++ b/FightSystem_Main/src/de/steamwar/fightsystem/record/REntity.java @@ -0,0 +1,378 @@ +/* + 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 . +*/ + +package de.steamwar.fightsystem.record; + +import com.comphenix.protocol.PacketType; +import com.comphenix.protocol.ProtocolLibrary; +import com.comphenix.protocol.events.PacketContainer; +import com.comphenix.protocol.reflect.StructureModifier; +import com.comphenix.protocol.wrappers.*; +import com.mojang.authlib.GameProfile; +import de.steamwar.core.Core; +import de.steamwar.core.VersionedCallable; +import de.steamwar.fightsystem.listener.FightScoreboard; +import de.steamwar.sql.SteamwarUser; +import net.royawesome.jlibnoise.MathHelper; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.scoreboard.NameTagVisibility; +import org.bukkit.scoreboard.Team; + +import java.lang.reflect.InvocationTargetException; +import java.util.*; +import java.util.logging.Level; + +public class REntity { + + private static final Map entities = new HashMap<>(); + + public static REntity getEntity(int internalId){ + return entities.get(internalId); + } + + public static void tickFire() { + entities.forEach((integer, entity) -> { + if(entity.fireTick > 0) { + entity.fireTick--; + if(entity.fireTick == 0) { + ProtocolLibrary.getProtocolManager().broadcastServerPacket(entity.getDataWatcherPacket(0, (byte)0)); + } + } + }); + } + + public static void playerJoins(Player player) { + try{ + for(REntity entity : entities.values()){ + if(entity.entityType == EntityType.PLAYER){ + ProtocolLibrary.getProtocolManager().sendServerPacket(player, entity.getPlayerInfoPacket()); + ProtocolLibrary.getProtocolManager().sendServerPacket(player, entity.getNamedSpawnPacket()); + for (Map.Entry entry : entity.itemSlots.entrySet()) { + ProtocolLibrary.getProtocolManager().sendServerPacket(player, entity.getEquipmentPacket(entry.getKey(), entry.getValue())); + } + }else{ + ProtocolLibrary.getProtocolManager().sendServerPacket(player, entity.getSpawnEntityPacket()); + } + //ProtocolLibrary.getProtocolManager().sendServerPacket(player, entity.getTeleportPacket()); Sollte nicht nötig sein? + if(entity.fireTick != 0) { + ProtocolLibrary.getProtocolManager().sendServerPacket(player, entity.getDataWatcherPacket(0, (byte) 1)); + } + if(entity.sneaks) { + if(Core.getVersion() > 12){ + ProtocolLibrary.getProtocolManager().sendServerPacket(player, entity.getDataWatcherPacket(6, getPose(true))); + }else{ + ProtocolLibrary.getProtocolManager().sendServerPacket(player, entity.getDataWatcherPacket(0, (byte) 2)); + } + } + } + }catch(InvocationTargetException e){ + Bukkit.getLogger().log(Level.SEVERE, "Could not sync player", e); + } + } + + public static void dieAll(){ + entities.forEach((id, entity) -> entity.broadcastDeath()); + entities.clear(); + } + + private static final String SCOREBOARD_TEAMNAME = "Replay"; + private static final Team team; + + static { + if(FightScoreboard.getBukkit().getTeam(SCOREBOARD_TEAMNAME) == null) + team = FightScoreboard.getBukkit().registerNewTeam(SCOREBOARD_TEAMNAME); + else + team = FightScoreboard.getBukkit().getTeam(SCOREBOARD_TEAMNAME); + team.setNameTagVisibility(NameTagVisibility.NEVER); + } + + private static int entityCount = Integer.MAX_VALUE; + private static final Random random = new Random(); + + private final int internalId; + private final int entityId; + private final UUID uuid; + private final EntityType entityType; + private final PlayerInfoData playerInfoData; + private final Map itemSlots = new HashMap<>(); + + private double locX; + private double locY; + private double locZ; + private byte yaw; + private byte pitch; + private byte headYaw; + private int fireTick; + private boolean sneaks; + + public REntity(int internalId, int userId){ + this.internalId = internalId; + this.entityType = EntityType.PLAYER; + this.entityId = entityCount--; + + SteamwarUser user = SteamwarUser.get(userId); + this.uuid = user.getUUID(); + this.playerInfoData = new PlayerInfoData(WrappedGameProfile.fromHandle(new GameProfile(uuid, user.getUserName())), 0, EnumWrappers.NativeGameMode.SURVIVAL, WrappedChatComponent.fromText(user.getUserName())); + entities.put(internalId, this); + + ProtocolLibrary.getProtocolManager().broadcastServerPacket(getPlayerInfoPacket()); + ProtocolLibrary.getProtocolManager().broadcastServerPacket(getNamedSpawnPacket()); + team.addEntry(user.getUserName()); + } + + public REntity(int internalId, EntityType entityType){ + this.internalId = internalId; + this.entityType = entityType; + this.entityId = entityCount--; + this.playerInfoData = null; + this.uuid = new UUID(random.nextLong() & -61441L | 16384L, random.nextLong() & 4611686018427387903L | -9223372036854775808L); + entities.put(internalId, this); + + ProtocolLibrary.getProtocolManager().broadcastServerPacket(getSpawnEntityPacket()); + } + + public void move(double locX, double locY, double locZ, float pitch, float yaw, byte headYaw){ + this.locX = locX; + this.locY = locY; + this.locZ = locZ; + this.yaw = (byte)((int)(yaw * 256.0F / 360.0F)); + this.pitch = (byte)((int)(pitch * 256.0F / 360.0F)); + this.headYaw = headYaw; + ProtocolLibrary.getProtocolManager().broadcastServerPacket(getTeleportPacket()); + ProtocolLibrary.getProtocolManager().broadcastServerPacket(getHeadRotationPacket()); + } + + public void animation(byte animation) { + PacketContainer animationPacket = ProtocolLibrary.getProtocolManager().createPacket(PacketType.Play.Server.ANIMATION); + StructureModifier ints = animationPacket.getIntegers(); + ints.write(0, entityId); + ints.write(1, (int) animation); + ProtocolLibrary.getProtocolManager().broadcastServerPacket(animationPacket); + } + + public void setVelocity(double dX, double dY, double dZ) { + PacketContainer velocityPacket = ProtocolLibrary.getProtocolManager().createPacket(PacketType.Play.Server.ENTITY_VELOCITY); + StructureModifier ints = velocityPacket.getIntegers(); + ints.write(0, entityId); + ints.write(1, calcVelocity(dX)); + ints.write(2, calcVelocity(dY)); + ints.write(3, calcVelocity(dZ)); + ProtocolLibrary.getProtocolManager().broadcastServerPacket(velocityPacket); + } + + public void damage() { + PacketContainer statusPacket = ProtocolLibrary.getProtocolManager().createPacket(PacketType.Play.Server.ENTITY_STATUS); + statusPacket.getIntegers().write(0, entityId); + statusPacket.getBytes().write(0, (byte) 2); + ProtocolLibrary.getProtocolManager().broadcastServerPacket(statusPacket); + } + + public void sneak(boolean sneaking) { + sneaks = sneaking; + + if(Core.getVersion() > 12){ + ProtocolLibrary.getProtocolManager().broadcastServerPacket(getDataWatcherPacket(6, getPose(sneaking))); + }else{ + ProtocolLibrary.getProtocolManager().broadcastServerPacket(getDataWatcherPacket(0, sneaking ? (byte) 2 : (byte) 0)); + } + } + + public void setOnFire(boolean perma) { + if(!perma) { + fireTick = 21; + } else { + fireTick = -1; + } + + ProtocolLibrary.getProtocolManager().broadcastServerPacket(getDataWatcherPacket(0, (byte) 1)); + } + + public void setBowDrawn(boolean drawn, boolean offHand) { + if(Core.getVersion() > 8){ + ProtocolLibrary.getProtocolManager().broadcastServerPacket(getDataWatcherPacket(Core.getVersion() > 12 ? 7 : 6, (byte) ((drawn ? 1 : 0) + (offHand ? 2 : 0)))); + }else{ + ProtocolLibrary.getProtocolManager().broadcastServerPacket(getDataWatcherPacket(0, (byte)0x10)); + } + } + + public void setItem(String item, boolean enchanted, String slot) { + ItemStack stack = new ItemStack(Material.valueOf(item.replace("minecraft:", "").toUpperCase()), 1); + if(enchanted) + stack.addUnsafeEnchantment(Enchantment.DURABILITY, 1); + itemSlots.put(slot, stack); + + ProtocolLibrary.getProtocolManager().broadcastServerPacket(getEquipmentPacket(slot, stack)); + } + + public void die(){ + broadcastDeath(); + entities.remove(internalId); + } + + private void broadcastDeath(){ + if(entityType == EntityType.PLAYER){ + PacketContainer infoPacket = ProtocolLibrary.getProtocolManager().createPacket(PacketType.Play.Server.PLAYER_INFO); + infoPacket.getPlayerInfoAction().write(0, EnumWrappers.PlayerInfoAction.REMOVE_PLAYER); + infoPacket.getPlayerInfoDataLists().write(0, Collections.singletonList(playerInfoData)); + ProtocolLibrary.getProtocolManager().broadcastServerPacket(infoPacket); + team.removeEntry(playerInfoData.getProfile().getName()); + } + + PacketContainer destroyPacket = ProtocolLibrary.getProtocolManager().createPacket(PacketType.Play.Server.ENTITY_DESTROY); + destroyPacket.getIntegerArrays().write(0, new int[]{entityId}); + ProtocolLibrary.getProtocolManager().broadcastServerPacket(destroyPacket); + } + + private int calcVelocity(double value) { + return (int)(Math.max(-3.9, Math.min(value, 3.9)) * 8000); + } + + private void fillPositioningPacket(PacketContainer packet, StructureModifier ints){ + ints.write(0, entityId); + if(Core.getVersion() > 8){ + StructureModifier doubles = packet.getDoubles(); + doubles.write(0, locX); + doubles.write(1, locY); + doubles.write(2, locZ); + }else{ + ints.write(1, MathHelper.floor(locX * 32)); + ints.write(2, MathHelper.floor(locY * 32)); + ints.write(3, MathHelper.floor(locZ * 32)); + } + } + + private void fillByteRotation(PacketContainer packet){ + StructureModifier bytes = packet.getBytes(); + bytes.write(0, yaw); + bytes.write(1, pitch); + } + + private PacketContainer getDataWatcherPacket(int index, Object value) { + PacketContainer metadataPacket = ProtocolLibrary.getProtocolManager().createPacket(PacketType.Play.Server.ENTITY_METADATA); + metadataPacket.getIntegers().write(0, entityId); + WrappedWatchableObject watchable = new WrappedWatchableObject(new WrappedDataWatcher.WrappedDataWatcherObject(index, WrappedDataWatcher.Registry.get(value.getClass())), value); + watchable.setDirtyState(true); + metadataPacket.getWatchableCollectionModifier().write(0, Collections.singletonList(watchable)); + return metadataPacket; + } + + private PacketContainer getTeleportPacket(){ + PacketContainer teleportPacket = ProtocolLibrary.getProtocolManager().createPacket(PacketType.Play.Server.ENTITY_TELEPORT); + fillPositioningPacket(teleportPacket, teleportPacket.getIntegers()); + fillByteRotation(teleportPacket); + return teleportPacket; + } + + private PacketContainer getHeadRotationPacket(){ + PacketContainer headRotation = ProtocolLibrary.getProtocolManager().createPacket(PacketType.Play.Server.ENTITY_HEAD_ROTATION); + headRotation.getIntegers().write(0, entityId); + headRotation.getBytes().write(0, headYaw); + return headRotation; + } + + private PacketContainer getSpawnEntityPacket(){ + PacketContainer spawnPacket = ProtocolLibrary.getProtocolManager().createPacket(PacketType.Play.Server.SPAWN_ENTITY); + StructureModifier ints = spawnPacket.getIntegers(); + fillPositioningPacket(spawnPacket, ints); + spawnPacket.getUUIDs().write(0, uuid); + if(Core.getVersion() > 8){ + spawnPacket.getUUIDs().write(0, uuid); + ints.write(1, 0); // dX + ints.write(2, 0); // dY + ints.write(3, 0); // dZ + } + ints.write(4, (int)pitch); + ints.write(5, (int)yaw); + if(Core.getVersion() > 12){ + spawnPacket.getEntityTypeModifier().write(0, entityType); + }else{ + switch(entityType){ + case PRIMED_TNT: + ints.write(6, 50); + break; + case ARROW: + ints.write(6, 60); + break; + case FIREBALL: + ints.write(6, 63); + break; + } + } + return spawnPacket; + } + + private PacketContainer getEquipmentPacket(String slot, ItemStack stack){ + PacketContainer equipmentPacket = ProtocolLibrary.getProtocolManager().createPacket(PacketType.Play.Server.ENTITY_EQUIPMENT); + StructureModifier ints = equipmentPacket.getIntegers(); + ints.write(0, entityId); + if(Core.getVersion() == 8){ + switch(slot){ + case "MAINHAND": + case "OFFHAND": + ints.write(1, 0); + break; + case "HEAD": + ints.write(1, 4); + break; + case "CHEST": + ints.write(1, 3); + break; + case "LEGS": + ints.write(1, 2); + break; + case "FEET": + default: + ints.write(1, 1); + } + }else{ + equipmentPacket.getItemSlots().write(0, EnumWrappers.ItemSlot.valueOf(slot)); + } + equipmentPacket.getItemModifier().write(0, stack); + return equipmentPacket; + } + + private PacketContainer getPlayerInfoPacket(){ + PacketContainer infoPacket = ProtocolLibrary.getProtocolManager().createPacket(PacketType.Play.Server.PLAYER_INFO); + infoPacket.getPlayerInfoAction().write(0, EnumWrappers.PlayerInfoAction.ADD_PLAYER); + infoPacket.getPlayerInfoDataLists().write(0, Collections.singletonList(playerInfoData)); + return infoPacket; + } + + private PacketContainer getNamedSpawnPacket(){ + PacketContainer namedSpawnPacket = ProtocolLibrary.getProtocolManager().createPacket(PacketType.Play.Server.NAMED_ENTITY_SPAWN); + StructureModifier ints = namedSpawnPacket.getIntegers(); + fillPositioningPacket(namedSpawnPacket, ints); + namedSpawnPacket.getUUIDs().write(0, uuid); + fillByteRotation(namedSpawnPacket); + if(Core.getVersion() < 13){ + namedSpawnPacket.getDataWatcherModifier().write(0, new WrappedDataWatcher()); + } + return namedSpawnPacket; + } + + private static Object getPose(boolean sneaking){ + return VersionedCallable.call(new VersionedCallable<>(() -> RecordSystem_14.getPose(sneaking), 14), + new VersionedCallable<>(() -> RecordSystem_15.getPose(sneaking), 15)); + } +} diff --git a/FightSystem_Main/src/de/steamwar/fightsystem/record/RecordSystem.java b/FightSystem_Main/src/de/steamwar/fightsystem/record/RecordSystem.java deleted file mode 100644 index 52e31ba..0000000 --- a/FightSystem_Main/src/de/steamwar/fightsystem/record/RecordSystem.java +++ /dev/null @@ -1,328 +0,0 @@ -/* - 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 . -*/ - -package de.steamwar.fightsystem.record; - -import de.steamwar.core.VersionedCallable; -import de.steamwar.fightsystem.ArenaMode; -import de.steamwar.fightsystem.Config; -import de.steamwar.fightsystem.FightSystem; -import de.steamwar.fightsystem.fight.*; -import de.steamwar.fightsystem.states.FightState; -import de.steamwar.sql.SteamwarUser; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.block.Block; -import org.bukkit.entity.Entity; -import org.bukkit.entity.Player; -import org.bukkit.entity.TNTPrimed; -import org.bukkit.inventory.ItemStack; -import org.bukkit.util.Vector; - -public class RecordSystem { - private RecordSystem(){} - - private static final World WORLD = Bukkit.getWorlds().get(0); - - public static void init(){ - if(!Config.recording()) - return; - - Bukkit.getScheduler().runTaskTimer(FightSystem.getPlugin(), RecordSystem::checkWorldState, 1, 1); - if (Config.SpectateSystem) - new SpectateConnection(); - new FileRecorder(); - if(Config.mode == ArenaMode.EVENT) - teamIds(Config.EventTeamBlueID, Config.EventTeamRedID); - } - - /* - * PlayerJoinPacket (0x00) + int EntityId + int SWUserId - * EntityMovePacket (0x01) + int EntityId + double x, y, z + float pitch, yaw + byte headyaw - * EntityDespawnsPacket (0x02) + int EntityId - * PlayerSneakPacket (0x03) + int EntityId + boolean sneaks - * EntityAnimationPacket (0x04) + int EntityId + byte animation - * TNTSpawnPacket (0x05) + int EntityId - * EntitySpeedPacket (0x06) + int EntityId + double dx, dy, dz - * PlayerItemPacket (0x07) + int EntityId + String item + boolean enchanted + String slot - * ArrowSpawnPacket (0x08) + int EntityId - * FireballSpawnPacket (0x09) + int EntityId - * BowSpanPacket (0x0A) + int EntityId + boolean start + hand - * PlayerDamagePacket (0x0B) + int EntityId - * SetOnFire (0x0C) + int EntityId + boolean perma - * - * - * BlockPacket (0x30) + pos int, byte, int + int BlockState - * ParticlePacket (0x31) + double x, y, z + string particleType - * SoundPacket (0x32) + int x, y, z + string soundType + string soundCategory + float volume, pitch - * ShortBlockPacket (0x33) + pos relative to ArenaMinX,ArenaMinZ byte, byte, byte + short BlockState - * SoundAtPlayerPacket (0x34) + string (soundType, soundCategory) + float volume, pitch - * - * - * ChatPacket (0xA0) + String message - * ActionBarPacket (0xA1) + String message - * SystemPacket (0xA2) + String message - * BlueSchemPacket (0xB0) + int blueSchemId - * RedSchemPacket (0xB1) + int redSchemId - * TeamIDPacket (0xB2) + int blueTeamId, redTeamId - * ScoreboardTitlePacket (0xC0) + String scoreboardTitle - * ScoreboardDataPacket (0xC1) + String key + int value - * - * CommentPacket (0xfe) + String comment - * TickPacket (0xff) - * */ - - public static synchronized void playerJoins(Player p){ - SteamwarUser user = SteamwarUser.get(p.getUniqueId()); - - Recorder.rByte(0x00); - Recorder.rInt(p.getEntityId()); - Recorder.rInt(user.getId()); - entityMoves(p); - } - - public static synchronized void entityMoves(Entity e){ - Location location = e.getLocation(); - - Recorder.rByte(0x01); - Recorder.rInt(e.getEntityId()); - Recorder.rDouble(location.getX()); - Recorder.rDouble(location.getY()); - Recorder.rDouble(location.getZ()); - Recorder.rFloat(location.getPitch()); - Recorder.rFloat(location.getYaw()); - Recorder.rByte((int)(VersionedCallable.call( - new VersionedCallable<>(() -> FightWorld_8.headRotation(e), 8), - new VersionedCallable<>(() -> FightWorld_9.headRotation(e), 9), - new VersionedCallable<>(() -> FightWorld_10.headRotation(e), 10), - new VersionedCallable<>(() -> FightWorld_12.headRotation(e), 12), - new VersionedCallable<>(() -> FightWorld_14.headRotation(e), 14), - new VersionedCallable<>(() -> FightWorld_15.headRotation(e), 15) - ) * 256 / 360)); - Recorder.flush(); - } - - public static synchronized void entityDespawns(Entity e){ - Recorder.rByte(0x02); - Recorder.rInt(e.getEntityId()); - Recorder.flush(); - } - - public static synchronized void playerSneak(Player p, boolean sneaks){ - Recorder.rByte(0x03); - Recorder.rInt(p.getEntityId()); - Recorder.rBoolean(sneaks); - Recorder.flush(); - } - - public static synchronized void entityAnimation(Entity e, int animation){ - Recorder.rByte(0x04); - Recorder.rInt(e.getEntityId()); - Recorder.rByte(animation); - Recorder.flush(); - } - - public static synchronized void tntSpawn(Entity e){ - Recorder.rByte(0x05); - spawnEntity(e); - } - - public static synchronized void entitySpeed(Entity e){ - Vector velocity = e.getVelocity(); - Recorder.rByte(0x06); - Recorder.rInt(e.getEntityId()); - Recorder.rDouble(velocity.getX()); - Recorder.rDouble(velocity.getY()); - Recorder.rDouble(velocity.getZ()); - Recorder.flush(); - } - - public static synchronized void item(Player p, ItemStack item, String slot){ - Recorder.rByte(0x07); - Recorder.rInt(p.getEntityId()); - Recorder.rString(item.getType().getKey().toString()); - Recorder.rBoolean(!item.getEnchantments().isEmpty()); - Recorder.rString(slot); - Recorder.flush(); - } - - public static synchronized void arrowSpawn(Entity e){ - Recorder.rByte(0x08); - spawnEntity(e); - if(e.getFireTicks() > 0) - setOnFire(e, true); - } - - public static synchronized void fireballSpawn(Entity e){ - Recorder.rByte(0x09); - spawnEntity(e); - } - - public static synchronized void bowSpan(Entity e, boolean start, boolean offHand) { - Recorder.rByte(0x0A); - Recorder.rInt(e.getEntityId()); - Recorder.rBoolean(start); - Recorder.rBoolean(offHand); - Recorder.flush(); - } - - public static synchronized void damageAnimation(Player p) { - Recorder.rByte(0x0B); - Recorder.rInt(p.getEntityId()); - Recorder.flush(); - } - - public static synchronized void setOnFire(Entity e, boolean perma) { - Recorder.rByte(0x0C); - Recorder.rInt(e.getEntityId()); - Recorder.rBoolean(perma); - Recorder.flush(); - } - - public static synchronized void blockChange(Block block){ - int blockState = blockToId(block); - - int shortX = block.getX() - Config.ArenaRegion.getMinX(); - int shortZ = block.getZ() - Config.ArenaRegion.getMinZ(); - if((short)blockState == blockState && shortX > 0 && shortX < 256 && shortZ > 0 && shortZ < 256){ - //Short block packet - Recorder.rByte(0x33); - Recorder.rByte(shortX); - Recorder.rByte(block.getY()); - Recorder.rByte(shortZ); - Recorder.rShort((short)blockState); - }else{ - //Block packet - Recorder.rByte(0x30); - Recorder.rInt(block.getX()); - Recorder.rByte(block.getY()); - Recorder.rInt(block.getZ()); - Recorder.rInt(blockState); - } - Recorder.flush(); - } - - public static synchronized void particle(double x, double y, double z, String particleType){ - Recorder.rByte(0x31); - Recorder.rDouble(x); - Recorder.rDouble(y); - Recorder.rDouble(z); - Recorder.rString(particleType); - Recorder.flush(); - } - - public static synchronized void sound(int x, int y, int z, String soundType, String soundCategory, float volume, float pitch){ - Recorder.rByte(0x32); - Recorder.rInt(x); - Recorder.rInt(y); - Recorder.rInt(z); - Recorder.rString(soundType); - Recorder.rString(soundCategory); - Recorder.rFloat(volume); - Recorder.rFloat(pitch); - Recorder.flush(); - } - - public static synchronized void soundAtPlayer(String soundType, float volume, float pitch){ - Recorder.rByte(0x34); - Recorder.rString(soundType); - Recorder.rFloat(volume); - Recorder.rFloat(pitch); - Recorder.flush(); - } - - public static synchronized void chat(String s) { - Recorder.rByte(0xA0); - Recorder.rString(s); - Recorder.flush(); - } - - public static synchronized void actionBar(String s) { - Recorder.rByte(0xA1); - Recorder.rString(s); - Recorder.flush(); - } - - public static synchronized void systemChat(String s) { - Recorder.rByte(0xA2); - Recorder.rString(s); - Recorder.flush(); - } - - public static synchronized void blueSchem(int schemId) { - Recorder.rByte(0xB0); - Recorder.rInt(schemId); - Recorder.flush(); - } - - public static synchronized void redSchem(int schemId) { - Recorder.rByte(0xB1); - Recorder.rInt(schemId); - Recorder.flush(); - } - - public static synchronized void teamIds(int blueTeamId, int redTeamId) { - Recorder.rByte(0xB2); - Recorder.rInt(blueTeamId); - Recorder.rInt(redTeamId); - Recorder.flush(); - } - - public static synchronized void scoreboardTitle(String title){ - Recorder.rByte(0xC0); - Recorder.rString(title); - Recorder.flush(); - } - - public static synchronized void scoreboardData(String key, int value){ - Recorder.rByte(0xC1); - Recorder.rString(key); - Recorder.rInt(value); - Recorder.flush(); - } - - public static synchronized void tick(){ - Recorder.rByte(0xff); - Recorder.flush(); - } - - private static void checkWorldState(){ - tick(); - - if(FightState.getFightState() == FightState.SPECTATE) - return; - - for(TNTPrimed tnt : WORLD.getEntitiesByClass(TNTPrimed.class)){ - entityMoves(tnt); - entitySpeed(tnt); - } - } - - private static void spawnEntity(Entity e){ - Recorder.rInt(e.getEntityId()); - entityMoves(e); - entitySpeed(e); - } - - private static int blockToId(Block block){ - return VersionedCallable.call(new VersionedCallable<>(() -> RecordSystem_8.blockToId(block), 8), - new VersionedCallable<>(() -> RecordSystem_15.blockToId(block), 15)); - } -} diff --git a/FightSystem_Main/src/de/steamwar/fightsystem/record/Recorder.java b/FightSystem_Main/src/de/steamwar/fightsystem/record/Recorder.java index a332331..56ec873 100644 --- a/FightSystem_Main/src/de/steamwar/fightsystem/record/Recorder.java +++ b/FightSystem_Main/src/de/steamwar/fightsystem/record/Recorder.java @@ -19,72 +19,301 @@ package de.steamwar.fightsystem.record; -import java.util.ArrayList; -import java.util.List; +import de.steamwar.core.VersionedCallable; +import de.steamwar.fightsystem.ArenaMode; +import de.steamwar.fightsystem.Config; +import de.steamwar.fightsystem.fight.*; +import de.steamwar.fightsystem.states.FightState; +import de.steamwar.sql.Schematic; +import de.steamwar.sql.SteamwarUser; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.block.Block; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.util.Vector; -public abstract class Recorder { +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.logging.Level; - private static final List recorders = new ArrayList<>(); +public interface Recorder { + DataOutputStream getStream(); - public static void rBoolean(boolean b){ - recorders.forEach((recorder) -> recorder.writeBoolean(b)); + default void enable() { + GlobalRecorder.getInstance().add(this); + + if(ArenaMode.Event.contains(Config.mode)){ + teamIds(Config.EventTeamBlueID, Config.EventTeamRedID); + } + + arenaInfo(); + enableTeam(Fight.getBlueTeam()); + enableTeam(Fight.getRedTeam()); } - public static void rByte(int b){ - recorders.forEach((recorder) -> recorder.writeByte(b)); + default void enableTeam(FightTeam team){ + if(FightState.Schem.contains(FightState.getFightState())){ + if(team.isBlue()) + blueSchem(team.getSchematic()); + else + redSchem(team.getSchematic()); + } + + if(FightState.AntiSpectate.contains(FightState.getFightState())){ + for(FightPlayer player : team.getPlayers()){ + if(player.isLiving()){ + playerJoins(player.getPlayer()); + } + } + } } - public static void rShort(short s){ - recorders.forEach((recorder) -> recorder.writeShort(s)); + default void disable() { + GlobalRecorder.getInstance().remove(this); + try { + getStream().close(); + } catch (IOException e) { + Bukkit.getLogger().log(Level.SEVERE, "Could not close OutputStream", e); + } } - public static void rInt(int i){ - recorders.forEach((recorder) -> recorder.writeInt(i)); + /* + * PlayerJoinPacket (0x00) + int EntityId + int SWUserId + * EntityMovePacket (0x01) + int EntityId + double x, y, z + float pitch, yaw + byte headyaw + * EntityDespawnsPacket (0x02) + int EntityId + * PlayerSneakPacket (0x03) + int EntityId + boolean sneaks + * EntityAnimationPacket (0x04) + int EntityId + byte animation + * TNTSpawnPacket (0x05) + int EntityId + * EntitySpeedPacket (0x06) + int EntityId + double dx, dy, dz + * PlayerItemPacket (0x07) + int EntityId + String item + boolean enchanted + String slot + * ArrowSpawnPacket (0x08) + int EntityId + * FireballSpawnPacket (0x09) + int EntityId + * BowSpanPacket (0x0A) + int EntityId + boolean start + hand + * PlayerDamagePacket (0x0B) + int EntityId + * SetOnFire (0x0C) + int EntityId + boolean perma + * + * ArenaInfo (0x20) + bool blueNegZ + byte arenaY + int arenaMinX + int arenaMinZ + * + * BlockPacket (0x30) + pos int, byte, int + int BlockState + * ParticlePacket (0x31) + double x, y, z + string particleType + * SoundPacket (0x32) + int x, y, z + string soundType + string soundCategory + float volume, pitch + * ShortBlockPacket (0x33) + pos relative to ArenaMinX,ArenaMinZ byte, byte, byte + short BlockState + * SoundAtPlayerPacket (0x34) + string (soundType, soundCategory) + float volume, pitch + * ShortBlockPacket (0x35) + pos relative to ArenaMinX,BluePasteY,ArenaMinZ byte, byte, byte + short BlockState + * + * + * ChatPacket (0xA0) + String message + * ActionBarPacket (0xA1) + String message + * SystemPacket (0xA2) + String message + * + * BlueSchemPacket (0xB0) + int blueSchemId + * RedSchemPacket (0xB1) + int redSchemId + * TeamIDPacket (0xB2) + int blueTeamId, redTeamId + * BlueEmbeddedSchemPacket (0xB3) + int blueSchemId + gzipt NBT blob + * RedEmbeddedSchemPacket (0xB4) + int redSchemId + gzipt NBT blob + * + * ScoreboardTitlePacket (0xC0) + String scoreboardTitle + * ScoreboardDataPacket (0xC1) + String key + int value + * + * CommentPacket (0xfe) + String comment + * TickPacket (0xff) + * */ + + default void playerJoins(Player p){ + SteamwarUser user = SteamwarUser.get(p.getUniqueId()); + + write(0x00, p.getEntityId(), user.getId()); + entityMoves(p); } - public static void rLong(long l){ - recorders.forEach((recorder) -> recorder.writeLong(l)); + default void entityMoves(Entity e){ + Location location = e.getLocation(); + write(0x01, e.getEntityId(), location.getX(), location.getY(), location.getZ(), location.getPitch(), location.getYaw(), (byte)(VersionedCallable.call( + new VersionedCallable<>(() -> FightWorld_8.headRotation(e), 8), + new VersionedCallable<>(() -> FightWorld_9.headRotation(e), 9), + new VersionedCallable<>(() -> FightWorld_10.headRotation(e), 10), + new VersionedCallable<>(() -> FightWorld_12.headRotation(e), 12), + new VersionedCallable<>(() -> FightWorld_14.headRotation(e), 14), + new VersionedCallable<>(() -> FightWorld_15.headRotation(e), 15) + ) * 256 / 360)); } - public static void rFloat(float f){ - recorders.forEach((recorder) -> recorder.writeFloat(f)); + default void entityDespawns(Entity e){ + write(0x02, e.getEntityId()); } - public static void rDouble(double d){ - recorders.forEach((recorder) -> recorder.writeDouble(d)); + default void playerSneak(Player p, boolean sneaks){ + write(0x03, p.getEntityId(), sneaks); } - public static void rString(String s){ - recorders.forEach((recorder) -> recorder.writeString(s)); + default void entityAnimation(Entity e, int animation){ + write(0x04, e.getEntityId(), (byte)animation); } - public static void flush(){ - recorders.forEach(Recorder::doFlush); + default void tntSpawn(Entity e){ + write(0x05, e.getEntityId()); + entityMoves(e); + entitySpeed(e); } - public static void closeAll(){ - while(!recorders.isEmpty()) - recorders.get(0).close(); + default void entitySpeed(Entity e){ + Vector velocity = e.getVelocity(); + write(0x06, e.getEntityId(), velocity.getX(), velocity.getY(), velocity.getZ()); } - protected Recorder(){ - recorders.add(this); + default void item(Player p, ItemStack item, String slot){ + write(0x07, p.getEntityId(), "minecraft:" + item.getType().name().toLowerCase(), !item.getEnchantments().isEmpty(), slot); } - protected void close(){ - closeRecorder(); - recorders.remove(this); + default void arrowSpawn(Entity e){ + write(0x08, e.getEntityId()); + entityMoves(e); + entitySpeed(e); + if(e.getFireTicks() > 0) + setOnFire(e, true); } - protected abstract void writeBoolean(boolean b); - protected abstract void writeByte(int b); - protected abstract void writeShort(short s); - protected abstract void writeInt(int i); - protected abstract void writeLong(long l); - protected abstract void writeFloat(float f); - protected abstract void writeDouble(double d); - protected abstract void writeString(String s); - protected abstract void doFlush(); + default void fireballSpawn(Entity e){ + write(0x09, e.getEntityId()); + entityMoves(e); + entitySpeed(e); + } - protected abstract void closeRecorder(); + default void bowSpan(Entity e, boolean start, boolean offHand) { + write(0x0a, e.getEntityId(), start, offHand); + } + + default void damageAnimation(Player p) { + write(0x0b, p.getEntityId()); + } + + default void setOnFire(Entity e, boolean perma) { + write(0x0c, e.getEntityId(), perma); + } + + default void arenaInfo(){ + write(0x20, Config.blueNegZ(), (byte)Config.BluePasteRegion.getMinY(), + Config.ArenaRegion.getMinX(), Config.ArenaRegion.getMinZ()); + } + + default void blockChange(Block block){ + int blockState = VersionedCallable.call(new VersionedCallable<>(() -> RecordSystem_8.blockToId(block), 8), + new VersionedCallable<>(() -> RecordSystem_14.blockToId(block), 14), + new VersionedCallable<>(() -> RecordSystem_15.blockToId(block), 15)); + + int shortX = block.getX() - Config.ArenaRegion.getMinX(); + int shortY = block.getY() - Config.BluePasteRegion.getMinY(); + int shortZ = block.getZ() - Config.ArenaRegion.getMinZ(); + if((short)blockState == blockState && shortX >= 0 && shortX < 256 && shortY >= 0 && shortZ >= 0 && shortZ < 256){ + //Short block packet + write(0x35, (byte)shortX, (byte)shortY, (byte)shortZ, (short)blockState); + }else{ + //Block packet + write(0x30, block.getX(), (byte)block.getY(), block.getZ(), blockState); + } + } + + default void particle(double x, double y, double z, String particleType){ + write(0x31, x, y, z, particleType); + } + + default void sound(int x, int y, int z, String soundType, String soundCategory, float volume, float pitch){ + write(0x32, x, y, z, soundType, soundCategory, volume, pitch); + } + + default void soundAtPlayer(String soundType, float volume, float pitch){ + write(0x34, soundType, volume, pitch); + } + + default void chat(String s) { + write(0xa0, s); + } + + default void actionBar(String s) { + write(0xa1, s); + } + + default void systemChat(String s) { + write(0xa2, s); + } + + default void teamIds(int blueTeamId, int redTeamId) { + write(0xb2, blueTeamId, redTeamId); + } + + default void blueSchem(int schemId) { + try { + write(0xb3, schemId, Schematic.getSchemFromDB(schemId).schemData()); + } catch (IOException e) { + Bukkit.getLogger().log(Level.SEVERE, "Could not embed schematic", e); + write(0xb0, schemId); + } + } + + default void redSchem(int schemId) { + try { + write(0xb4, schemId, Schematic.getSchemFromDB(schemId).schemData()); + } catch (IOException e) { + Bukkit.getLogger().log(Level.SEVERE, "Could not embed schematic", e); + write(0xb1, schemId); + } + } + + default void scoreboardTitle(String title){ + write(0xc0, title); + } + + default void scoreboardData(String key, int value){ + write(0xc1, key, value); + } + + default void tick(){ + write(0xff); + } + + default void write(int id, Object... objects){ + DataOutputStream stream = getStream(); + try { + stream.writeByte(id); + for(Object o : objects){ + if(o instanceof Boolean) + stream.writeBoolean((Boolean)o); + else if(o instanceof Byte) + stream.writeByte((Byte)o); + else if(o instanceof Short) + stream.writeShort((Short)o); + else if(o instanceof Integer) + stream.writeInt((Integer)o); + else if(o instanceof Float) + stream.writeFloat((Float)o); + else if(o instanceof Double) + stream.writeDouble((Double)o); + else if(o instanceof String) + stream.writeUTF((String)o); + else if(o instanceof InputStream) + copy((InputStream) o, stream); + else + throw new SecurityException("Undefined write for: " + o.getClass().getName()); + } + stream.flush(); + } catch (IOException e) { + Bukkit.getLogger().log(Level.SEVERE, "Could not write", e); + try { + stream.close(); + } catch (IOException ioException) { + Bukkit.getLogger().log(Level.SEVERE, "Could not close", e); + } + } + } + + static void copy(InputStream var0, OutputStream var1) throws IOException { + int var5; + for(byte[] var4 = new byte[8192]; (var5 = var0.read(var4)) > 0;) { + var1.write(var4, 0, var5); + } + } } diff --git a/FightSystem_Main/src/de/steamwar/fightsystem/record/SpectateConnection.java b/FightSystem_Main/src/de/steamwar/fightsystem/record/SpectateConnection.java deleted file mode 100644 index 9951321..0000000 --- a/FightSystem_Main/src/de/steamwar/fightsystem/record/SpectateConnection.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - 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 . -*/ - -package de.steamwar.fightsystem.record; - -import de.steamwar.fightsystem.Config; -import org.bukkit.Bukkit; - -import java.io.*; -import java.net.Socket; -import java.util.logging.Level; - -public class SpectateConnection extends Recorder{ - - private Socket socket; - private DataOutputStream outputStream; - - SpectateConnection(){ - super(); - try { - this.socket = new Socket(Config.spectateIP, Config.spectatePort); - socket.setSoTimeout(1); // Wait a maximum of 1ms on a blocking operation (flush) - socket.setSoLinger(true, 1); // Wait a maximum of 1ms on close - socket.setTcpNoDelay(true); // Don't wait always on ack - this.outputStream = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream())); - } catch (IOException e) { - Bukkit.getLogger().log(Level.WARNING, "Could not init connection to spectate server", e); - close(); - } - } - - @Override - protected void writeBoolean(boolean b) { - try{ - outputStream.writeBoolean(b); - } catch (IOException e) { - close(); - Bukkit.getLogger().log(Level.SEVERE, "Could not send", e); - } - } - - @Override - protected void writeByte(int b) { - try{ - outputStream.writeByte(b); - } catch (IOException e) { - close(); - Bukkit.getLogger().log(Level.SEVERE, "Could not send", e); - } - } - - @Override - protected void writeShort(short s) { - try{ - outputStream.writeShort(s); - } catch (IOException e) { - close(); - Bukkit.getLogger().log(Level.SEVERE, "Could not send", e); - } - } - - @Override - protected void writeInt(int i) { - try{ - outputStream.writeInt(i); - } catch (IOException e) { - close(); - Bukkit.getLogger().log(Level.SEVERE, "Could not send", e); - } - } - - @Override - protected void writeLong(long l) { - try{ - outputStream.writeLong(l); - } catch (IOException e) { - close(); - Bukkit.getLogger().log(Level.SEVERE, "Could not send", e); - } - } - - @Override - protected void writeFloat(float f) { - try{ - outputStream.writeFloat(f); - } catch (IOException e) { - close(); - Bukkit.getLogger().log(Level.SEVERE, "Could not send", e); - } - } - - @Override - protected void writeDouble(double d) { - try{ - outputStream.writeDouble(d); - } catch (IOException e) { - close(); - Bukkit.getLogger().log(Level.SEVERE, "Could not send", e); - } - } - - @Override - protected void writeString(String s) { - try{ - outputStream.writeUTF(s); - } catch (IOException e) { - close(); - Bukkit.getLogger().log(Level.SEVERE, "Could not send", e); - } - } - - @Override - protected void doFlush() { - try{ - outputStream.flush(); - } catch (IOException e) { - close(); - Bukkit.getLogger().log(Level.SEVERE, "Could not flush", e); - } - } - - @Override - protected void closeRecorder() { - try { - socket.close(); - outputStream.close(); - } catch (IOException e) { - Bukkit.getLogger().log(Level.WARNING, "IOException on socket close", e); - } - } -} diff --git a/FightSystem_Main/src/de/steamwar/fightsystem/states/FightState.java b/FightSystem_Main/src/de/steamwar/fightsystem/states/FightState.java index 52c1490..84deb25 100644 --- a/FightSystem_Main/src/de/steamwar/fightsystem/states/FightState.java +++ b/FightSystem_Main/src/de/steamwar/fightsystem/states/FightState.java @@ -42,7 +42,9 @@ public enum FightState { public static final Set Ingame = Collections.unmodifiableSet(EnumSet.of(PRE_RUNNING, RUNNING)); public static final Set TeamFix = Collections.unmodifiableSet(EnumSet.of(PRE_RUNNING, RUNNING, SPECTATE)); public static final Set Schem = Collections.unmodifiableSet(EnumSet.complementOf(EnumSet.of(PRE_LEADER_SETUP, PRE_SCHEM_SETUP))); + public static final Set Recording = Collections.unmodifiableSet(EnumSet.complementOf(EnumSet.of(PRE_LEADER_SETUP, PRE_SCHEM_SETUP, SPECTATE))); public static final Set AntiRunning = Collections.unmodifiableSet(EnumSet.complementOf(EnumSet.of(RUNNING))); + public static final Set AntiSpectate = Collections.unmodifiableSet(EnumSet.complementOf(EnumSet.of(SPECTATE))); private static final Map stateDependentFeatures = new HashMap<>(); private static FightState fightState = PRE_LEADER_SETUP; diff --git a/FightSystem_Main/src/de/steamwar/fightsystem/utils/FightStatistics.java b/FightSystem_Main/src/de/steamwar/fightsystem/utils/FightStatistics.java index 4e7928f..3075e68 100644 --- a/FightSystem_Main/src/de/steamwar/fightsystem/utils/FightStatistics.java +++ b/FightSystem_Main/src/de/steamwar/fightsystem/utils/FightStatistics.java @@ -19,23 +19,27 @@ package de.steamwar.fightsystem.utils; +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.fight.Fight; import de.steamwar.fightsystem.fight.FightPlayer; import de.steamwar.fightsystem.fight.FightTeam; +import de.steamwar.fightsystem.record.FileRecorder; import de.steamwar.fightsystem.winconditions.Wincondition; import de.steamwar.sql.Elo; import de.steamwar.sql.Schematic; import de.steamwar.sql.SteamwarUser; import org.bukkit.Bukkit; +import java.nio.file.Files; import java.sql.Timestamp; import java.time.Instant; import java.util.logging.Level; import static de.steamwar.sql.Fight.create; +import static de.steamwar.sql.Fight.setReplay; public class FightStatistics { private FightStatistics(){} @@ -92,6 +96,12 @@ public class FightStatistics { savePlayerStats(fp, fightId); for (FightPlayer fp : Fight.getRedTeam().getPlayers()) savePlayerStats(fp, fightId); + + setReplay(fightId, Files.readAllBytes(FileRecorder.getFile().toPath())); + + if(ArenaMode.Event.contains(Config.mode)){ + FightSystem.getEventFight().setFight(fightId); + } }catch(Exception e){ Bukkit.getLogger().log(Level.SEVERE, "Failed to save statistics", e); } diff --git a/FightSystem_Main/src/de/steamwar/fightsystem/utils/TechHider.java b/FightSystem_Main/src/de/steamwar/fightsystem/utils/TechHider.java index 9f8e8a4..49e39e6 100644 --- a/FightSystem_Main/src/de/steamwar/fightsystem/utils/TechHider.java +++ b/FightSystem_Main/src/de/steamwar/fightsystem/utils/TechHider.java @@ -50,7 +50,7 @@ import static de.steamwar.fightsystem.utils.ITechHider.bypass; public class TechHider extends StateDependent { - private static final boolean enabled = !Config.OnlyPublicSchematics && !Config.test() && Config.TechhiderActive; + public static final boolean ENABLED = !Config.OnlyPublicSchematics && !Config.test() && Config.TechhiderActive; private final ProtocolManager protocolManager = ProtocolLibrary.getProtocolManager(); private final Map packetCache = new HashMap<>(); @@ -59,16 +59,10 @@ public class TechHider extends StateDependent { private final int threadMultiplier; public TechHider(){ - super(enabled, FightState.Schem); + super(ENABLED, FightState.Schem); - Set hiddenBlockIds = VersionedCallable.call( - new VersionedCallable<>(TechHider_8::getHiddenBlockIds, 8), - new VersionedCallable<>(TechHider_14::getHiddenBlockIds, 14), - new VersionedCallable<>(TechHider_15::getHiddenBlockIds, 15)); - int obfuscateWith = VersionedCallable.call( - new VersionedCallable<>(TechHider_8::getObfuscateWith, 8), - new VersionedCallable<>(TechHider_14::getObfuscateWith, 14), - new VersionedCallable<>(TechHider_15::getObfuscateWith, 15)); + Set hiddenBlockIds = getHiddenBlockIds(); + int obfuscateWith = getObfuscateWith(); obfuscateMaterial = Material.getMaterial(Config.ObfuscateWith.toUpperCase()); chunkHider = VersionedCallable.call(new VersionedCallable<>(() -> null, 8), @@ -263,8 +257,22 @@ public class TechHider extends StateDependent { } }; + public static Set getHiddenBlockIds(){ + return VersionedCallable.call( + new VersionedCallable<>(TechHider_8::getHiddenBlockIds, 8), + new VersionedCallable<>(TechHider_14::getHiddenBlockIds, 14), + new VersionedCallable<>(TechHider_15::getHiddenBlockIds, 15)); + } + + public static int getObfuscateWith(){ + return VersionedCallable.call( + new VersionedCallable<>(TechHider_8::getObfuscateWith, 8), + new VersionedCallable<>(TechHider_14::getObfuscateWith, 14), + new VersionedCallable<>(TechHider_15::getObfuscateWith, 15)); + } + public static List prepareChunkReload(Player p, boolean hide){ - if(!enabled) + if(!ENABLED) return Collections.emptyList(); List chunksToReload = new ArrayList<>(); Config.ArenaRegion.forEachChunk((x, z) -> { @@ -275,7 +283,7 @@ public class TechHider extends StateDependent { } public static void reloadChunks(Player p, List chunksToReload, boolean hide){ - if(!enabled) + if(!ENABLED) return; Bukkit.getScheduler().runTaskLater(FightSystem.getPlugin(), () -> { for(ChunkPos chunk : chunksToReload){ diff --git a/FightSystem_Main/src/de/steamwar/fightsystem/winconditions/WinconditionTimeTechKO.java b/FightSystem_Main/src/de/steamwar/fightsystem/winconditions/WinconditionTimeTechKO.java index 7dea0d1..dfc9f6d 100644 --- a/FightSystem_Main/src/de/steamwar/fightsystem/winconditions/WinconditionTimeTechKO.java +++ b/FightSystem_Main/src/de/steamwar/fightsystem/winconditions/WinconditionTimeTechKO.java @@ -52,7 +52,7 @@ public class WinconditionTimeTechKO extends Wincondition { public WinconditionTimeTechKO(){ super("TechKO"); - if(Config.BlueToRedZ > 0) { + if(Config.blueNegZ()) { smallerZteam = Fight.getBlueTeam(); biggerZteam = Fight.getRedTeam(); }else{ diff --git a/FightSystem_Main/src/plugin.yml b/FightSystem_Main/src/plugin.yml index eae2084..88fbbec 100644 --- a/FightSystem_Main/src/plugin.yml +++ b/FightSystem_Main/src/plugin.yml @@ -18,6 +18,7 @@ commands: remove: leader: lockschem: + replay: state: skip: win: \ No newline at end of file