private static ScbFile ParseScbData(BinaryReader reader) { var assetNames = AssetNameCollection.Parse(reader); var result = new ScbFile(); var context = new MapParseContext(assetNames); context.PushAsset(nameof(ScbFile), reader.BaseStream.Length); Asset.ParseAssets(reader, context, assetName => { switch (assetName) { case ScriptImportSize.AssetName: result.ScriptImportSize = ScriptImportSize.Parse(reader, context); break; case PlayerScriptsList.AssetName: result.PlayerScripts = PlayerScriptsList.Parse(reader, context); break; case NamedCameras.AssetName: result.NamedCameras = NamedCameras.Parse(reader, context); break; case CameraAnimationList.AssetName: result.CameraAnimationList = CameraAnimationList.Parse(reader, context); break; case ScriptsPlayers.AssetName: result.ScriptsPlayers = ScriptsPlayers.Parse(reader, context); break; case ObjectsList.AssetName: result.ObjectsList = ObjectsList.Parse(reader, context); break; case PolygonTriggers.AssetName: result.PolygonTriggers = PolygonTriggers.Parse(reader, context); break; case ScriptTeams.AssetName: result.Teams = ScriptTeams.Parse(reader, context); break; case WaypointsList.AssetName: result.WaypointsList = WaypointsList.Parse(reader, context); break; default: throw new InvalidDataException($"Unknown asset name: {assetName}"); } }); context.PopAsset(); return(result); }
private void WriteMapDataTo(BinaryWriter writer, AssetNameCollection assetNames) { if (ScriptImportSize != null) { writer.Write(assetNames.GetOrCreateAssetIndex(ScriptImportSize.AssetName)); ScriptImportSize.WriteTo(writer, assetNames); } writer.Write(assetNames.GetOrCreateAssetIndex(PlayerScriptsList.AssetName)); PlayerScripts.WriteTo(writer, assetNames); if (NamedCameras != null) { writer.Write(assetNames.GetOrCreateAssetIndex(NamedCameras.AssetName)); NamedCameras.WriteTo(writer); } if (CameraAnimationList != null) { writer.Write(assetNames.GetOrCreateAssetIndex(CameraAnimationList.AssetName)); CameraAnimationList.WriteTo(writer); } writer.Write(assetNames.GetOrCreateAssetIndex(ScriptsPlayers.AssetName)); ScriptsPlayers.WriteTo(writer, assetNames); writer.Write(assetNames.GetOrCreateAssetIndex(ObjectsList.AssetName)); ObjectsList.WriteTo(writer, assetNames); if (PolygonTriggers != null) { writer.Write(assetNames.GetOrCreateAssetIndex(PolygonTriggers.AssetName)); PolygonTriggers.WriteTo(writer); } if (TriggerAreas != null) { writer.Write(assetNames.GetOrCreateAssetIndex(TriggerAreas.AssetName)); TriggerAreas.WriteTo(writer); } writer.Write(assetNames.GetOrCreateAssetIndex(ScriptTeams.AssetName)); Teams.WriteTo(writer, assetNames); writer.Write(assetNames.GetOrCreateAssetIndex(WaypointsList.AssetName)); WaypointsList.WriteTo(writer); }
private void LoadObjects( AssetLoadContext loadContext, HeightMap heightMap, MapObject[] mapObjects, NamedCameras namedCameras, List <Team> teams, out WaypointCollection waypointCollection, out RoadCollection roads, out Bridge[] bridges, out CameraCollection cameras) { var waypoints = new List <Waypoint>(); var bridgesList = new List <Bridge>(); var roadTopology = new RoadTopology(); for (var i = 0; i < mapObjects.Length; i++) { var mapObject = mapObjects[i]; switch (mapObject.RoadType & RoadType.PrimaryType) { case RoadType.None: switch (mapObject.TypeName) { case Waypoint.ObjectTypeName: waypoints.Add(new Waypoint(mapObject)); break; default: GameObject.FromMapObject(mapObject, loadContext.AssetStore, GameObjects, heightMap, null, teams); break; } break; case RoadType.BridgeStart: case RoadType.BridgeEnd: // Multiple invalid bridges can be found in e.g GLA01. if ((i + 1) >= mapObjects.Length || !mapObjects[i + 1].RoadType.HasFlag(RoadType.BridgeEnd)) { Logger.Warn($"Invalid bridge: {mapObject.ToString()}, skipping..."); continue; } var bridgeEnd = mapObjects[++i]; bridgesList.Add(AddDisposable(new Bridge( loadContext, heightMap, mapObject, mapObject.Position, bridgeEnd.Position, GameObjects))); break; case RoadType.Start: case RoadType.End: var roadEnd = mapObjects[++i]; // Some maps have roads with invalid start- or endpoints. // We'll skip processing them altogether. if (mapObject.TypeName == "" || roadEnd.TypeName == "") { Logger.Warn($"Road {mapObject.ToString()} has invalid start- or endpoint, skipping..."); continue; } if (!mapObject.RoadType.HasFlag(RoadType.Start) || !roadEnd.RoadType.HasFlag(RoadType.End)) { throw new InvalidDataException(); } // Note that we're searching with the type of either end. // This is because of weirdly corrupted roads with unmatched ends in USA04, which work fine in WB and SAGE. var roadTemplate = loadContext.AssetStore.RoadTemplates.GetByName(mapObject.TypeName) ?? loadContext.AssetStore.RoadTemplates.GetByName(roadEnd.TypeName); if (roadTemplate == null) { throw new InvalidDataException($"Missing road template: {mapObject.TypeName}"); } roadTopology.AddSegment(roadTemplate, mapObject, roadEnd); break; } loadContext.GraphicsDevice.WaitForIdle(); } cameras = new CameraCollection(namedCameras?.Cameras); roads = AddDisposable(new RoadCollection(roadTopology, loadContext, heightMap)); waypointCollection = new WaypointCollection(waypoints, MapFile.WaypointsList.WaypointPaths); bridges = bridgesList.ToArray(); }