public Ets2Item(ulong uid, Ets2Sector sector, int offset) { ItemUID = uid; Navigation = new Dictionary<Ets2Item, Tuple<float, float, IEnumerable<Ets2Item>>>(); Sector = sector; FileOffset = offset; FilePath = sector.FilePath; NodesList = new Dictionary<ulong, Ets2Node>(); Type = (Ets2ItemType)BitConverter.ToUInt32(sector.Stream, offset); int nodeCount; switch (Type) { case Ets2ItemType.Road: StartNodeUID = BitConverter.ToUInt64(sector.Stream, offset + 141); EndNodeUID = BitConverter.ToUInt64(sector.Stream, offset + 149); var lookId = BitConverter.ToUInt32(sector.Stream, offset + 61); // unique UINT32 ID with road look RoadLook = Sector.Mapper.LookupRoadLookID(lookId); // Need to create LUT to translate road_look.sii <> ID // Then we can parse highway routes etc. HideUI = (sector.Stream[offset + 0x37] & 0x02) != 0; // Make sure these UID's exist in the world. if ((StartNodeUID != 0 && sector.Mapper.Nodes.ContainsKey(StartNodeUID)) || (EndNodeUID != 0 && sector.Mapper.Nodes.ContainsKey(EndNodeUID))) { Valid = true; var stamps = BitConverter.ToInt32(sector.Stream, offset + 433); BlockSize = 437 + stamps*24; } else { Valid = false; } break; case Ets2ItemType.Prefab: if (uid == 0x2935de9c700704) { // } nodeCount = BitConverter.ToInt32(sector.Stream, offset + 81); HideUI = (sector.Stream[offset + 0x36] & 0x02) != 0; if (nodeCount > 0x20) { Valid = false; return; } var somethingOffset = offset + 85 + 8*nodeCount; if (somethingOffset < offset || somethingOffset > sector.Stream.Length) { Valid = false; return; } var something = BitConverter.ToInt32(sector.Stream,somethingOffset); if (something < 0 || something > 32) { Valid = false; return; } var OriginOffset = offset + 0x61 + nodeCount*8 + something*8; if (OriginOffset < offset || OriginOffset > sector.Stream.Length) { Valid = false; return; } Origin = sector.Stream[OriginOffset] & 0x03; //Console.WriteLine("PREFAB @ " + uid.ToString("X16") + " origin: " + Origin); var prefabId = (int)BitConverter.ToUInt32(sector.Stream, offset + 57); // Invalidate unreasonable amount of node counts.. if (nodeCount < 0x20 && nodeCount != 0) { Valid = true; for (int i = 0; i < nodeCount; i++) { var nodeUid = BitConverter.ToUInt64(sector.Stream, offset + 81 + 4 + i*8); //Console.WriteLine("prefab node link " + i + ": " + nodeUid.ToString("X16")); // TODO: if node is in other sector.. if (AddNodeUID(nodeUid) == false) { //Console.WriteLine("Could not add prefab node " + nodeUid.ToString("X16") + " for item " + uid.ToString("X16")); break; } } PrefabNodeUID = NodesList.Keys.FirstOrDefault(); } //Console.WriteLine("PREFAB ID: " + prefabId.ToString("X8")); Prefab = sector.Mapper.LookupPrefab(prefabId); if (Prefab == null) { //Console.WriteLine("Prefab ID: " + uid.ToString("X16") + " / " + prefabId.ToString("X") + // " not found"); } break; case Ets2ItemType.Company: Valid = true; // There are 3 nodes subtracted from found in sector: // 1) The node of company itself // 2) The node of loading area // 3) The node of job nodeCount = Sector.Nodes.Count(x => x.ForwardItemUID == uid) - 2; BlockSize = nodeCount*8 + 109; // Invalidate unreasonable amount of node counts.. if (nodeCount < 0x20) { var prefabItemUid = BitConverter.ToUInt64(sector.Stream, offset + 73); var loadAreaNodeUid = BitConverter.ToUInt64(sector.Stream, offset + 93); var jobAreaNodeUid = BitConverter.ToUInt64(sector.Stream, offset + 81); if (AddNodeUID(loadAreaNodeUid) == false) { //Console.WriteLine("Could not add loading area node " + loadAreaNodeUid.ToString("X16")); } else if (AddNodeUID(jobAreaNodeUid) == false) { //Console.WriteLine("Could not add job area node" + jobAreaNodeUid.ToString("X16")); } else { for (int i = 0; i < nodeCount; i++) { var nodeUid = BitConverter.ToUInt64(sector.Stream, offset + 113 + i*8); //Console.WriteLine("company node link " + i + ": " + nodeUid.ToString("X16")); if (AddNodeUID(nodeUid) == false) { //Console.WriteLine("Could not add cargo area node " + nodeUid.ToString("X16") + " for item " + uid.ToString("X16")); break; } } } } else { Valid = false; } break; case Ets2ItemType.Building: var buildingNodeUid1 = BitConverter.ToUInt64(sector.Stream, offset + 73); var buildingNodeUid2 = BitConverter.ToUInt64(sector.Stream, offset + 65); Valid = AddNodeUID(buildingNodeUid1) && AddNodeUID(buildingNodeUid2); BlockSize = 97; break; case Ets2ItemType.Sign: var signNodeUid = BitConverter.ToUInt64(sector.Stream, offset + 65); BlockSize = 153; Valid = AddNodeUID(signNodeUid); break; case Ets2ItemType.Model: var modelNodeUid = BitConverter.ToUInt64(sector.Stream, offset + 81); BlockSize = 101; Valid = AddNodeUID(modelNodeUid); break; case Ets2ItemType.MapOverlay: var mapOverlayNodeUid = BitConverter.ToUInt64(sector.Stream, offset + 65); BlockSize = 73; Valid = AddNodeUID(mapOverlayNodeUid); break; case Ets2ItemType.Ferry: var ferryNodeUid = BitConverter.ToUInt64(sector.Stream, offset + 73); BlockSize = 93; Valid = AddNodeUID(ferryNodeUid); break; case Ets2ItemType.CutPlane: nodeCount = BitConverter.ToInt32(sector.Stream, offset + 57); // Invalidate unreasonable amount of node counts.. if (nodeCount < 0x20) { Valid = true; for (int i = 0; i < nodeCount; i++) { var nodeUid = BitConverter.ToUInt64(sector.Stream, offset + 57 + 4 + i * 8); //Console.WriteLine("cut plane node " + i + ": " + nodeUid.ToString("X16")); if (AddNodeUID(nodeUid) == false) { //Console.WriteLine("Could not add cut plane node " + nodeUid.ToString("X16") + " for item " + uid.ToString("X16")); break; } } } BlockSize = 61 + 8 * nodeCount; break; case Ets2ItemType.TrafficRule: nodeCount = BitConverter.ToInt32(sector.Stream, offset + 57); // Invalidate unreasonable amount of node counts.. if (nodeCount < 0x20) { Valid = true; for (int i = 0; i < nodeCount; i++) { var nodeUid = BitConverter.ToUInt64(sector.Stream, offset + 57 + 4 + i * 8); //Console.WriteLine("traffic area node " + i + ": " + nodeUid.ToString("X16")); if (AddNodeUID(nodeUid) == false) { //Console.WriteLine("Could not add traffic area node " + nodeUid.ToString("X16") + " for item " + uid.ToString("X16")); break; } } } BlockSize = 73 + 8 * nodeCount; break; case Ets2ItemType.Trigger: nodeCount = BitConverter.ToInt32(sector.Stream, offset + 57); // Invalidate unreasonable amount of node counts.. if (nodeCount < 0x20) { Valid = true; for (int i = 0; i < nodeCount; i++) { var nodeUid = BitConverter.ToUInt64(sector.Stream, offset + 57 + 4 + i * 8); //Console.WriteLine("trigger node " + i + ": " + nodeUid.ToString("X16")); if (AddNodeUID(nodeUid) == false) { //Console.WriteLine("Could not add trigger node " + nodeUid.ToString("X16") + " for item " + uid.ToString("X16")); break; } } } BlockSize = 117 + 8 * nodeCount; break; case Ets2ItemType.BusStop: var busStopUid = BitConverter.ToUInt64(sector.Stream, offset + 73); BlockSize = 81; Valid = AddNodeUID(busStopUid); break; case Ets2ItemType.Garage: // TODO: at offset 65 there is a int '1' value.. is it a list? var garageUid = BitConverter.ToUInt64(sector.Stream, offset + 69); BlockSize = 85; Valid = AddNodeUID(garageUid); break; case Ets2ItemType.FuelPump: var dunno2Uid = BitConverter.ToUInt64(sector.Stream, offset + 57); BlockSize = 73; Valid = AddNodeUID(dunno2Uid); break; case Ets2ItemType.Dunno: Valid = true; break; case Ets2ItemType.Service: var locationNodeUid = BitConverter.ToUInt64(sector.Stream, offset + 57); Valid = AddNodeUID(locationNodeUid); BlockSize = 73; break; case Ets2ItemType.City: var CityID = BitConverter.ToUInt64(sector.Stream, offset + 57); var NodeID = BitConverter.ToUInt64(sector.Stream, offset + 73); if ((CityID >> 56) != 0) { break; } City = Sector.Mapper.LookupCityID(CityID); Valid = City != string.Empty && NodeID != 0 && sector.Mapper.Nodes.ContainsKey(NodeID); if (!Valid) { Console.WriteLine("Unknown city ID " + CityID.ToString("X16") + " at " + ItemUID.ToString("X16")); } else { StartNodeUID = NodeID; //Console.WriteLine(CityID.ToString("X16") + " === " + City); } BlockSize = 81; break; default: Valid = false; break; } //if (Valid) // Console.WriteLine("Item " + uid.ToString("X16") + " (" + Type.ToString() + ") is found at " + offset.ToString("X")); }
public Ets2Item(ulong uid, Ets2Sector sector, int offset) { ItemUID = uid; Navigation = new Dictionary <Ets2Item, Tuple <float, float, IEnumerable <Ets2Item> > >(); Sector = sector; FileOffset = offset; FilePath = sector.FilePath; NodesList = new Dictionary <ulong, Ets2Node>(); Type = (Ets2ItemType)BitConverter.ToUInt32(sector.Stream, offset); int nodeCount; switch (Type) { case Ets2ItemType.Road: StartNodeUID = BitConverter.ToUInt64(sector.Stream, offset + 141); EndNodeUID = BitConverter.ToUInt64(sector.Stream, offset + 149); var lookId = BitConverter.ToUInt32(sector.Stream, offset + 61); // unique UINT32 ID with road look RoadLook = Sector.Mapper.LookupRoadLookID(lookId); // Need to create LUT to translate road_look.sii <> ID // Then we can parse highway routes etc. HideUI = (sector.Stream[offset + 0x37] & 0x02) != 0; // Make sure these UID's exist in the world. if ((StartNodeUID != 0 && sector.Mapper.Nodes.ContainsKey(StartNodeUID)) || (EndNodeUID != 0 && sector.Mapper.Nodes.ContainsKey(EndNodeUID))) { Valid = true; var stamps = BitConverter.ToInt32(sector.Stream, offset + 433); BlockSize = 437 + stamps * 24; } else { Valid = false; } break; case Ets2ItemType.Prefab: if (uid == 0x2935de9c700704) { // } nodeCount = BitConverter.ToInt32(sector.Stream, offset + 81); HideUI = (sector.Stream[offset + 0x36] & 0x02) != 0; if (nodeCount > 0x20) { Valid = false; return; } var somethingOffset = offset + 85 + 8 * nodeCount; if (somethingOffset < offset || somethingOffset > sector.Stream.Length) { Valid = false; return; } var something = BitConverter.ToInt32(sector.Stream, somethingOffset); if (something < 0 || something > 32) { Valid = false; return; } var OriginOffset = offset + 0x61 + nodeCount * 8 + something * 8; if (OriginOffset < offset || OriginOffset > sector.Stream.Length) { Valid = false; return; } Origin = sector.Stream[OriginOffset] & 0x03; //Console.WriteLine("PREFAB @ " + uid.ToString("X16") + " origin: " + Origin); var prefabId = (int)BitConverter.ToUInt32(sector.Stream, offset + 57); // Invalidate unreasonable amount of node counts.. if (nodeCount < 0x20 && nodeCount != 0) { Valid = true; for (int i = 0; i < nodeCount; i++) { var nodeUid = BitConverter.ToUInt64(sector.Stream, offset + 81 + 4 + i * 8); //Console.WriteLine("prefab node link " + i + ": " + nodeUid.ToString("X16")); // TODO: if node is in other sector.. if (AddNodeUID(nodeUid) == false) { //Console.WriteLine("Could not add prefab node " + nodeUid.ToString("X16") + " for item " + uid.ToString("X16")); break; } } PrefabNodeUID = NodesList.Keys.FirstOrDefault(); } //Console.WriteLine("PREFAB ID: " + prefabId.ToString("X8")); Prefab = sector.Mapper.LookupPrefab(prefabId); if (Prefab == null) { //Console.WriteLine("Prefab ID: " + uid.ToString("X16") + " / " + prefabId.ToString("X") + // " not found"); } break; case Ets2ItemType.Company: Valid = true; // There are 3 nodes subtracted from found in sector: // 1) The node of company itself // 2) The node of loading area // 3) The node of job nodeCount = Sector.Nodes.Count(x => x.ForwardItemUID == uid) - 2; BlockSize = nodeCount * 8 + 109; // Invalidate unreasonable amount of node counts.. if (nodeCount < 0x20) { var prefabItemUid = BitConverter.ToUInt64(sector.Stream, offset + 73); var loadAreaNodeUid = BitConverter.ToUInt64(sector.Stream, offset + 93); var jobAreaNodeUid = BitConverter.ToUInt64(sector.Stream, offset + 81); if (AddNodeUID(loadAreaNodeUid) == false) { //Console.WriteLine("Could not add loading area node " + loadAreaNodeUid.ToString("X16")); } else if (AddNodeUID(jobAreaNodeUid) == false) { //Console.WriteLine("Could not add job area node" + jobAreaNodeUid.ToString("X16")); } else { for (int i = 0; i < nodeCount; i++) { var nodeUid = BitConverter.ToUInt64(sector.Stream, offset + 113 + i * 8); //Console.WriteLine("company node link " + i + ": " + nodeUid.ToString("X16")); if (AddNodeUID(nodeUid) == false) { //Console.WriteLine("Could not add cargo area node " + nodeUid.ToString("X16") + " for item " + uid.ToString("X16")); break; } } } } else { Valid = false; } break; case Ets2ItemType.Building: var buildingNodeUid1 = BitConverter.ToUInt64(sector.Stream, offset + 73); var buildingNodeUid2 = BitConverter.ToUInt64(sector.Stream, offset + 65); Valid = AddNodeUID(buildingNodeUid1) && AddNodeUID(buildingNodeUid2); BlockSize = 97; break; case Ets2ItemType.Sign: var signNodeUid = BitConverter.ToUInt64(sector.Stream, offset + 65); BlockSize = 153; Valid = AddNodeUID(signNodeUid); break; case Ets2ItemType.Model: var modelNodeUid = BitConverter.ToUInt64(sector.Stream, offset + 81); BlockSize = 101; Valid = AddNodeUID(modelNodeUid); break; case Ets2ItemType.MapOverlay: var mapOverlayNodeUid = BitConverter.ToUInt64(sector.Stream, offset + 65); BlockSize = 73; Valid = AddNodeUID(mapOverlayNodeUid); break; case Ets2ItemType.Ferry: var ferryNodeUid = BitConverter.ToUInt64(sector.Stream, offset + 73); BlockSize = 93; Valid = AddNodeUID(ferryNodeUid); break; case Ets2ItemType.CutPlane: nodeCount = BitConverter.ToInt32(sector.Stream, offset + 57); // Invalidate unreasonable amount of node counts.. if (nodeCount < 0x20) { Valid = true; for (int i = 0; i < nodeCount; i++) { var nodeUid = BitConverter.ToUInt64(sector.Stream, offset + 57 + 4 + i * 8); //Console.WriteLine("cut plane node " + i + ": " + nodeUid.ToString("X16")); if (AddNodeUID(nodeUid) == false) { //Console.WriteLine("Could not add cut plane node " + nodeUid.ToString("X16") + " for item " + uid.ToString("X16")); break; } } } BlockSize = 61 + 8 * nodeCount; break; case Ets2ItemType.TrafficRule: nodeCount = BitConverter.ToInt32(sector.Stream, offset + 57); // Invalidate unreasonable amount of node counts.. if (nodeCount < 0x20) { Valid = true; for (int i = 0; i < nodeCount; i++) { var nodeUid = BitConverter.ToUInt64(sector.Stream, offset + 57 + 4 + i * 8); //Console.WriteLine("traffic area node " + i + ": " + nodeUid.ToString("X16")); if (AddNodeUID(nodeUid) == false) { //Console.WriteLine("Could not add traffic area node " + nodeUid.ToString("X16") + " for item " + uid.ToString("X16")); break; } } } BlockSize = 73 + 8 * nodeCount; break; case Ets2ItemType.Trigger: nodeCount = BitConverter.ToInt32(sector.Stream, offset + 57); // Invalidate unreasonable amount of node counts.. if (nodeCount < 0x20) { Valid = true; for (int i = 0; i < nodeCount; i++) { var nodeUid = BitConverter.ToUInt64(sector.Stream, offset + 57 + 4 + i * 8); //Console.WriteLine("trigger node " + i + ": " + nodeUid.ToString("X16")); if (AddNodeUID(nodeUid) == false) { //Console.WriteLine("Could not add trigger node " + nodeUid.ToString("X16") + " for item " + uid.ToString("X16")); break; } } } BlockSize = 117 + 8 * nodeCount; break; case Ets2ItemType.BusStop: var busStopUid = BitConverter.ToUInt64(sector.Stream, offset + 73); BlockSize = 81; Valid = AddNodeUID(busStopUid); break; case Ets2ItemType.Garage: // TODO: at offset 65 there is a int '1' value.. is it a list? var garageUid = BitConverter.ToUInt64(sector.Stream, offset + 69); BlockSize = 85; Valid = AddNodeUID(garageUid); break; case Ets2ItemType.FuelPump: var dunno2Uid = BitConverter.ToUInt64(sector.Stream, offset + 57); BlockSize = 73; Valid = AddNodeUID(dunno2Uid); break; case Ets2ItemType.Dunno: Valid = true; break; case Ets2ItemType.Service: var locationNodeUid = BitConverter.ToUInt64(sector.Stream, offset + 57); Valid = AddNodeUID(locationNodeUid); BlockSize = 73; break; case Ets2ItemType.City: var CityID = BitConverter.ToUInt64(sector.Stream, offset + 57); var NodeID = BitConverter.ToUInt64(sector.Stream, offset + 73); if ((CityID >> 56) != 0) { break; } City = Sector.Mapper.LookupCityID(CityID); Valid = City != string.Empty && NodeID != 0 && sector.Mapper.Nodes.ContainsKey(NodeID); if (!Valid) { Console.WriteLine("Unknown city ID " + CityID.ToString("X16") + " at " + ItemUID.ToString("X16")); } else { StartNodeUID = NodeID; //Console.WriteLine(CityID.ToString("X16") + " === " + City); } BlockSize = 81; break; default: Valid = false; break; } //if (Valid) // Console.WriteLine("Item " + uid.ToString("X16") + " (" + Type.ToString() + ") is found at " + offset.ToString("X")); }