Exemple #1
0
        /// <summary>
        /// Starts spring game
        /// </summary>
        /// <param name="client">tasclient to get current battle from</param>
        /// <param name="priority">spring process priority</param>
        /// <param name="affinity">spring process cpu affinity</param>
        /// <param name="scriptOverride">if set, overrides generated script with supplied one</param>
        /// <param name="userName">lobby user name - used to submit score</param>
        /// <param name="passwordHash">lobby password hash - used to submit score</param>
        /// <returns>generates script</returns>
        public string StartGame(TasClient client, ProcessPriorityClass?priority, int?affinity, string scriptOverride, bool useSafeMode = false, bool useMultithreaded = false)
        {
            if (!File.Exists(paths.Executable) && !File.Exists(paths.DedicatedServer))
            {
                throw new ApplicationException(string.Format("Spring or dedicated server executable not found: {0}, {1}", paths.Executable, paths.DedicatedServer));
            }

            this.client = client;
            wasKilled   = false;

            if (!IsRunning)
            {
                gameEndedOk   = false;
                IsBattleOver  = false;
                lobbyUserName = client.UserName;
                lobbyPassword = client.UserPassword;
                battleResult  = new BattleResult();

                talker              = new Talker();
                talker.SpringEvent += talker_SpringEvent;
                isHosting           = client != null && client.MyBattle != null && client.MyBattle.Founder.Name == client.MyUser.Name;

                if (isHosting)
                {
                    scriptPath = Utils.MakePath(paths.WritableDirectory, "script_" + client.MyBattle.Founder + ".txt").Replace('\\', '/');
                }
                else
                {
                    scriptPath = Utils.MakePath(paths.WritableDirectory, "script.txt").Replace('\\', '/');
                }

                statsPlayers.Clear();
                statsData.Clear();
                StartContext = null;

                string script;
                if (!string.IsNullOrEmpty(scriptOverride))
                {
                    battleResult.IsMission = true;
                    isHosting = false;
                    script    = scriptOverride;
                }
                else
                {
                    List <UserBattleStatus> players;
                    battleGuid = Guid.NewGuid();
                    var service = new SpringieService()
                    {
                        Proxy = null
                    };
                    SpringBattleStartSetup startSetup = null;
                    if (isHosting && GlobalConst.IsZkMod(client.MyBattle.ModName))
                    {
                        try {
                            StartContext = client.MyBattle.GetContext();
                            startSetup   = service.GetSpringBattleStartSetup(StartContext);
                            if (startSetup.BalanceTeamsResult != null)
                            {
                                StartContext.Players = startSetup.BalanceTeamsResult.Players;
                                StartContext.Bots    = startSetup.BalanceTeamsResult.Bots;
                            }
                            connectedPlayers.Clear();
                            foreach (var p in StartContext.Players)
                            {
                                p.IsIngame = true;
                            }
                        } catch (Exception ex) {
                            Trace.TraceError("Error getting start setup: {0}", ex);
                        }
                    }

                    script = client.MyBattle.GenerateScript(out players, client.MyUser, talker.LoopbackPort, battleGuid.ToString(), startSetup);
                    battleResult.IsMission     = client.MyBattle.IsMission;
                    battleResult.IsBots        = client.MyBattle.Bots.Any();
                    battleResult.Title         = client.MyBattle.Title;
                    battleResult.Mod           = client.MyBattle.ModName;
                    battleResult.Map           = client.MyBattle.MapName;
                    battleResult.EngineVersion = paths.SpringVersion;
                    talker.SetPlayers(players);
                    statsPlayers = players.ToDictionary(x => x.Name,
                                                        x => new BattlePlayerResult
                    {
                        LobbyID       = x.LobbyUser.LobbyID,
                        AllyNumber    = x.AllyNumber,
                        CommanderType = null,
                        // todo commandertype
                        IsSpectator   = x.IsSpectator,
                        IsVictoryTeam = false,
                        Rank          = x.LobbyUser.Rank,
                    });
                }
                if (isHosting)
                {
                    timer.Start();
                }

                File.WriteAllText(scriptPath, script);

                LogLines = new StringBuilder();

                var optirun = Environment.GetEnvironmentVariable("OPTIRUN");

                process = new Process();
                process.StartInfo.CreateNoWindow = true;
                List <string> arg = new List <string>();


                if (string.IsNullOrEmpty(optirun))
                {
                    if (UseDedicatedServer)
                    {
                        process.StartInfo.FileName         = paths.DedicatedServer;
                        process.StartInfo.WorkingDirectory = Path.GetDirectoryName(paths.DedicatedServer);
                    }
                    else
                    {
                        process.StartInfo.FileName         = useMultithreaded ? paths.MtExecutable : paths.Executable;
                        process.StartInfo.WorkingDirectory = Path.GetDirectoryName(paths.Executable);
                    }
                }
                else
                {
                    Trace.TraceInformation("Using optirun {0} to start the game (OPTIRUN env var defined)", optirun);
                    process.StartInfo.FileName = optirun;
                    arg.Add(string.Format("\"{0}\"", (useMultithreaded ? paths.MtExecutable : paths.Executable)));
                }



                arg.Add(string.Format("--config \"{0}\"", paths.GetSpringConfigPath()));
                process.StartInfo.EnvironmentVariables["OMP_WAIT_POLICY"] = "ACTIVE";

                if (useSafeMode)
                {
                    arg.Add("--safemode");
                }
                arg.Add(string.Format("\"{0}\"", scriptPath));
                //Trace.TraceInformation("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments);

                process.StartInfo.Arguments              = string.Join(" ", arg);
                process.StartInfo.UseShellExecute        = false;
                process.StartInfo.RedirectStandardOutput = true;
                process.StartInfo.RedirectStandardError  = true;
                process.Exited             += springProcess_Exited;
                process.ErrorDataReceived  += process_ErrorDataReceived;
                process.OutputDataReceived += process_OutputDataReceived;
                process.EnableRaisingEvents = true;

                gamePrivateMessages    = new Dictionary <string, int>();
                battleResult.StartTime = DateTime.UtcNow;
                process.Start();
                process.BeginOutputReadLine();
                process.BeginErrorReadLine();
                if (IsRunning && SpringStarted != null)
                {
                    SpringStarted(this, EventArgs.Empty);
                }

                Utils.StartAsync(() =>
                {
                    Thread.Sleep(1000);
                    try {
                        if (priority != null)
                        {
                            process.PriorityClass = priority.Value;
                        }
                        if (affinity != null)
                        {
                            process.ProcessorAffinity = (IntPtr)affinity.Value;
                        }
                    } catch (Exception ex) {
                        Trace.TraceWarning("Error setting spring process affinity: {0}", ex);
                    }
                });

                return(script);
            }
            else
            {
                Trace.TraceError("Spring already running");
            }
            return(null);
        }
