public void TsMapOverlayItem825(int startOffset) { var fileOffset = startOffset + 0x34; // Set position at start of flags ZoomLevelVisibility = MemoryHelper.ReadUint8(Sector.Stream, fileOffset); var dlcGuardCount = (Sector.Mapper.IsEts2) ? Common.Ets2DlcGuardCount : Common.AtsDlcGuardCount; Hidden = MemoryHelper.ReadInt8(Sector.Stream, fileOffset + 0x01) > dlcGuardCount || ZoomLevelVisibility == 255; var type = MemoryHelper.ReadUint8(Sector.Stream, fileOffset + 0x02); var overlayToken = MemoryHelper.ReadUInt64(Sector.Stream, fileOffset += 0x05); if (type == 1 && overlayToken == 0) { overlayToken = ScsHash.StringToToken("parking_ico"); // parking } Overlay = Sector.Mapper.LookupOverlay(overlayToken); OverlayName = ScsHash.TokenToString(overlayToken); if (Overlay == null) { Valid = false; if (overlayToken != 0) { Log.Msg($"Could not find Overlay: '{OverlayName}'({ScsHash.StringToToken(OverlayName):X}), in {Path.GetFileName(Sector.FilePath)} @ {fileOffset}"); } } fileOffset += 0x08 + 0x08; // 0x08(overlayId) + 0x08(nodeUid) BlockSize = fileOffset - startOffset; }
public void TsPrefabItem855(int startOffset) { var fileOffset = startOffset + 0x34; // Set position at start of flags var dlcGuardCount = (Sector.Mapper.IsEts2) ? Common.Ets2DlcGuardCount : Common.AtsDlcGuardCount; Hidden = MemoryHelper.ReadInt8(Sector.Stream, fileOffset + 0x01) > dlcGuardCount || (MemoryHelper.ReadUint8(Sector.Stream, fileOffset + 0x02) & 0x02) != 0; var prefabId = MemoryHelper.ReadUInt64(Sector.Stream, fileOffset += 0x05); // 0x05(flags) Prefab = Sector.Mapper.LookupPrefab(prefabId); if (Prefab == null) { Valid = false; Log.Msg($"Could not find Prefab: '{ScsHash.TokenToString(prefabId)}'({MemoryHelper.ReadUInt64(Sector.Stream, fileOffset):X}), " + $"in {Path.GetFileName(Sector.FilePath)} @ {fileOffset} (item uid: 0x{Uid:X})"); } var additionalPartsCount = MemoryHelper.ReadInt32(Sector.Stream, fileOffset += 0x08 + 0x08); // 0x08(prefabId) + 0x08(m_variant) var nodeCount = MemoryHelper.ReadInt32(Sector.Stream, fileOffset += 0x04 + (additionalPartsCount * 0x08)); // 0x04(addPartsCount) + additionalParts fileOffset += 0x04; // set cursor after nodeCount for (var i = 0; i < nodeCount; i++) { Nodes.Add(MemoryHelper.ReadUInt64(Sector.Stream, fileOffset)); fileOffset += 0x08; } var connectedItemCount = MemoryHelper.ReadInt32(Sector.Stream, fileOffset); Origin = MemoryHelper.ReadUint8(Sector.Stream, fileOffset += 0x04 + (0x08 * connectedItemCount) + 0x08); // 0x04(connItemCount) + connItemUids + 0x08(m_some_uid) fileOffset += 0x02 + nodeCount * 0x0C + 0x08; // 0x02(origin & padding) + nodeLooks + 0x08(padding2) BlockSize = fileOffset - startOffset; }
public void TsCompanyItem858(int startOffset) { var fileOffset = startOffset + 0x34; // Set position at start of flags var dlcGuardCount = (Sector.Mapper.IsEts2) ? Common.Ets2DlcGuardCount : Common.AtsDlcGuardCount; Hidden = MemoryHelper.ReadInt8(Sector.Stream, fileOffset + 0x01) > dlcGuardCount; OverlayToken = MemoryHelper.ReadUInt64(Sector.Stream, fileOffset += 0x05); // 0x05(flags) Overlay = Sector.Mapper.LookupOverlay(OverlayToken); if (Overlay == null) { Valid = false; if (OverlayToken != 0) { Log.Msg( $"Could not find Company Overlay: '{ScsHash.TokenToString(OverlayToken)}'({OverlayToken:X}), in {Path.GetFileName(Sector.FilePath)} @ {fileOffset}"); } } Nodes.Add(MemoryHelper.ReadUInt64(Sector.Stream, fileOffset += 0x08 + 0x08)); // (prefab uid) | 0x08(OverlayToken) + 0x08(uid[0]) var count = MemoryHelper.ReadInt32(Sector.Stream, fileOffset += 0x08 + 0x08); // count | 0x08 (uid[1] & uid[2]) count = MemoryHelper.ReadInt32(Sector.Stream, fileOffset += 0x04 + (0x08 * count)); // count2 count = MemoryHelper.ReadInt32(Sector.Stream, fileOffset += 0x04 + (0x08 * count)); // count3 count = MemoryHelper.ReadInt32(Sector.Stream, fileOffset += 0x04 + (0x08 * count)); // count4 count = MemoryHelper.ReadInt32(Sector.Stream, fileOffset += 0x04 + (0x08 * count)); // count5 count = MemoryHelper.ReadInt32(Sector.Stream, fileOffset += 0x04 + (0x08 * count)); // count6 fileOffset += 0x04 + (0x08 * count); BlockSize = fileOffset - startOffset; }
public TsCity(TsMapper mapper, string path) { _mapper = mapper; var file = _mapper.Rfs.GetFileEntry(path); if (file == null) { return; } var fileContent = file.Entry.Read(); var lines = Encoding.UTF8.GetString(fileContent).Split('\n'); foreach (var line in lines) { if (line.Contains("city_data")) { Token = ScsHash.StringToToken(line.Split('.')[1].Trim()); } else if (line.Contains("city_name") && !line.Contains("uppercase")) { Name = line.Split('"')[1]; } else if (line.Contains("country")) { Country = line.Split(':')[1].Trim(); } } }
private void ParsePrefabFiles() { var worldDirectory = Rfs.GetDirectory("def/world"); if (worldDirectory == null) { Log.Msg("Could not read 'def/world' dir"); return; } var prefabFiles = worldDirectory.GetFiles("prefab"); if (prefabFiles == null) { Log.Msg("Could not read prefab files"); return; } foreach (var prefabFile in prefabFiles) { var data = prefabFile.Entry.Read(); var lines = Encoding.UTF8.GetString(data).Split('\n'); var token = 0UL; var path = ""; var category = ""; foreach (var line in lines) { if (line.Contains("prefab_model")) { token = ScsHash.StringToToken(line.Split('.')[1].Trim()); } else if (line.Contains("prefab_desc")) { path = Helper.GetFilePath(line.Split('"')[1]); } else if (line.Contains("category")) { category = line.Split('"')[1]; } if (line.Contains("}") && token != 0 && path != "") { var prefab = new TsPrefab(this, path, token, category); if (prefab.Token != 0 && !_prefabLookup.ContainsKey(prefab.Token)) { _prefabLookup.Add(prefab.Token, prefab); } token = 0; path = ""; category = ""; } } } }
public void TsTriggerItem875(int startOffset) { var fileOffset = startOffset + 0x34; // Set position at start of flags var dlcGuardCount = (Sector.Mapper.IsEts2) ? Common.Ets2DlcGuardCount : Common.AtsDlcGuardCount; Hidden = MemoryHelper.ReadInt8(Sector.Stream, fileOffset + 0x01) > dlcGuardCount; var tagCount = MemoryHelper.ReadInt32(Sector.Stream, fileOffset += 0x05); // 0x05(flags) var nodeCount = MemoryHelper.ReadInt32(Sector.Stream, fileOffset += 0x04 + (0x08 * tagCount)); // 0x04(nodeCount) + tags var triggerActionCount = MemoryHelper.ReadInt32(Sector.Stream, fileOffset += 0x04 + (0x08 * nodeCount)); // 0x04(nodeCount) + nodeUids fileOffset += 0x04; // cursor after triggerActionCount for (var i = 0; i < triggerActionCount; i++) { var action = MemoryHelper.ReadUInt64(Sector.Stream, fileOffset); if (action == ScsHash.StringToToken("hud_parking")) { OverlayName = "parking_ico"; Overlay = Sector.Mapper.LookupOverlay(ScsHash.StringToToken(OverlayName)); if (Overlay == null) { Console.WriteLine("Could not find parking overlay"); Valid = false; } } var hasOverride = MemoryHelper.ReadInt32(Sector.Stream, fileOffset += 0x08); // 0x08(action) fileOffset += 0x04; // set cursor after hasOverride if (hasOverride < 0) { continue; } fileOffset += 0x04 * hasOverride; // set cursor after override values var parameterCount = MemoryHelper.ReadInt32(Sector.Stream, fileOffset); fileOffset += 0x04; // set cursor after parameterCount for (var j = 0; j < parameterCount; j++) { var paramLength = MemoryHelper.ReadInt32(Sector.Stream, fileOffset); fileOffset += 0x04 + 0x04 + paramLength; // 0x04(paramLength) + 0x04(padding) + (param) } var targetTagCount = MemoryHelper.ReadInt32(Sector.Stream, fileOffset); fileOffset += 0x04 + targetTagCount * 0x08 + 0x08; // 0x04(targetTagCount) + targetTags + 0x04(m_range & m_type) } if (nodeCount == 1) { fileOffset += 0x04; // 0x04(m_radius) } BlockSize = fileOffset - startOffset; }
public TsCountry(TsMapper mapper, string path) { _mapper = mapper; var file = _mapper.Rfs.GetFileEntry(path); if (file == null) { return; } LocalizedNames = new Dictionary <string, string>(); var fileContent = file.Entry.Read(); var lines = Encoding.UTF8.GetString(fileContent).Split('\n'); foreach (var line in lines) { var(validLine, key, value) = SiiHelper.ParseLine(line); if (!validLine) { continue; } if (key == "country_data") { Token = ScsHash.StringToToken(SiiHelper.Trim(value.Split('.')[2])); } else if (key == "country_id") { CountryId = int.Parse(value); } else if (key == "name") { Name = value.Split('"')[1]; } else if (key == "name_localized") { LocalizationToken = value.Split('"')[1]; LocalizationToken = LocalizationToken.Replace("@", ""); } else if (key == "country_code") { CountryCode = value.Split('"')[1]; } else if (key == "pos") { var vector = value.Split('(')[1].Split(')')[0]; var values = vector.Split(','); X = float.Parse(values[0], CultureInfo.InvariantCulture); Y = float.Parse(values[2], CultureInfo.InvariantCulture); } } }
public void TsTriggerItem829(int startOffset) { var fileOffset = startOffset + 0x34; // Set position at start of flags var dlcGuardCount = (Sector.Mapper.IsEts2) ? Common.Ets2DlcGuardCount : Common.AtsDlcGuardCount; Hidden = MemoryHelper.ReadInt8(Sector.Stream, fileOffset + 0x01) > dlcGuardCount; var tagCount = MemoryHelper.ReadInt32(Sector.Stream, fileOffset += 0x05); // 0x05(flags) var nodeCount = MemoryHelper.ReadInt32(Sector.Stream, fileOffset += 0x04 + (0x08 * tagCount)); // 0x04(nodeCount) + tags var triggerActionCount = MemoryHelper.ReadInt32(Sector.Stream, fileOffset += 0x04 + (0x08 * nodeCount)); // 0x04(nodeCount) + nodeUids fileOffset += 0x04; // cursor after triggerActionCount for (var i = 0; i < triggerActionCount; i++) { var action = MemoryHelper.ReadUInt64(Sector.Stream, fileOffset); if (action == ScsHash.StringToToken("hud_parking")) { OverlayName = "parking_ico"; Overlay = Sector.Mapper.LookupOverlay(ScsHash.StringToToken(OverlayName)); if (Overlay == null) { Console.WriteLine("Could not find parking overlay"); Valid = false; } } var hasOverride = MemoryHelper.ReadInt32(Sector.Stream, fileOffset += 0x08); // 0x08(action) if (hasOverride > 0) { fileOffset += 0x04 * hasOverride; } var hasParameters = MemoryHelper.ReadInt32(Sector.Stream, fileOffset += 0x04); // 0x04(hasOverride) fileOffset += 0x04; // set cursor after hasParameters if (hasParameters == 1) { var parametersLength = MemoryHelper.ReadInt32(Sector.Stream, fileOffset); fileOffset += 0x04 + 0x04 + parametersLength; // 0x04(parametersLength) + 0x04(padding) + text(parametersLength * 0x01) } else if (hasParameters == 3) { fileOffset += 0x08; // 0x08 (m_some_uid) } var targetTagCount = MemoryHelper.ReadInt32(Sector.Stream, fileOffset += 0x08); // 0x08(unk/padding) fileOffset += 0x04 + targetTagCount * 0x08; // 0x04(targetTagCount) + targetTags } fileOffset += 0x18; // 0x18(range & reset_delay & reset_distance & min_speed & max_speed & flags2) BlockSize = fileOffset - startOffset; }
public void TsFeryItem825(int startOffset) { var fileOffset = startOffset + 0x34; // Set position at start of flags Train = MemoryHelper.ReadUint8(Sector.Stream, fileOffset) != 0; if (Train) { Overlay = Sector.Mapper.LookupOverlay(ScsHash.StringToToken("train_ico")); } else { Overlay = Sector.Mapper.LookupOverlay(ScsHash.StringToToken("port_overlay")); } FerryPortId = MemoryHelper.ReadUInt64(Sector.Stream, fileOffset += 0x05); Sector.Mapper.AddFerryPortLocation(FerryPortId, X, Z); fileOffset += 0x08 + 0x1C; // 0x08(ferryPorId) + 0x1C(prefab_uid & node_uid & unloadoffset) BlockSize = fileOffset - startOffset; }
public TsFerryItem(TsSector sector, int startOffset) : base(sector, startOffset) { Valid = true; var fileOffset = startOffset + 0x34; // Set position at start of flags Train = (Sector.Stream[fileOffset] != 0); if (Train) { Overlay = Sector.Mapper.LookupOverlay(ScsHash.StringToToken("train_ico")); } else { Overlay = Sector.Mapper.LookupOverlay(ScsHash.StringToToken("port_overlay")); } FerryPortId = BitConverter.ToUInt64(Sector.Stream, fileOffset += 0x05); sector.Mapper.AddFerryPortLocation(FerryPortId, X, Z); fileOffset += 0x08 + 0x1C; BlockSize = fileOffset - startOffset; }
public void TsCityItem825(int startOffset) { var fileOffset = startOffset + 0x34; // Set position at start of flags Hidden = (MemoryHelper.ReadUint8(Sector.Stream, fileOffset) & 0x01) != 0; var cityId = MemoryHelper.ReadUInt64(Sector.Stream, fileOffset + 0x05); City = Sector.Mapper.LookupCity(cityId); if (City == null) { Valid = false; Log.Msg($"Could not find City: '{ScsHash.TokenToString(cityId)}'({cityId:X}), " + $"in {Path.GetFileName(Sector.FilePath)} @ {fileOffset}"); } Width = MemoryHelper.ReadSingle(Sector.Stream, fileOffset += 0x05 + 0x08); // 0x05(flags) + 0x08(cityId) Height = MemoryHelper.ReadSingle(Sector.Stream, fileOffset += 0x04); // 0x08(Width) NodeUid = MemoryHelper.ReadUInt64(Sector.Stream, fileOffset += 0x04); // 0x08(height) fileOffset += 0x08; // nodeUid BlockSize = fileOffset - startOffset; }
public void TsPrefabItem825(int startOffset) { var fileOffset = startOffset + 0x34; // Set position at start of flags var dlcGuardCount = (Sector.Mapper.IsEts2) ? Common.Ets2DlcGuardCount : Common.AtsDlcGuardCount; Hidden = MemoryHelper.ReadInt8(Sector.Stream, fileOffset + 0x01) > dlcGuardCount || (MemoryHelper.ReadUint8(Sector.Stream, fileOffset + 0x02) & 0x02) != 0; var prefabId = MemoryHelper.ReadUInt64(Sector.Stream, fileOffset += 0x05); // 0x05(flags) Prefab = Sector.Mapper.LookupPrefab(prefabId); if (Prefab == null) { Valid = false; Log.Msg($"Could not find Prefab: '{ScsHash.TokenToString(prefabId)}'({MemoryHelper.ReadUInt64(Sector.Stream, fileOffset):X}), " + $"in {Path.GetFileName(Sector.FilePath)} @ {fileOffset} (item uid: 0x{Uid:X})"); } var nodeCount = MemoryHelper.ReadInt32(Sector.Stream, fileOffset += 0x18); // 0x18(id & look & variant) fileOffset += 0x04; // set cursor after nodeCount for (var i = 0; i < nodeCount; i++) { Nodes.Add(MemoryHelper.ReadUInt64(Sector.Stream, fileOffset)); fileOffset += 0x08; } var connectedItemCount = MemoryHelper.ReadInt32(Sector.Stream, fileOffset); Origin = MemoryHelper.ReadUint8(Sector.Stream, fileOffset += 0x04 + (0x08 * connectedItemCount) + 0x08); // 0x04(connItemCount) + connItemUids + 0x08(m_some_uid) var prefabVegetationCount = MemoryHelper.ReadInt32(Sector.Stream, fileOffset += 0x01 + 0x01 + (NodeLookBlockSize825 * nodeCount)); // 0x01(origin) + 0x01(padding) + nodeLooks var vegetationSphereCount = MemoryHelper.ReadInt32(Sector.Stream, fileOffset += 0x04 + (PrefabVegetaionBlockSize * prefabVegetationCount) + 0x04); // 0x04(prefabVegCount) + prefabVegs + 0x04(padding2) fileOffset += 0x04 + (VegetationSphereBlockSize825 * vegetationSphereCount); // 0x04(vegSphereCount) + vegSpheres BlockSize = fileOffset - startOffset; }
public void TsRoadItem854(int startOffset) { var fileOffset = startOffset + 0x34; // Set position at start of flags var dlcGuardCount = (Sector.Mapper.IsEts2) ? Common.Ets2DlcGuardCount : Common.AtsDlcGuardCount; Hidden = MemoryHelper.ReadInt8(Sector.Stream, fileOffset + 0x06) > dlcGuardCount || (MemoryHelper.ReadUint8(Sector.Stream, fileOffset + 0x03) & 0x02) != 0; var roadLookId = MemoryHelper.ReadUInt64(Sector.Stream, fileOffset += 0x09); RoadLook = Sector.Mapper.LookupRoadLook(roadLookId); if (RoadLook == null) { Valid = false; Log.Msg($"Could not find RoadLook: '{ScsHash.TokenToString(roadLookId)}'({MemoryHelper.ReadUInt64(Sector.Stream, fileOffset):X}), " + $"in {Path.GetFileName(Sector.FilePath)} @ {fileOffset}"); } StartNodeUid = MemoryHelper.ReadUInt64(Sector.Stream, fileOffset += 0x08 + 0xA4); // 0x08(RoadLook) + 0xA4(sets cursor before node_uid[]) EndNodeUid = MemoryHelper.ReadUInt64(Sector.Stream, fileOffset += 0x08); // 0x08(startNodeUid) fileOffset += 0x08 + 0x04; // 0x08(EndNodeUid) + 0x04(m_unk) BlockSize = fileOffset - startOffset; }
/// <summary> /// Creates a json file with the positions and names (w/ localizations) of all cities /// </summary> public void ExportCities(ExportFlags exportFlags, string path) { if (!Directory.Exists(path)) { return; } var citiesJArr = new JArray(); foreach (var city in Cities) { if (city.Hidden) { continue; } var cityJObj = JObject.FromObject(city.City); cityJObj["X"] = city.X; cityJObj["Y"] = city.Z; if (_countriesLookup.ContainsKey(ScsHash.StringToToken(city.City.Country))) { var country = _countriesLookup[ScsHash.StringToToken(city.City.Country)]; cityJObj["CountryId"] = country.CountryId; } else { Log.Msg($"Could not find country for {city.City.Name}"); } if (exportFlags.IsActive(ExportFlags.CityLocalizedNames)) { cityJObj["LocalizedNames"] = JObject.FromObject(city.City.LocalizedNames); } citiesJArr.Add(cityJObj); } File.WriteAllText(Path.Combine(path, "Cities.json"), citiesJArr.ToString(Formatting.Indented)); }
public TsCity(TsMapper mapper, string path) { _mapper = mapper; var file = _mapper.Rfs.GetFileEntry(path); if (file == null) { return; } var fileContent = file.Entry.Read(); var lines = Encoding.UTF8.GetString(fileContent).Split('\n'); var offsetCount = 0; XOffsets = new List <int>(); YOffsets = new List <int>(); foreach (var line in lines) { if (line.Contains("city_data")) { Token = ScsHash.StringToToken(line.Split('.')[1].Trim()); } else if (line.Contains("city_name") && !line.Contains("uppercase") && !line.Contains("short") && !line.Contains("localized")) { Name = line.Split('"')[1]; } else if (line.Contains("city_name_localized")) { NameLocalized = line.Split('"')[1]; NameLocalized = NameLocalized.Substring(2, NameLocalized.Length - 4); } else if (line.Contains("country")) { Country = line.Split(':')[1].Trim(); } else if (line.Contains("map_x_offsets[]")) { if (++offsetCount > 4) { var offset = 0; if (int.TryParse(line.Split(':')[1].Trim(), out offset)) { XOffsets.Add(offset); } } if (offsetCount == 8) { offsetCount = 0; } } else if (line.Contains("map_y_offsets[]")) { if (++offsetCount > 4) { var offset = 0; if (int.TryParse(line.Split(':')[1].Trim(), out offset)) { YOffsets.Add(offset); } } } } }
public TsCity(TsMapper mapper, string path) { _mapper = mapper; var file = _mapper.Rfs.GetFileEntry(path); if (file == null) { return; } LocalizedNames = new Dictionary <string, string>(); var fileContent = file.Entry.Read(); var lines = Encoding.UTF8.GetString(fileContent).Split('\n'); var offsetCount = 0; XOffsets = new List <int>(); YOffsets = new List <int>(); foreach (var line in lines) { var(validLine, key, value) = SiiHelper.ParseLine(line); if (!validLine) { continue; } if (key == "city_data") { Token = ScsHash.StringToToken(SiiHelper.Trim(value.Split('.')[1])); } else if (key == "city_name") { Name = line.Split('"')[1]; } else if (key == "city_name_localized") { LocalizationToken = value.Split('"')[1]; LocalizationToken = LocalizationToken.Replace("@", ""); } else if (key == "country") { Country = value; } else if (key.Contains("map_x_offsets[]")) { if (++offsetCount > 4) { if (int.TryParse(value, out var offset)) { XOffsets.Add(offset); } } if (offsetCount == 8) { offsetCount = 0; } } else if (key.Contains("map_y_offsets[]")) { if (++offsetCount > 4) { if (int.TryParse(value, out var offset)) { YOffsets.Add(offset); } } } } }
private void ParseFerryConnections() { var connectionDirectory = Rfs.GetDirectory("def/ferry/connection"); if (connectionDirectory == null) { Log.Msg("Could not read 'def/ferry/connection' dir"); return; } var ferryConnectionFiles = connectionDirectory.GetFiles("sii"); if (ferryConnectionFiles == null) { Log.Msg("Could not read ferry connection files files"); return; } foreach (var ferryConnectionFile in ferryConnectionFiles) { var data = ferryConnectionFile.Entry.Read(); var lines = Encoding.UTF8.GetString(data).Split('\n'); TsFerryConnection conn = null; foreach (var line in lines) { var(validLine, key, value) = SiiHelper.ParseLine(line); if (validLine) { if (conn != null) { if (key.Contains("connection_positions")) { var index = int.Parse(key.Split('[')[1].Split(']')[0]); var vector = value.Split('(')[1].Split(')')[0]; var values = vector.Split(','); var x = float.Parse(values[0], CultureInfo.InvariantCulture); var z = float.Parse(values[2], CultureInfo.InvariantCulture); conn.AddConnectionPosition(index, x, z); } else if (key.Contains("connection_directions")) { var index = int.Parse(key.Split('[')[1].Split(']')[0]); var vector = value.Split('(')[1].Split(')')[0]; var values = vector.Split(','); var x = float.Parse(values[0], CultureInfo.InvariantCulture); var z = float.Parse(values[2], CultureInfo.InvariantCulture); conn.AddRotation(index, Math.Atan2(z, x)); } } if (key == "ferry_connection") { var portIds = value.Split('.'); conn = new TsFerryConnection { StartPortToken = ScsHash.StringToToken(portIds[1]), EndPortToken = ScsHash.StringToToken(portIds[2].TrimEnd('{').Trim()) }; } } if (!line.Contains("}") || conn == null) { continue; } ; var existingItem = _ferryConnectionLookup.FirstOrDefault(item => (item.StartPortToken == conn.StartPortToken && item.EndPortToken == conn.EndPortToken) || (item.StartPortToken == conn.EndPortToken && item.EndPortToken == conn.StartPortToken)); // Check if connection already exists if (existingItem == null) { _ferryConnectionLookup.Add(conn); } conn = null; } } }
public TsCountry GetCountryByTokenName(string name) { var token = ScsHash.StringToToken(name); return(_countriesLookup.ContainsKey(token) ? _countriesLookup[token] : null); }
private void ParseOverlays() { var uiMapDirectory = Rfs.GetDirectory("material/ui/map"); if (uiMapDirectory == null) { Log.Msg("Could not read 'material/ui/map' dir"); return; } var matFiles = uiMapDirectory.GetFiles(".mat"); if (matFiles == null) { Log.Msg("Could not read .mat files"); return; } var uiMapRoadDirectory = Rfs.GetDirectory("material/ui/map/road"); if (uiMapRoadDirectory != null) { var data = uiMapRoadDirectory.GetFiles(".mat"); if (data != null) { matFiles.AddRange(data); } } else { Log.Msg("Could not read 'material/ui/map/road' dir"); } var uiCompanyDirectory = Rfs.GetDirectory("material/ui/company/small"); if (uiCompanyDirectory != null) { var data = uiCompanyDirectory.GetFiles(".mat"); if (data != null) { matFiles.AddRange(data); } } else { Log.Msg("Could not read 'material/ui/company/small' dir"); } foreach (var matFile in matFiles) { var data = matFile.Entry.Read(); var lines = Encoding.UTF8.GetString(data).Split('\n'); foreach (var line in lines) { if (line.Contains("texture") && !line.Contains("_name")) { var tobjPath = Helper.CombinePath(matFile.GetLocalPath(), line.Split('"')[1]); var tobjData = Rfs.GetFileEntry(tobjPath)?.Entry?.Read(); if (tobjData == null) { break; } var path = Helper.GetFilePath(Encoding.UTF8.GetString(tobjData, 0x30, tobjData.Length - 0x30)); var name = matFile.GetFileName(); if (name.StartsWith("map")) { continue; } if (name.StartsWith("road_")) { name = name.Substring(5); } var token = ScsHash.StringToToken(name); if (!_overlayLookup.ContainsKey(token)) { _overlayLookup.Add(token, new TsMapOverlay(this, path)); } } } } }
private void ParseRoadLookFiles() { var worldDirectory = Rfs.GetDirectory("def/world"); if (worldDirectory == null) { Log.Msg("Could not read 'def/world' dir"); return; } var roadLookFiles = worldDirectory.GetFiles("road_look"); if (roadLookFiles == null) { Log.Msg("Could not read road look files"); return; } foreach (var roadLookFile in roadLookFiles) { var data = roadLookFile.Entry.Read(); var lines = Encoding.UTF8.GetString(data).Split('\n'); TsRoadLook roadLook = null; foreach (var line in lines) { if (line.Contains(":") && roadLook != null) { var value = line.Substring(line.IndexOf(':') + 1).Trim(); var key = line.Substring(0, line.IndexOf(':')).Trim(); switch (key) { case "lanes_left[]": roadLook.LanesLeft.Add(value); break; case "lanes_right[]": roadLook.LanesRight.Add(value); break; case "road_offset": float.TryParse(value.Replace('.', ','), out roadLook.Offset); break; } } if (line.Contains("road_look")) { roadLook = new TsRoadLook(ScsHash.StringToToken(line.Split('.')[1].Trim('{').Trim())); } if (line.Contains("}") && roadLook != null) { if (roadLook.Token != 0 && !_roadLookup.ContainsKey(roadLook.Token)) { _roadLookup.Add(roadLook.Token, roadLook); roadLook = null; } } } } }
/// <summary> /// Saves all overlays as .png images. /// Creates a json file with all positions of said overlays /// </summary> /// <remarks> /// ZoomLevelVisibility flags: Multiple can be selected at the same time, /// eg. if value is 3 then 0 and 1 are both selected /// Selected = hidden (0-7 => numbers in game editor) /// 1 = (Nav map, 3D view, zoom 0) (0) /// 2 = (Nav map, 3D view, zoom 1) (1) /// 4 = (Nav map, 2D view, zoom 0) (2) /// 8 = (Nav map, 2D view, zoom 1) (3) /// 16 = (World map, zoom 0) (4) /// 32 = (World map, zoom 1) (5) /// 64 = (World map, zoom 2) (6) /// 128 = (World map, zoom 3) (7) /// </remarks> /// <param name="path"></param> public void ExportOverlays(ExportFlags exportFlags, string path) { if (!Directory.Exists(path)) { return; } var saveAsPNG = exportFlags.IsActive(ExportFlags.OverlayPNGs); var overlayPath = Path.Combine(path, "Overlays"); if (saveAsPNG) { Directory.CreateDirectory(overlayPath); } var overlaysJArr = new JArray(); foreach (var overlay in MapOverlays) { if (overlay.Hidden) { continue; } var overlayName = overlay.OverlayName; var b = overlay.Overlay?.GetBitmap(); if (b == null) { continue; } var overlayJObj = new JObject { ["X"] = overlay.X, ["Y"] = overlay.Z, ["ZoomLevelVisibility"] = overlay.ZoomLevelVisibility, ["Name"] = overlayName, ["Type"] = "Overlay", ["Width"] = b.Width, ["Height"] = b.Height, }; overlaysJArr.Add(overlayJObj); if (saveAsPNG && !File.Exists(Path.Combine(overlayPath, $"{overlayName}.png"))) { b.Save(Path.Combine(overlayPath, $"{overlayName}.png")); } } foreach (var company in Companies) { if (company.Hidden) { continue; } var overlayName = ScsHash.TokenToString(company.OverlayToken); var point = new PointF(company.X, company.Z); if (company.Nodes.Count > 0) { var prefab = Prefabs.FirstOrDefault(x => x.Uid == company.Nodes[0]); if (prefab != null) { var originNode = GetNodeByUid(prefab.Nodes[0]); if (prefab.Prefab.PrefabNodes == null) { continue; } var mapPointOrigin = prefab.Prefab.PrefabNodes[prefab.Origin]; var rot = (float)(originNode.Rotation - Math.PI - Math.Atan2(mapPointOrigin.RotZ, mapPointOrigin.RotX) + Math.PI / 2); var prefabstartX = originNode.X - mapPointOrigin.X; var prefabStartZ = originNode.Z - mapPointOrigin.Z; var companyPos = prefab.Prefab.SpawnPoints.FirstOrDefault(x => x.Type == TsSpawnPointType.CompanyPos); if (companyPos != null) { point = RenderHelper.RotatePoint(prefabstartX + companyPos.X, prefabStartZ + companyPos.Z, rot, originNode.X, originNode.Z); } } } var b = company.Overlay?.GetBitmap(); if (b == null) { continue; } var overlayJObj = new JObject { ["X"] = point.X, ["Y"] = point.Y, ["Name"] = overlayName, ["Type"] = "Company", ["Width"] = b.Width, ["Height"] = b.Height, }; overlaysJArr.Add(overlayJObj); if (saveAsPNG && !File.Exists(Path.Combine(overlayPath, $"{overlayName}.png"))) { b.Save(Path.Combine(overlayPath, $"{overlayName}.png")); } } foreach (var trigger in Triggers) { if (trigger.Hidden) { continue; } var overlayName = trigger.OverlayName; var b = trigger.Overlay?.GetBitmap(); if (b == null) { continue; } var overlayJObj = new JObject { ["X"] = trigger.X, ["Y"] = trigger.Z, ["Name"] = overlayName, ["Type"] = "Parking", ["Width"] = b.Width, ["Height"] = b.Height, }; overlaysJArr.Add(overlayJObj); if (saveAsPNG && !File.Exists(Path.Combine(overlayPath, $"{overlayName}.png"))) { b.Save(Path.Combine(overlayPath, $"{overlayName}.png")); } } foreach (var ferry in FerryConnections) { if (ferry.Hidden) { continue; } var overlayName = ScsHash.TokenToString(ferry.OverlayToken); var b = ferry.Overlay?.GetBitmap(); if (b == null) { continue; } var overlayJObj = new JObject { ["X"] = ferry.X, ["Y"] = ferry.Z, ["Name"] = overlayName, ["Type"] = (ferry.Train) ? "Train" : "Ferry", ["Width"] = b.Width, ["Height"] = b.Height, }; overlaysJArr.Add(overlayJObj); if (saveAsPNG && !File.Exists(Path.Combine(overlayPath, $"{overlayName}.png"))) { b.Save(Path.Combine(overlayPath, $"{overlayName}.png")); } } foreach (var prefab in Prefabs) { if (prefab.Hidden) { continue; } var originNode = GetNodeByUid(prefab.Nodes[0]); if (prefab.Prefab.PrefabNodes == null) { continue; } var mapPointOrigin = prefab.Prefab.PrefabNodes[prefab.Origin]; var rot = (float)(originNode.Rotation - Math.PI - Math.Atan2(mapPointOrigin.RotZ, mapPointOrigin.RotX) + Math.PI / 2); var prefabStartX = originNode.X - mapPointOrigin.X; var prefabStartZ = originNode.Z - mapPointOrigin.Z; foreach (var spawnPoint in prefab.Prefab.SpawnPoints) { var newPoint = RenderHelper.RotatePoint(prefabStartX + spawnPoint.X, prefabStartZ + spawnPoint.Z, rot, originNode.X, originNode.Z); var overlayJObj = new JObject { ["X"] = newPoint.X, ["Y"] = newPoint.Y, }; string overlayName; switch (spawnPoint.Type) { case TsSpawnPointType.GasPos: { overlayName = "gas_ico"; overlayJObj["Type"] = "Fuel"; break; } case TsSpawnPointType.ServicePos: { overlayName = "service_ico"; overlayJObj["Type"] = "Service"; break; } case TsSpawnPointType.WeightStationPos: { overlayName = "weigh_station_ico"; overlayJObj["Type"] = "WeightStation"; break; } case TsSpawnPointType.TruckDealerPos: { overlayName = "dealer_ico"; overlayJObj["Type"] = "TruckDealer"; break; } case TsSpawnPointType.BuyPos: { overlayName = "garage_large_ico"; overlayJObj["Type"] = "Garage"; break; } case TsSpawnPointType.RecruitmentPos: { overlayName = "recruitment_ico"; overlayJObj["Type"] = "Recruitment"; break; } default: continue; } overlayJObj["Name"] = overlayName; var overlay = LookupOverlay(ScsHash.StringToToken(overlayName)); var b = overlay.GetBitmap(); if (b == null) { continue; } overlayJObj["Width"] = b.Width; overlayJObj["Height"] = b.Height; overlaysJArr.Add(overlayJObj); if (saveAsPNG && !File.Exists(Path.Combine(overlayPath, $"{overlayName}.png"))) { b.Save(Path.Combine(overlayPath, $"{overlayName}.png")); } } var lastId = -1; foreach (var triggerPoint in prefab.Prefab.TriggerPoints) { var newPoint = RenderHelper.RotatePoint(prefabStartX + triggerPoint.X, prefabStartZ + triggerPoint.Z, rot, originNode.X, originNode.Z); if (triggerPoint.TriggerId == lastId) { continue; } lastId = (int)triggerPoint.TriggerId; var overlayJObj = new JObject { ["X"] = newPoint.X, ["Y"] = newPoint.Y, ["Name"] = "parking_ico", ["Type"] = "Parking", }; if (triggerPoint.TriggerActionToken != ScsHash.StringToToken("hud_parking")) { continue; } const string overlayName = "parking_ico"; var overlay = LookupOverlay(ScsHash.StringToToken(overlayName)); var b = overlay.GetBitmap(); if (b == null) { continue; } overlayJObj["Width"] = b.Width; overlayJObj["Height"] = b.Height; overlaysJArr.Add(overlayJObj); if (saveAsPNG && !File.Exists(Path.Combine(overlayPath, $"{overlayName}.png"))) { b.Save(Path.Combine(overlayPath, $"{overlayName}.png")); } } } File.WriteAllText(Path.Combine(path, "Overlays.json"), overlaysJArr.ToString(Formatting.Indented)); }
public void Render(Graphics g, Rectangle clip, float scale, PointF startPoint, MapPalette palette, RenderFlags renderFlags = RenderFlags.All) { var startTime = DateTime.Now.Ticks; g.ResetTransform(); g.FillRectangle(palette.Background, new Rectangle(0, 0, clip.Width, clip.Height)); g.ScaleTransform(scale, scale); g.TranslateTransform(-startPoint.X, -startPoint.Y); g.InterpolationMode = InterpolationMode.NearestNeighbor; g.PixelOffsetMode = PixelOffsetMode.None; g.SmoothingMode = SmoothingMode.AntiAlias; if (_mapper == null) { g.DrawString("Map object not initialized", _defaultFont, palette.Error, 5, 5); return; } var zoomIndex = RenderHelper.GetZoomIndex(clip, scale); var endPoint = new PointF(startPoint.X + clip.Width / scale, startPoint.Y + clip.Height / scale); var ferryStartTime = DateTime.Now.Ticks; if (renderFlags.IsActive(RenderFlags.FerryConnections)) { var ferryConnections = _mapper.FerryConnections.Where(item => !item.Hidden) .ToList(); var ferryPen = new Pen(palette.FerryLines, 50) { DashPattern = new[] { 10f, 10f } }; foreach (var ferryConnection in ferryConnections) { var connections = _mapper.LookupFerryConnection(ferryConnection.FerryPortId); foreach (var conn in connections) { if (conn.Connections.Count == 0) // no extra nodes -> straight line { g.DrawLine(ferryPen, conn.StartPortLocation, conn.EndPortLocation); continue; } var startYaw = Math.Atan2(conn.Connections[0].Z - conn.StartPortLocation.Y, // get angle of the start port to the first node conn.Connections[0].X - conn.StartPortLocation.X); var bezierNodes = RenderHelper.GetBezierControlNodes(conn.StartPortLocation.X, conn.StartPortLocation.Y, startYaw, conn.Connections[0].X, conn.Connections[0].Z, conn.Connections[0].Rotation); var bezierPoints = new List <PointF> { new PointF(conn.StartPortLocation.X, conn.StartPortLocation.Y), // start new PointF(conn.StartPortLocation.X + bezierNodes.Item1.X, conn.StartPortLocation.Y + bezierNodes.Item1.Y), // control1 new PointF(conn.Connections[0].X - bezierNodes.Item2.X, conn.Connections[0].Z - bezierNodes.Item2.Y), // control2 new PointF(conn.Connections[0].X, conn.Connections[0].Z) }; for (var i = 0; i < conn.Connections.Count - 1; i++) // loop all extra nodes { var ferryPoint = conn.Connections[i]; var nextFerryPoint = conn.Connections[i + 1]; bezierNodes = RenderHelper.GetBezierControlNodes(ferryPoint.X, ferryPoint.Z, ferryPoint.Rotation, nextFerryPoint.X, nextFerryPoint.Z, nextFerryPoint.Rotation); bezierPoints.Add(new PointF(ferryPoint.X + bezierNodes.Item1.X, ferryPoint.Z + bezierNodes.Item1.Y)); // control1 bezierPoints.Add(new PointF(nextFerryPoint.X - bezierNodes.Item2.X, nextFerryPoint.Z - bezierNodes.Item2.Y)); // control2 bezierPoints.Add(new PointF(nextFerryPoint.X, nextFerryPoint.Z)); // end } var lastFerryPoint = conn.Connections[conn.Connections.Count - 1]; var endYaw = Math.Atan2(conn.EndPortLocation.Y - lastFerryPoint.Z, // get angle of the last node to the end port conn.EndPortLocation.X - lastFerryPoint.X); bezierNodes = RenderHelper.GetBezierControlNodes(lastFerryPoint.X, lastFerryPoint.Z, lastFerryPoint.Rotation, conn.EndPortLocation.X, conn.EndPortLocation.Y, endYaw); bezierPoints.Add(new PointF(lastFerryPoint.X + bezierNodes.Item1.X, lastFerryPoint.Z + bezierNodes.Item1.Y)); // control1 bezierPoints.Add(new PointF(conn.EndPortLocation.X - bezierNodes.Item2.X, conn.EndPortLocation.Y - bezierNodes.Item2.Y)); // control2 bezierPoints.Add(new PointF(conn.EndPortLocation.X, conn.EndPortLocation.Y)); // end g.DrawBeziers(ferryPen, bezierPoints.ToArray()); } } ferryPen.Dispose(); } var ferryTime = DateTime.Now.Ticks - ferryStartTime; var mapAreaStartTime = DateTime.Now.Ticks; if (renderFlags.IsActive(RenderFlags.MapAreas)) { var mapAreas = _mapper.MapAreas.Where(item => item.X >= startPoint.X - itemDrawMargin && item.X <= endPoint.X + itemDrawMargin && item.Z >= startPoint.Y - itemDrawMargin && item.Z <= endPoint.Y + itemDrawMargin && !item.Hidden) .ToList(); foreach (var mapArea in mapAreas.OrderBy(x => x.DrawOver)) { var points = new List <PointF>(); foreach (var mapAreaNode in mapArea.NodeUids) { var node = _mapper.GetNodeByUid(mapAreaNode); if (node == null) { continue; } points.Add(new PointF(node.X, node.Z)); } Brush fillColor = palette.PrefabLight; if ((mapArea.ColorIndex & 0x01) != 0) { fillColor = palette.PrefabLight; } else if ((mapArea.ColorIndex & 0x02) != 0) { fillColor = palette.PrefabDark; } else if ((mapArea.ColorIndex & 0x03) != 0) { fillColor = palette.PrefabGreen; } g.FillPolygon(fillColor, points.ToArray()); } } var mapAreaTime = DateTime.Now.Ticks - mapAreaStartTime; var prefabStartTime = DateTime.Now.Ticks; var prefabs = _mapper.Prefabs.Where(item => item.X >= startPoint.X - itemDrawMargin && item.X <= endPoint.X + itemDrawMargin && item.Z >= startPoint.Y - itemDrawMargin && item.Z <= endPoint.Y + itemDrawMargin && !item.Hidden) .ToList(); if (renderFlags.IsActive(RenderFlags.Prefabs)) { List <TsPrefabLook> drawingQueue = new List <TsPrefabLook>(); foreach (var prefabItem in prefabs) { var originNode = _mapper.GetNodeByUid(prefabItem.Nodes[0]); if (prefabItem.Prefab.PrefabNodes == null) { continue; } if (!prefabItem.HasLooks()) { var mapPointOrigin = prefabItem.Prefab.PrefabNodes[prefabItem.Origin]; var rot = (float)(originNode.Rotation - Math.PI - Math.Atan2(mapPointOrigin.RotZ, mapPointOrigin.RotX) + Math.PI / 2); var prefabstartX = originNode.X - mapPointOrigin.X; var prefabStartZ = originNode.Z - mapPointOrigin.Z; List <int> pointsDrawn = new List <int>(); for (var i = 0; i < prefabItem.Prefab.MapPoints.Count; i++) { var mapPoint = prefabItem.Prefab.MapPoints[i]; pointsDrawn.Add(i); if (mapPoint.LaneCount == -1) // non-road Prefab { Dictionary <int, PointF> polyPoints = new Dictionary <int, PointF>(); var nextPoint = i; do { if (prefabItem.Prefab.MapPoints[nextPoint].Neighbours.Count == 0) { break; } foreach (var neighbour in prefabItem.Prefab.MapPoints[nextPoint].Neighbours) { if (!polyPoints.ContainsKey(neighbour)) // New Polygon Neighbour { nextPoint = neighbour; var newPoint = RenderHelper.RotatePoint( prefabstartX + prefabItem.Prefab.MapPoints[nextPoint].X, prefabStartZ + prefabItem.Prefab.MapPoints[nextPoint].Z, rot, originNode.X, originNode.Z); polyPoints.Add(nextPoint, new PointF(newPoint.X, newPoint.Y)); break; } nextPoint = -1; } } while (nextPoint != -1); if (polyPoints.Count < 2) { continue; } var colorFlag = prefabItem.Prefab.MapPoints[polyPoints.First().Key].PrefabColorFlags; Brush fillColor = palette.PrefabLight; if ((colorFlag & 0x02) != 0) { fillColor = palette.PrefabLight; } else if ((colorFlag & 0x04) != 0) { fillColor = palette.PrefabDark; } else if ((colorFlag & 0x08) != 0) { fillColor = palette.PrefabGreen; } // else fillColor = _palette.Error; // Unknown var prefabLook = new TsPrefabPolyLook(polyPoints.Values.ToList()) { ZIndex = ((colorFlag & 0x01) != 0) ? 3 : 2, Color = fillColor }; prefabItem.AddLook(prefabLook); continue; } var mapPointLaneCount = mapPoint.LaneCount; if (mapPointLaneCount == -2 && i < prefabItem.Prefab.PrefabNodes.Count) { if (mapPoint.ControlNodeIndex != -1) { mapPointLaneCount = prefabItem.Prefab.PrefabNodes[mapPoint.ControlNodeIndex].LaneCount; } } foreach (var neighbourPointIndex in mapPoint.Neighbours) // TODO: Fix connection between road segments { if (pointsDrawn.Contains(neighbourPointIndex)) { continue; } var neighbourPoint = prefabItem.Prefab.MapPoints[neighbourPointIndex]; if ((mapPoint.Hidden || neighbourPoint.Hidden) && prefabItem.Prefab.PrefabNodes.Count + 1 < prefabItem.Prefab.MapPoints.Count) { continue; } var roadYaw = Math.Atan2(neighbourPoint.Z - mapPoint.Z, neighbourPoint.X - mapPoint.X); var neighbourLaneCount = neighbourPoint.LaneCount; if (neighbourLaneCount == -2 && neighbourPointIndex < prefabItem.Prefab.PrefabNodes.Count) { if (neighbourPoint.ControlNodeIndex != -1) { neighbourLaneCount = prefabItem.Prefab.PrefabNodes[neighbourPoint.ControlNodeIndex].LaneCount; } } if (mapPointLaneCount == -2 && neighbourLaneCount != -2) { mapPointLaneCount = neighbourLaneCount; } else if (neighbourLaneCount == -2 && mapPointLaneCount != -2) { neighbourLaneCount = mapPointLaneCount; } else if (mapPointLaneCount == -2 && neighbourLaneCount == -2) { Console.WriteLine($"Could not find lane count for ({i}, {neighbourPointIndex}), defaulting to 1 for {prefabItem.Prefab.FilePath}"); mapPointLaneCount = neighbourLaneCount = 1; } var cornerCoords = new List <PointF>(); var coords = RenderHelper.GetCornerCoords(prefabstartX + mapPoint.X, prefabStartZ + mapPoint.Z, (Common.LaneWidth * mapPointLaneCount + mapPoint.LaneOffset) / 2f, roadYaw + Math.PI / 2); cornerCoords.Add(RenderHelper.RotatePoint(coords.X, coords.Y, rot, originNode.X, originNode.Z)); coords = RenderHelper.GetCornerCoords(prefabstartX + neighbourPoint.X, prefabStartZ + neighbourPoint.Z, (Common.LaneWidth * neighbourLaneCount + neighbourPoint.LaneOffset) / 2f, roadYaw + Math.PI / 2); cornerCoords.Add(RenderHelper.RotatePoint(coords.X, coords.Y, rot, originNode.X, originNode.Z)); coords = RenderHelper.GetCornerCoords(prefabstartX + neighbourPoint.X, prefabStartZ + neighbourPoint.Z, (Common.LaneWidth * neighbourLaneCount + mapPoint.LaneOffset) / 2f, roadYaw - Math.PI / 2); cornerCoords.Add(RenderHelper.RotatePoint(coords.X, coords.Y, rot, originNode.X, originNode.Z)); coords = RenderHelper.GetCornerCoords(prefabstartX + mapPoint.X, prefabStartZ + mapPoint.Z, (Common.LaneWidth * mapPointLaneCount + mapPoint.LaneOffset) / 2f, roadYaw - Math.PI / 2); cornerCoords.Add(RenderHelper.RotatePoint(coords.X, coords.Y, rot, originNode.X, originNode.Z)); TsPrefabLook prefabLook = new TsPrefabPolyLook(cornerCoords) { Color = palette.PrefabRoad, ZIndex = 4, }; prefabItem.AddLook(prefabLook); } } } prefabItem.GetLooks().ForEach(x => drawingQueue.Add(x)); } foreach (var prefabLook in drawingQueue.OrderBy(p => p.ZIndex)) { prefabLook.Draw(g); } } var prefabTime = DateTime.Now.Ticks - prefabStartTime; var roadStartTime = DateTime.Now.Ticks; if (renderFlags.IsActive(RenderFlags.Roads)) { var roads = _mapper.Roads.Where(item => item.X >= startPoint.X - itemDrawMargin && item.X <= endPoint.X + itemDrawMargin && item.Z >= startPoint.Y - itemDrawMargin && item.Z <= endPoint.Y + itemDrawMargin && !item.Hidden) .ToList(); foreach (var road in roads) { var startNode = road.GetStartNode(); var endNode = road.GetEndNode(); if (!road.HasPoints()) { var newPoints = new List <PointF>(); var sx = startNode.X; var sz = startNode.Z; var ex = endNode.X; var ez = endNode.Z; var radius = Math.Sqrt(Math.Pow(sx - ex, 2) + Math.Pow(sz - ez, 2)); var tanSx = Math.Cos(-(Math.PI * 0.5f - startNode.Rotation)) * radius; var tanEx = Math.Cos(-(Math.PI * 0.5f - endNode.Rotation)) * radius; var tanSz = Math.Sin(-(Math.PI * 0.5f - startNode.Rotation)) * radius; var tanEz = Math.Sin(-(Math.PI * 0.5f - endNode.Rotation)) * radius; for (var i = 0; i < 8; i++) { var s = i / (float)(8 - 1); var x = (float)TsRoadLook.Hermite(s, sx, ex, tanSx, tanEx); var z = (float)TsRoadLook.Hermite(s, sz, ez, tanSz, tanEz); newPoints.Add(new PointF(x, z)); } road.AddPoints(newPoints); } var roadWidth = road.RoadLook.GetWidth(); var roadPen = new Pen(palette.Road, roadWidth); g.DrawCurve(roadPen, road.GetPoints()?.ToArray()); roadPen.Dispose(); } } var roadTime = DateTime.Now.Ticks - roadStartTime; var mapOverlayStartTime = DateTime.Now.Ticks; if (renderFlags.IsActive(RenderFlags.MapOverlays)) { var overlays = _mapper.MapOverlays.Where(item => item.X >= startPoint.X - itemDrawMargin && item.X <= endPoint.X + itemDrawMargin && item.Z >= startPoint.Y - itemDrawMargin && item.Z <= endPoint.Y + itemDrawMargin && !item.Hidden) .ToList(); foreach (var overlayItem in overlays) // TODO: Scaling { Bitmap b = overlayItem.Overlay.GetBitmap(); if (b != null) { g.DrawImage(b, overlayItem.X - b.Width, overlayItem.Z - b.Height, b.Width * 2, b.Height * 2); } } } var mapOverlayTime = DateTime.Now.Ticks - mapOverlayStartTime; var mapOverlay2StartTime = DateTime.Now.Ticks; if (renderFlags.IsActive(RenderFlags.MapOverlays)) { var companies = _mapper.Companies.Where(item => item.X >= startPoint.X - itemDrawMargin && item.X <= endPoint.X + itemDrawMargin && item.Z >= startPoint.Y - itemDrawMargin && item.Z <= endPoint.Y + itemDrawMargin && !item.Hidden) .ToList(); foreach (var companyItem in companies) // TODO: Scaling { var point = new PointF(companyItem.X, companyItem.Z); if (companyItem.Nodes.Count > 0) { var prefab = _mapper.Prefabs.FirstOrDefault(x => x.Uid == companyItem.Nodes[0]); if (prefab != null) { var originNode = _mapper.GetNodeByUid(prefab.Nodes[0]); if (prefab.Prefab.PrefabNodes == null) { continue; } var mapPointOrigin = prefab.Prefab.PrefabNodes[prefab.Origin]; var rot = (float)(originNode.Rotation - Math.PI - Math.Atan2(mapPointOrigin.RotZ, mapPointOrigin.RotX) + Math.PI / 2); var prefabstartX = originNode.X - mapPointOrigin.X; var prefabStartZ = originNode.Z - mapPointOrigin.Z; var companyPos = prefab.Prefab.SpawnPoints.FirstOrDefault(x => x.Type == TsSpawnPointType.CompanyPos); if (companyPos != null) { point = RenderHelper.RotatePoint(prefabstartX + companyPos.X, prefabStartZ + companyPos.Z, rot, originNode.X, originNode.Z); } } } Bitmap b = companyItem.Overlay?.GetBitmap(); if (b != null) { g.DrawImage(b, point.X, point.Y, b.Width, b.Height); } } foreach (var prefab in prefabs) // Draw all prefab overlays { var originNode = _mapper.GetNodeByUid(prefab.Nodes[0]); if (prefab.Prefab.PrefabNodes == null) { continue; } var mapPointOrigin = prefab.Prefab.PrefabNodes[prefab.Origin]; var rot = (float)(originNode.Rotation - Math.PI - Math.Atan2(mapPointOrigin.RotZ, mapPointOrigin.RotX) + Math.PI / 2); var prefabstartX = originNode.X - mapPointOrigin.X; var prefabStartZ = originNode.Z - mapPointOrigin.Z; foreach (var spawnPoint in prefab.Prefab.SpawnPoints) { var newPoint = RenderHelper.RotatePoint(prefabstartX + spawnPoint.X, prefabStartZ + spawnPoint.Z, rot, originNode.X, originNode.Z); Bitmap b = null; switch (spawnPoint.Type) { case TsSpawnPointType.GasPos: { var overlay = _mapper.LookupOverlay(ScsHash.StringToToken("gas_ico")); b = overlay?.GetBitmap(); break; } case TsSpawnPointType.ServicePos: { var overlay = _mapper.LookupOverlay(ScsHash.StringToToken("service_ico")); b = overlay?.GetBitmap(); break; } case TsSpawnPointType.WeightStationPos: { var overlay = _mapper.LookupOverlay(ScsHash.StringToToken("weigh_station_ico")); b = overlay?.GetBitmap(); break; } case TsSpawnPointType.TruckDealerPos: { var overlay = _mapper.LookupOverlay(ScsHash.StringToToken("dealer_ico")); b = overlay?.GetBitmap(); break; } case TsSpawnPointType.BuyPos: { var overlay = _mapper.LookupOverlay(ScsHash.StringToToken("garage_large_ico")); b = overlay?.GetBitmap(); break; } case TsSpawnPointType.RecruitmentPos: { var overlay = _mapper.LookupOverlay(ScsHash.StringToToken("recruitment_ico")); b = overlay?.GetBitmap(); break; } } if (b != null) { g.DrawImage(b, newPoint.X - b.Width / 2f, newPoint.Y - b.Height / 2f, b.Width, b.Height); } } var lastId = -1; foreach (var triggerPoint in prefab.Prefab.TriggerPoints) // trigger points in prefabs: garage, hotel, ... { var newPoint = RenderHelper.RotatePoint(prefabstartX + triggerPoint.X, prefabStartZ + triggerPoint.Z, rot, originNode.X, originNode.Z); if (triggerPoint.TriggerId == lastId) { continue; } lastId = (int)triggerPoint.TriggerId; if (triggerPoint.TriggerActionToken == ScsHash.StringToToken("hud_parking")) // parking trigger { var overlay = _mapper.LookupOverlay(ScsHash.StringToToken("parking_ico")); Bitmap b = overlay?.GetBitmap(); if (b != null) { g.DrawImage(b, newPoint.X - b.Width / 2f, newPoint.Y - b.Height / 2f, b.Width, b.Height); } } } } var triggers = _mapper.Triggers.Where(item => item.X >= startPoint.X - itemDrawMargin && item.X <= endPoint.X + itemDrawMargin && item.Z >= startPoint.Y - itemDrawMargin && item.Z <= endPoint.Y + itemDrawMargin && !item.Hidden) .ToList(); foreach (var triggerItem in triggers) // TODO: Scaling { Bitmap b = triggerItem.Overlay?.GetBitmap(); if (b != null) { g.DrawImage(b, triggerItem.X, triggerItem.Z, b.Width, b.Height); } } var ferryItems = _mapper.FerryConnections.Where(item => item.X >= startPoint.X - itemDrawMargin && item.X <= endPoint.X + itemDrawMargin && item.Z >= startPoint.Y - itemDrawMargin && item.Z <= endPoint.Y + itemDrawMargin) .ToList(); foreach (var ferryItem in ferryItems) // TODO: Scaling { Bitmap b = ferryItem.Overlay?.GetBitmap(); if (b != null) { g.DrawImage(b, ferryItem.X, ferryItem.Z, b.Width, b.Height); } } } var mapOverlay2Time = DateTime.Now.Ticks - mapOverlay2StartTime; var cityStartTime = DateTime.Now.Ticks; if (renderFlags.IsActive(RenderFlags.CityNames)) // TODO: Fix position and scaling { var cities = _mapper.Cities.Where(item => !item.Hidden).ToList(); var cityFont = new Font("Arial", 100 + zoomCaps[zoomIndex] / 100, FontStyle.Bold); foreach (var city in cities) { var name = city.City.GetLocalizedName(_mapper.SelectedLocalization); var node = _mapper.GetNodeByUid(city.NodeUid); var coords = (node == null) ? new PointF(city.X, city.Z) : new PointF(node.X, node.Z); if (city.City.XOffsets.Count > zoomIndex && city.City.YOffsets.Count > zoomIndex) { coords.X += city.City.XOffsets[zoomIndex] / (scale * zoomCaps[zoomIndex]); coords.Y += city.City.YOffsets[zoomIndex] / (scale * zoomCaps[zoomIndex]); } var textSize = g.MeasureString(name, cityFont); g.DrawString(name, cityFont, _cityShadowColor, coords.X + 2, coords.Y + 2); g.DrawString(name, cityFont, palette.CityName, coords.X, coords.Y); } cityFont.Dispose(); } var cityTime = DateTime.Now.Ticks - cityStartTime; g.ResetTransform(); var elapsedTime = DateTime.Now.Ticks - startTime; if (renderFlags.IsActive(RenderFlags.TextOverlay)) { g.DrawString( $"DrawTime: {elapsedTime / TimeSpan.TicksPerMillisecond} ms, x: {startPoint.X}, y: {startPoint.Y}, scale: {scale}", _defaultFont, Brushes.WhiteSmoke, 5, 5); //g.FillRectangle(new SolidBrush(Color.FromArgb(100, 0, 0, 0)), 5, 20, 150, 150); //g.DrawString($"Road: {roadTime / TimeSpan.TicksPerMillisecond}ms", _defaultFont, Brushes.White, 10, 40); //g.DrawString($"Prefab: {prefabTime / TimeSpan.TicksPerMillisecond}ms", _defaultFont, Brushes.White, 10, 55); //g.DrawString($"Ferry: {ferryTime / TimeSpan.TicksPerMillisecond}ms", _defaultFont, Brushes.White, 10, 70); //g.DrawString($"MapOverlay: {mapOverlayTime / TimeSpan.TicksPerMillisecond}ms", _defaultFont, Brushes.White, 10, 85); //g.DrawString($"MapOverlay2: {mapOverlay2Time / TimeSpan.TicksPerMillisecond}ms", _defaultFont, Brushes.White, 10, 100); //g.DrawString($"MapArea: {mapAreaTime / TimeSpan.TicksPerMillisecond}ms", _defaultFont, Brushes.White, 10, 115); //g.DrawString($"City: {cityTime / TimeSpan.TicksPerMillisecond}ms", _defaultFont, Brushes.White, 10, 130); } }
private void ParseFerryConnections() { var connectionDirectory = Rfs.GetDirectory("def/ferry/connection"); if (connectionDirectory == null) { Log.Msg("Could not read 'def/ferry/connection' dir"); return; } var ferryConnectionFiles = connectionDirectory.GetFiles("sii"); if (ferryConnectionFiles == null) { Log.Msg("Could not read ferry connection files files"); return; } foreach (var ferryConnectionFile in ferryConnectionFiles) { var data = ferryConnectionFile.Entry.Read(); var lines = Encoding.UTF8.GetString(data).Split('\n'); TsFerryConnection conn = null; foreach (var line in lines) { if (line.Contains(":")) { var value = line.Split(':')[1].Trim(); var key = line.Split(':')[0].Trim(); if (conn != null) { if (key.Contains("connection_positions")) { var vector = value.Split('(')[1].Split(')')[0]; var values = vector.Split(','); var x = float.Parse(values[0].Replace('.', ',')); var z = float.Parse(values[2].Replace('.', ',')); conn.AddConnectionPosition(x, z); } } if (line.Contains("ferry_connection")) { var portIds = value.Split('.'); conn = new TsFerryConnection { StartPortToken = ScsHash.StringToToken(portIds[1]), EndPortToken = ScsHash.StringToToken(portIds[2].TrimEnd('{').Trim()) }; } } if (!line.Contains("}") || conn == null) { continue; } ; var existingItem = _ferryConnectionLookup.FirstOrDefault(item => (item.StartPortToken == conn.StartPortToken && item.EndPortToken == conn.EndPortToken) || (item.StartPortToken == conn.EndPortToken && item.EndPortToken == conn.StartPortToken)); // Check if connection already exists if (existingItem == null) { _ferryConnectionLookup.Add(conn); } conn = null; } } }
private void ParseRoadLookFiles() { var worldDirectory = Rfs.GetDirectory("def/world"); if (worldDirectory == null) { Log.Msg("Could not read 'def/world' dir"); return; } var roadLookFiles = worldDirectory.GetFiles("road_look"); if (roadLookFiles == null) { Log.Msg("Could not read road look files"); return; } foreach (var roadLookFile in roadLookFiles) { if (!roadLookFile.GetFileName().StartsWith("road")) { continue; } var data = roadLookFile.Entry.Read(); var lines = Encoding.UTF8.GetString(data).Split('\n'); TsRoadLook roadLook = null; foreach (var line in lines) { var(validLine, key, value) = SiiHelper.ParseLine(line); if (validLine) { if (key == "road_look") { roadLook = new TsRoadLook(ScsHash.StringToToken(SiiHelper.Trim(value.Split('.')[1].Trim('{')))); } if (roadLook == null) { continue; } if (key == "lanes_left[]") { roadLook.LanesLeft.Add(value); } else if (key == "lanes_right[]") { roadLook.LanesRight.Add(value); } else if (key == "road_offset") { roadLook.Offset = float.Parse(value, CultureInfo.InvariantCulture); } } if (line.Contains("}") && roadLook != null) { if (roadLook.Token != 0 && !_roadLookup.ContainsKey(roadLook.Token)) { _roadLookup.Add(roadLook.Token, roadLook); roadLook = null; } } } } }