Skip to content

Commit 33c992f

Browse files
committed
feat(core): add tutorial 47 code
1 parent 16c43fe commit 33c992f

9 files changed

Lines changed: 2370 additions & 236 deletions

File tree

Assets/Scenes/MainMenu.unity

Lines changed: 2124 additions & 193 deletions
Large diffs are not rendered by default.

Assets/Scripts/Core/CoreDataHandler.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ public void SetGameUID(MapData d)
2323
{
2424
_gameUID = $"{d.sceneName}__{System.Guid.NewGuid().ToString()}";
2525
}
26+
public void SetGameUID(string uid)
27+
{
28+
_gameUID = uid;
29+
}
2630

2731
public void SetMapData(MapData d)
2832
{

Assets/Scripts/GameData.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@ public class GamePlayerUnitData : BinarySerializable
1717
// building-specific
1818
public int constructionHP;
1919

20+
public GamePlayerUnitData() { }
21+
22+
protected GamePlayerUnitData(SerializationInfo info, StreamingContext context)
23+
{
24+
BinarySerializable.Deserialize(this, info, context);
25+
}
2026
}
2127
[System.Serializable]
2228
public class GamePlayerData
@@ -29,6 +35,8 @@ public class GamePlayerData
2935
public class GameData : BinarySerializable
3036
{
3137
public static string gameUid;
38+
private static GameData _instance;
39+
public static GameData Instance => _instance;
3240

3341
public static string DATA_FILE_NAME = "GameData.data";
3442

@@ -43,6 +51,19 @@ private static string _GetFilePath()
4351
gameUid,
4452
DATA_FILE_NAME);
4553

54+
public GameData() { }
55+
56+
protected GameData(SerializationInfo info, StreamingContext context)
57+
{
58+
BinarySerializable.Deserialize(this, info, context);
59+
}
60+
61+
public static GameData Load()
62+
{
63+
_instance = (GameData) BinarySerializable.Load(_GetFilePath());
64+
return _instance;
65+
}
66+
4667
public static void Save(GameData instance)
4768
{
4869
BinarySerializable.Save(_GetFilePath(), instance);

Assets/Scripts/GameResource.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ public void AddAmount(int value)
1616
}
1717

1818
public string Name { get => _name; }
19-
public int Amount { get => _currentAmount; }
19+
public int Amount { get => _currentAmount; set { _currentAmount = value; } }
2020
}
2121

2222
[System.Serializable]

Assets/Scripts/Managers/MainMenuManager.cs

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,23 +28,31 @@ public class MainMenuManager : MonoBehaviour
2828
public Text newGameDetailInfoText;
2929
public Transform newGamePlayersList;
3030
public Button startGameButton;
31+
public Transform loadGameScrollview;
32+
public Image loadGameDetailMapCapture;
33+
public Text loadGameDetailInfoText;
34+
public Button loadGameButton;
3135

36+
private MapData[] _maps;
3237
private MapData _selectedMap;
3338
private List<bool> _activePlayers;
3439
private Dictionary<int, PlayerData> _playersData;
3540
private List<Color> _availableColors;
3641

42+
private string _selectedLoadGameUid;
43+
3744
private void Start()
3845
{
46+
_maps = Resources.LoadAll<MapData>("ScriptableObjects/Maps");
3947
_PopulateMapsList();
48+
_PopulateLoadsList();
4049
}
4150

