using System; using System.IO; using System.Linq; using System.Xml.Serialization; using System.Collections.Generic; using RageCoop.Core; using GTA; using GTA.Math; using GTA.Native; namespace RageCoop.Client { /// /// /// [XmlRoot(ElementName = "Map")] public class Map { /// /// /// [XmlArray("Props")] [XmlArrayItem("Prop")] public List Props { get; set; } = new List(); } /// /// /// public struct CoopProp { /// /// /// public Vector3 Position { get; set; } /// /// /// public Vector3 Rotation { get; set; } /// /// /// public int Hash { get; set; } /// /// /// public bool Dynamic { get; set; } /// /// /// public int Texture { get; set; } } internal static class MapLoader { // string = file name private static readonly Dictionary _maps = new Dictionary(); private static readonly List _createdObjects = new List(); public static void LoadAll() { string downloadFolder = DownloadManager.ResourceFolder; if (!Directory.Exists(downloadFolder)) { try { Directory.CreateDirectory(downloadFolder); } catch (Exception ex) { Main.Logger.Error(ex.Message); // Without the directory we can't do the other stuff return; } } string[] files = Directory.GetFiles(downloadFolder, "*.xml"); lock (_maps) { for (int i = 0; i < files.Length; i++) { string filePath = files[i]; string fileName = Path.GetFileName(filePath); XmlSerializer serializer = new XmlSerializer(typeof(Map)); Map map; using (var stream = new FileStream(filePath, FileMode.Open)) { try { map = (Map)serializer.Deserialize(stream); } catch (Exception ex) { Main.Logger.Error($"The map with the name \"{fileName}\" couldn't be added!"); Main.Logger.Error($"{ex.Message}"); continue; } } _maps.Add(fileName, map); } } } public static void LoadMap(string name) { lock (_maps) lock (_createdObjects) { if (!_maps.ContainsKey(name) || _createdObjects.Count != 0) { GTA.UI.Notification.Show($"The map with the name \"{name}\" couldn't be loaded!"); Main.Logger.Error($"The map with the name \"{name}\" couldn't be loaded!"); return; } Map map = _maps[name]; foreach (CoopProp prop in map.Props) { Model model = prop.Hash.ModelRequest(); if (model == null) { Main.Logger.Error($"Model for object \"{model.Hash}\" couldn't be loaded!"); continue; } int handle = Function.Call(Hash.CREATE_OBJECT, model.Hash, prop.Position.X, prop.Position.Y, prop.Position.Z, 1, 1, prop.Dynamic); model.MarkAsNoLongerNeeded(); if (handle == 0) { Main.Logger.Error($"Object \"{prop.Hash}\" couldn't be created!"); continue; } _createdObjects.Add(handle); if (prop.Texture > 0 && prop.Texture < 16) { Function.Call(Hash._SET_OBJECT_TEXTURE_VARIATION, handle, prop.Texture); } } } } public static bool AnyMapLoaded() { lock (_createdObjects) return _createdObjects.Any(); } public static void UnloadMap() { lock (_createdObjects) { foreach (int handle in _createdObjects) { unsafe { int tmpHandle = handle; Function.Call(Hash.DELETE_OBJECT, &tmpHandle); } } _createdObjects.Clear(); } } public static void DeleteAll() { UnloadMap(); lock (_maps) { _maps.Clear(); } } } }