Exemple #2
0
        public static void ScriptAddUser(StringBuilder script, int userNum, List <UserBattleStatus> playersExport, SpringBattleStartSetup startSetup, int teamNum, UserBattleStatus status)
        {
            var export = status.Clone();

            export.TeamNumber = teamNum;
            playersExport.Add(status);

            // PLAYERS
            script.AppendFormat("  [PLAYER{0}]\n", userNum);
            script.AppendLine("  {");
            script.AppendFormat("     Name={0};\n", status.Name);

            script.AppendFormat("     Spectator={0};\n", status.IsSpectator ? 1 : 0);
            if (!status.IsSpectator)
            {
                script.AppendFormat("     Team={0};\n", teamNum);
            }

            if (status.LobbyUser != null)
            {
                script.AppendFormat("     Rank={0};\n", status.LobbyUser.Rank);
                script.AppendFormat("     CountryCode={0};\n", status.LobbyUser.Country);
                script.AppendFormat("     LobbyID={0};\n", status.LobbyUser.LobbyID);
                script.AppendFormat("     LobbyRank={0};\n", status.LobbyUser.Rank);
            }
            if (status.ScriptPassword != null)
            {
                script.AppendFormat("     Password={0};\n", status.ScriptPassword);
            }

            if (startSetup != null)
            {
                var entry = startSetup.UserParameters.FirstOrDefault(x => x.LobbyID == status.LobbyUser.LobbyID);
                if (entry != null)
                {
                    foreach (var kvp in entry.Parameters)
                    {
                        script.AppendFormat("     {0}={1};\n", kvp.Key, kvp.Value);
                    }
                }
            }
            script.AppendLine("  }");
        }
