mirror of
https://github.com/simon987/Much-Assembly-Required.git
synced 2025-04-19 18:46:43 +00:00
Added functionality to archive list of saves when the game server exits.
The number of saves that will be archived can be modified using max_archive_size in config.properties. Added shutdown hook to Main.java to handle dumping of zip files. Essential functions are in ZipUtils.java.
This commit is contained in:
parent
94c1d4689c
commit
f08b5632cc
@ -1,6 +1,5 @@
|
||||
package net.simon987.server;
|
||||
|
||||
|
||||
import net.simon987.server.event.GameEvent;
|
||||
import net.simon987.server.event.GameEventDispatcher;
|
||||
import net.simon987.server.event.TickEvent;
|
||||
@ -33,6 +32,10 @@ public class GameServer implements Runnable {
|
||||
|
||||
private int maxExecutionTime;
|
||||
|
||||
public ArrayList<byte[]> saveArchive;
|
||||
|
||||
public int maxArchiveSize;
|
||||
|
||||
public GameServer() {
|
||||
|
||||
this.config = new ServerConfiguration(new File("config.properties"));
|
||||
@ -42,7 +45,7 @@ public class GameServer implements Runnable {
|
||||
|
||||
maxExecutionTime = config.getInt("user_timeout");
|
||||
|
||||
//Load all plugins in plugins folder, if it doesn't exist, create it
|
||||
// Load all plugins in plugins folder, if it doesn't exist, create it
|
||||
File pluginDir = new File("plugins/");
|
||||
File[] pluginDirListing = pluginDir.listFiles();
|
||||
|
||||
@ -62,6 +65,9 @@ public class GameServer implements Runnable {
|
||||
|
||||
eventDispatcher = new GameEventDispatcher(pluginManager);
|
||||
|
||||
saveArchive = new ArrayList<byte[]>();
|
||||
|
||||
maxArchiveSize = config.getInt("max_archive_size");
|
||||
}
|
||||
|
||||
public GameUniverse getGameUniverse() {
|
||||
@ -76,9 +82,9 @@ public class GameServer implements Runnable {
|
||||
public void run() {
|
||||
LogManager.LOGGER.info("(G) Started game loop");
|
||||
|
||||
long startTime; //Start time of the loop
|
||||
long uTime; //update time
|
||||
long waitTime; //time to wait
|
||||
long startTime; // Start time of the loop
|
||||
long uTime; // update time
|
||||
long waitTime; // time to wait
|
||||
|
||||
boolean running = true;
|
||||
|
||||
@ -91,7 +97,8 @@ public class GameServer implements Runnable {
|
||||
uTime = System.currentTimeMillis() - startTime;
|
||||
waitTime = config.getInt("tick_length") - uTime;
|
||||
|
||||
LogManager.LOGGER.info("Wait time : " + waitTime + "ms | Update time: " + uTime + "ms | " + (int) (((double) uTime / waitTime) * 100) + "% load");
|
||||
LogManager.LOGGER.info("Wait time : " + waitTime + "ms | Update time: " + uTime + "ms | "
|
||||
+ (int) (((double) uTime / waitTime) * 100) + "% load");
|
||||
|
||||
try {
|
||||
if (waitTime >= 0) {
|
||||
@ -103,18 +110,16 @@ public class GameServer implements Runnable {
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private void tick() {
|
||||
gameUniverse.incrementTime();
|
||||
|
||||
//Dispatch tick event
|
||||
// Dispatch tick event
|
||||
GameEvent event = new TickEvent(gameUniverse.getTime());
|
||||
GameServer.INSTANCE.getEventDispatcher().dispatch(event); //Ignore cancellation
|
||||
GameServer.INSTANCE.getEventDispatcher().dispatch(event); // Ignore cancellation
|
||||
|
||||
|
||||
//Process user code
|
||||
// Process user code
|
||||
ArrayList<User> users_ = gameUniverse.getUsers();
|
||||
for (User user : users_) {
|
||||
|
||||
@ -135,14 +140,14 @@ public class GameServer implements Runnable {
|
||||
}
|
||||
}
|
||||
|
||||
//Process each worlds
|
||||
//Avoid concurrent modification
|
||||
// Process each worlds
|
||||
// Avoid concurrent modification
|
||||
ArrayList<World> worlds = new ArrayList<>(gameUniverse.getWorlds());
|
||||
for (World world : worlds) {
|
||||
world.update();
|
||||
}
|
||||
|
||||
//Save
|
||||
// Save
|
||||
if (gameUniverse.getTime() % config.getInt("save_interval") == 0) {
|
||||
save(new File("save.json"));
|
||||
}
|
||||
@ -155,10 +160,18 @@ public class GameServer implements Runnable {
|
||||
/**
|
||||
* Save game universe to file in JSON format
|
||||
*
|
||||
* @param file JSON file to save
|
||||
* @param file
|
||||
* JSON file to save
|
||||
*/
|
||||
public void save(File file) {
|
||||
|
||||
if (new File(new File("save.json").getAbsolutePath()).exists()) {
|
||||
saveArchive.add(ZipUtils.bytifyFile("save.json"));
|
||||
while(saveArchive.size() > maxArchiveSize) {
|
||||
saveArchive.remove(0);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
FileWriter fileWriter = new FileWriter(file);
|
||||
|
||||
@ -194,4 +207,8 @@ public class GameServer implements Runnable {
|
||||
public void setSocketServer(SocketServer socketServer) {
|
||||
this.socketServer = socketServer;
|
||||
}
|
||||
|
||||
public ArrayList<byte[]> getSaveArchive() {
|
||||
return this.saveArchive;
|
||||
}
|
||||
}
|
||||
|
@ -4,12 +4,24 @@ import net.simon987.server.logging.LogManager;
|
||||
import net.simon987.server.webserver.SocketServer;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
|
||||
|
||||
public class Main {
|
||||
public static void main(String[] args) {
|
||||
|
||||
//Writes all of the files stored in GameServer.saveArray to a zip file.
|
||||
Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
ZipUtils.writeSavesToZip(GameServer.INSTANCE.getSaveArchive());
|
||||
} catch (IOException e) {
|
||||
System.out.println("Error writing saves to zip");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}, "Shutdown-thread"));
|
||||
|
||||
LogManager.initialize();
|
||||
ServerConfiguration config = new ServerConfiguration(new File("config.properties"));
|
||||
|
91
Server/src/main/java/net/simon987/server/ZipUtils.java
Normal file
91
Server/src/main/java/net/simon987/server/ZipUtils.java
Normal file
@ -0,0 +1,91 @@
|
||||
package net.simon987.server;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import net.simon987.server.logging.LogManager;
|
||||
|
||||
public class ZipUtils {
|
||||
|
||||
private static final int BUFFER_SIZE = 1024;
|
||||
|
||||
public static byte[] bytifyFile(String fileName) {
|
||||
|
||||
Path path = Paths.get(fileName);
|
||||
byte[] bytes = null;
|
||||
|
||||
try {
|
||||
bytes = Files.readAllBytes(path);
|
||||
|
||||
} catch (IOException e) {
|
||||
System.out.println("Failed to extract bytes from: " + fileName);
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
public static String getByteArrAsString(byte[] bytes) throws UnsupportedEncodingException {
|
||||
return new String(bytes, "UTF-8");
|
||||
}
|
||||
|
||||
public static void writeSavesToZip(ArrayList<byte[]> array) throws IOException {
|
||||
|
||||
int writeCount = 0;
|
||||
FileOutputStream output = new FileOutputStream("archive_" + getDateTimeStamp() + ".zip");
|
||||
ZipOutputStream stream = new ZipOutputStream(output);
|
||||
byte[] buffer = new byte[BUFFER_SIZE];
|
||||
ByteArrayInputStream bais = new ByteArrayInputStream(buffer);
|
||||
|
||||
while ((bais.read(buffer)) > -1) {
|
||||
for (int i = 0; i < array.size(); i++) {
|
||||
|
||||
ZipEntry entry = new ZipEntry("save_" + getTickTime(array.get(i)) + ".json");
|
||||
stream.putNextEntry(entry);
|
||||
stream.write(array.get(i));
|
||||
stream.closeEntry();
|
||||
writeCount++;
|
||||
}
|
||||
}
|
||||
|
||||
stream.close();
|
||||
output.close();
|
||||
|
||||
LogManager.LOGGER.info(writeCount + " saves moved to zip file archive");
|
||||
}
|
||||
|
||||
private static String getTickTime(byte[] bytes) throws UnsupportedEncodingException {
|
||||
|
||||
Pattern pattern = Pattern.compile("\"time\"");
|
||||
String stringedBytes = getByteArrAsString(bytes);
|
||||
Matcher matcher = pattern.matcher(stringedBytes);
|
||||
int startIndex = 0;
|
||||
|
||||
while (matcher.find()) {
|
||||
startIndex = matcher.end() + 1;
|
||||
}
|
||||
|
||||
int endIndex = stringedBytes.indexOf(",", startIndex);
|
||||
|
||||
return stringedBytes.substring(startIndex, endIndex);
|
||||
}
|
||||
|
||||
private static String getDateTimeStamp() {
|
||||
Date millisToDate = new Date(System.currentTimeMillis());
|
||||
SimpleDateFormat f = new SimpleDateFormat("yyyyMMddHHmmss");
|
||||
return f.format(millisToDate);
|
||||
}
|
||||
|
||||
}
|
@ -63,3 +63,6 @@ wg_maxCopperCount=2
|
||||
user_timeout=500
|
||||
# Free CPU execution time in ms
|
||||
user_free_execution_time=2
|
||||
# ----------------------------------------------
|
||||
# Max saves to archive when the server is shutdown
|
||||
max_archive_size=10
|
Loading…
x
Reference in New Issue
Block a user