4251
#region New Game
4352
private void _PopulateMapsList()
4453
{
45-
MapData[] maps = Resources.LoadAll<MapData>("ScriptableObjects/Maps");
4654
Transform t; Sprite s;
47-
foreach (MapData map in maps)
55+
foreach (MapData map in _maps)
4856
{
4957
GameObject g = Instantiate(menuScenePickPrefab, newGameScrollview);
5058
t = g.transform;
@@ -231,4 +239,59 @@ public void StartNewGame()
231239
}
232240
#endregion
233241

242+
#region Load Game
243+
private void _PopulateLoadsList()
244+
{
245+
Dictionary<string, MapData> mapsByScene = new Dictionary<string, MapData>();
246+
foreach (MapData m in _maps) mapsByScene[m.sceneName] = m;
247+
248+
// get list of available saves
249+
List<(string, System.DateTime)> availableGames = DataHandler.GetGamesList();
250+
251+
Transform t; Sprite s; MapData map;
252+
string gameUid, sceneName;
253+
foreach ((string gamePath, System.DateTime lastModification) in availableGames)
254+
{
255+
gameUid = System.IO.Path.GetFileName(gamePath);
256+
sceneName = gameUid.Split(
257+
new string[] { "__" }, System.StringSplitOptions.None)[0];
258+
map = mapsByScene[sceneName];
259+
GameObject g = Instantiate(menuScenePickPrefab, loadGameScrollview);
260+
t = g.transform;
261+
s = Resources.Load<Sprite>($"MapCaptures/{map.sceneName}");
262+
t.Find("MapCapture").GetComponent<Image>().sprite = s;
263+
t.Find("Data/Name").GetComponent<Text>().text = map.mapName;
264+
t.Find("Data/Desc").GetComponent<Text>().text =
265+
$"Last modification: {lastModification.ToShortDateString()}, " +
266+
$"{lastModification.ToShortTimeString()}";
267+
_AddSceneLoadListener(g.GetComponent<Button>(), gameUid, map, s);
268+
}
269+
}
270+
271+
private void _SelectLoad(string gameUid, MapData map, Sprite mapSprite)
272+
{
273+
_selectedLoadGameUid = gameUid;
274+
loadGameButton.interactable = true;
275+
loadGameDetailMapCapture.sprite = mapSprite;
276+
loadGameDetailInfoText.text =
277+
$"{map.mapName} <size=20>({map.mapSize}x{map.mapSize})</size>";
278+
}
279+
280+
private void _AddSceneLoadListener(Button b, string gameUid, MapData map, Sprite mapSprite)
281+
{
282+
b.onClick.AddListener(() => _SelectLoad(gameUid, map, mapSprite));
283+
}
284+
285+
public void LoadGame()
286+
{
287+
if (_selectedLoadGameUid == "") return;
288+
289+
CoreDataHandler.instance.SetGameUID(_selectedLoadGameUid);
290+
string sceneName = _selectedLoadGameUid.Split(
291+
new string[] { "__" },
292+
System.StringSplitOptions.None)[0];
293+
CoreBooter.instance.LoadMap(sceneName);
294+
}
295+
#endregion
296+
234297
}

Assets/Scripts/Tools/DataHandler.cs

Lines changed: 107 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,16 @@
1-
using System.Collections.Generic;
1+
using System.Collections.Generic;
2+
using System.IO;
3+
using System.Linq;
24
using UnityEngine;
5+
using UnityEngine.AI;
36

4-
public static class DataHandler
7+
public class DataHandler : MonoBehaviour
58
{
9+
public void Start()
10+
{
11+
DeserializeGameData();
12+
}
13+
614
public static void LoadGameData()
715
{
816
// load building data
@@ -12,14 +20,20 @@ public static void LoadGameData()
1220
Globals.CHARACTER_DATA[d.code] = d;
1321

1422
// load game parameters
23+
string gameUid = CoreDataHandler.instance.GameUID;
24+
1525
GameParameters[] gameParametersList = Resources.LoadAll<GameParameters>("ScriptableObjects/Parameters");
1626
foreach (GameParameters parameters in gameParametersList)
1727
{
1828
if (parameters is GamePlayersParameters pp)
19-
pp.LoadFromFile($"Games/{CoreDataHandler.instance.GameUID}/PlayerParameters");
29+
pp.LoadFromFile($"Games/{gameUid}/PlayerParameters");
2030
else
2131
parameters.LoadFromFile();
2232
}
33+
34+
// load game scene data
35+
GameData.gameUid = gameUid;
36+
GameData.Load();
2337
}
2438

2539
public static void SaveGameData()
@@ -34,6 +48,65 @@ public static void SaveGameData()
3448
GameData.Save(SerializeGameData());
3549
}
3650