Exemple #3
0
        void GeneratePlayerSection(List <UserBattleStatus> playersExport,
                                   User localUser,
                                   SpringBattleStartSetup startSetup,
                                   List <UserBattleStatus> users,
                                   StringBuilder script,
                                   List <StartPos> positions,
                                   List <BotBattleStatus> bots)
        {
            if (mod != null && mod.IsMission) // mission stuff
            {
                var aiNum         = 0;
                var declaredTeams = new HashSet <int>();
                var orderedUsers  = users.OrderBy(x => x.TeamNumber).ToList();
                for (var i = 0; i < orderedUsers.Count; i++)
                {
                    var u = orderedUsers[i];
                    ScriptAddUser(script, i, playersExport, startSetup, u.TeamNumber, u);
                    if (!u.IsSpectator && !declaredTeams.Contains(u.TeamNumber))
                    {
                        ScriptAddTeam(script, u.TeamNumber, positions, i, u, mod, Details);
                        declaredTeams.Add(u.TeamNumber);
                    }
                }

                for (var i = 0; i < orderedUsers.Count; i++)
                {
                    var u = orderedUsers[i];
                    foreach (var b in bots.Where(x => x.owner == u.Name))
                    {
                        ScriptAddBot(script, aiNum++, b.TeamNumber, i, b);
                        if (!declaredTeams.Contains(b.TeamNumber))
                        {
                            ScriptAddTeam(script, b.TeamNumber, positions, i, b, mod, Details);
                            declaredTeams.Add(b.TeamNumber);
                        }
                    }
                }
            }
            else
            {
                // ordinary battle stuff

                var userNum = 0;
                var teamNum = 0;
                var aiNum   = 0;
                //players is excluding self (so "springie doesn't appear as spec ingame") & excluding bots (bots is added later for each owner)
                foreach (var u in users.Where(u => !bots.Any(b => b.Name == u.Name)).OrderBy(x => x.TeamNumber).Where(x => x.Name != localUser.Name))
                {
                    ScriptAddUser(script, userNum, playersExport, startSetup, teamNum, u);

                    if (!u.IsSpectator)
                    {
                        ScriptAddTeam(script, teamNum, positions, userNum, u, mod, Details);
                        teamNum++;
                    }

                    foreach (var b in bots.Where(x => x.owner == u.Name))
                    {
                        ScriptAddBot(script, aiNum, teamNum, userNum, b);
                        aiNum++;
                        ScriptAddTeam(script, teamNum, positions, userNum, b, mod, Details);
                        teamNum++;
                    }
                    userNum++;
                }
            }

            // ALLIANCES
            script.AppendLine();
            foreach (var allyNumber in
                     users.Where(x => !x.IsSpectator).Select(x => x.AllyNumber).Union(bots.Select(x => x.AllyNumber)).Union(Rectangles.Keys).Distinct())
            {
                // get allies from each player, bot and rectangles (for koth)
                script.AppendFormat("[ALLYTEAM{0}]\n", allyNumber);
                script.AppendLine("{");
                script.AppendFormat("     NumAllies={0};\n", 0);
                double     left = 0, top = 0, right = 1, bottom = 1;
                BattleRect rect;
                if (Rectangles.TryGetValue(allyNumber, out rect))
                {
                    rect.ToFractions(out left, out top, out right, out bottom);
                }
                script.AppendFormat(CultureInfo.InvariantCulture, "     StartRectLeft={0};\n", left);
                script.AppendFormat(CultureInfo.InvariantCulture, "     StartRectTop={0};\n", top);
                script.AppendFormat(CultureInfo.InvariantCulture, "     StartRectRight={0};\n", right);
                script.AppendFormat(CultureInfo.InvariantCulture, "     StartRectBottom={0};\n", bottom);
                script.AppendLine("}");
            }

            script.AppendLine();
            script.AppendFormat("  NumRestrictions={0};\n", DisabledUnits.Count);
            script.AppendLine();

            if (!mod.IsMission)
            {
                script.AppendLine("  [RESTRICT]");
                script.AppendLine("  {");
                for (var i = 0; i < DisabledUnits.Count; ++i)
                {
                    script.AppendFormat("    Unit{0}={1};\n", i, DisabledUnits[i]);
                    script.AppendFormat("    Limit{0}=0;\n", i);
                }
                script.AppendLine("  }");

                script.AppendLine("  [MODOPTIONS]");
                script.AppendLine("  {");

                var options = new Dictionary <string, string>();

                // put standard modoptions to options dictionary
                foreach (var o in mod.Options.Where(x => x.Type != OptionType.Section))
                {
                    var v = o.Default;
                    if (ModOptions.ContainsKey(o.Key))
                    {
                        v = ModOptions[o.Key];
                    }
                    options[o.Key] = v;
                }

                // replace/add custom modoptions from startsetup (if they exist)
                if (startSetup != null && startSetup.ModOptions != null)
                {
                    foreach (var entry in startSetup.ModOptions)
                    {
                        options[entry.Key] = entry.Value;
                    }
                }

                // write final options to script
                foreach (var kvp in options)
                {
                    script.AppendFormat("    {0}={1};\n", kvp.Key, kvp.Value);
                }

                script.AppendLine("  }");
            }

            script.AppendLine("}");
        }
