Renderer/src/main/java/electrosphere/util/FileUtils.java
2025-05-18 12:45:03 -04:00

571 lines
19 KiB
Java

package electrosphere.util;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import electrosphere.data.entity.creature.ai.AITreeData;
import electrosphere.data.entity.creature.ai.AITreeDataSerializer;
import electrosphere.data.entity.creature.movement.MovementSystem;
import electrosphere.data.entity.creature.movement.MovementSystemSerializer;
import electrosphere.logger.LoggerInterface;
import electrosphere.server.macro.character.data.CharacterData;
import electrosphere.server.macro.character.data.CharacterDataSerializer;
import electrosphere.server.physics.terrain.generation.noise.NoiseModuleSerializer;
import electrosphere.server.physics.terrain.generation.noise.NoiseSampler;
import electrosphere.util.annotation.AnnotationExclusionStrategy;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.nio.ByteBuffer;
import java.nio.channels.SeekableByteChannel;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import javax.imageio.ImageIO;
import org.lwjgl.BufferUtils;
/**
* Utilities for dealing with files
*/
public class FileUtils {
/**
* Creates the gson instance
*/
static {
//init gson
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(MovementSystem.class, new MovementSystemSerializer());
gsonBuilder.registerTypeAdapter(AITreeData.class, new AITreeDataSerializer());
gsonBuilder.registerTypeAdapter(NoiseSampler.class, new NoiseModuleSerializer());
gsonBuilder.registerTypeAdapter(CharacterData.class, new CharacterDataSerializer());
gsonBuilder.addDeserializationExclusionStrategy(new AnnotationExclusionStrategy());
gsonBuilder.addSerializationExclusionStrategy(new AnnotationExclusionStrategy());
gson = gsonBuilder.create();
//init gamedir
gameDir = Paths.get("").toFile();
}
//used for serialization/deserialization in file operations
static Gson gson;
//the game's root directory
static File gameDir = null;
//maximum number of attempt to read the file
static final int maxReadFails = 3;
//Timeout duration between read attempts
static final int READ_TIMEOUT_DURATION = 5;
/**
* Reads a file to a string
* @param f The file
* @return The string
*/
public static String readFileToString(File f){
String rVal = "";
BufferedReader reader;
try {
reader = Files.newBufferedReader(f.toPath());
int failCounter = 0;
boolean reading = true;
StringBuilder builder = new StringBuilder("");
while(reading){
if(reader.ready()){
failCounter = 0;
int nextValue = reader.read();
if(nextValue == -1){
reading = false;
} else {
builder.append((char)nextValue);
}
} else {
failCounter++;
if(failCounter > maxReadFails){
reading = false;
} else {
try {
TimeUnit.MILLISECONDS.sleep(READ_TIMEOUT_DURATION);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
}
}
rVal = builder.toString();
} catch (IOException ex) {
ex.printStackTrace();
}
return rVal;
}
public static String readStreamToString(InputStream resourceInputStream){
String rVal = "";
BufferedReader reader;
try {
reader = new BufferedReader(new InputStreamReader(resourceInputStream));
int failCounter = 0;
boolean reading = true;
StringBuilder builder = new StringBuilder("");
while(reading){
if(reader.ready()){
failCounter = 0;
int nextValue = reader.read();
if(nextValue == -1){
reading = false;
} else {
builder.append((char)nextValue);
}
} else {
failCounter++;
if(failCounter > maxReadFails){
reading = false;
} else {
try {
TimeUnit.MILLISECONDS.sleep(READ_TIMEOUT_DURATION);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
}
}
rVal = builder.toString();
} catch (IOException ex) {
ex.printStackTrace();
}
return rVal;
}
/**
* Sanitizes a relative file path, guaranteeing that the initial slash is correct
* @param filePath The raw file path
* @return The sanitized file path
*/
public static String sanitizeFilePath(String filePath){
String rVal = new String(filePath);
rVal = rVal.trim();
if(rVal.startsWith("./")){
return rVal;
} else if(!rVal.startsWith("/")){
rVal = "/" + rVal;
}
return rVal;
}
/**
* Serializes an object to a filepath
* @param filePath The filepath
* @param object The object
*/
public static void serializeObjectToFilePath(String filePath, Object object){
Path path = new File(filePath).toPath();
try {
Files.write(path, gson.toJson(object).getBytes());
} catch (IOException ex) {
LoggerInterface.loggerFileIO.ERROR(filePath, ex);
}
}
/**
* Serializes an object to a filepath
* @param file The file to save to
* @param object The object
*/
public static void serializeObjectToFilePath(File file, Object object){
Path path = file.toPath();
try {
Files.write(path, gson.toJson(object).getBytes());
} catch (IOException ex) {
LoggerInterface.loggerFileIO.ERROR(file.getAbsolutePath(), ex);
}
}
/**
* Gets an assets file
* @param pathName The relative path in the assets folder
* @return The file
*/
public static File getAssetFile(String pathName){
String sanitizedFilePath = sanitizeFilePath(pathName);
File targetFile = new File("./assets" + sanitizedFilePath);
return targetFile;
}
/**
* Gets an assets file
* @param pathName The relative path in the assets folder
* @return The file
*/
public static String getAssetFileString(String pathName){
String sanitizedFilePath = sanitizeFilePath(pathName);
return "./assets" + sanitizedFilePath;
}
/**
* Gets an assets file as a byte buffer
* @param pathName The relative path in the assets folder
* @return The byte buffer containing the contents of the asset file
* @throws IOException Thrown if there are any io issues
*/
public static ByteBuffer getAssetFileAsByteBuffer(String pathName) throws IOException{
String sanitizedFilePath = sanitizeFilePath(pathName);
File targetFile = new File("./assets" + sanitizedFilePath);
ByteBuffer buff = null;
try(SeekableByteChannel byteChannel = Files.newByteChannel(targetFile.toPath())){
buff = BufferUtils.createByteBuffer((int)(byteChannel.size() + 1));
while(byteChannel.read(buff) != -1){
}
buff.flip();
}
return buff;
}
/**
* Gets a cache file
* @param pathName The relative path in the cache folder
* @return The file
*/
public static File getCacheFile(String pathName){
String sanitizedFilePath = sanitizeFilePath(pathName);
File targetFile = new File("./.cache" + sanitizedFilePath);
return targetFile;
}
/**
* Gets a save file
* @param saveName The name of the save
* @param pathName The relative path in the save's folder
* @return the file
*/
public static File getSaveFile(String saveName, String pathName){
String sanitizedFilePath = sanitizeFilePath(pathName);
String fullPath = "./saves/" + saveName + "/" + sanitizedFilePath;
File targetFile = new File(fullPath);
return targetFile;
}
/**
* Gets an asset file as a stream
* @param pathName The path of the file
* @return The stream
* @throws IOException Thrown if Files fails to create the stream
*/
public static InputStream getAssetFileAsStream(String pathName) throws IOException{
String sanitizedFilePath = sanitizeFilePath(pathName);
File targetFile = new File("./assets" + sanitizedFilePath);
return Files.newInputStream(targetFile.toPath());
}
/**
* Gets an asset file as a string
* @param pathName The path of the file
* @return The string
* @throws IOException Thrown if Files fails to read the file
*/
public static String getAssetFileAsString(String pathName) throws IOException{
String sanitizedFilePath = sanitizeFilePath(pathName);
File targetFile = new File("./assets" + sanitizedFilePath);
return Files.readString(targetFile.toPath());
}
/**
* Loads an object from the assets folder
* @param <T> The type of object
* @param pathName The relative path to the file
* @param className The class of the object inside the file
* @return The file
*/
public static <T>T loadObjectFromAssetPath(String pathName, Class<T> className){
T rVal = null;
String sanitizedFilePath = sanitizeFilePath(pathName);
try {
rVal = gson.fromJson(Files.newBufferedReader(getAssetFile(sanitizedFilePath).toPath()), className);
} catch (IOException ex) {
LoggerInterface.loggerFileIO.ERROR(ex);
}
return rVal;
}
/**
* Loads an object from the assets folder
* @param <T> The type of object
* @param file The file to load from
* @param className The class of the object inside the file
* @return The file
*/
public static <T>T loadObjectFromFile(File file, Class<T> className){
T rVal = null;
try {
rVal = gson.fromJson(Files.newBufferedReader(file.toPath()), className);
} catch (IOException ex) {
LoggerInterface.loggerFileIO.ERROR(ex);
}
return rVal;
}
/**
* Gets an sql script file as a string
* @param pathName The path of the sql script
* @return The file's contents as a string
* @throws IOException Thrown if the engine fails to read the file
*/
public static String getSQLScriptFileAsString(String pathName) throws IOException {
String sanitizedFilePath = sanitizeFilePath(pathName);
File targetFile = new File("./assets/DB/" + sanitizedFilePath);
return Files.readString(targetFile.toPath());
}
/**
* Loads an object from a save folder
* @param <T> The type of the object
* @param saveName The name of the save
* @param pathName The path of the file containing the object json
* @param className The class of the object
* @return The object
*/
public static <T>T loadObjectFromSavePath(String saveName, String pathName, Class<T> className){
T rVal = null;
String sanitizedFilePath = sanitizeFilePath(pathName);
try {
rVal = gson.fromJson(Files.newBufferedReader(getSaveFile(saveName,sanitizedFilePath).toPath()), className);
} catch (IOException ex) {
ex.printStackTrace();
}
return rVal;
}
/**
* Serializes an object to a save folder
* @param saveName The name of the save
* @param pathName The path within the save folder to the file
* @param object The object to save
*/
public static void serializeObjectToSavePath(String saveName, String pathName, Object object){
String sanitizedFilePath = sanitizeFilePath(pathName);
try {
Files.write(getSaveFile(saveName,sanitizedFilePath).toPath(), gson.toJson(object).getBytes());
} catch (IOException ex) {
ex.printStackTrace();
}
}
/**
* Reads a binary file as an array of bytes
* @param saveName The save name
* @param pathName The path within the save folder
* @return The array of bytes
*/
public static byte[] loadBinaryFromSavePath(String saveName, String pathName){
byte[] rVal = null;
String sanitizedFilePath = FileUtils.sanitizeFilePath(pathName);
try {
rVal = Files.readAllBytes(FileUtils.getSaveFile(saveName,sanitizedFilePath).toPath());
} catch (IOException e) {
LoggerInterface.loggerFileIO.ERROR(e);
}
return rVal;
}
/**
* Writes a binary file to a save folder's file
* @param saveName The name of the save
* @param pathName The path within the save folder
* @param data The data to write
*/
public static void saveBinaryToSavePath(String saveName, String pathName, byte[] data){
String sanitizedFilePath = FileUtils.sanitizeFilePath(pathName);
try {
File file = FileUtils.getSaveFile(saveName,sanitizedFilePath);
Files.createDirectories(file.getParentFile().toPath());
Files.write(file.toPath(), data);
} catch (IOException ex) {
ex.printStackTrace();
}
}
/**
* Checks if a given file exists in a given save
* @param saveName the name of the save
* @param filePath The path to the file RELATIVE TO THE SAVE DIRECTORY
* @return true if it exists, false otherwise
*/
public static boolean checkSavePathExists(String saveName, String filePath){
String sanitizedFilePath = FileUtils.sanitizeFilePath(filePath);
return FileUtils.getSaveFile(saveName,sanitizedFilePath).exists();
}
/**
* Checks if a directory exists
* @param fileName
* @return true if directory exists, false otherwise
*/
public static boolean checkFileExists(String fileName){
File targetDir = new File(FileUtils.sanitizeFilePath(fileName));
if(targetDir.exists()){
return true;
} else {
return false;
}
}
/**
* Trys to create a directory
* @param directoryName
* @return true if directory was created, false if it was not
*/
public static boolean createDirectory(String directoryName){
String sanitizedPath = sanitizeFilePath(directoryName);
File targetDir = new File(sanitizedPath);
if(targetDir.exists()){
return false;
} else {
return targetDir.mkdirs();
}
}
/**
* Lists the files in a directory
* @param directoryName The path of the directory
* @return A list containing the names of all files inside that directory
*/
public static List<String> listDirectory(String directoryName){
List<String> rVal = new LinkedList<String>();
String sanitizedPath = sanitizeFilePath(directoryName);
File targetDir = new File(sanitizedPath);
String[] files = targetDir.list();
for(String name : files){
rVal.add(name);
}
return rVal;
}
/**
* Recursively deletes a path
* @param path The path
*/
public static void recursivelyDelete(String path){
File file = new File(path);
if(file.isDirectory()){
for(File child : file.listFiles()){
recursivelyDelete(child.getAbsolutePath());
}
}
if(file.exists()){
try {
Files.delete(file.toPath());
} catch (IOException e) {
LoggerInterface.loggerFileIO.ERROR(e);
}
}
}
/**
* Writes a buffered image to a given path
* @param image The image
* @param path The path
*/
public static void writeBufferedImage(BufferedImage image, String path){
//write the buffered image out
try {
File outputFile = FileUtils.getAssetFile(path);
if(!outputFile.getParentFile().exists()){
outputFile.getParentFile().mkdirs();
}
if(!outputFile.exists()){
outputFile.createNewFile();
}
ImageIO.write(image,"png",outputFile);
} catch (IOException e) {
LoggerInterface.loggerRenderer.ERROR(e);
}
}
/**
* Gets a file's path relative to a given directory
* @param file The file
* @param directory The directory
* @return The relative path
*/
public static String relativize(File file, File directory){
return directory.toURI().relativize(file.toURI()).getPath();
}
/**
* Computes the checksum of an object
* @param object The object
* @return The checksum
* @throws IOException Thrown on io errors reading the file
* @throws NoSuchAlgorithmException Thrown if MD5 isn't supported
*/
public static String getChecksum(Serializable object) throws IOException, NoSuchAlgorithmException {
ByteArrayOutputStream baos = null;
ObjectOutputStream oos = null;
try {
baos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(baos);
oos.writeObject(object);
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] bytes = md.digest(baos.toByteArray());
StringBuffer builder = new StringBuffer();
for(byte byteCurr : bytes){
builder.append(String.format("%02x",byteCurr));
}
return builder.toString();
} finally {
oos.close();
baos.close();
}
}
/**
* Writes a ByteBuffer to a file and compresses it
* @param file The file
* @param buff The buffer
*/
public static void writeBufferToCompressedFile(File file, ByteBuffer buff) throws IOException {
try (GZIPOutputStream outStream = new GZIPOutputStream(Files.newOutputStream(file.toPath()))){
outStream.write(buff.array());
}
}
/**
* Writes a ByteBuffer to a file and compresses it
* @param file The file
* @param buff The buffer
*/
public static ByteBuffer readBufferFromCompressedFile(File file) throws IOException {
ByteBuffer buff = null;
try (GZIPInputStream inStream = new GZIPInputStream(Files.newInputStream(file.toPath()))){
byte[] bytes = inStream.readAllBytes();
buff = ByteBuffer.allocate(bytes.length);
buff.put(bytes);
buff.flip();
}
return buff;
}
}