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
.container
.ContainerController
;
10 import ru
.deadsoftware
.cavedroid
.game
.world
.GameWorld
;
12 import javax
.annotation
.CheckForNull
;
14 import java
.nio
.ByteBuffer
;
15 import java
.util
.HashMap
;
18 public class GameSaver
{
20 private static final String TAG
= "GameSaver";
22 public static class Data
{
24 private MobsController mMobsController
;
26 private DropController mDropController
;
28 private ContainerController mContainerController
;
30 private Block
[][] mForeMap
, mBackMap
;
32 public Data(MobsController mobsController
,
33 DropController dropController
,
34 ContainerController containerController
,
37 mMobsController
= mobsController
;
38 mDropController
= dropController
;
39 mContainerController
= containerController
;
44 public MobsController
retrieveMobsController() {
45 assert mMobsController
!= null;
46 MobsController mobsController
= mMobsController
;
47 mMobsController
= null;
48 return mobsController
;
51 public DropController
retrieveDropController() {
52 assert mDropController
!= null;
53 DropController dropController
= mDropController
;
54 mDropController
= null;
55 return dropController
;
58 public ContainerController
retrieveFurnaceController() {
59 assert mContainerController
!= null;
60 ContainerController containerController
= mContainerController
;
61 mContainerController
= null;
62 return containerController
;
65 public Block
[][] retrieveForeMap() {
66 assert mForeMap
!= null;
67 Block
[][] foreMap
= mForeMap
;
72 public Block
[][] retrieveBackMap() {
73 assert mBackMap
!= null;
74 Block
[][] backMap
= mBackMap
;
79 public boolean isEmpty() {
80 return mMobsController
== null &&
81 mDropController
== null &&
82 mContainerController
== null &&
88 private static final int SAVE_VERSION
= 1;
90 private static byte[] intToBytes(int i
) {
91 return ByteBuffer
.allocate(4).putInt(i
).array();
94 private static Map
<String
, Integer
> buildBlocksDictionary(Block
[][] foreMap
, Block
[][] backMap
) {
95 final HashMap
<String
, Integer
> dict
= new HashMap
<>();
98 for (int i
= 0; i
< foreMap
.length
; i
++) {
99 for (int j
= 0; j
< foreMap
[i
].length
; j
++) {
100 for (int k
= 0; k
< 2; k
++) {
101 final Block block
= k
== 0 ? foreMap
[i
][j
] : backMap
[i
][j
];
102 final String key
= block
.getParams().getKey();
103 if (!dict
.containsKey(key
)) {
113 private static void saveDict(FileHandle file
, Map
<String
, Integer
> dict
) {
114 final String
[] arr
= new String
[dict
.size()];
116 for (Map
.Entry
<String
, Integer
> entry
: dict
.entrySet()) {
117 arr
[entry
.getValue()] = entry
.getKey();
120 final StringBuilder builder
= new StringBuilder();
121 for (String key
: arr
) {
123 builder
.append('\n');
126 file
.writeString(builder
.toString(), false);
129 private static String
[] loadDict(FileHandle file
) {
130 return file
.readString().split("\n");
133 private static void saveMap(FileHandle file
, Block
[][] map
, Map
<String
, Integer
> dict
) throws IOException
{
135 int width
= map
.length
;
136 int height
= map
[0].length
;
138 BufferedOutputStream out
= new BufferedOutputStream(file
.write(false));
140 out
.write(SAVE_VERSION
);
141 out
.write(intToBytes(width
));
142 out
.write(intToBytes(height
));
144 for (int y
= 0; y
< height
; y
++) {
145 block
= dict
.get(map
[0][y
].getParams().getKey());
147 for (Block
[] blocks
: map
) {
148 int newValue
= dict
.get(blocks
[y
].getParams().getKey());
149 if (run
>= 0xFF || newValue
!= block
) {
153 block
= dict
.get(blocks
[y
].getParams().getKey());
165 private static Block
[][] loadMap(GameItemsHolder gameItemsHolder
, FileHandle file
, String
[] dict
) throws Exception
{
167 int version
, width
, height
;
170 DataInputStream in
= new DataInputStream(file
.read());
172 version
= in
.readByte();
174 if (SAVE_VERSION
== version
) {
175 width
= in
.readInt();
176 height
= in
.readInt();
177 map
= new Block
[width
][height
];
178 for (int y
= 0; y
< height
; y
++) {
179 for (int x
= 0; x
< width
; x
+= run
) {
180 run
= in
.readUnsignedByte();
181 block
= in
.readUnsignedByte();
182 for (int i
= x
; i
< x
+ run
; i
++) {
183 map
[i
][y
] = gameItemsHolder
.getBlock(dict
[block
]);
188 throw new Exception("version mismatch");
196 public static Data
load(MainConfig mainConfig
, GameItemsHolder gameItemsHolder
) {
197 String folder
= mainConfig
.getGameFolder();
198 FileHandle file
= Gdx
.files
.absolute(folder
+ "/saves/game.sav");
201 ObjectInputStream in
= new ObjectInputStream(file
.read());
202 int version
= in
.readInt();
203 DropController dropController
;
204 MobsController mobsController
;
205 ContainerController containerController
;
207 if (SAVE_VERSION
== version
) {
208 dropController
= (DropController
) in
.readObject();
209 mobsController
= (MobsController
) in
.readObject();
210 containerController
= (ContainerController
) in
.readObject();
212 throw new Exception("version mismatch");
217 final String
[] dict
= loadDict(Gdx
.files
.absolute(mainConfig
.getGameFolder() + "/saves/dict"));
218 Block
[][] foreMap
= loadMap(gameItemsHolder
, Gdx
.files
.absolute(mainConfig
.getGameFolder() + "/saves/foremap.sav"), dict
);
219 Block
[][] backMap
= loadMap(gameItemsHolder
, Gdx
.files
.absolute(mainConfig
.getGameFolder() + "/saves/backmap.sav"), dict
);
221 if (dropController
== null || mobsController
== null) {
222 throw new Exception("couldn't load");
225 return new Data(mobsController
, dropController
, containerController
, foreMap
, backMap
);
226 } catch (Exception e
) {
227 Gdx
.app
.error("GameSaver", e
.getMessage());
233 public static void save(MainConfig mainConfig
,
234 DropController dropController
,
235 MobsController mobsController
,
236 ContainerController containerController
,
237 GameWorld gameWorld
) {
238 String folder
= mainConfig
.getGameFolder();
239 FileHandle file
= Gdx
.files
.absolute(folder
+ "/saves/");
241 file
= Gdx
.files
.absolute(folder
+ "/saves/game.sav");
243 final Block
[][] foreMap
, backMap
;
244 foreMap
= gameWorld
.getFullForeMap();
245 backMap
= gameWorld
.getFullBackMap();
247 final Map
<String
, Integer
> dict
= buildBlocksDictionary(foreMap
, backMap
);
250 ObjectOutputStream out
= new ObjectOutputStream(file
.write(false));
251 out
.writeInt(SAVE_VERSION
);
252 out
.writeObject(dropController
);
253 out
.writeObject(mobsController
);
254 out
.writeObject(containerController
);
257 saveDict(Gdx
.files
.absolute(folder
+ "/saves/dict"), dict
);
258 saveMap(Gdx
.files
.absolute(folder
+ "/saves/foremap.sav"), gameWorld
.getFullForeMap(), dict
);
259 saveMap(Gdx
.files
.absolute(folder
+ "/saves/backmap.sav"), gameWorld
.getFullBackMap(), dict
);
260 } catch (Exception e
) {
265 public static boolean exists(MainConfig mainConfig
) {
266 String folder
= mainConfig
.getGameFolder();
267 return (Gdx
.files
.absolute(folder
+ "/saves/game.sav").exists() &&
268 Gdx
.files
.absolute(folder
+ "/saves/foremap.sav").exists() &&
269 Gdx
.files
.absolute(folder
+ "/saves/backmap.sav").exists());