示例#1
0
        private static MapFile ParseMapData(BinaryReader reader)
        {
            var assetNames = AssetNameCollection.Parse(reader);

            var result = new MapFile();

            var context = new MapParseContext(assetNames);

            context.PushAsset(nameof(MapFile), reader.BaseStream.Length);

            Asset.ParseAssets(reader, context, assetName =>
            {
                switch (assetName)
                {
                case AssetList.AssetName:
                    result.AssetList = AssetList.Parse(reader, context);
                    break;

                case GlobalVersion.AssetName:
                    result.GlobalVersion = GlobalVersion.Parse(reader, context);
                    break;

                case HeightMapData.AssetName:
                    result.HeightMapData = HeightMapData.Parse(reader, context);
                    break;

                case BlendTileData.AssetName:
                    result.BlendTileData = BlendTileData.Parse(reader, context, result.HeightMapData);
                    break;

                case WorldInfo.AssetName:
                    result.WorldInfo = WorldInfo.Parse(reader, context);
                    break;

                case MPPositionList.AssetName:
                    result.MPPositionList = MPPositionList.Parse(reader, context);
                    break;

                case SidesList.AssetName:
                    result.SidesList = SidesList.Parse(reader, context, result.AssetList != null);
                    break;

                case LibraryMapLists.AssetName:
                    result.LibraryMapLists = LibraryMapLists.Parse(reader, context);
                    break;

                case Teams.AssetName:
                    result.Teams = Teams.Parse(reader, context);
                    break;

                case PlayerScriptsList.AssetName:
                    result.PlayerScriptsList = PlayerScriptsList.Parse(reader, context);
                    break;

                case BuildLists.AssetName:
                    result.BuildLists = BuildLists.Parse(reader, context, result.AssetList != null);
                    break;

                case ObjectsList.AssetName:
                    result.ObjectsList = ObjectsList.Parse(reader, context);
                    break;

                case PolygonTriggers.AssetName:
                    result.PolygonTriggers = PolygonTriggers.Parse(reader, context);
                    break;

                case TriggerAreas.AssetName:
                    result.TriggerAreas = TriggerAreas.Parse(reader, context);
                    break;

                case GlobalWaterSettings.AssetName:
                    result.GlobalWaterSettings = GlobalWaterSettings.Parse(reader, context);
                    break;

                case FogSettings.AssetName:
                    result.FogSettings = FogSettings.Parse(reader, context);
                    break;

                case MissionHotSpots.AssetName:
                    result.MissionHotSpots = MissionHotSpots.Parse(reader, context);
                    break;

                case MissionObjectives.AssetName:
                    result.MissionObjectives = MissionObjectives.Parse(reader, context);
                    break;

                case StandingWaterAreas.AssetName:
                    result.StandingWaterAreas = StandingWaterAreas.Parse(reader, context);
                    break;

                case RiverAreas.AssetName:
                    result.RiverAreas = RiverAreas.Parse(reader, context);
                    break;

                case StandingWaveAreas.AssetName:
                    result.StandingWaveAreas = StandingWaveAreas.Parse(reader, context);
                    break;

                case GlobalLighting.AssetName:
                    result.GlobalLighting = GlobalLighting.Parse(reader, context);
                    break;

                case PostEffectsChunk.AssetName:
                    result.PostEffectsChunk = PostEffectsChunk.Parse(reader, context);
                    break;

                case EnvironmentData.AssetName:
                    result.EnvironmentData = EnvironmentData.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 CastleTemplates.AssetName:
                    result.CastleTemplates = CastleTemplates.Parse(reader, context);
                    break;

                case WaypointsList.AssetName:
                    result.WaypointsList = WaypointsList.Parse(reader, context);
                    break;

                case SkyboxSettings.AssetName:
                    result.SkyboxSettings = SkyboxSettings.Parse(reader, context);
                    break;

                default:
                    throw new NotImplementedException(assetName);
                }
            });

            context.PopAsset();

            return(result);
        }
