Merge pull request 'File based replays' (#2) from newReplays into main

Reviewed-on: SteamWar/SteamWar#2
Reviewed-by: Chaoscaot <max@chaoscaot.de>
This commit is contained in:
2025-01-20 14:55:09 +01:00
4 changed files with 22 additions and 83 deletions
@@ -35,8 +35,9 @@ import java.util.stream.Collectors;
public class Fight {
private static final Table<Fight> table = new Table<>(Fight.class);
private static final SelectStatement<Fight> getPage = new SelectStatement<>(table, "SELECT f.*, (b.NodeId IS NULL OR b.AllowReplay) AND (r.NodeId IS NULL OR r.AllowReplay) AS ReplayAllowed, (SELECT COUNT(1) FROM Replay WHERE Replay.FightID = f.FightID) as ReplayAvailable FROM Fight f LEFT OUTER JOIN SchematicNode b ON f.BlueSchem = b.NodeId LEFT OUTER JOIN SchematicNode r ON f.RedSchem = r.NodeId ORDER BY FightID DESC LIMIT ?, ?");
private static final SelectStatement<Fight> getPage = new SelectStatement<>(table, "SELECT f.*, (b.NodeId IS NULL OR b.AllowReplay) AND (r.NodeId IS NULL OR r.AllowReplay) AS ReplayAllowed FROM Fight f LEFT OUTER JOIN SchematicNode b ON f.BlueSchem = b.NodeId LEFT OUTER JOIN SchematicNode r ON f.RedSchem = r.NodeId ORDER BY FightID DESC LIMIT ?, ?");
private static final Statement insert = table.insertFields(true, "GameMode", "Server", "StartTime", "Duration", "BlueLeader", "RedLeader", "BlueSchem", "RedSchem", "Win", "WinCondition");
private static final Statement updateReplayAvailable = table.update(Table.PRIMARY, "ReplayAvailable");
public static List<Fight> getPage(int page, int elementsPerPage) {
List<Fight> fights = getPage.listSelect(page * elementsPerPage, elementsPerPage);
@@ -54,6 +55,10 @@ public class Fight {
return insert.insertGetKey(gamemode, server, starttime, duration, blueleader, redleader, blueschem, redschem, win, wincondition);
}
public static void markReplayAvailable(int fightID) {
updateReplayAvailable.update(true, fightID);
}
@Getter
@Field(keys = {Table.PRIMARY}, autoincrement = true)
private final int fightID;
@@ -80,10 +85,10 @@ public class Fight {
private final int win;
@Field
private final String wincondition;
@Field
private final boolean replayAvailable;
@Field // Virtual field for easy select
private final boolean replayAllowed;
@Field // Virtual field for easy select
private final boolean replayAvailable;
@Getter
private final List<FightPlayer> bluePlayers = new ArrayList<>();
@@ -1,74 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2022 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.sql;
import de.steamwar.sql.internal.*;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.sql.SQLException;
@AllArgsConstructor
public class Replay {
static {
new SqlTypeMapper<>(File.class, "BLOB", (rs, identifier) -> {
try {
File file = File.createTempFile("replay", ".replay");
file.deleteOnExit();
Files.copy(rs.getBinaryStream(identifier), file.toPath(), StandardCopyOption.REPLACE_EXISTING);
return file;
} catch (IOException e) {
throw new SQLException(e);
}
}, (st, index, value) -> {
try {
st.setBinaryStream(index, new FileInputStream(value));
} catch (FileNotFoundException e) {
throw new SQLException(e);
}
});
}
private static final Table<Replay> table = new Table<>(Replay.class);
private static final SelectStatement<Replay> get = table.select(Table.PRIMARY);
public static final Statement insert = table.insertAll();
public static Replay get(int fightID) {
return get.select(fightID);
}
public static void save(int fightID, File file) {
insert.update(fightID, file);
}
@Field(keys = {Table.PRIMARY})
private final int fightID;
@Getter
@Field
private final File replay;
}
@@ -20,15 +20,18 @@
package de.steamwar.fightsystem.record;
import de.steamwar.fightsystem.Config;
import de.steamwar.sql.Replay;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.util.zip.GZIPInputStream;
public class FileSource extends PacketSource {
public static File replayFile(int fightId) {
return new File("/mnt/storage/replays", fightId + ".replay");
}
public static void startReplay() {
if(Config.replayserver()) {
try {
@@ -41,7 +44,7 @@ public class FileSource extends PacketSource {
if(Config.ReplayID > 0) {
try {
new FileSource(Replay.get(Config.ReplayID).getReplay());
new FileSource(replayFile(Config.ReplayID));
} catch (IOException e) {
throw new SecurityException("Could not start replay", e);
}
@@ -49,7 +52,7 @@ public class FileSource extends PacketSource {
}
public FileSource(File fightFile) throws IOException {
super(new GZIPInputStream(new FileInputStream(fightFile)));
super(new GZIPInputStream(Files.newInputStream(fightFile.toPath())));
new PacketProcessor(this);
}
@@ -27,23 +27,25 @@ 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.record.FileSource;
import de.steamwar.fightsystem.states.FightState;
import de.steamwar.fightsystem.states.OneShotStateDependent;
import de.steamwar.fightsystem.winconditions.Wincondition;
import de.steamwar.network.NetworkSender;
import de.steamwar.network.packets.common.FightEndsPacket;
import de.steamwar.sql.Replay;
import de.steamwar.sql.SchematicNode;
import de.steamwar.sql.SteamwarUser;
import lombok.Getter;
import org.bukkit.Bukkit;
import java.io.IOException;
import java.sql.Timestamp;
import java.time.Instant;
import java.util.logging.Level;
import java.util.stream.Collectors;
import static de.steamwar.sql.Fight.create;
import static de.steamwar.sql.Fight.markReplayAvailable;
public class FightStatistics {
@@ -125,7 +127,10 @@ public class FightStatistics {
}
try {
Replay.save(fightId, FileRecorder.getFile());
if(!FileRecorder.getFile().renameTo(FileSource.replayFile(fightId)))
throw new IOException("Failed to move replay");
markReplayAvailable(fightId);
} catch (Exception e) {
Bukkit.getLogger().log(Level.INFO, "Failed to save replay", e);
}