Initial working version

This commit is contained in:
Jinks 2020-04-05 00:06:08 +02:00
parent f4a36fe3aa
commit 180d1df9ae
6 changed files with 311 additions and 34 deletions

View file

@ -11,9 +11,9 @@ apply plugin: 'net.minecraftforge.gradle.forge'
//Only edit below this line, the above code adds and enables the necessary things for Forge to be setup.
version = "1.0"
group = "com.yourname.modid" // http://maven.apache.org/guides/mini/guide-naming-conventions.html
archivesBaseName = "modid"
version = "1.12.2-1.0"
group = "com.github.jinks.extbackup" // http://maven.apache.org/guides/mini/guide-naming-conventions.html
archivesBaseName = "ExtBackup"
sourceCompatibility = targetCompatibility = '1.8' // Need this here so eclipse task generates correctly.
compileJava {

View file

@ -1,31 +0,0 @@
package com.example.examplemod;
import net.minecraft.init.Blocks;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.Mod.EventHandler;
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import org.apache.logging.log4j.Logger;
@Mod(modid = ExampleMod.MODID, name = ExampleMod.NAME, version = ExampleMod.VERSION)
public class ExampleMod
{
public static final String MODID = "examplemod";
public static final String NAME = "Example Mod";
public static final String VERSION = "1.0";
private static Logger logger;
@EventHandler
public void preInit(FMLPreInitializationEvent event)
{
logger = event.getModLog();
}
@EventHandler
public void init(FMLInitializationEvent event)
{
// some example code
logger.info("DIRT BLOCK >> {}", Blocks.DIRT.getRegistryName());
}
}

View file

@ -0,0 +1,150 @@
package com.github.jinks.extbackup;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.StandardOpenOption;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.management.PlayerList;
import net.minecraft.util.text.TextComponentString;
import net.minecraft.world.WorldServer;
import net.minecraft.world.storage.ThreadedFileIOBase;
public enum BackupHandler {
INSTANCE;
public long nextBackup = -1L;
public int doingBackup = 0;
public boolean hadPlayersOnline = false;
private boolean youHaveBeenWarned = false;
public void init() {
doingBackup = 0;
nextBackup = System.currentTimeMillis() + ExtBackupConfig.general.time();
File script = ExtBackupConfig.general.getScript();
if (!script.exists()) {
script.getParentFile().mkdirs();
try {
Files.write(script.toPath(), "#!/bin/bash\n# Put your backup script here!\n\nexit 0".getBytes(StandardCharsets.UTF_8));
script.setExecutable(true);
} catch (IOException e) {
ExtBackup.logger.error("Backup script does not exist and cannot be created!");
ExtBackup.logger.error("Disabling ExtBackup!");
ExtBackupConfig.general.enabled = false;
}
}
ExtBackup.logger.info("Starting "+ExtBackup.NAME+" v"+ExtBackup.VERSION);
ExtBackup.logger.info("Active script: " + script.getAbsolutePath());
ExtBackup.logger.info("Next Backup at: " + (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")).format(new Date(nextBackup)));
}
public boolean run(MinecraftServer server) {
if (doingBackup != 0 || !ExtBackupConfig.general.enabled) {
return false;
}
if (doingBackup != 0) {
ExtBackup.logger.warn("Tried to start backup while one is already running!");
return false;
}
File script = ExtBackupConfig.general.getScript();
if (!script.exists() || !script.canExecute()) {
ExtBackup.logger.error("Cannot access or execute backup script. Bailing out!");
return false;
}
doingBackup = 1;
ThreadedFileIOBase.getThreadedIOInstance().queueIO(() -> {
try {
doBackup(server, script);
} catch (Exception ex) {
ex.printStackTrace();
}
doingBackup = 2;
return false;
});
nextBackup = System.currentTimeMillis() + ExtBackupConfig.general.time();
return true;
}
private void doBackup(MinecraftServer server, File script) {
ExtBackup.logger.info("Starting backup.");
PlayerList pl = server.getPlayerList();
ExtBackupUtil.broadcast(server, "Starting Backup!");
try {
if (server.getPlayerList() != null) {
server.getPlayerList().saveAllPlayerData();
}
for (WorldServer world : server.worlds) {
if (world != null) {
world.saveAllChunks(true, null);
world.flushToDisk();
world.disableLevelSaving = true;
}
}
} catch (Exception ex) {
ExtBackup.logger.error("Saving the world failed!");
enableSaving(server);
ex.printStackTrace();
return;
}
ProcessBuilder pb = new ProcessBuilder(script.getAbsolutePath());
int returnValue = -1;
Map<String, String> env = pb.environment();
pb.redirectErrorStream(true);
try {
Process backup = pb.start();
returnValue = backup.waitFor();
} catch (Exception ex) {
enableSaving(server);
ExtBackup.logger.error("Something went wrong with the Backup script!");
ExtBackup.logger.error("Check your Backups.");
ex.printStackTrace();
}
enableSaving(server);
youHaveBeenWarned = false;
ExtBackup.logger.info("Backup done.");
ExtBackupUtil.broadcast(server, "Backup done!");
}
private void enableSaving(MinecraftServer server) {
for (WorldServer world : server.worlds) {
if (world != null) {
world.disableLevelSaving = false;
}
}
}
public void tick(MinecraftServer server, long now) {
if (nextBackup > 0L && nextBackup <= now) {
//ExtBackup.logger.info("Backup time!");
if (!ExtBackupConfig.general.only_if_players_online || hadPlayersOnline || !server.getPlayerList().getPlayers().isEmpty()) {
hadPlayersOnline = false;
run(server);
}
}
if (doingBackup > 1) {
doingBackup = 0;
} else if (doingBackup > 0) {
if (now - nextBackup > 1200000 && !youHaveBeenWarned) {
ExtBackup.logger.warn("There has been a running backup for more than 20 minutes.");
ExtBackup.logger.warn("Something seems to be wrong.");
youHaveBeenWarned = true;
}
}
}
}

View file

@ -0,0 +1,70 @@
package com.github.jinks.extbackup;
import org.apache.logging.log4j.Logger;
import net.minecraft.init.Blocks;
import net.minecraft.server.MinecraftServer;
import net.minecraftforge.fml.common.FMLCommonHandler;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import net.minecraftforge.fml.common.event.FMLServerStartedEvent;
import net.minecraftforge.fml.common.event.FMLServerStoppingEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.PlayerEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent;
@Mod(modid = ExtBackup.MODID, name = ExtBackup.NAME, version = ExtBackup.VERSION, acceptableRemoteVersions = "*")
@Mod.EventBusSubscriber
public class ExtBackup {
public static final String MODID = "extbackup";
public static final String NAME = "ExtBackup";
public static final String VERSION = "1.0";
public static Logger logger;
@Mod.EventHandler
public void preInit(FMLPreInitializationEvent event) {
logger = event.getModLog();
}
@Mod.EventHandler
public void init(FMLInitializationEvent event) {
// some example code
//logger.info("DIRT BLOCK >> {}", Blocks.DIRT.getRegistryName());
}
@Mod.EventHandler
public void serverStarted(FMLServerStartedEvent event) {
BackupHandler.INSTANCE.init();
}
@Mod.EventHandler
public void serverStopping(FMLServerStoppingEvent event) {
if (ExtBackupConfig.general.force_on_shutdown) {
MinecraftServer server = FMLCommonHandler.instance().getMinecraftServerInstance();
if (server != null) {
BackupHandler.INSTANCE.run(server);
}
}
}
@SubscribeEvent
public static void serverTick(TickEvent.ServerTickEvent event) {
if (event.phase != TickEvent.Phase.START) {
MinecraftServer server = FMLCommonHandler.instance().getMinecraftServerInstance();
if (server != null) {
//logger.debug("Server Tick! " + event.phase);
BackupHandler.INSTANCE.tick(server, System.currentTimeMillis());
}
}
}
@SubscribeEvent
public static void playerLoggedOut(PlayerEvent.PlayerLoggedOutEvent event) {
BackupHandler.INSTANCE.hadPlayersOnline = true;
}
}

View file

@ -0,0 +1,73 @@
package com.github.jinks.extbackup;
import net.minecraftforge.fml.client.config.ConfigGuiType;
import net.minecraftforge.fml.client.event.ConfigChangedEvent;
import net.minecraftforge.fml.common.FMLCommonHandler;
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import java.io.File;
import net.minecraftforge.common.config.Config;
import net.minecraftforge.common.config.ConfigManager;
@EventBusSubscriber(modid = ExtBackup.MODID)
@Config(modid = ExtBackup.MODID, category = "")
public class ExtBackupConfig {
public static final General general = new General();
public static class General {
@Config.Comment("Enables backups.")
public boolean enabled = true;
@Config.RangeInt(min = 1, max = 3600)
@Config.Comment({
"Timer in Minutes.",
" 5 - backups every 5 minutes",
" 60 - backups every hour",
"3600 - backups once a day",
})
public int backup_timer = 10;
@Config.Comment("If set to true, no messages will be displayed in chat/status bar.")
public boolean silent = false;
@Config.Comment("Only create backups when players have been online.")
public boolean only_if_players_online = true;
@Config.Comment("Create a backup when server is stopped.")
public boolean force_on_shutdown = true;
@Config.Comment({
"Path to backup script.",
"Default: 'local/extbackup/runbackup.sh' inside the Minecraft instance."})
public String script = "local/extbackup/runbackup.sh";
public long time() {
return (long) (backup_timer * 60000L);
}
private File cachedScript;
public File getScript() {
if (cachedScript == null) {
cachedScript = ExtBackupConfig.general.script.trim().isEmpty() ? new File(FMLCommonHandler.instance().getMinecraftServerInstance().getDataDirectory(), "local/extbackup/runbackup.sh") : new File(ExtBackupConfig.general.script.trim());
}
return cachedScript;
}
}
public static boolean sync() {
ConfigManager.sync(ExtBackup.MODID, Config.Type.INSTANCE);
general.cachedScript = null;
return true;
}
@SubscribeEvent
public static void onConfigChanged(ConfigChangedEvent.OnConfigChangedEvent event)
{
if (event.getModID().equals(ExtBackup.MODID)) {
sync();
}
}
}

View file

@ -0,0 +1,15 @@
package com.github.jinks.extbackup;
import net.minecraft.server.MinecraftServer;
import net.minecraft.util.text.TextComponentString;
public class ExtBackupUtil {
public static void broadcast(MinecraftServer server, String message) {
if (!ExtBackupConfig.general.silent) {
TextComponentString bcMessage = new TextComponentString("[§1ExtBackup§r] " + message);
server.getPlayerList().sendMessage(bcMessage);
}
}
}