package com.jmrapp.terralegion.game.io;
import java.io.IOException;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.files.FileHandle;
import com.jmrapp.terralegion.game.item.inventory.Inventory;
import com.jmrapp.terralegion.game.utils.JSONConverter;
import com.jmrapp.terralegion.game.world.block.BlockType;
import com.jmrapp.terralegion.game.world.chunk.Chunk;
import com.jmrapp.terralegion.game.world.chunk.ChunkManager;
import com.jmrapp.terralegion.game.world.World;
import com.jmrapp.terralegion.game.world.entity.impl.Player;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
public class WorldIO {
public static void saveWorld(World world) {
try {
String basePath = "worlds/" + world.getWorldName();
Gdx.files.external(basePath).mkdirs();
FileHandle handle = Gdx.files.external(basePath + "/world.save");
handle.file().createNewFile();
String totalToken = world.getSeed() + "\n" +
world.getChunkManager().CHUNKS_X + " " + world.getChunkManager().CHUNKS_Y + "\n";
handle.writeString(totalToken, false);
Chunk[][] chunks = world.getChunkManager().getChunks(); //Get the chunks and go through all
for (int y = 0; y < world.getChunkManager().CHUNKS_Y; y++) {
for (int x = 0; x < world.getChunkManager().CHUNKS_X; x++) {
if (chunks[x][y].isGenerated()) { //If it has been generated then save it
saveChunk(world.getWorldName(), chunks[x][y]);
}
}
}
// save player
savePlayer(world.getPlayer());
} catch (IOException e) {
e.printStackTrace();
}
}
public static LoadedWorldInfo loadWorld(World world) {
String basePath = "worlds/" + world.getWorldName();
FileHandle baseDir = Gdx.files.external(basePath);
if (baseDir.exists()) {
FileHandle worldDef = Gdx.files.external(basePath + "/world.save");
String[] lines = worldDef.readString().split("\n");
//Load seed
long seed = Long.parseLong(lines[0]);
//Load Chunk Dimensions
String[] dim = lines[1].split(" ");
int worldChunkSizeWidth = Integer.parseInt(dim[0]);
int worldChunkSizeHeight = Integer.parseInt(dim[1]);
//Load player
Player player = loadPlayer();
LoadedWorldInfo worldInfo = new LoadedWorldInfo(player, seed, worldChunkSizeWidth, worldChunkSizeHeight);
//Go through directory and find all chunks. Load them.
for (FileHandle handle : baseDir.list()) {
if (handle.name().startsWith("chunk")) {
String[] chunkName = handle.name().split("chunk");
String[] chunkPos = chunkName[1].replace(".save", "").split("_");
int x = Integer.parseInt(chunkPos[0]);
int y = Integer.parseInt(chunkPos[1]);
Chunk chunk = loadChunk(world, handle, x, y);
world.getChunkManager().setChunk(chunk, x, y);
}
}
return worldInfo;
}
return null;
}
public static void saveChunk(String worldFileName, Chunk chunk) {
try {
String basePath = "worlds/" + worldFileName;
Gdx.files.external(basePath).mkdirs();
FileHandle handle = Gdx.files.external(basePath + "/chunk" + chunk.getStartX() + "_" + chunk.getStartY() + ".save");
handle.file().createNewFile();
String totalToken = Chunk.CHUNK_SIZE + " " + Chunk.CHUNK_SIZE + "\n"; //First line is the width and the height of the world
for (int y = 0; y < Chunk.CHUNK_SIZE; y++) {
BlockType lastType = null;
int sameCount = 0;
for (int x = 0; x < Chunk.CHUNK_SIZE; x++) {
BlockType type = chunk.getBlock(x, y);
if (type == null) //In case it is null
type = BlockType.AIR;
if (lastType == null) //if it is the first instance because only the first run will be null
lastType = type;
if (type == lastType) { //We're still counting the same blocktype
sameCount++;
} else if (x != 0){ //We found a new blocktype. Save in format <#>-<typeId>
totalToken += lastType.getId() + "-" + sameCount + " ";
sameCount = 1;
lastType = type;
}
}
if (sameCount != 0) { //If there are values not saved and still counting
totalToken += lastType.getId() + "-" + sameCount + "\n";
} else {
totalToken += "\n";
}
}
totalToken += "\n"; //separate wall and blocks
for (int y = 0; y < Chunk.CHUNK_SIZE; y++) {
BlockType lastType = null;
int sameCount = 0;
for (int x = 0; x < Chunk.CHUNK_SIZE; x++) {
BlockType type = chunk.getWall(x, y);
if (type == null) //In case it is null
type = BlockType.AIR;
if (lastType == null) //if it is the first instance because only the first run will be null
lastType = type;
if (type == lastType) { //We're still counting the same blocktype
sameCount++;
} else if (x != 0){ //We found a new blocktype. Save in format <#>-<typeId>
totalToken += lastType.getId() + "-" + sameCount + " ";
sameCount = 1;
lastType = type;
}
}
if (sameCount != 0) { //If there are values not saved and still counting
totalToken += lastType.getId() + "-" + sameCount + "\n";
} else {
totalToken += "\n";
}
}
handle.writeString(totalToken, false);
} catch (IOException e) {
e.printStackTrace();
}
}
public static Chunk loadChunk(World world, FileHandle handle, int x, int y) {
if (handle.exists()) {
Chunk chunk = new Chunk(world.getChunkManager(), x, y, y == ChunkManager.CHUNKS_Y - 1); //Create a new chunk
String[] rows = handle.readString().split("\n"); //Get all rows
String[] dimensions = rows[0].split(" "); //Get the dimensions from the first line
int width = Integer.parseInt(dimensions[0]); //get the width
int height = Integer.parseInt(dimensions[1]); //get the height
for (int i = 0; i < height; i++) { //Go through each row
String[] rowData = rows[i + 1].split(" "); //Get each column information. + 1 so that we skip the dimension row
int xOffset = 0; //The offset from the last data count
for (int j = 0; j < rowData.length; j++) { //Go through each column entry
String[] data = rowData[j].split("-");
int id = Integer.parseInt(data[0]);
int count = Integer.parseInt(data[1]);
for (int k = 0; k < count; k++) {
BlockType type = BlockType.getBlockType(id);
chunk.setBlock(type, xOffset + k, i, false); //Set the block and call any place events (this will automatically set light values for example)
}
xOffset += count;
}
}
for (int i = 0; i < height; i++) { //Go through each row
String[] rowData = rows[i + 2 + height].split(" "); //Get each column information. + 2 + height so that we skip the dimensions row, the space row, and the block rows
int xOffset = 0; //The offset from the last data count
for (int j = 0; j < rowData.length; j++) { //Go through each column entry
String[] data = rowData[j].split("-");
int id = Integer.parseInt(data[0]);
int count = Integer.parseInt(data[1]);
for (int k = 0; k < count; k++) {
BlockType type = BlockType.getBlockType(id);
chunk.setWall(type, xOffset + k, i, false); //Set the block and call any place events (this will automatically set light values for example)
}
xOffset += count;
}
}
chunk.setGenerated(true);
return chunk;
}
return null; //Chunk file doesn't exist
}
public static boolean chunkFileExists(String worldFileName, int x, int y) {
return Gdx.files.external("worlds/" + worldFileName + "/chunk" + x + "_" + y + ".save").exists();
}
public static void savePlayer(Player player) {
// create the JSONObject for the player information
JSONObject playerInfo = new JSONObject();
// create a JSONObject for the x and y position of the player
JSONObject playerPosition = new JSONObject();
playerPosition.put("x", player.getX());
playerPosition.put("y", player.getY());
// add the position to the JSONObject playerInfo
playerInfo.put("playerPosition", playerPosition);
// create a JSONArray for the inventory items of the player
JSONObject playerInventory = JSONConverter.getJSONFromInventory(player.getInventory());
// add the playerInventory "list" to the JSONObject playerInfo
playerInfo.put("playerInventory", playerInventory);
// write to file
try {
FileHandle handle = Gdx.files.external("player.save");
if (!handle.exists()) {
handle.file().createNewFile();
}
handle.writeString(playerInfo.toJSONString(), false);
} catch(IOException ex) {
ex.printStackTrace();
}
}
public static Player loadPlayer() {
try {
FileHandle handle = Gdx.files.external("player.save");
if (!handle.exists()) {
// not saved player yet
return null;
}
String JSONString = handle.readString();
JSONObject playerInfo = (JSONObject) new JSONParser().parse(JSONString);
JSONObject playerPosition = (JSONObject) playerInfo.get("playerPosition");
Player player = new Player(Float.parseFloat(playerPosition.get("x").toString()), Float.parseFloat(playerPosition.get("y").toString()));
JSONObject jsonInventory = (JSONObject) playerInfo.get("playerInventory");
Inventory inventory = JSONConverter.getInventoryFromJSON(jsonInventory);
player.setInventory(inventory);
return player;
} catch(ParseException ex) {
ex.printStackTrace();
}
return null;
}
}