示例#2
0
        private static void SetupSkirmishGameSides(
            Game game,
            MapFile mapFile,
            PlayerSetting[] playerSettings,
            GameType gameType,
            List <Player> mapPlayers,
            List <Team> mapTeams,
            List <ScriptList> mapScriptLists)
        {
            var originalMapPlayers = mapFile.SidesList.Players;

            // Neutral player.
            mapPlayers.Add(originalMapPlayers[0]);

            // Civilian player. It isn't necessarily the second player.
            // TODO: There might be more than one civilian player.
            mapPlayers.Add(originalMapPlayers.FirstOrDefault(x => (string)x.Properties["playerFaction"].Value == "FactionCivilian"));

            //var hasAIPlayer = false;
            for (var i = 0; i < playerSettings.Length; i++)
            {
                var playerSetting = playerSettings[i];

                var factionPlayer = originalMapPlayers.Single(x => (string)x.Properties["playerFaction"].Value == playerSetting.SideName);

                var isHuman = playerSetting.Owner == PlayerOwner.Player;

                var playerName = isHuman
                    ? $"player{i}"
                    : $"{factionPlayer.Properties["playerName"].Value}{i}";

                //if (!isHuman)
                //{
                //    hasAIPlayer = true;
                //}

                var playerProperties = new AssetPropertyCollection();
                playerProperties.AddAsciiString("playerFaction", (string)factionPlayer.Properties["playerFaction"].Value);
                playerProperties.AddAsciiString("playerName", playerName);
                playerProperties.AddAsciiString("playerDisplayName", (string)factionPlayer.Properties["playerDisplayName"].Value);
                playerProperties.AddBoolean("playerIsHuman", isHuman);
                playerProperties.AddInteger("playerColor", playerSetting.Color.ToUInt32());

                // TODO: Other player properties.

                mapPlayers.Add(new Player
                {
                    Properties = playerProperties,
                    BuildList  = factionPlayer.BuildList,
                });
            }

            // Setup player relationships.
            var playerAllies  = new string[playerSettings.Length];
            var playerEnemies = new string[playerSettings.Length];

            for (var i = 0; i < playerSettings.Length; i++)
            {
                playerAllies[i]  = "";
                playerEnemies[i] = "";
            }
            for (var i = 0; i < playerSettings.Length; i++)
            {
                var outerPlayer = playerSettings[i];

                for (var j = i + 1; j < playerSettings.Length; j++)
                {
                    var innerPlayer = playerSettings[j];
                    if (outerPlayer.Team == innerPlayer.Team && outerPlayer.Team != 0)
                    {
                        playerAllies[i] += mapPlayers[j + 2].Properties["playerName"].Value + " ";
                        playerAllies[j] += mapPlayers[i + 2].Properties["playerName"].Value + " ";
                    }
                    else
                    {
                        playerEnemies[i] += mapPlayers[j + 2].Properties["playerName"].Value + " ";
                        playerEnemies[j] += mapPlayers[i + 2].Properties["playerName"].Value + " ";
                    }
                }
            }
            for (var i = 0; i < playerSettings.Length; i++)
            {
                mapPlayers[i + 2].Properties.AddAsciiString("playerAllies", playerAllies[i]);
                mapPlayers[i + 2].Properties.AddAsciiString("playerEnemies", playerEnemies[i]);
            }

            var originalMapScriptLists = mapFile.SidesList.PlayerScripts.ScriptLists;

            var playerNames = mapPlayers
                              .Select(p => p.Properties.GetPropOrNull("playerName")?.Value.ToString())
                              .ToArray();

            while (mapScriptLists.Count < mapPlayers.Count)
            {
                mapScriptLists.Add(null);
            }

            // Copy neutral player scripts.
            var neutralPlayerName = (string)mapPlayers[0].Properties["playerName"].Value;

            CopyScripts(
                originalMapScriptLists,
                playerNames,
                neutralPlayerName,
                mapScriptLists,
                0,
                appendIndex: false);

            // Copy civilian player scripts.
            var civilianPlayerName = (string)mapPlayers[1].Properties["playerName"].Value;

            CopyScripts(
                originalMapScriptLists,
                playerNames,
                civilianPlayerName,
                mapScriptLists,
                1,
                appendIndex: false);

            var skirmishScriptsEntry = game.ContentManager.GetScriptEntry(@"Data\Scripts\SkirmishScripts.scb");

            // TODO: Generals and ZH use SkirmishScripts.scb,
            // but later games use "libraries".
            if (skirmishScriptsEntry != null)
            {
                using var stream = skirmishScriptsEntry.Open();
                var skirmishScripts = ScbFile.FromStream(stream);

                // This probably isn't right, but it does make the teams match those in .sav files.
                // We first add human player(s) teams, then the replay observer team,
                // then neutral and civilian teams, and then finally AI skirmish players.

                var skirmishScriptsPlayerNames = skirmishScripts.ScriptsPlayers.Players.Select(p => p.Name).ToArray();

                // Skip neutral and civilian players.
                for (var i = 2; i < mapPlayers.Count; i++)
                {
                    if ((bool)mapPlayers[i].Properties["playerIsHuman"].Value)
                    {
                        // Copy the scripts from the civilian player to all human players.
                        CopyScripts(
                            skirmishScripts.PlayerScripts.ScriptLists,
                            skirmishScriptsPlayerNames,
                            civilianPlayerName,
                            mapScriptLists,
                            i,
                            appendIndex: true);

                        mapTeams.Add(CreateDefaultTeam((string)mapPlayers[i].Properties["playerName"].Value));
                    }
                }

                mapTeams.Add(CreateDefaultTeam("ReplayObserver"));

                mapTeams.Add(CreateDefaultTeam(neutralPlayerName));
                mapTeams.Add(CreateDefaultTeam(civilianPlayerName));

                // Skip neutral and civilian players.
                for (var i = 2; i < mapPlayers.Count; i++)
                {
                    if (!(bool)mapPlayers[i].Properties["playerIsHuman"].Value)
                    {
                        var playerSide       = game.AssetStore.PlayerTemplates.GetByName(playerSettings[i - 2].SideName).Side;
                        var sourcePlayerName = $"Skirmish{playerSide}";

                        // Copy the scripts from the according skirmish player for all AI players.
                        CopyScripts(
                            skirmishScripts.PlayerScripts.ScriptLists,
                            skirmishScriptsPlayerNames,
                            sourcePlayerName,
                            mapScriptLists,
                            i,
                            appendIndex: true);

                        // TODO: Not sure about the order the teams are added.
                        foreach (var team in skirmishScripts.Teams.Teams)
                        {
                            var teamOwner = (string)team.Properties["teamOwner"].Value;
                            if (teamOwner == sourcePlayerName)
                            {
                                var teamName = $"{team.Properties["teamName"].Value}{i}";
                                mapTeams.Add(CreateTeam(
                                                 teamName,
                                                 (string)mapPlayers[i].Properties["playerName"].Value,
                                                 (bool)team.Properties["teamIsSingleton"].Value));
                            }
                        }
                    }
                }
            }

            if (playerSettings.Length > 1)
            {
                var multiplayerScriptsEntry = game.ContentManager.GetScriptEntry(@"Data\Scripts\MultiplayerScripts.scb");

                if (multiplayerScriptsEntry != null)
                {
                    using var stream = multiplayerScriptsEntry.Open();
                    var multiplayerScripts = ScbFile.FromStream(stream);

                    // TODO: This is a bit hardcoded.
                    mapScriptLists[0] = multiplayerScripts.PlayerScripts.ScriptLists[0];
                }
            }
        }