51+
public static void DeserializeGameData()
52+
{
53+
GameData data = GameData.Instance;
54+
if (data == null) return;
55+
56+
GamePlayersParameters playerParameters = GameManager.instance.gamePlayersParameters;
57+
for (int p = 0; p < playerParameters.players.Length; p++)
58+
{
59+
GamePlayerData d = data.players[p];
60+
61+
// restore resources
62+
for (int i = 0; i < d.resources.Length; i++)
63+
{
64+
InGameResource r = Globals.GAME_RESOURCE_KEYS[i];
65+
Globals.GAME_RESOURCES[p][r].Amount = d.resources[i];
66+
}
67+
68+
// restore units
69+
foreach (GamePlayerUnitData unit in d.units)
70+
{
71+
Unit u;
72+
string type = unit.unitType;
73+
List<ResourceValue> production = new List<ResourceValue>();
74+
for (int i = 0; i < unit.production.Length; i++)
75+
{
76+
InGameResource r = Globals.GAME_RESOURCE_KEYS[i];
77+
production.Add(new ResourceValue(r, unit.production[i]));
78+
}
79+
if (type == "building")
80+
{
81+
BuildingData bd = Globals.BUILDING_DATA
82+
.Where((BuildingData x) => x.code == unit.code)
83+
.First();
84+
u = new Building(bd, p, production);
85+
u.SetPosition(unit.position);
86+
u.Place(true);
87+
((Building)u).SetConstructionHP(unit.constructionHP, true);
88+
}
89+
else
90+
{
91+
CharacterData cd = Globals.CHARACTER_DATA[unit.code];
92+
u = new Character(cd, p);
93+
u.ComputeProduction();
94+
u.Transform.GetComponent<NavMeshAgent>().Warp(unit.position);
95+
}
96+
97+
u.Uid = unit.uid;
98+
u.HP = unit.currentHealth;
99+
u.Level = unit.level - 1;
100+
u.LevelUp(true);
101+
u.AttackDamage = unit.attackDamage;
102+
u.AttackRange = unit.attackRange;
103+
}
104+
}
105+
106+
Camera.main.transform.position = data.camPosition;
107+
EventManager.TriggerEvent("UpdateResourceTexts");
108+
}
109+
37110
public static GameData SerializeGameData()
38111
{
39112
List<GamePlayerData> players = new List<GamePlayerData>();
@@ -55,6 +128,8 @@ public static GameData SerializeGameData()
55128
List<GamePlayerUnitData> units = new List<GamePlayerUnitData>();
56129
foreach (Unit unit in Unit.UNITS_BY_OWNER[p])
57130
{
131+
if (!unit.Transform) continue;
132+
58133
int[] production = new int[Globals.GAME_RESOURCE_KEYS.Length];
59134
for (int i = 0; i < Globals.GAME_RESOURCE_KEYS.Length; i++)
60135
{
@@ -89,4 +164,33 @@ public static GameData SerializeGameData()
89164
data.camPosition = Camera.main.transform.position;
90165
return data;
91166
}
167+
168+
public static List<(string, System.DateTime)> GetGamesList()
169+
{
170+
string rootPath = Path.Combine(
171+
Application.persistentDataPath,
172+
BinarySerializable.DATA_DIRECTORY,
173+
"Games");
174+
string[] gameDirs = Directory.GetDirectories(rootPath);
175+
176+
// filter to keep only game folders with a game save
177+
IEnumerable<string> validGameDirs = gameDirs
178+
.Where((string d)
179+
=> File.Exists(Path.Combine(d, GameData.DATA_FILE_NAME)));
180+
181+
// extract the last modification time
182+
List<(string, System.DateTime)> games = new List<(string, System.DateTime)>();
183+
foreach (string dir in validGameDirs)
184+
{
185+
games.Add((
186+
dir,
187+
File.GetLastWriteTime(Path.Combine(dir, GameData.DATA_FILE_NAME))
188+
));
189+
}
190+
191+
// sort by reverse chronological order (most recent first)
192+
return games
193+
.OrderByDescending(((string, System.DateTime) x) => x.Item2)
194+
.ToList();
195+
}
92196
}

Assets/Scripts/Units/Buildings/Building.cs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System.Collections.Generic;
1+
using System.Collections.Generic;
22
using UnityEngine;
33

44
public enum BuildingPlacement
@@ -90,9 +90,9 @@ public void SetMaterials(BuildingPlacement placement)
9090
_buildingManager.meshRenderer.materials = materials.ToArray();
9191
}
9292

