DEADSOFTWARE

Fix furnace bugs
[cavedroid.git] / core / src / ru / deadsoftware / cavedroid / game / GameSaver.java
1 package ru.deadsoftware.cavedroid.game;
3 import com.badlogic.gdx.Gdx;
4 import com.badlogic.gdx.files.FileHandle;
5 import ru.deadsoftware.cavedroid.MainConfig;
6 import ru.deadsoftware.cavedroid.game.mobs.MobsController;
7 import ru.deadsoftware.cavedroid.game.model.block.Block;
8 import ru.deadsoftware.cavedroid.game.objects.drop.DropController;
9 import ru.deadsoftware.cavedroid.game.objects.furnace.FurnaceController;
10 import ru.deadsoftware.cavedroid.game.world.GameWorld;
12 import javax.annotation.CheckForNull;
13 import java.io.*;
14 import java.nio.ByteBuffer;
15 import java.util.HashMap;
16 import java.util.Map;
18 public class GameSaver {
20 private static final String TAG = "GameSaver";
22 public static class Data {
23 @CheckForNull
24 private MobsController mMobsController;
25 @CheckForNull
26 private DropController mDropController;
27 @CheckForNull
28 private FurnaceController mFurnaceController;
29 @CheckForNull
30 private Block[][] mForeMap, mBackMap;
32 public Data(MobsController mobsController,
33 DropController dropController,
34 FurnaceController furnaceController,
35 Block[][] foreMap,
36 Block[][] backMap) {
37 mMobsController = mobsController;
38 mDropController = dropController;
39 mFurnaceController = furnaceController;
40 mForeMap = foreMap;
41 mBackMap = backMap;
42 }
44 public MobsController retrieveMobsController() {
45 assert mMobsController != null;
46 MobsController mobsController = mMobsController;
47 mMobsController = null;
48 return mobsController;
49 }
51 public DropController retrieveDropController() {
52 assert mDropController != null;
53 DropController dropController = mDropController;
54 mDropController = null;
55 return dropController;
56 }
58 public FurnaceController retrueveFurnaceController() {
59 assert mFurnaceController != null;
60 FurnaceController furnaceController = mFurnaceController;
61 mFurnaceController = null;
62 return furnaceController;
63 }
65 public Block[][] retrieveForeMap() {
66 assert mForeMap != null;
67 Block[][] foreMap = mForeMap;
68 mForeMap = null;
69 return foreMap;
70 }
72 public Block[][] retrieveBackMap() {
73 assert mBackMap != null;
74 Block[][] backMap = mBackMap;
75 mBackMap = null;
76 return backMap;
77 }
79 public boolean isEmpty() {
80 return mMobsController == null && mDropController == null && mForeMap == null && mBackMap == null;
81 }
82 }
84 private static final int SAVE_VERSION = 1;
86 private static byte[] intToBytes(int i) {
87 return ByteBuffer.allocate(4).putInt(i).array();
88 }
90 private static Map<String, Integer> buildBlocksDictionary(Block[][] foreMap, Block[][] backMap) {
91 final HashMap<String, Integer> dict = new HashMap<>();
93 int id = 0;
94 for (int i = 0; i < foreMap.length; i++) {
95 for (int j = 0; j < foreMap[i].length; j++) {
96 for (int k = 0; k < 2; k++) {
97 final Block block = k == 0 ? foreMap[i][j] : backMap[i][j];
98 final String key = block.getParams().getKey();
99 if (!dict.containsKey(key)) {
100 dict.put(key, id++);
106 return dict;
109 private static void saveDict(FileHandle file, Map<String, Integer> dict) {
110 final String[] arr = new String[dict.size()];
112 for (Map.Entry<String, Integer> entry : dict.entrySet()) {
113 arr[entry.getValue()] = entry.getKey();
116 final StringBuilder builder = new StringBuilder();
117 for (String key : arr) {
118 builder.append(key);
119 builder.append('\n');
122 file.writeString(builder.toString(), false);
125 private static String[] loadDict(FileHandle file) {
126 return file.readString().split("\n");
129 private static void saveMap(FileHandle file, Block[][] map, Map<String, Integer> dict) throws IOException {
130 int run, block;
131 int width = map.length;
132 int height = map[0].length;
134 BufferedOutputStream out = new BufferedOutputStream(file.write(false));
136 out.write(SAVE_VERSION);
137 out.write(intToBytes(width));
138 out.write(intToBytes(height));
140 for (int y = 0; y < height; y++) {
141 block = dict.get(map[0][y].getParams().getKey());
142 run = 0;
143 for (Block[] blocks : map) {
144 int newValue = dict.get(blocks[y].getParams().getKey());
145 if (run >= 0xFF || newValue != block) {
146 out.write(run);
147 out.write(block);
148 run = 0;
149 block = dict.get(blocks[y].getParams().getKey());
151 run++;
153 out.write(run);
154 out.write(block);
157 out.flush();
158 out.close();
161 private static Block[][] loadMap(GameItemsHolder gameItemsHolder, FileHandle file, String[] dict) throws Exception {
162 Block[][] map;
163 int version, width, height;
164 int run, block;
166 DataInputStream in = new DataInputStream(file.read());
168 version = in.readByte();
170 if (SAVE_VERSION == version) {
171 width = in.readInt();
172 height = in.readInt();
173 map = new Block[width][height];
174 for (int y = 0; y < height; y++) {
175 for (int x = 0; x < width; x += run) {
176 run = in.readUnsignedByte();
177 block = in.readUnsignedByte();
178 for (int i = x; i < x + run; i++) {
179 map[i][y] = gameItemsHolder.getBlock(dict[block]);
183 } else {
184 throw new Exception("version mismatch");
187 in.close();
188 return map;
191 @CheckForNull
192 public static Data load(MainConfig mainConfig, GameItemsHolder gameItemsHolder) {
193 String folder = mainConfig.getGameFolder();
194 FileHandle file = Gdx.files.absolute(folder + "/saves/game.sav");
196 try {
197 ObjectInputStream in = new ObjectInputStream(file.read());
198 int version = in.readInt();
199 DropController dropController;
200 MobsController mobsController;
201 FurnaceController furnaceController;
203 if (SAVE_VERSION == version) {
204 dropController = (DropController) in.readObject();
205 mobsController = (MobsController) in.readObject();
206 furnaceController = (FurnaceController) in.readObject();
207 } else {
208 throw new Exception("version mismatch");
211 in.close();
213 final String[] dict = loadDict(Gdx.files.absolute(mainConfig.getGameFolder() + "/saves/dict"));
214 Block[][] foreMap = loadMap(gameItemsHolder, Gdx.files.absolute(mainConfig.getGameFolder() + "/saves/foremap.sav"), dict);
215 Block[][] backMap = loadMap(gameItemsHolder, Gdx.files.absolute(mainConfig.getGameFolder() + "/saves/backmap.sav"), dict);
217 if (dropController == null || mobsController == null) {
218 throw new Exception("couldn't load");
221 return new Data(mobsController, dropController, furnaceController, foreMap, backMap);
222 } catch (Exception e) {
223 Gdx.app.error("GameSaver", e.getMessage());
226 return null;
229 public static void save(MainConfig mainConfig,
230 DropController dropController,
231 MobsController mobsController,
232 FurnaceController furnaceController,
233 GameWorld gameWorld) {
234 String folder = mainConfig.getGameFolder();
235 FileHandle file = Gdx.files.absolute(folder + "/saves/");
236 file.mkdirs();
237 file = Gdx.files.absolute(folder + "/saves/game.sav");
239 final Block[][] foreMap, backMap;
240 foreMap = gameWorld.getFullForeMap();
241 backMap = gameWorld.getFullBackMap();
243 final Map<String, Integer> dict = buildBlocksDictionary(foreMap, backMap);
245 try {
246 ObjectOutputStream out = new ObjectOutputStream(file.write(false));
247 out.writeInt(SAVE_VERSION);
248 out.writeObject(dropController);
249 out.writeObject(mobsController);
250 out.writeObject(furnaceController);
251 out.close();
253 saveDict(Gdx.files.absolute(folder + "/saves/dict"), dict);
254 saveMap(Gdx.files.absolute(folder + "/saves/foremap.sav"), gameWorld.getFullForeMap(), dict);
255 saveMap(Gdx.files.absolute(folder + "/saves/backmap.sav"), gameWorld.getFullBackMap(), dict);
256 } catch (Exception e) {
257 e.printStackTrace();
261 public static boolean exists(MainConfig mainConfig) {
262 String folder = mainConfig.getGameFolder();
263 return (Gdx.files.absolute(folder + "/saves/game.sav").exists() &&
264 Gdx.files.absolute(folder + "/saves/foremap.sav").exists() &&
265 Gdx.files.absolute(folder + "/saves/backmap.sav").exists());