public static string GetModOptionSummary(Mod mod, Dictionary<string, string> setOptions, bool useSectionHeaders)
		{
			try
			{
				var sectionNames = mod.Options.Where(o => o.Type == OptionType.Section).ToDictionary(o => o.Key.ToUpper(), o => o.Name);

				var sections = from option in mod.Options
				               join pair in setOptions on option.Key equals pair.Key
				               where pair.Value != option.Default
				               group new { pair, option } by option.Section;

				var optionBuilder = new StringBuilder();
				foreach (var section in sections)
				{
					var indent = false;
					if (useSectionHeaders && !String.IsNullOrEmpty(section.Key))
					{
						indent = true;
						optionBuilder.AppendLine(sectionNames[section.Key.ToUpper()]);
						optionBuilder.AppendLine();
					}
					foreach (var o in section)
					{
						string line = null;
						switch (o.option.Type)
						{
							case OptionType.Bool:
								line = o.option.Name + ": " + (o.pair.Value == "0" ? "No" : "Yes");
								break;
							case OptionType.Number:
								line = o.option.Name + ": " + o.pair.Value;
								break;
							case OptionType.String:
								line = o.option.Name + ": " + o.pair.Value;
								break;
							case OptionType.List:
								var valueName = o.option.ListOptions.Single(opt => opt.Key == o.pair.Value).Name;
								line = o.option.Name + ": " + valueName;
								break;
						}
						optionBuilder.AppendLine((indent ? "\t" : String.Empty) + line);
					}
					if (useSectionHeaders) optionBuilder.AppendLine();
				}

				return optionBuilder.ToString();
			}
			catch (Exception e)
			{
				Trace.WriteLine("Error in building mod option summary: " + e);
				return String.Empty;
			}
		}
		public ModStore()
		{
			Program.TasClient.ModOptionsChanged += (s, e) => SetModOptions(e.ModOptions);
			Program.TasClient.BattleJoinSuccess += (s, e) =>
				{
					if (mod != null && mod.Name != Program.TasClient.MyBattle.ModName)
					{
						Ais = null;
						mod = null;
					}
					Program.MetaData.GetModAsync(Program.TasClient.MyBattle.ModName, HandleMod, exception => { });
				};
		}
 public ModOptionsControl(Mod forOffline = null, Dictionary<string,string> currentOption = null)
 {
   if (forOffline != null)
   {
       offlineMode = true;
       mod = forOffline;
       offlineOptions = currentOption;
       if (currentOption == null)
           offlineOptions = new Dictionary<string, string>();
   }
   InitializeComponent();
   changesBox = new TextBox { Multiline = true, ReadOnly = true, BackColor = Color.White, Dock = DockStyle.Fill };
   var changesTab = new TabPage { Text = "Changes" };
   changesTab.Controls.Add(changesBox);
   tabControl.TabPages.Add(changesTab);
   tooltip.UseFading = false;
   tooltip.UseAnimation = false;
   tooltip.InitialDelay = 0;
   tooltip.ReshowDelay = 0;
   tooltip.AutoPopDelay = 10000;
   tooltip.BackColor = Color.FromArgb(255, 255, 225); // its ignored by it
 }
        public void UpdateMission(ZkDataContext db, Mission mission, Mod modInfo) {
            var file = mission.Mutator.ToArray();
            var tempName = Path.GetTempFileName() + ".zip";
            File.WriteAllBytes(tempName, file);

            

            using (var zf = ZipFile.Open(tempName, ZipArchiveMode.Update))
            {
                var modinfoEntry = zf.GetEntry("modinfo.lua");
                modinfoEntry.Delete();
                modinfoEntry = zf.CreateEntry("modinfo.lua");
                WriteZipArchiveEntry(modinfoEntry, GetModInfo(mission.NameWithVersion, mission.ModRapidTag, mission.Name, "ZK"));
                FixScript(mission, zf, "script.txt");
                var script = FixScript(mission, zf, GlobalConst.MissionScriptFileName);
                modInfo.MissionScript = script;
                //modInfo.ShortName = mission.Name;
                modInfo.Name = mission.NameWithVersion;
            }
            mission.Mutator = File.ReadAllBytes(tempName);
            if (string.IsNullOrEmpty(mission.Script)) mission.Script = " "; // tweak for silly update validation
            mission.Script = Regex.Replace(mission.Script, "GameType=([^;]+);", (m) => $"GameType={mission.NameWithVersion};");
            
            File.Delete(tempName);
            
            var resource = db.Resources.FirstOrDefault(x => x.MissionID == mission.MissionID); 
            if (resource == null)
            {
                resource = new Resource() { DownloadCount = 0, TypeID = ZkData.ResourceType.Mod };
                db.Resources.Add(resource);
            }
            resource.InternalName = mission.NameWithVersion;
            resource.MissionID = mission.MissionID;

            resource.ResourceDependencies.Clear();
            resource.ResourceDependencies.Add(new ResourceDependency() { NeedsInternalName = mission.Map });
            resource.ResourceDependencies.Add(new ResourceDependency() { NeedsInternalName = mission.Mod });
            resource.ResourceContentFiles.Clear();
            

            // generate torrent
            var tempFile = Path.Combine(Path.GetTempPath(), mission.SanitizedFileName);
            File.WriteAllBytes(tempFile, mission.Mutator.ToArray());
            var creator = new TorrentCreator();
            creator.Path = tempFile;
            var torrentStream = new MemoryStream();
            creator.Create(torrentStream);
            try
            {
                File.Delete(tempFile);
            }
            catch { }

            var md5 = Hash.HashBytes(mission.Mutator.ToArray()).ToString();
            resource.ResourceContentFiles.Add(new ResourceContentFile()
            {
                FileName = mission.SanitizedFileName,
                Length = mission.Mutator.Length,
                LinkCount = 1,
                Links = string.Format(MissionFileUrl, mission.MissionID),
                Md5 = md5
            });


            var basePath = GlobalConst.SiteDiskPath + @"\resources\";
            if (!Directory.Exists(basePath)) Directory.CreateDirectory(basePath);
            File.WriteAllBytes(string.Format(@"{2}\{0}_{1}.torrent", resource.InternalName.EscapePath(), md5, basePath), torrentStream.ToArray());
            
            File.WriteAllBytes(string.Format(@"{1}\{0}.metadata.xml.gz", resource.InternalName.EscapePath(), basePath),
                                   MetaDataCache.SerializeAndCompressMetaData(modInfo));
            
            var imgPath = GlobalConst.SiteDiskPath + @"\img\missions\";
            if (!Directory.Exists(imgPath)) Directory.CreateDirectory(imgPath);
            
            File.WriteAllBytes(string.Format(imgPath + "{0}.png", mission.MissionID, basePath), mission.Image.ToArray());
        }
        public static List<Mod> GetPartialSddMods()
        {
            var sddMods = new List<Mod>();
            var modFolder = Utils.MakePath(Program.SpringPaths.DataDirectories.First(), "games");
            var sddFolder = System.IO.Directory.EnumerateDirectories(modFolder, "*.sdd"); //.ToList<string>();
            foreach (string path in sddFolder)
            {
                var modinfo = Utils.MakePath(path,"modinfo.lua");
                if (File.Exists(modinfo))
                {
                    var mod = new Mod();
                
                    mod.ArchiveName = GetFolderOrFileName(path);
                    
                    CrudeLUAReader.ParseModInfo(modinfo,ref mod);

                    sddMods.Add(mod);
                }
            }
            return sddMods;
        }
        public Mod GetMod(ResourceInfo ae)
        {
            if (disposed) throw new ObjectDisposedException("Unitsync has already been released.");
            NativeMethods.RemoveAllArchives();
            NativeMethods.GetPrimaryModCount(); // pre-requisite for the following calls
            NativeMethods.AddAllArchives(ae.Name);
            string[] sides;

            var mod = new Mod(ae)
            {
                UnitDefs = GetUnitList().Select(ui => new UnitInfo(ui.Name, ui.FullName)).ToArray(),
                StartUnits = new SerializableDictionary<string, string>(GetStartUnits(out sides)),
                Sides = sides,
                Options = GetModOptions().ToArray(),
                SideIcons = GetSideIcons(sides).ToArray(),
                ModAis = GetAis().Where(ai => ai.IsLuaAi).ToArray()
            };

            Trace.TraceInformation("Mod Information: Description {0}, Game {1}, Mutator {2}, ShortGame {3}, PrimaryModVersion {4}",
                mod.Description,
                mod.Game,
                mod.Mutator,
                mod.ShortGame,
                mod.PrimaryModVersion);

            var buf = ReadVfsFile(GlobalConst.MissionScriptFileName);
            if ((buf != null) && (buf.Length > 0)) mod.MissionScript = Encoding.UTF8.GetString(buf, 0, buf.Length);

            if (!string.IsNullOrEmpty(mod.MissionScript))
                try
                {
                    buf = ReadVfsFile(GlobalConst.MissionSlotsFileName);
                    var slotString = Encoding.UTF8.GetString(buf, 0, buf.Length);
                    var ser = new XmlSerializer(typeof(List<MissionSlot>));
                    mod.MissionSlots = (List<MissionSlot>)ser.Deserialize(new StringReader(slotString));
                }
                catch (Exception ex)
                {
                    Trace.TraceError("Error reading mission slots from mod {0}: {1}", mod.Name, ex);
                }

            if (mod.Sides.Length == 0) Trace.WriteLine("Mod has no faction");
            if (mod.UnitDefs.Length == 0) Trace.WriteLine("No unit found.");

            NativeMethods.RemoveAllArchives();
            TraceErrors();
            return mod;
        }
        private void Setup_MissionModInfo(Mod mod)
        {
            myItem.MissionSlot = null;
            if (missionSlots.Count == 0) missionSlots = null;
            if (missionSlots != null)
            {
                foreach (MissionSlot slot in missionSlots.Where(s => s.IsHuman))
                {
                    myItem.MissionSlot = slot;
                    Set_MyBattleStatus(slot.AllyID, slot.TeamID, false);
                    break;
                }

                botsMissionSlot.Clear();
                Bots.Clear(); 
                foreach (var slot in missionSlots.Where(s => s.AiShortName != null))
                {
                    botsMissionSlot.Add(slot);
                    Set_BotBattleStatus(slot.AiShortName, myItem.UserName, slot.TeamID, slot.AllyID, (int)(MyCol)slot.Color,slot.AiVersion);
                }
            }
            else
            {
                if (botsMissionSlot.Count > 0)
                {
                    Bots.Clear();
                    botsMissionSlot.Clear();
                }
            }
            if (currentMod.IsMission)
            {
                //disable some button for mission mod. playerBox shortcut is disabled in Event_PlayerBox_MouseDown()
                spectateCheckBox.Enabled = false;
                addAIButton.Enabled = false;
                editTeamButton.Enabled = false;

                //get targeted map for mission mod
                string mapname;
                var script = mod.MissionScript;
                if (mod.MissionMap != null)
                    mapname = mod.MissionMap;
                else
                {
                    var open = script.IndexOf("mapname", 7, script.Length - 8, StringComparison.InvariantCultureIgnoreCase) + 8;
                    var close = script.IndexOf(';', open);
                    mapname = script.Substring(open, close - open);
                    mapname = mapname.Trim(new char[3]{' ','=','\t'});
                }
                suppressEvent_SelectedIndexChanged = true;
                map_comboBox.SelectedItem = mapname;
                suppressEvent_SelectedIndexChanged = false;
                int selectedView = normalRadioButton.Checked ? 0 : (elevationRadioButton.Checked ? 1 : 2);
                Set_MapImages(mapname, selectedView);

                //get customized modoptions
                {
                    var open = script.IndexOf("[MODOPTIONS]", 7, script.Length - 8, StringComparison.InvariantCultureIgnoreCase) + 12;
                    open = script.IndexOf("{", open) + 1;
                    var close = script.IndexOf("}", open);
                    var options = script.Substring(open, close - open);
                    options = options.Trim();
                    string[] optionList = options.Split(new char[1]{';'}, StringSplitOptions.RemoveEmptyEntries);
                    string[] keypair;
                    for (int i = 0; i < optionList.Length; i++)
                    {
                        optionList[i] = optionList[i].Trim();
                        keypair = optionList[i].Split(new char[1] { '=' });
                        if (keypair[1] != null)
                            ModOptions.Add(keypair[0], keypair[1]);
                    }
                }
            }
            else
            {
                spectateCheckBox.Enabled = true;
                addAIButton.Enabled = true;
                editTeamButton.Enabled = true;
            }
            Refresh_PlayerBox();//update playerbox (in case there's mission slot, or when there was mission slot but no longer, or to update some related icons)
        }
        public static void ScriptAddTeam(StringBuilder script, int teamNum, List<StartPos> positions, int userNum, UserBattleStatus status, Mod mod, BattleDetails Details)
        {
            // BOT TEAM
            script.AppendFormat("  [TEAM{0}]\n", teamNum);
            script.AppendLine("  {");
            script.AppendFormat("     TeamLeader={0};\n", userNum);
            script.AppendFormat("     AllyTeam={0};\n", status.AllyNumber);
            script.AppendFormat(CultureInfo.InvariantCulture,"     RGBColor={0:F5} {1:F5} {2:F5};\n",
                                (status.TeamColor & 255)/255.0,
                                ((status.TeamColor >> 8) & 255)/255.0,
                                ((status.TeamColor >> 16) & 255)/255.0);
            var side = "mission";
            if (mod.Sides.Length > status.Side) side = mod.Sides[status.Side];
            script.AppendFormat("     Side={0};\n", side);

            script.AppendFormat("     Handicap={0};\n", 0);
            if (mod.IsMission)
            {
                script.AppendFormat("      StartPosX={0};\n", 0);
                script.AppendFormat("      StartPosZ={0};\n", 0);
            }
            else
            {
                if ((Details.StartPos == BattleStartPos.Random || Details.StartPos == BattleStartPos.Fixed) && positions.Count > teamNum)
                {
                    var pos = positions[teamNum];
                    script.AppendFormat("      StartPosX={0};\n", pos.x);
                    script.AppendFormat("      StartPosZ={0};\n", pos.z);
                }
            }
            script.AppendLine("  }");
        }
        /// <summary>
        /// Read options from EngineOptions.lua or ModOptions.lua
        /// </summary>
        public static void ReadOptionsTable(String filePath, ref Mod modInfo)
        {
            if (!File.Exists(filePath)) 
            {
                return;
            }
            
            var allOptions = new List<Option>();
            using (FileStream fileStream = File.OpenRead(filePath))
            using (var stream = new StreamReader(fileStream))
            {
                var allText = stream.ReadToEnd();
                int offset =0;
                var config = new TableReaderConfig();
                var table = TableReader.ParseTable(config,0,allText,filePath,out offset);
                
                foreach (var kvp in table)
                {
                    var anOption = new Option();
                    bool isBoolOption = false;
                    foreach(var kvp2 in (kvp.Value as Dictionary<String,Object>))
                    {
                        var value = (kvp2.Value as String);
                        float numbers;
                        //uncomment to take a peek on what it read!: 
                        //System.Diagnostics.Trace.TraceWarning("key: " + kvp2.Key + " value:" + value);
                        switch(kvp2.Key)
                        {
                            case "key":
                                anOption.Key = value;
                                break;
                            case "name":
                                anOption.Name = value;
                                break;
                            case "desc":
                                anOption.Description = value;
                                break;
                            case "type":
                                switch(value)
                                {
                                    case "bool":
                                        anOption.Type = OptionType.Bool;
                                        isBoolOption = true;
                                        break;
                                    case "list":
                                        anOption.Type = OptionType.List;
                                        break;
                                    case "number":
                                        anOption.Type = OptionType.Number;
                                        break;
                                    case "string":
                                        anOption.Type = OptionType.String;
                                        break;
                                    case "section":
                                        anOption.Type = OptionType.Section;
                                        continue;
                                    default:
                                        anOption.Type = OptionType.Undefined;
                                        break;
                                }
                                break;
                            case "def":
                                anOption.Default = value;
                                if (isBoolOption)
                                {
                                    if (value=="false")
                                        anOption.Default = "0";
                                    else
                                        anOption.Default = "1";
                                }
                                break;
                            case "min":
                                float.TryParse(value,NumberStyles.Float,CultureInfo.InvariantCulture,out numbers);
                                anOption.Min = numbers;
                                break;
                            case "max":
                                float.TryParse(value,NumberStyles.Float,CultureInfo.InvariantCulture,out numbers);
                                anOption.Max = numbers;
                                break;
                            case "step":
                                float.TryParse(value,NumberStyles.Float,CultureInfo.InvariantCulture,out numbers);
                                anOption.Step = numbers;
                                break;
                            case "maxlen":
                                float.TryParse(value,NumberStyles.Float,CultureInfo.InvariantCulture,out numbers);
                                anOption.StrMaxLen = numbers;
                                break;
                            case "items":
                                var listOptions = new List<ListOption>();
                                foreach(var kvp3 in (kvp2.Value as Dictionary<String,Object>))
                                {
                                    var listOption = new ListOption();
                                    foreach(var kvp4 in (kvp3.Value as Dictionary<String,Object>))
                                    {
                                        var value2 = (kvp4.Value as String);
                                        switch(kvp4.Key)
                                        {
                                            case "key":
                                                listOption.Key = value2;
                                                break;
                                            case "name":
                                                listOption.Name = value2;
                                                break;
                                            case "desc":
                                                listOption.Description = value2;
                                                break;
                                        }
                                    }

                                    if (listOption.Key!=null)
                                        listOptions.Add(listOption);
                                }
                                anOption.ListOptions = listOptions;
                                break;
                            case "scope":
                                anOption.Scope = value;
                                break;
                            case "section":
                                anOption.Section = value;
                                break;
                        }     
                    }

                    if (anOption.Key!=null)
                        allOptions.Add(anOption);   
                }
            }
            if (modInfo.Options!=null)
                modInfo.Options = modInfo.Options.ToList().Concat(allOptions).ToArray();
            else 
                modInfo.Options = allOptions.ToArray();
        }
 /// <summary>
 /// Read mod information from modInfo.lua
 /// </summary>
 public static void ParseModInfo(string filePath, ref Mod modInfo)
 {
     if (!File.Exists(filePath))
     {
         return;
     }
     
     using (FileStream fileStream = File.OpenRead(filePath))
     using (var stream = new StreamReader(fileStream))
     {
         var allText = stream.ReadToEnd();
         int offset =0;
         var config = new TableReaderConfig();
         var table = TableReader.ParseTable(config,0,allText,filePath,out offset);
         
         foreach (var kvp in table)
         {
             var value = (kvp.Value as String);
             switch(kvp.Key)
             {
                 case "name":
                     modInfo.Name = value;
                     break;
                 case "description":
                     modInfo.Description = value;
                     break;
                 case "shortname":
                     modInfo.ShortName = value;
                     break;
                 case "version":
                     modInfo.PrimaryModVersion = value;
                     break;
                 case "mutator":
                     modInfo.Mutator = value;
                     break;
                 case "game":
                     modInfo.Game = value;
                     break;
                 case "shortGame":
                     modInfo.ShortGame = value;
                     break;
                 case "modtype":
                     //TODO modtype??
                     break;
                 case "depend":
                     var listDepend = new List<string>();
                     foreach (var kvp2 in (kvp.Value as Dictionary<String,Object>))
                     {
                         var value2 = (kvp2.Value as String);
                         listDepend.Add(value2);
                     }
                     
                     modInfo.Dependencies = listDepend;
                     break;
             }
         }
     }
 }
 /// <summary>
 /// Read mod luaAI from LuaAI.lua
 /// </summary>
 public static void ReadLuaAI(string filePath, ref Mod modInfo)
 {
     if (!File.Exists(filePath)) 
     {
         return;
     }
        
     using (FileStream fileStream = File.OpenRead(filePath))
     using (var stream = new StreamReader(fileStream))
     {
         var allText = stream.ReadToEnd();
         int offset =0;
         var config = new TableReaderConfig();
         var table = TableReader.ParseTable(config,0,allText,filePath,out offset);
         
         List<Ai> modAis = new List<Ai>();
         
         foreach (var kvp in table)
         {
             String name = "";
             String desc = "";
             foreach (var kvp2 in (kvp.Value as Dictionary<String,Object>))
             {
                 var value = (kvp2.Value as String);
                 
                 switch(kvp2.Key)
                 {
                     case "name":
                         name = value;
                         break;
                     case "desc":
                         desc = value;
                         break;
                 }
             }
             if (name!="" && desc!="")
             {
                 var bot = new Ai()
                 {
                     Info = new AiInfoPair[2] 
                 { 
                     new AiInfoPair { Key = "shortName", Value = name } , //usually equivalent to AI folder name (aiName[i])
                     new AiInfoPair { Key = "description", Value = desc } ,
                 }
                 };
                 modAis.Add(bot);
             }
         }
         modInfo.ModAis = modAis.ToArray();
     }
 }
        /// <summary>
        /// Read mission.lua file.
        /// </summary>
        public static void ReadMissionSlot(string filePath, ref Mod modInfo)
        {
            if (!File.Exists(filePath))
            {
                return;
            }

            using (FileStream fileStream = File.OpenRead(filePath))
            using (var stream = new StreamReader(fileStream))
            {
                var allText = stream.ReadToEnd();
                int offset =0;
                var config = new TableReaderConfig();
                var table = TableReader.ParseTable(config,0,allText,filePath,out offset);
                
                var allSlots = new List<MissionSlot>();
                
                foreach (var kvp in table)
                {
                    var slot = new MissionSlot();
                    int numbers = 0;
                    foreach (var kvp2 in (kvp.Value as Dictionary<String,Object>))
                    {
                        var value = (kvp2.Value as String);
                        switch(kvp2.Key)
                        {
                            case "AllyID":
                                int.TryParse(value,NumberStyles.Integer,CultureInfo.InvariantCulture,out numbers);
                                slot.AllyID = numbers;
                                break;
                            case "AllyName":
                                slot.AllyName = value;
                                break;
                            case "IsHuman":
                                slot.IsHuman = (value=="true");
                                break;
                            case "IsRequired":
                                slot.IsRequired = (value =="true");
                                break;
                            case "TeamID":
                                int.TryParse(value,NumberStyles.Integer,CultureInfo.InvariantCulture,out numbers);
                                slot.TeamID = numbers;
                                break;
                            case "TeamName":
                                slot.TeamName = value;
                                break;
                            case "Color":
                                int.TryParse(value,NumberStyles.Integer,CultureInfo.InvariantCulture,out numbers);
                                slot.Color = numbers;
                                //var springColor = (MyCol)numbers;
                                //slot.ColorR = springColor.R;
                                //slot.ColorG = springColor.G;
                                //slot.ColorB = springColor.B;
                                break;
                            //case "ColorR":
                            //    break;
                            //case "ColorG":
                            //    break;
                            //case "ColorB":
                            //    break;
                            case "AiShortName":
                                slot.AiShortName = value;
                                break;
                            case "AiVersion":
                                slot.AiVersion = value;
                                break;
                        }
                    }
                    if (slot.AiShortName!=null)
                    {
                        allSlots.Add(slot);
                    }
                }
                modInfo.MissionSlots = allSlots;
            }
        }
 /// <summary>
 /// Parse sides name from gamedata/sidedata.lua and side icon (.bmp format with same name as side name) from sidepics/
 /// </summary>
 public static void ReadSideInfo(string sidedataluaPath, string picPath, ref Mod modInfo)
 {
     if (!File.Exists(sidedataluaPath))
     {
         modInfo.Sides = new string[0];
         //modInfo.SideIcons = (new List<Byte[]>()).ToArray();
         //modInfo.StartUnits = new PlasmaShared.SerializableDictionary<string, string>(new Dictionary<string,string>());
         return;
     }
     
     using (FileStream fileStream = File.OpenRead(sidedataluaPath))
     using (var stream = new StreamReader(fileStream))
     {
         var allText = stream.ReadToEnd();
         int offset =0;
         var config = new TableReaderConfig();
         var table = TableReader.ParseTable(config,0,allText,sidedataluaPath,out offset);
         
         List<String> sides = new List<String>();
         List<byte[]> sideIcons = new List<byte[]>();
         var startUnits = new Dictionary<string,string>(); //PlasmaShared.SerializableDictionary<string,string>();
         
         foreach (var kvp in table)
         {
             String name = "";
             String startunit = "";
             foreach (var kvp2 in (kvp.Value as Dictionary<String,Object>))
             {
                 var value = (kvp2.Value as String);
                 
                 switch(kvp2.Key)
                 {
                     case "name":
                         name = value;
                         break;
                     case "startunit":
                         startunit = value;
                         break;
                 }
             }
             if (name!="")
             {
                 var picBytes = new Byte[0];
                 try{
                 var picList = Directory.EnumerateFiles(picPath);
                 using(FileStream fileStream2 = File.OpenRead(picList.First(x => SkirmishControlTool.GetFolderOrFileName(x).StartsWith(name,StringComparison.InvariantCultureIgnoreCase))))
                 {
                     picBytes = new Byte[fileStream2.Length];
                     fileStream2.Read(picBytes,0,picBytes.Length);
                 }
                 }catch(Exception e) {System.Diagnostics.Trace.TraceError(e.ToString());}
                 sides.Add(name);
                 sideIcons.Add(picBytes);
                 startUnits.Add(name,startunit);
             }
         }
         modInfo.Sides = sides.ToArray();
         modInfo.SideIcons = sideIcons.ToArray();
         modInfo.StartUnits = new SerializableDictionary<string, string>(startUnits);
     }
 }
        public static Mod GetOneSddMod(Mod mod)
        {
            if (mod.Options!=null || mod.ModAis!=null || mod.MissionScript!=null ||mod.Sides!=null)
                return mod;

            var modFolder = Utils.MakePath(Program.SpringPaths.DataDirectories.First(), "games");
            var path = Utils.MakePath(modFolder, mod.ArchiveName );

            String engineOptions = null;
            String modOptions = null;
            String luaAI = null;
            String missionScriptPath = null;
            String missionSlotPath = null;
            
            var rootFiles = Directory.EnumerateFiles(path);
            foreach(var pathOfFile in rootFiles)
            {
                var fileName = GetFolderOrFileName(pathOfFile);
                if(fileName.StartsWith("EngineOptions.lua",StringComparison.InvariantCultureIgnoreCase))
                    engineOptions = pathOfFile;
                else if(fileName.StartsWith("ModOptions.lua",StringComparison.InvariantCultureIgnoreCase))
                    modOptions = pathOfFile;
                else if(fileName.StartsWith("LuaAI.lua",StringComparison.InvariantCultureIgnoreCase))
                    luaAI = pathOfFile;
                else if(fileName.StartsWith("script.txt",StringComparison.InvariantCultureIgnoreCase))
                    missionScriptPath = pathOfFile;
                else if(fileName.StartsWith("slots.lua",StringComparison.InvariantCultureIgnoreCase))
                    missionSlotPath = pathOfFile;
            }
            
            if (modOptions!=null)
                CrudeLUAReader.ReadOptionsTable(modOptions, ref mod);
            if (engineOptions!=null)
                CrudeLUAReader.ReadOptionsTable(engineOptions, ref mod);
            if (luaAI!=null)
                CrudeLUAReader.ReadLuaAI(luaAI,ref mod);
            if (missionSlotPath!=null)
                CrudeLUAReader.ReadMissionSlot(missionSlotPath,ref mod);

            if (missionScriptPath!=null)
            {
                try{
                using (FileStream fileStream = File.OpenRead(missionScriptPath))
                using (var stream = new StreamReader(fileStream))
                {
                    mod.MissionScript = stream.ReadToEnd();

                    var open = mod.MissionScript.IndexOf("mapname", 7, mod.MissionScript.Length - 8, StringComparison.InvariantCultureIgnoreCase) + 8;
                    var close = mod.MissionScript.IndexOf(';', open);
                    var mapname = mod.MissionScript.Substring(open, close - open);
                    mod.MissionMap = mapname.Trim(new char[3]{' ','=','\t'});
                }
                }catch(Exception e)
                {}
            }

            var sideData = Utils.MakePath(path,"gamedata","sidedata.lua");
            var picPath = Utils.MakePath(path,"sidepics");
            CrudeLUAReader.ReadSideInfo(sideData,picPath,ref mod);

            return mod;
        }
		public void HandleMod(Mod mod)
		{
			if (mod != null)
			{
			  Ais = mod.ModAis;
				ModLoaded(this, new EventArgs<Mod>(mod));
				lock (locker)
				{
					if (Program.TasClient.MyBattle.ModName == mod.Name)
					{
						this.mod = mod;
						ChangedOptions = GetModOptionSummary(mod, Program.TasClient.MyBattle.ModOptions, false);

					}
					else return;
				}
			}
		}
        public Battle(string engineVersion, string password, int port, int maxplayers, int rank, Map map, string title, Mod mod, BattleDetails details): this()
        {
            if (!String.IsNullOrEmpty(password)) Password = password;
            if (port == 0) HostPort = 8452; else HostPort = port;
            try {
                var ports = IPGlobalProperties.GetIPGlobalProperties().GetActiveUdpListeners().OrderBy(x => x.Port).Select(x=>x.Port).ToList();
                if (ports.Contains(HostPort)) {
                    var blockedPort = HostPort;
                    while (ports.Contains(HostPort)) HostPort++;
                    Trace.TraceWarning("Host port {0} was used, using backup port {1}", blockedPort, HostPort);
                }
            } catch {}




            EngineVersion = engineVersion;
            MaxPlayers = maxplayers;
            Rank = rank;
            this.map = map;
            MapName = map.Name;
            MapHash = 0;
            Title = title;
            this.mod = mod;
            ModName = mod.Name;
            ModHash = 0;
            if (details != null) Details = details;
        }
    public void HandleMod(Mod mod)
    {
      this.mod = mod;
      SuspendLayout();
      try
      {
        options = mod.Options.ToDictionary(option => option.Key);
        var sections = mod.Options.GroupBy(option => option.Section).OrderBy(group => group.Key).ToArray();
        var sectionNames = mod.Options.Where(option => option.Type == OptionType.Section).ToDictionary(option => option.Key, option => option.Name);
        optionControls = new Dictionary<string, Control>();

        const int rowHeight = 30;
        foreach (var section in sections)
        {
          if (!section.Any()) continue;

          // set the section title
          string sectionName;
          if (String.IsNullOrEmpty(section.Key)) sectionName = "Other";
          else if (!sectionNames.TryGetValue(section.Key, out sectionName)) sectionName = section.Key.ToLower();
          var tabPage = new TabPage { Text = sectionName, Name = sectionName, AutoScroll = true };
          tabControl.TabPages.Add(tabPage);

          var sectionY = 20;

          foreach (var option in section)
          {
            Control control = null;
            switch (option.Type)
            {
              case OptionType.Bool:
                control = new CheckBox { Checked = option.Default != "0" };
                ((CheckBox)control).CheckedChanged += proposedChanged;
                break;
              case OptionType.Number:
                control = new NumericUpDown
                          {
                            Minimum = (decimal)option.Min,
                            Maximum = (decimal)option.Max,
                            Increment = (decimal)option.Step,
                            Value = decimal.Parse(option.Default, CultureInfo.InvariantCulture),
                            DecimalPlaces = (int)(-Math.Floor(Math.Min(0, Math.Log10(option.Step)))),
                          };
                ((NumericUpDown)control).ValueChanged += proposedChanged;
                break;
              case OptionType.String:
                control = new TextBox { Text = option.Default };
                control.TextChanged += proposedChanged;
                break;
              case OptionType.List:
                var optionIndex = option.ListOptions.IndexOf(option.ListOptions.Single(o => o.Key == option.Default));
                var box = new ComboBox { DropDownStyle = ComboBoxStyle.DropDownList };
                box.Items.AddRange(option.ListOptions.Select(o => o.Name).ToArray());
                if (optionIndex > -1) box.SelectedIndex = optionIndex;
                control = box;
                box.SelectedIndexChanged += proposedChanged;
                break;
            }
            if (control != null)
            {
              var tooltipText = string.Format("{0}\nDefault: {1} = {2}", option.Description, option.Key, option.Default);
              tooltip.SetToolTip(control, tooltipText);
              var label = new Label { Text = option.Name, Location = new Point(3, sectionY), Width = 145 };
              tooltip.SetToolTip(label, tooltipText);
              tabPage.Controls.Add(label);
              control.Location = new Point(150, sectionY);
              optionControls[option.Key] = control;
              tabPage.Controls.Add(control);
              sectionY += rowHeight;
            }
          }
        }
      }
      catch (Exception e)
      {
        Trace.TraceError("Error in creating mod options controls: " + e);
      }
      ResumeLayout();
      if (offlineMode)
      {
          SetModOptions();
          return;
      }

      SetModOptions(Program.TasClient.MyBattle.ModOptions);
    }
        private void CallBack_Mod(Mod mod)
        {
            if (mod != null)
            {
                //Initialize "side" (faction) dropdown list. copied from Notification.BattleBar.cs
                {
                    sideCB.Visible = mod.Sides.Length > 1;
                    if (sideCB.Visible)
                    {
                        var previousSide = sideCB.SelectedItem != null ? sideCB.SelectedItem.ToString() : null;
                        sideCB.Items.Clear();
                        var cnt = 0;
                        foreach (var side in mod.Sides) sideCB.Items.Add(new ZeroKLobby.Notifications.SideItem(side, mod.SideIcons[cnt++]));
                        var pickedItem = sideCB.Items.OfType<ZeroKLobby.Notifications.SideItem>()
                              .FirstOrDefault(x => x.Side == previousSide);
                        if (pickedItem != null) sideCB.SelectedItem = pickedItem;
                        else if (sideCB.Items.Count > 0) sideCB.SelectedIndex = sideCB.Items.Count-1; // random.Next(sideCB.Items.Count);
                    }
                }
                //end "side" (faction) dropdown list

                ModOptions.Clear();
                currentMod = mod;
                aiList = mod.ModAis;
                missionSlots = mod.MissionSlots;
                Setup_MissionModInfo(mod);
                Set_InfoLabel();
            }
            else
            {
                sideCB.Visible = false;
                currentMod = null;
                aiList = null;
                missionSlots = null;
                myItem.MissionSlot = null;
                botsMissionSlot.Clear();
                if (currentMod != null) Refresh_PlayerBox();
            }
        }
 private static void RecordMissionResult(Spring spring, Mod modInfo)
 {
     if (spring.Context.GameEndedOk && !spring.Context.IsCheating)
     {
         Trace.TraceInformation("Submitting score for mission " + modInfo.Name);
         try
         {
             var service = GlobalConst.GetContentService();
             Task.Factory.StartNew(() =>
             {
                 try
                 {
                     service.SubmitMissionScore(Program.Conf.LobbyPlayerName,
                         ZkData.Utils.HashLobbyPassword(Program.Conf.LobbyPlayerPassword),
                         modInfo.Name,
                         spring.Context.MissionScore ?? 0,
                         spring.Context.MissionFrame/30,
                         spring.Context.MissionVars);
                 }
                 catch (Exception ex)
                 {
                     Trace.TraceError("Error sending score: {0}", ex);
                 }
             });
         }
         catch (Exception ex)
         {
             Trace.TraceError($"Error sending mission score: {ex}");
         }
     }
 }
        public void UpdateMission(ZkDataContext db, Mission mission, Mod modInfo) {
            var file = mission.Mutator.ToArray();
            var tempName = Path.GetTempFileName() + ".zip";
            File.WriteAllBytes(tempName, file);

            using (var zf = new ZipFile(tempName))
            {
                zf.UpdateEntry("modinfo.lua", Encoding.UTF8.GetBytes(GetModInfo(mission.NameWithVersion, mission.Mod, mission.Name, "ZK")));    // FIXME hardcoded crap
                FixScript(mission, zf, "script.txt");
                var script = FixScript(mission, zf, GlobalConst.MissionScriptFileName);
                modInfo.MissionScript = script;
                //modInfo.ShortName = mission.Name;
                modInfo.Name = mission.NameWithVersion;
                zf.Save();
            }
            mission.Mutator = File.ReadAllBytes(tempName);
            mission.Script = Regex.Replace(mission.Script, "GameType=([^;]+);", (m) => { return string.Format("GameType={0};", mission.NameWithVersion); });
            
            File.Delete(tempName);
            
            var resource = db.Resources.FirstOrDefault(x => x.MissionID == mission.MissionID); 
            if (resource == null)
            {
                resource = new Resource() { DownloadCount = 0, TypeID = ZkData.ResourceType.Mod };
                db.Resources.Add(resource);
            }
            resource.InternalName = mission.NameWithVersion;
            resource.MissionID = mission.MissionID;

            resource.ResourceDependencies.Clear();
            resource.ResourceDependencies.Add(new ResourceDependency() { NeedsInternalName = mission.Map });
            resource.ResourceDependencies.Add(new ResourceDependency() { NeedsInternalName = mission.Mod });
            resource.ResourceContentFiles.Clear();
            

            // generate torrent
            var tempFile = Path.Combine(Path.GetTempPath(), mission.SanitizedFileName);
            File.WriteAllBytes(tempFile, mission.Mutator.ToArray());
            var creator = new TorrentCreator();
            creator.Path = tempFile;
            var torrentStream = new MemoryStream();
            creator.Create(torrentStream);
            try
            {
                File.Delete(tempFile);
            }
            catch { }

            var md5 = Hash.HashBytes(mission.Mutator.ToArray()).ToString();
            resource.ResourceContentFiles.Add(new ResourceContentFile()
            {
                FileName = mission.SanitizedFileName,
                Length = mission.Mutator.Length,
                LinkCount = 1,
                Links = string.Format(MissionFileUrl, mission.MissionID),
                Md5 = md5
            });


            var basePath = GlobalConst.SiteDiskPath + @"\resources\";
            File.WriteAllBytes(string.Format(@"{2}\{0}_{1}.torrent", resource.InternalName.EscapePath(), md5, basePath), torrentStream.ToArray());
            
            File.WriteAllBytes(string.Format(@"{1}\{0}.metadata.xml.gz", resource.InternalName.EscapePath(), basePath),
                                   MetaDataCache.SerializeAndCompressMetaData(modInfo));
            
            File.WriteAllBytes(string.Format(GlobalConst.SiteDiskPath + @"\img\missions\{0}.png", mission.MissionID, basePath), mission.Image.ToArray());

        }
        public void OpenBattleRoom(string modname, string mapname, bool now = true) {
            if (!now && spring.IsRunning) spring.WaitForExit();
            Stop();

            bossName = "";
            lastMapChange = DateTime.Now;

            if (String.IsNullOrEmpty(modname)) modname = config.Mod;
            if (String.IsNullOrEmpty(mapname)) mapname = config.Map;

            string title = config.Title.Replace("%1", MainConfig.SpringieVersion);

            string password = null;
            if (!string.IsNullOrEmpty(config.BattlePassword)) password = config.BattlePassword;

            int maxPlayers = config.MaxPlayers;
            string engine = springPaths.SpringVersion;
            if (SpawnConfig != null) {
                modname = SpawnConfig.Mod;
                if (SpawnConfig.MaxPlayers > 0) maxPlayers = SpawnConfig.MaxPlayers;
                if (!String.IsNullOrEmpty(SpawnConfig.Map)) mapname = SpawnConfig.Map;
                title = SpawnConfig.Title;
                if (!String.IsNullOrEmpty(SpawnConfig.Password)) password = SpawnConfig.Password;
                if (!String.IsNullOrEmpty(SpawnConfig.Engine)) engine = SpawnConfig.Engine;
                {
                    //Something needs to go here to properly tell Springie to use a specific engine version,
                    //attempted code below may or may not be responsible for recent springie drops, so commenting.
                    
                    //the below may be causing a rehost
                    //requestedEngineChange = SpawnConfig.Engine;
                    
                    //alternate attempt
                    /*
                    Program.main.Downloader.GetAndSwitchEngine(SpawnConfig.Engine);
                    config.SpringVersion = SpawnConfig.Engine;
                    springPaths.SetEnginePath(Program.main.paths.GetEngineFolderByVersion(SpawnConfig.Engine));
                    */
                }
            }

            //title = title + string.Format(" [engine{0}]", springPaths.SpringVersion);

            // no mod was provided, auto update is on, check if newer version exists, if it does use that instead of config one
            if (string.IsNullOrEmpty(modname) && !String.IsNullOrEmpty(config.AutoUpdateRapidTag)) {
                var ver = Program.main.Downloader.PackageDownloader.GetByTag(config.AutoUpdateRapidTag);
                
                if (ver != null && cache.GetResourceDataByInternalName(ver.InternalName) != null) modname = config.AutoUpdateRapidTag;
            }

            PackageDownloader.Version version = Program.main.Downloader.PackageDownloader.GetByTag(modname);
            if (version != null && version.InternalName != null) modname = version.InternalName;

            hostedMod = new Mod() {Name = modname};
            cache.GetMod(modname, (m) => { hostedMod = m; }, (m) => {});
            if (hostedMod.IsMission && !String.IsNullOrEmpty(hostedMod.MissionMap)) mapname = hostedMod.MissionMap;

            //Map mapi = null;
            //cache.GetMap(mapname, (m, x, y, z) => { mapi = m; }, (e) => { }, springPaths.SpringVersion);
            //int mint, maxt;
            if (!springPaths.HasEngineVersion(engine)) {
                Program.main.Downloader.GetAndSwitchEngine(engine,springPaths);
            } else {
                springPaths.SetEnginePath(springPaths.GetEngineFolderByVersion(engine));
            }

            var b = new Battle(engine, password, hostingPort, maxPlayers, mapname, title,modname);
            b.Ip = Program.main.Config.IpOverride;
            tas.OpenBattle(b);
        }
	    public void SendMission(Mission mission, List<MissionSlot> slots, string author, string password, Mod modInfo)
		{
            if (mission == null) throw new ApplicationException("Mission is null");

			Account acc = null;
			var db = new ZkDataContext();
			if (Debugger.IsAttached) acc = db.Accounts.SingleOrDefault(x => x.Name == "Testor303");
			else acc = AuthServiceClient.VerifyAccountPlain(author, password);

		    if (acc == null)
		    {
                Trace.TraceWarning("Invalid login attempt for {0}", author);
                System.Threading.Thread.Sleep(new Random().Next(2000));
                throw new ApplicationException("Cannot verify user account");
		    }


            Mission prev = db.Missions.SingleOrDefault(x => x.MissionID == mission.MissionID || (x.Name == mission.Name && x.AccountID == acc.AccountID)); // previous mission by id or name + account
			if (prev == null && db.Missions.Any(x =>x.Name == mission.Name)) throw new ApplicationException("Mission name must be unique");
			var map = db.Resources.SingleOrDefault(x => x.InternalName == mission.Map && x.TypeID == ZkData.ResourceType.Map);
			if (map == null) throw new ApplicationException("Map name is unknown");
			var mod = db.Resources.SingleOrDefault(x => x.InternalName == mission.Mod && x.TypeID == ZkData.ResourceType.Mod);
			if (mod == null) throw new ApplicationException("Mod name is unknown");
			//if (db.Resources.Any(x => x.InternalName == mission.Name && x.MissionID != null)) throw new ApplicationException("Name already taken by other mod/map");

            modInfo.MissionMap = mission.Map;

			if (prev != null)
			{
				if (prev.AccountID != acc.AccountID && !acc.IsZeroKAdmin) throw new ApplicationException("Invalid author or password");
				prev.Description = mission.Description;
                prev.DescriptionStory = mission.DescriptionStory;
				prev.Mod = mission.Mod;
				prev.Map = mission.Map;
				prev.Name = mission.Name;
				prev.ScoringMethod = mission.ScoringMethod;
				prev.ModRapidTag = mission.ModRapidTag;
				prev.ModOptions = mission.ModOptions;
				prev.Image = mission.Image;
				prev.MissionEditorVersion = mission.MissionEditorVersion;
				prev.SpringVersion = mission.SpringVersion;
				prev.Revision++;
				prev.Mutator = mission.Mutator;
                prev.ForumThread.Title = mission.Name;
				mission = prev;
			}
			else
			{
				mission.CreatedTime = DateTime.UtcNow;
                mission.ForumThread = new ForumThread() { Title = mission.Name, ForumCategory = db.ForumCategories.FirstOrDefault(x=>x.ForumMode==ForumMode.Missions), CreatedAccountID = acc.AccountID, LastPostAccountID= acc.AccountID };
                mission.ForumThread.UpdateLastRead(acc.AccountID, true);
				db.Missions.InsertOnSubmit(mission);
			}
			mission.AccountID = acc.AccountID;
			mission.Script = Regex.Replace(mission.Script, "GameType=([^;]+);", (m) => { return string.Format("GameType={0};", mission.NameWithVersion); });
			mission.MinHumans = slots.Count(x => x.IsHuman && x.IsRequired);
			mission.MaxHumans = slots.Count(x => x.IsHuman);
			mission.ModifiedTime = DateTime.UtcNow;
			mission.IsDeleted = true;
			mission.IsCoop = slots.Where(x => x.IsHuman).GroupBy(x => x.AllyID).Count() == 1;

	        db.SaveChanges();

	        var updater = new MissionUpdater();
            updater.UpdateMission(db, mission, modInfo);

			mission.IsDeleted = false;
	        db.SaveChanges();
		}