93-
public override void Place()
93+
public override void Place(bool fromSavedData = false)
9494
{
95-
base.Place();
95+
base.Place(fromSavedData);
9696
// set placement state
9797
_placement = BuildingPlacement.FIXED;
9898
// change building materials
@@ -101,7 +101,7 @@ public override void Place()
101101
SetConstructionHP(0);
102102
}
103103

104-
public void SetConstructionHP(int constructionHP)
104+
public void SetConstructionHP(int constructionHP, bool fromSavedData = false)
105105
{
106106
if (_isAlive) return;
107107

@@ -115,7 +115,7 @@ public void SetConstructionHP(int constructionHP)
115115
_rendererMesh.sharedMesh = m;
116116

117117
if (constructionRatio >= 1)
118-
_SetAlive();
118+
_SetAlive(fromSavedData);
119119
}
120120

121121
public void CheckValidPlacement()
@@ -160,7 +160,7 @@ public void RemoveConstructor(int index)
160160
_buildingManager.ambientSource.Pause();
161161
}
162162

163-
private void _SetAlive()
163+
private void _SetAlive(bool fromSavedData = false)
164164
{
165165
_isAlive = true;
166166
_bt.enabled = true;
@@ -173,7 +173,8 @@ private void _SetAlive()
173173
_smokeVfx.Clear();
174174
if (_owner == GameManager.instance.gamePlayersParameters.myPlayerId)
175175
{
176-
EventManager.TriggerEvent("PlaySoundByName", "onBuildingPlacedSound");
176+
if (!fromSavedData)
177+
EventManager.TriggerEvent("PlaySoundByName", "onBuildingPlacedSound");
177178
// replace construction sound
178179
if (_ambientSound)
179180
{

Assets/Scripts/Units/Buildings/BuildingPlacer.cs

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,21 @@ private void Start()
1818
{
1919
instance = this;
2020

21-
Transform spawnpoints = GameObject.Find("Spawnpoints").transform;
22-
23-
BuildingData initialBuilding = GameManager.instance.gameGlobalParameters.initialBuilding;
24-
GamePlayersParameters p = GameManager.instance.gamePlayersParameters;
25-
Vector3 pos;
26-
for (int i = 0; i < p.players.Length; i++)
21+
// if no previous game data, spawn initial buildings
22+
if (GameData.Instance == null)
2723
{
28-
pos = spawnpoints.GetChild(i).position;
29-
SpawnBuilding(initialBuilding, i, pos);
30-
if (i == p.myPlayerId)
31-
Camera.main.GetComponent<CameraManager>().SetPosition(pos);
24+
Transform spawnpoints = GameObject.Find("Spawnpoints").transform;
25+
26+
BuildingData initialBuilding = GameManager.instance.gameGlobalParameters.initialBuilding;
27+
GamePlayersParameters p = GameManager.instance.gamePlayersParameters;
28+
Vector3 pos;
29+
for (int i = 0; i < p.players.Length; i++)
30+
{
31+
pos = spawnpoints.GetChild(i).position;
32+
SpawnBuilding(initialBuilding, i, pos);
33+
if (i == p.myPlayerId)
34+
Camera.main.GetComponent<CameraManager>().SetPosition(pos);
35+
}
3236
}
3337
}
3438

0 commit comments

Comments
 (0)