示例#3
0
        private MapCache BuildMapCache(FileSystemEntry fileSystemEntry, FileInfo fileInfo, AssetStore assetStore)
        {
            var timestamp = fileInfo.LastWriteTime.ToFileTime();

            var mapCache = new MapCache()
            {
                FileSize      = (int)fileInfo.Length,
                TimestampLo   = (int)timestamp,
                TimestampHi   = (int)(timestamp >> 32),
                IsOfficial    = false,
                NameLookupTag = null
            };

            var mapFile = MapFile.FromFileSystemEntry(fileSystemEntry);

            var border = mapFile.HeightMapData.Borders[0];

            mapCache.ExtentMin = new Vector3(border.Corner1X, border.Corner1Y, 0f);
            mapCache.ExtentMax = new Vector3(border.Corner2X, border.Corner2Y, 0f);

            byte startingPositionsFound = 0;

            foreach (var mapObject in mapFile.ObjectsList.Objects)
            {
                // ignore roads
                if ((mapObject.RoadType & RoadType.PrimaryType) == RoadType.None)
                {
                    // handle special waypoints
                    if (mapObject.TypeName == Waypoint.ObjectTypeName)
                    {
                        var waypointName = (string)mapObject.Properties["waypointName"].Value;
                        switch (waypointName)
                        {
                        case "InitialCameraPosition":
                            mapCache.InitialCameraPosition = mapObject.Position;
                            break;

                        case "Player_1_Start":
                            mapCache.Player1Start   = mapObject.Position;
                            startingPositionsFound |= 1 << 0;
                            break;

                        case "Player_2_Start":
                            mapCache.Player2Start   = mapObject.Position;
                            startingPositionsFound |= 1 << 1;
                            break;

                        case "Player_3_Start":
                            mapCache.Player3Start   = mapObject.Position;
                            startingPositionsFound |= 1 << 2;
                            break;

                        case "Player_4_Start":
                            mapCache.Player4Start   = mapObject.Position;
                            startingPositionsFound |= 1 << 3;
                            break;

                        case "Player_5_Start":
                            mapCache.Player5Start   = mapObject.Position;
                            startingPositionsFound |= 1 << 4;
                            break;

                        case "Player_6_Start":
                            mapCache.Player6Start   = mapObject.Position;
                            startingPositionsFound |= 1 << 5;
                            break;

                        case "Player_7_Start":
                            mapCache.Player7Start   = mapObject.Position;
                            startingPositionsFound |= 1 << 6;
                            break;

                        case "Player_8_Start":
                            mapCache.Player8Start   = mapObject.Position;
                            startingPositionsFound |= 1 << 7;
                            break;
                        }
                    }
                    else
                    {
                        // check "normal" objects
                        var definition = assetStore.ObjectDefinitions.GetByName(mapObject.TypeName);
                        if (definition?.KindOf?.Get(ObjectKinds.SupplySourceOnPreview) ?? false)
                        {
                            mapCache.SupplyPositions.Add(mapObject.Position);
                        }

                        if (definition?.KindOf?.Get(ObjectKinds.TechBuilding) ?? false)
                        {
                            mapCache.TechPositions.Add(mapObject.Position);
                        }
                    }
                }
            }

            // Only consecutive numbers are recognized, so if there are
            // starting positions 1, 2 and 4, the game treats it as a
            // 2 player map.
            // There is always at least one player though, even if there
            // are no starting positions (single player maps).
            mapCache.NumPlayers = 1;
            while ((startingPositionsFound & (1 << mapCache.NumPlayers)) > 0)
            {
                mapCache.NumPlayers++;
            }

            mapCache.IsMultiplayer = mapCache.NumPlayers > 1;

            // TODO
            // mapCache.DisplayName
            // mapCache.Description
            // mapCache.FileCrc
            // mapCache.IsScenarioMP
            // mapCache.PlayerPositions

            return(mapCache);
        }