Exemple #4
0
        /// <summary>
        /// Generates script
        /// </summary>
        /// <param name="playersExport">list of players</param>
        /// <param name="localUser">myself</param>
        /// <param name="loopbackListenPort">listen port for autohost interface</param>
        /// <param name="zkSearchTag">hackish search tag</param>
        /// <param name="startSetup">structure with custom extra data</param>
        /// <returns></returns>
        public string GenerateScript(out List <UserBattleStatus> playersExport,
                                     User localUser,
                                     int loopbackListenPort,
                                     string zkSearchTag,
                                     SpringBattleStartSetup startSetup)
        {
            var previousCulture = Thread.CurrentThread.CurrentCulture;

            try
            {
                Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;

                playersExport = new List <UserBattleStatus>();
                var isHost = localUser.Name == Founder.Name;
                var myUbs  = Users.SingleOrDefault(x => x.Name == localUser.Name);
                if (!isHost)
                {
                    var sb = new StringBuilder();
                    sb.AppendLine("[GAME]");
                    sb.AppendLine("{");
                    sb.AppendFormat("HostIP={0};\n", Ip);
                    sb.AppendFormat("HostPort={0};\n", HostPort);
                    sb.AppendLine("IsHost=0;");
                    sb.AppendFormat("MyPlayerName={0};\n", localUser.Name);
                    if (myUbs != null)
                    {
                        if (myUbs.ScriptPassword != null)
                        {
                            sb.AppendFormat("MyPasswd={0};\n", myUbs.ScriptPassword);
                        }
                    }
                    else
                    {
                        sb.AppendFormat("MyPasswd={0};\n", localUser.Name); // used for mid-game join .. if no userbattlestatus, use own name
                    }
                    sb.AppendLine("}");
                    return(sb.ToString());
                }
                else
                {
                    if (mod == null)
                    {
                        throw new ApplicationException("Mod not downloaded yet");
                    }

                    var script = new StringBuilder();

                    script.AppendLine("[GAME]");
                    script.AppendLine("{");

                    script.AppendFormat("   ZkSearchTag={0};\n", zkSearchTag);
                    script.AppendFormat("  Mapname={0};\n", MapName);

                    if (mod.IsMission)
                    {
                        script.AppendFormat("  StartPosType=3;\n");
                    }
                    else
                    {
                        if (Details.StartPos == BattleStartPos.Choose)
                        {
                            script.AppendFormat("  StartPosType=2;\n");
                        }
                        else
                        {
                            script.AppendFormat("  StartPosType=3;\n");  // workaround for random/fixed
                        }
                        // script.AppendFormat("  StartPosType={0};\n", (int)Details.StartPos);
                    }

                    script.AppendFormat("  GameType={0};\n", ModName);
                    if (ModHash.HasValue)
                    {
                        script.AppendFormat("  ModHash={0};\n", ModHash.Value != 0 ? (uint)ModHash.Value : 1);
                    }
                    // hack dont set to 1 when dedi srever is patched
                    if (MapHash.HasValue)
                    {
                        script.AppendFormat("  MapHash={0};\n", MapHash.Value != 0 ? (uint)MapHash.Value : 1);
                    }
                    script.AppendFormat("  AutohostPort={0};\n", loopbackListenPort);
                    script.AppendLine();
                    script.AppendFormat("  HostIP={0};\n", Ip);
                    script.AppendFormat("  HostPort={0};\n", HostPort);
                    script.AppendFormat("  SourcePort={0};\n", 8300);
                    script.AppendFormat("  IsHost=1;\n");
                    script.AppendLine();

                    //script.AppendFormat("  MyPlayerName={0};\n", localUser.Name);

                    var positions = map.Positions != null?map.Positions.ToList() : new List <StartPos>();

                    if (Details.StartPos == BattleStartPos.Random)
                    {
                        positions = positions.Shuffle();
                    }

                    List <UserBattleStatus> users;
                    List <BotBattleStatus>  bots;

                    if (startSetup != null && startSetup.BalanceTeamsResult != null && startSetup.BalanceTeamsResult.Players != null)
                    {
                        // if there is a balance results as a part of start setup, use values from this (override lobby state)
                        users = new List <UserBattleStatus>(this.Users.Select(x => x.Clone()));
                        bots  = new List <BotBattleStatus>(this.Bots.Select(x => (BotBattleStatus)x.Clone()));
                        foreach (var p in startSetup.BalanceTeamsResult.Players)
                        {
                            var us = users.FirstOrDefault(x => x.Name == p.Name);
                            if (us == null)
                            {
                                us = new UserBattleStatus(p.Name, new User()
                                {
                                    LobbyID = p.LobbyID
                                }, Password);
                                users.Add(us);
                            }
                            us.TeamNumber  = p.TeamID;
                            us.IsSpectator = p.IsSpectator;
                            us.AllyNumber  = p.AllyID;
                        }
                        foreach (var p in startSetup.BalanceTeamsResult.Bots)
                        {
                            var bot = bots.FirstOrDefault(x => x.Name == p.BotName);
                            if (bot == null)
                            {
                                bot = new BotBattleStatus(p.BotName, p.Owner, p.BotAI);
                                bots.Add(bot);
                            }
                            bot.AllyNumber = bot.AllyNumber;
                            bot.TeamNumber = bot.TeamNumber;
                        }

                        foreach (var u in users.Where(x => !startSetup.BalanceTeamsResult.Players.Any(y => y.Name == x.Name)))
                        {
                            u.IsSpectator = true;
                        } // spec those not known at the time of balance
                    }
                    else
                    {
                        users = this.Users;
                        bots  = this.Bots;
                    }


                    GeneratePlayerSection(playersExport, localUser, startSetup, users, script, positions, bots);

                    return(script.ToString());
                }
            }
            finally
            {
                Thread.CurrentThread.CurrentCulture = previousCulture;
            }
        }
