Exemplo n.º 1
0
        public static RoadTopology FromMapObjects(MapObject[] mapObjects)
        {
            var roadTopology = new RoadTopology();
            var templates    = new Dictionary <string, RoadTemplate>();

            for (var i = 0; i < mapObjects.Length; i++)
            {
                var mapObject = mapObjects[i];

                switch (mapObject.RoadType & RoadType.PrimaryType)
                {
                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 == "")
                    {
                        continue;
                    }

                    if (!templates.TryGetValue(mapObject.TypeName, out var template))
                    {
                        template = new RoadTemplate(mapObject.TypeName);
                        templates.Add(mapObject.TypeName, template);
                    }

                    roadTopology.AddSegment(template, mapObject, roadEnd);
                    break;
                }
            }

            return(roadTopology);
        }
Exemplo n.º 2
0
        public void CurveType(
            NodePosition startPosition1, RoadType startType1,
            NodePosition endPosition1, RoadType endType1,
            NodePosition startPosition2, RoadType startType2,
            NodePosition endPosition2, RoadType endType2,
            RoadTextureType expectedCurveType)
        {
            var start1 = new MapObject(NodePositions[startPosition1], 0, startType1, default);
            var end1   = new MapObject(NodePositions[endPosition1], 0, endType1, default);
            var start2 = new MapObject(NodePositions[startPosition2], 0, startType2, default);
            var end2   = new MapObject(NodePositions[endPosition2], 0, endType2, default);

            var template = new RoadTemplate("SideWalk3");

            var topology = new RoadTopology();

            topology.AddSegment(template, start1, end1);
            topology.AddSegment(template, start2, end2);

            topology.AlignOrientation();

            var curveNode       = topology.Nodes.Single(n => n.Edges.Count == 2);
            var actualCurveType = CurvedRoadSegment.ChooseCurveType(topology.Edges[0], topology.Edges[1], curveNode.Position);

            Assert.Equal(expectedCurveType, actualCurveType);
        }
Exemplo n.º 3
0
        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();
        }
Exemplo n.º 4
0
        private void LoadObjects(
            ContentManager contentManager,
            HeightMap heightMap,
            MapObject[] mapObjects,
            Team[] teams,
            out WaypointCollection waypointCollection,
            out GameObjectCollection gameObjects,
            out Road[] roads,
            out Bridge[] bridges)
        {
            var waypoints = new List <Waypoint>();

            gameObjects = new GameObjectCollection(contentManager);
            var roadsList   = new List <Road>();
            var bridgesList = new List <Bridge>();

            var roadTopology = new RoadTopology();

            for (var i = 0; i < mapObjects.Length; i++)
            {
                var mapObject = mapObjects[i];

                var position = mapObject.Position;

                switch (mapObject.RoadType & RoadType.PrimaryType)
                {
                case RoadType.None:
                    switch (mapObject.TypeName)
                    {
                    case "*Waypoints/Waypoint":
                        waypoints.Add(CreateWaypoint(mapObject));
                        break;

                    default:
                        position.Z += heightMap.GetHeight(position.X, position.Y);

                        var gameObject = CreateGameObject(mapObject, teams, contentManager);

                        if (gameObject != null)
                        {
                            gameObject.Transform.Translation = position;
                            gameObject.Transform.Rotation    = Quaternion.CreateFromAxisAngle(Vector3.UnitZ, mapObject.Angle);

                            gameObjects.Add(gameObject);

                            if (gameObject.Definition.IsBridge)
                            {
                                // This is a landmark bridge. We need to add towers at the corners.
                                CreateTowers(contentManager, gameObjects, gameObject, mapObject);
                            }
                        }

                        break;
                    }
                    break;

                case RoadType.BridgeStart:
                case RoadType.BridgeEnd:
                    // Multiple invalid bridges can be found in e.g GLA01.
                    // TODO: Log a warning.
                    if ((i + 1) >= mapObjects.Length || !mapObjects[i + 1].RoadType.HasFlag(RoadType.BridgeEnd))
                    {
                        continue;
                    }

                    var bridgeEnd = mapObjects[++i];

                    var bridgeTemplate = GetBridgeTemplate(contentManager, mapObject);

                    if (Bridge.TryCreateBridge(
                            contentManager,
                            heightMap,
                            bridgeTemplate,
                            mapObject.Position,
                            bridgeEnd.Position,
                            out var bridge))
                    {
                        bridgesList.Add(AddDisposable(bridge));
                    }


                    break;

                default:
                    var roadEnd = mapObjects[++i];

                    // Some maps have roads with invalid start- or endpoints.
                    // We'll skip processing them altogether.
                    // TODO: Log a warning.
                    if (mapObject.TypeName == "" || roadEnd.TypeName == "")
                    {
                        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 = contentManager.IniDataContext.RoadTemplates.Find(x =>
                                                                                        x.Name == mapObject.TypeName || x.Name == roadEnd.TypeName);

                    if (roadTemplate == null)
                    {
                        throw new InvalidDataException($"Missing road template: {mapObject.TypeName}");
                    }

                    roadTopology.AddSegment(roadTemplate, mapObject, roadEnd);
                    break;
                }

                contentManager.GraphicsDevice.WaitForIdle();
            }

            // The map stores road segments with no connectivity:
            // - a segment is from point A to point B
            // - with a road type name
            // - and start and end curve types (angled, tight curve, broad curve).

            // The goal is to create road networks of connected road segments,
            // where a network has only a single road type.

            // A road network is composed of 2 or more nodes.
            // A network is a (potentially) cyclic graph.

            // A road node has > 1 and <= 4 edges connected to it.
            // A node can be part of multiple networks.

            // An edge can only exist in one network.

            // TODO: If a node stored in the map has > 4 edges, the extra edges
            // are put into a separate network.

            var networks = roadTopology.BuildNetworks();

            foreach (var network in networks)
            {
                foreach (var edge in network.Edges)
                {
                    var startPosition = edge.Start.TopologyNode.Position;
                    var endPosition   = edge.End.TopologyNode.Position;

                    startPosition.Z += heightMap.GetHeight(startPosition.X, startPosition.Y);
                    endPosition.Z   += heightMap.GetHeight(endPosition.X, endPosition.Y);

                    roadsList.Add(AddDisposable(new Road(
                                                    contentManager,
                                                    heightMap,
                                                    edge.TopologyEdge.Template,
                                                    startPosition,
                                                    endPosition)));
                }
            }

            waypointCollection = new WaypointCollection(waypoints);
            roads   = roadsList.ToArray();
            bridges = bridgesList.ToArray();
        }