Exemple #23
0
        public Mod GetMod(string modName)
        {
            if (disposed)
            {
                throw new ObjectDisposedException("Unitsync has already been released.");
            }
            if (modName == null)
            {
                throw new ArgumentNullException("modName");
            }
            NativeMethods.RemoveAllArchives();
            NativeMethods.GetPrimaryModCount();             // pre-requisite for the following calls
            var archiveName = GetModArchiveName(modName);

            NativeMethods.AddAllArchives(archiveName);
            int modIndex = NativeMethods.GetPrimaryModIndex(modName);

            string[] sides;

            var mod = new Mod
            {
                Name              = modName,
                ArchiveName       = archiveName,
                UnitDefs          = GetUnitList(modName).Select(ui => new UnitInfo(ui.Name, ui.FullName)).ToArray(),
                Description       = NativeMethods.GetPrimaryModDescription(modIndex),
                Game              = NativeMethods.GetPrimaryModGame(modIndex),
                Mutator           = NativeMethods.GetPrimaryModMutator(modIndex),
                ShortGame         = NativeMethods.GetPrimaryModShortGame(modIndex),
                ShortName         = NativeMethods.GetPrimaryModShortName(modIndex),
                PrimaryModVersion = NativeMethods.GetPrimaryModVersion(modIndex),
                StartUnits        = new SerializableDictionary <string, string>(GetStartUnits(modName, out sides)),
                Sides             = sides,
                Options           = GetModOptions(archiveName).ToArray(),
                SideIcons         = GetSideIcons(sides).ToArray(),
                Dependencies      = GetModDependencies(modIndex).Where(x => x != modName && !string.IsNullOrEmpty(x)).ToArray(),
                ModAis            = GetAis().Where(ai => ai.IsLuaAi).ToArray()
            };

            System.Diagnostics.Trace.TraceInformation("Mod Information: Description {0}, Game {1}, Mutator {2}, ShortGame {3}, PrimaryModVersion {4}", mod.Description, mod.Game, mod.Mutator, mod.ShortGame, mod.PrimaryModVersion);

            var buf = ReadVfsFile(GlobalConst.MissionScriptFileName);

            if (buf != null && buf.Length > 0)
            {
                mod.MissionScript = Encoding.UTF8.GetString(buf, 0, buf.Length);
            }

            if (!string.IsNullOrEmpty(mod.MissionScript))
            {
                try
                {
                    buf = ReadVfsFile(GlobalConst.MissionSlotsFileName);
                    var slotString = Encoding.UTF8.GetString(buf, 0, buf.Length);
                    var ser        = new XmlSerializer(typeof(List <MissionSlot>));
                    mod.MissionSlots = (List <MissionSlot>)ser.Deserialize(new StringReader(slotString));
                }
                catch (Exception ex)
                {
                    Trace.TraceError("Error reading mission slots from mod {0}: {1}", mod.Name, ex);
                }
            }

            if (mod.Sides.Length == 0)
            {
                Trace.WriteLine("Mod has no faction");
            }
            if (mod.UnitDefs.Length == 0)
            {
                Trace.WriteLine("No unit found.");
            }

            NativeMethods.RemoveAllArchives();
            TraceErrors();
            return(mod);
        }