示例#4
0
        private static void SetupSkirmishGameSides(
            Game game,
            MapFile mapFile,
            PlayerSetting[] playerSettings,
            GameType gameType,
            List <Player> mapPlayers,
            List <Team> mapTeams,
            List <ScriptList> mapScriptLists)
        {
            var originalMapPlayers = mapFile.SidesList.Players;

            // Neutral player.
            mapPlayers.Add(originalMapPlayers[0]);

            // Civilian player. It isn't necessarily the second player.
            // TODO: There might be more than one civilian player.
            mapPlayers.Add(originalMapPlayers.FirstOrDefault(x => (string)x.Properties["playerFaction"].Value == "FactionCivilian"));

            //var hasAIPlayer = false;
            for (var i = 0; i < playerSettings.Length; i++)
            {
                var playerSetting = playerSettings[i];

                var factionPlayer = originalMapPlayers.First(x => (string)x.Properties["playerFaction"].Value == playerSetting.SideName);

                var isHuman = playerSetting.Owner == PlayerOwner.Player;

                var playerName = isHuman
                    ? $"player{i}"
                    : $"{factionPlayer.Properties["playerName"].Value}{i}";

                //if (!isHuman)
                //{
                //    hasAIPlayer = true;
                //}

                var playerProperties = new AssetPropertyCollection();
                playerProperties.AddAsciiString("playerFaction", (string)factionPlayer.Properties["playerFaction"].Value);
                playerProperties.AddAsciiString("playerName", playerName);
                playerProperties.AddAsciiString("playerDisplayName", (string)factionPlayer.Properties["playerDisplayName"].Value);
                playerProperties.AddBoolean("playerIsHuman", isHuman);
                playerProperties.AddInteger("playerColor", playerSetting.Color.ToUInt32());

                // TODO: Other player properties.

                mapPlayers.Add(new Player
                {
                    Properties = playerProperties,
                    BuildList  = factionPlayer.BuildList,
                });
            }

            // Setup player relationships.
            var playerAllies  = new string[playerSettings.Length];
            var playerEnemies = new string[playerSettings.Length];

            for (var i = 0; i < playerSettings.Length; i++)
            {
                playerAllies[i]  = "";
                playerEnemies[i] = "";
            }
            for (var i = 0; i < playerSettings.Length; i++)
            {
                var outerPlayer = playerSettings[i];

                for (var j = i + 1; j < playerSettings.Length; j++)
                {
                    var innerPlayer = playerSettings[j];
                    if (outerPlayer.Team == innerPlayer.Team && outerPlayer.Team != 0)
                    {
                        playerAllies[i] += mapPlayers[j + 2].Properties["playerName"].Value + " ";
                        playerAllies[j] += mapPlayers[i + 2].Properties["playerName"].Value + " ";
                    }
                    else
                    {
                        playerEnemies[i] += mapPlayers[j + 2].Properties["playerName"].Value + " ";
                        playerEnemies[j] += mapPlayers[i + 2].Properties["playerName"].Value + " ";
                    }
                }
            }
            for (var i = 0; i < playerSettings.Length; i++)
            {
                mapPlayers[i + 2].Properties.AddAsciiString("playerAllies", playerAllies[i]);
                mapPlayers[i + 2].Properties.AddAsciiString("playerEnemies", playerEnemies[i]);
            }

            var originalMapScriptLists = mapFile.GetPlayerScriptsList().ScriptLists;

            var playerNames = mapPlayers
                              .Select(p => p.Properties.GetPropOrNull("playerName")?.Value.ToString())
                              .ToArray();

            while (mapScriptLists.Count < mapPlayers.Count)
            {
                mapScriptLists.Add(null);
            }

            // Copy neutral player scripts.
            var neutralPlayerName = (string)mapPlayers[0].Properties["playerName"].Value;

            CopyScripts(
                originalMapScriptLists,
                playerNames,
                neutralPlayerName,
                mapScriptLists,
                0,
                appendIndex: false);

            // Copy civilian player scripts.
            var civilianPlayerName = (string)mapPlayers[1].Properties["playerName"].Value;

            CopyScripts(
                originalMapScriptLists,
                playerNames,
                civilianPlayerName,
                mapScriptLists,
                1,
                appendIndex: false);

            switch (game.SageGame)
            {
            case SageGame.CncGenerals:
            case SageGame.CncGeneralsZeroHour:
                CreateTeamsFromScbFile(game, mapPlayers, mapTeams, mapScriptLists, playerSettings, neutralPlayerName, civilianPlayerName);
                break;

            case SageGame.Bfme:
            case SageGame.Bfme2:
            case SageGame.Bfme2Rotwk:
                mapTeams.AddRange(mapFile.GetTeams());
                break;
            }

            if (playerSettings.Length > 1)
            {
                var multiplayerScriptsEntry = game.ContentManager.GetScriptEntry(@"Data\Scripts\MultiplayerScripts.scb");

                if (multiplayerScriptsEntry != null)
                {
                    using var stream = multiplayerScriptsEntry.Open();
                    var multiplayerScripts = ScbFile.FromStream(stream);

                    // TODO: This is a bit hardcoded.
                    mapScriptLists[0] = multiplayerScripts.PlayerScripts.ScriptLists[0];
                }
            }
        }