Exemple #5
0
        public static void GeneratePlayerSection(List <UserBattleStatus> playersExport,
                                                 List <UserBattleStatus> users,
                                                 StringBuilder script,
                                                 List <BotBattleStatus> bots,
                                                 IDictionary <int, BattleRect> _rectangles,
                                                 Dictionary <string, string> _modOptions,
                                                 User localUser = null,
                                                 SpringBattleStartSetup startSetup = null
                                                 )
        {
            // ordinary battle stuff

            var userNum = 0;
            var teamNum = 0;
            var aiNum   = 0;

            //players is excluding self (so "springie doesn't appear as spec ingame") & excluding bots (bots is added later for each owner)
            var non_botUsers = users.Where(u => !bots.Any(b => b.Name == u.Name)); //.OrderBy(x => x.TeamNumber);

            if (localUser != null)                                                 //I am a server
            {
                non_botUsers = non_botUsers.Where(x => x.Name != localUser.Name);
            }

            foreach (var u in non_botUsers.OrderBy(x => x.TeamNumber))
            {
                ScriptAddUser(script, userNum, playersExport, startSetup, teamNum, u);

                if (!u.IsSpectator)
                {
                    ScriptAddTeam(script, teamNum, userNum, u);
                    teamNum++;
                }

                foreach (var b in bots.Where(x => x.owner == u.Name))
                {
                    ScriptAddBot(script, aiNum, teamNum, userNum, b);
                    aiNum++;
                    ScriptAddTeam(script, teamNum, userNum, b);
                    teamNum++;
                }
                userNum++;
            }

            // ALLIANCES
            script.AppendLine();
            foreach (var allyNumber in
                     users.Where(x => !x.IsSpectator).Select(x => x.AllyNumber).Union(bots.Select(x => x.AllyNumber)).Union(_rectangles.Keys).Distinct())
            {
                // get allies from each player, bot and rectangles (for koth)
                script.AppendFormat("[ALLYTEAM{0}]\n", allyNumber);
                script.AppendLine("{");
                script.AppendFormat("     NumAllies={0};\n", 0);
                double     left = 0, top = 0, right = 1, bottom = 1;
                BattleRect rect;
                if (_rectangles.TryGetValue(allyNumber, out rect))
                {
                    rect.ToFractions(out left, out top, out right, out bottom);
                }
                script.AppendFormat(CultureInfo.InvariantCulture, "     StartRectLeft={0};\n", left);
                script.AppendFormat(CultureInfo.InvariantCulture, "     StartRectTop={0};\n", top);
                script.AppendFormat(CultureInfo.InvariantCulture, "     StartRectRight={0};\n", right);
                script.AppendFormat(CultureInfo.InvariantCulture, "     StartRectBottom={0};\n", bottom);
                script.AppendLine("}");
            }

            script.AppendLine();

            script.AppendLine("  [MODOPTIONS]");
            script.AppendLine("  {");

            var options = new Dictionary <string, string>(_modOptions);

            // replace/add custom modoptions from startsetup (if they exist)
            if (startSetup != null && startSetup.ModOptions != null)
            {
                foreach (var entry in startSetup.ModOptions)
                {
                    options[entry.Key] = entry.Value;
                }
            }

            // write final options to script
            foreach (var kvp in options)
            {
                script.AppendFormat("    {0}={1};\n", kvp.Key, kvp.Value);
            }

            script.AppendLine("  }");


            script.AppendLine("}");
        }
