package com.jenjinstudios.world.client; import com.jenjinstudios.core.io.Message; import com.jenjinstudios.world.World; import com.jenjinstudios.world.io.WorldDocumentException; import com.jenjinstudios.world.io.WorldDocumentReader; import com.jenjinstudios.world.io.WorldDocumentWriter; import java.io.*; import java.util.Arrays; import java.util.logging.Level; import java.util.logging.Logger; /** * @author Caleb Brinkman */ public class ServerWorldFileTracker { private static final Logger LOGGER = Logger.getLogger(ServerWorldFileTracker.class.getName()); private final WorldClient worldClient; private final File worldFile; private boolean waitingForChecksum; private byte[] checksum; private boolean waitingForFile; private byte[] bytes; private WorldDocumentReader worldDocumentReader; public ServerWorldFileTracker(WorldClient worldClient, File worldFile) { this.worldClient = worldClient; this.worldFile = worldFile; } public void requestServerWorldFileChecksum() { Message worldFileChecksumRequest = this.worldClient.getMessageFactory().generateWorldChecksumRequest(); this.worldClient.getMessageIO().queueOutgoingMessage(worldFileChecksumRequest); } public void requestServerWorldFile() { if (needsWorldFile()) { this.worldClient.getMessageIO().queueOutgoingMessage(this.worldClient.getMessageFactory() .generateWorldFileRequest()); } else { setWaitingForFile(false); } } public void writeReceivedWorldToFile() throws WorldDocumentException { createNewFileIfNecessary(); writeServerWorldToFile(); } public byte[] getChecksum() { return checksum; } public void setChecksum(byte[] checksum) { this.checksum = checksum; } public byte[] getBytes() { return bytes; } public void setBytes(byte[] bytes) { this.bytes = bytes; } public boolean isWaitingForChecksum() { return waitingForChecksum; } public void setWaitingForChecksum(boolean bool) { this.waitingForChecksum = bool; } public boolean isWaitingForFile() { return waitingForFile; } public void setWaitingForFile(boolean waiting) { this.waitingForFile = waiting; } protected World readWorldFromServer() throws WorldDocumentException { World world = null; if (bytes != null) { ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes); worldDocumentReader = new WorldDocumentReader(byteArrayInputStream); world = worldDocumentReader.read(); } return world; } protected World readWorldFromFile() throws WorldDocumentException { World world = null; if (worldFile != null && worldFile.exists()) { try { FileInputStream inputStream = new FileInputStream(worldFile); worldDocumentReader = new WorldDocumentReader(inputStream); world = worldDocumentReader.read(); bytes = worldDocumentReader.getWorldFileBytes(); } catch (FileNotFoundException e) { throw new WorldDocumentException("Couldn't find world file.", e); } } return world; } private boolean needsWorldFile() { boolean checksumsMatch = false; boolean readerNull = worldDocumentReader == null; if (!readerNull) { checksumsMatch = Arrays.equals(getChecksum(), worldDocumentReader.getWorldFileChecksum()); } return !checksumsMatch; } private void createNewFileIfNecessary() throws WorldDocumentException { if (!tryCreateWorldFileDirectory() || !tryCreateWorldFile()) { throw new WorldDocumentException("Unable to create new world file!"); } } private boolean tryCreateWorldFile() throws WorldDocumentException { try { return worldFile.exists() || worldFile.createNewFile(); } catch (IOException e) { throw new WorldDocumentException("Unable to create new file.", e); } } private boolean tryCreateWorldFileDirectory() { return worldFile.getParentFile().exists() || worldFile.getParentFile().mkdirs(); } public void waitForWorldFile() { while (isWaitingForFile()) { waitTenMillis(); } } private void waitTenMillis() { try { Thread.sleep(10); } catch (InterruptedException e) { LOGGER.log(Level.WARNING, "Interrupted while waiting."); } } public void waitForWorldFileChecksum() { while (isWaitingForChecksum()) { waitTenMillis(); } } private void writeServerWorldToFile() throws WorldDocumentException { try (FileOutputStream worldOut = new FileOutputStream(worldFile)) { WorldDocumentWriter worldDocumentWriter = new WorldDocumentWriter(readWorldFromServer()); worldDocumentWriter.write(worldOut); } catch (IOException ex) { throw new WorldDocumentException("Unable to write world file.", ex); } catch (NullPointerException ex) { throw new WorldDocumentException("Can't write world to file until world data has been received."); } } }