Exemple #6
0
        /// <summary>
        /// Generates script
        /// </summary>
        /// <param name="playersExport">list of players</param>
        /// <param name="localUser">myself</param>
        /// <param name="loopbackListenPort">listen port for autohost interface</param>
        /// <param name="zkSearchTag">hackish search tag</param>
        /// <param name="startSetup">structure with custom extra data</param>
        /// <returns></returns>
        public string GenerateScript(out List <UserBattleStatus> playersExport,
                                     User localUser,
                                     int loopbackListenPort,
                                     string zkSearchTag,
                                     SpringBattleStartSetup startSetup)
        {
            var previousCulture = Thread.CurrentThread.CurrentCulture;

            try
            {
                Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;

                playersExport = new List <UserBattleStatus>();
                var isHost = localUser.Name == Founder.Name;

                var myUbs = Users[localUser.Name];
                if (!isHost)
                {
                    var sb = new StringBuilder();
                    sb.AppendLine("[GAME]");
                    sb.AppendLine("{");
                    sb.AppendFormat("HostIP={0};\n", Ip);
                    sb.AppendFormat("HostPort={0};\n", HostPort);
                    sb.AppendLine("IsHost=0;");
                    sb.AppendFormat("MyPlayerName={0};\n", localUser.Name);
                    if (myUbs != null)
                    {
                        if (myUbs.ScriptPassword != null)
                        {
                            sb.AppendFormat("MyPasswd={0};\n", myUbs.ScriptPassword);
                        }
                    }
                    else
                    {
                        sb.AppendFormat("MyPasswd={0};\n", localUser.Name); // used for mid-game join .. if no userbattlestatus, use own name
                    }
                    sb.AppendLine("}");
                    return(sb.ToString());
                }
                else
                {
                    var script = new StringBuilder();

                    script.AppendLine("[GAME]");
                    script.AppendLine("{");

                    script.AppendFormat("   ZkSearchTag={0};\n", zkSearchTag);
                    script.AppendFormat("  Mapname={0};\n", MapName);

                    script.AppendFormat("  StartPosType=2;\n");

                    script.AppendFormat("  GameType={0};\n", ModName);
                    script.AppendFormat("  ModHash=1;\n");
                    script.AppendFormat("  MapHash=1;\n");

                    script.AppendFormat("  AutohostPort={0};\n", loopbackListenPort);
                    script.AppendLine();
                    script.AppendFormat("  HostIP={0};\n", Ip);
                    script.AppendFormat("  HostPort={0};\n", HostPort);
                    script.AppendFormat("  SourcePort={0};\n", 8300);
                    script.AppendFormat("  IsHost=1;\n");
                    script.AppendLine();

                    //script.AppendFormat("  MyPlayerName={0};\n", localUser.Name);

                    List <UserBattleStatus> users;
                    List <BotBattleStatus>  bots;

                    if (startSetup != null && startSetup.BalanceTeamsResult != null && startSetup.BalanceTeamsResult.Players != null)
                    {
                        // if there is a balance results as a part of start setup, use values from this (override lobby state)
                        users = Users.Values.ToList();
                        bots  = new List <BotBattleStatus>(this.Bots.Values.Select(x => (BotBattleStatus)x.Clone()));
                        foreach (var p in startSetup.BalanceTeamsResult.Players)
                        {
                            var us = users.FirstOrDefault(x => x.Name == p.Name);
                            if (us == null)
                            {
                                us = new UserBattleStatus(p.Name, new User()
                                {
                                    AccountID = p.LobbyID
                                }, Password);                                                                      // TODO this "password" use does not look right
                                users.Add(us);
                            }
                            us.TeamNumber  = p.TeamID;
                            us.IsSpectator = p.IsSpectator;
                            us.AllyNumber  = p.AllyID;
                        }
                        foreach (var p in startSetup.BalanceTeamsResult.Bots)
                        {
                            var bot = bots.FirstOrDefault(x => x.Name == p.BotName);
                            if (bot == null)
                            {
                                bot = new BotBattleStatus(p.BotName, p.Owner, p.BotAI);
                                bots.Add(bot);
                            }
                            bot.AllyNumber = bot.AllyNumber;
                            bot.TeamNumber = bot.TeamNumber;
                        }

                        foreach (var u in users.Where(x => !startSetup.BalanceTeamsResult.Players.Any(y => y.Name == x.Name)))
                        {
                            u.IsSpectator = true;
                        } // spec those not known at the time of balance
                    }
                    else
                    {
                        users = this.Users.Values.ToList();
                        bots  = this.Bots.Values.ToList();
                    }


                    GeneratePlayerSection(playersExport, users, script, bots, Rectangles, ModOptions, localUser, startSetup);

                    return(script.ToString());
                }
            }
            finally
            {
                Thread.CurrentThread.CurrentCulture = previousCulture;
            }
        }