public event EventHandler <CancelEventArgs <CacheItem> > RetryResourceCheck     = delegate { }; // raised before attempting to reconnect to server to check for resource info

        public SpringScanner(SpringPaths springPaths)
        {
            this.springPaths = springPaths;
            MetaData         = new MetaDataCache(springPaths, this);

            foreach (var folder in springPaths.DataDirectories)
            {
                var modsPath = Utils.MakePath(folder, "games");
                if (Directory.Exists(modsPath))
                {
                    modsWatchers.Add(new FileSystemWatcher(modsPath));
                }
                var mapsPath = Utils.MakePath(folder, "maps");
                if (Directory.Exists(mapsPath))
                {
                    mapsWatchers.Add(new FileSystemWatcher(mapsPath));
                }
                var packagesPath = Utils.MakePath(folder, "packages");
                if (Directory.Exists(packagesPath))
                {
                    packagesWatchers.Add(new FileSystemWatcher(packagesPath));
                }
            }

            SetupWatcherEvents(mapsWatchers);
            SetupWatcherEvents(modsWatchers);
            SetupWatcherEvents(packagesWatchers);

            Directory.CreateDirectory(springPaths.Cache);
            cachePath = Utils.MakePath(springPaths.Cache, "ScannerCache.json");
            Directory.CreateDirectory(Utils.MakePath(springPaths.Cache, "Resources"));
        }
Example #2
0
        public Main(string path)
        {
            RootWorkPath = path;
            LoadConfig();
            Config.RestartCounter++;
            if (Config.RestartCounter > 3) Config.RestartCounter = 0;
            SaveConfig();
            paths = new SpringPaths(Path.GetDirectoryName(Config.ExecutableName), writableFolderOverride: Config.DataDir);
            if (!string.IsNullOrEmpty(Config.ExecutableName)) paths.OverrideDedicatedServer(Config.ExecutableName);
            paths.MakeFolders();

            MetaCache = new MetaDataCache(paths);

            timer = new Timer(30000);
            timer.Elapsed += timer_Elapsed;
            timer.AutoReset = true;
            timer.Start();

            Downloader = new PlasmaDownloader.PlasmaDownloader(Config, null, paths);
        }
        public event EventHandler<CancelEventArgs<CacheItem>> RetryResourceCheck = delegate { }; // raised before attempting to reconnect to server to check for resource info

        public SpringScanner(SpringPaths springPaths)
        {
            this.springPaths = springPaths;
            MetaData = new MetaDataCache(springPaths, this);

            foreach (var folder in springPaths.DataDirectories)
            {
                var modsPath = Utils.MakePath(folder, "games");
                if (Directory.Exists(modsPath)) modsWatchers.Add(new FileSystemWatcher(modsPath));
                var mapsPath = Utils.MakePath(folder, "maps");
                if (Directory.Exists(mapsPath)) mapsWatchers.Add(new FileSystemWatcher(mapsPath));
                var packagesPath = Utils.MakePath(folder, "packages");
                if (Directory.Exists(packagesPath)) packagesWatchers.Add(new FileSystemWatcher(packagesPath));
            }

            SetupWatcherEvents(mapsWatchers);
            SetupWatcherEvents(modsWatchers);
            SetupWatcherEvents(packagesWatchers);

            Directory.CreateDirectory(springPaths.Cache);
            cachePath = Utils.MakePath(springPaths.Cache, "ScannerCache.json");
            Directory.CreateDirectory(Utils.MakePath(springPaths.Cache, "Resources"));
        }
        public event EventHandler<CancelEventArgs<CacheItem>> RetryResourceCheck = delegate { }; // raised before attempting to reconnect to server to check for resource info

        public SpringScanner(SpringPaths springPaths)
        {
            this.SpringPaths = springPaths;
            MetaData = new MetaDataCache(springPaths, this);

            foreach (var folder in springPaths.DataDirectories)
            {
                var modsPath = Utils.MakePath(folder, "games");
                if (Directory.Exists(modsPath)) modsWatchers.Add(new FileSystemWatcher(modsPath));
                var mapsPath = Utils.MakePath(folder, "maps");
                if (Directory.Exists(mapsPath)) mapsWatchers.Add(new FileSystemWatcher(mapsPath));
                var packagesPath = Utils.MakePath(folder, "packages");
                if (Directory.Exists(packagesPath)) packagesWatchers.Add(new FileSystemWatcher(packagesPath));
            }

            SetupWatcherEvents(mapsWatchers);
            SetupWatcherEvents(modsWatchers);
            SetupWatcherEvents(packagesWatchers);

            Directory.CreateDirectory(springPaths.Cache);
            cachePath = Utils.MakePath(springPaths.Cache, "ScannerCache.json");
            Directory.CreateDirectory(Utils.MakePath(springPaths.Cache, "Resources"));

            if (UseUnitSync)
            {
                try
                {
                    unitSync = new UnitSync(springPaths);
                }
                catch (Exception ex)
                {
                    Trace.TraceWarning("UnitSync init failed: {0}",ex);
                }
            }
        }
        public AutoHost(MetaDataCache cache, AhConfig config, int hostingPort, SpawnConfig spawn) {
            this.config = config;
            Commands = new CommandList(config);
            this.cache = cache;
            SpawnConfig = spawn;
            this.hostingPort = hostingPort;

            
            string version = config.SpringVersion ?? Program.main.Config.SpringVersion ?? GlobalConst.DefaultEngineOverride;
            springPaths = new SpringPaths(Program.main.paths.GetEngineFolderByVersion(version), Program.main.Config.DataDir);
            
            springPaths.SpringVersionChanged += (s, e) =>
                {
                    if (!String.IsNullOrEmpty(requestedEngineChange) && requestedEngineChange == springPaths.SpringVersion) {
                        config.SpringVersion = requestedEngineChange;
                        springPaths.SetEnginePath(Program.main.paths.GetEngineFolderByVersion(requestedEngineChange));
                        requestedEngineChange = null;

                        tas.Say(SayPlace.Battle, "", "rehosting to engine version " + springPaths.SpringVersion, true);
                        ComRehost(TasSayEventArgs.Default, new string[] { });
                    }
                };

            spring = new Spring(springPaths) { UseDedicatedServer = true };
            bool isManaged = SpawnConfig == null && config.Mode != AutohostMode.None;

            tas = new TasClient(MainConfig.SpringieVersion,
                                isManaged ? Login.ClientTypes.SpringieManaged : Login.ClientTypes.Springie,
                                Program.main.Config.IpOverride);

            pollTimer = new Timer(PollTimeout*1000);
            pollTimer.Enabled = false;
            pollTimer.AutoReset = false;
            pollTimer.Elapsed += pollTimer_Elapsed;

            spring.SpringExited += spring_SpringExited;
            spring.GameOver += spring_GameOver;

            spring.SpringExited += spring_SpringExited;
            spring.SpringStarted += spring_SpringStarted;
            spring.PlayerSaid += spring_PlayerSaid;
            spring.BattleStarted += spring_BattleStarted;

            tas.BattleUserLeft += tas_BattleUserLeft;
            tas.UserStatusChanged += tas_UserStatusChanged;
            tas.BattleUserJoined += tas_BattleUserJoined;
            tas.MyBattleMapChanged += tas_MyBattleMapChanged;
            tas.BattleOpened += tas_BattleOpened;
            tas.UserAdded += (o, u) => { if (u.Name == GetAccountName()) OpenBattleRoom(null, null); };

            tas.RegistrationDenied += (s, e) =>
                {
                    Trace.TraceWarning("Registration denied: {0} {1}", e.ResultCode.Description(), e.Reason);
                    CloneNumber++;
                    tas.Login(GetAccountName(), config.Password);
                };

            tas.RegistrationAccepted += (s, e) => tas.Login(GetAccountName(), config.Password);

            tas.ConnectionLost += tas_ConnectionLost;
            tas.Connected += tas_Connected;
            tas.LoginDenied += tas_LoginDenied;
            tas.LoginAccepted += tas_LoginAccepted;
            tas.Said += tas_Said;
            tas.MyBattleStarted += tas_MyStatusChangedToInGame;

            linkSpringieClient = new ResourceLinkSpringieClient(this);

            // queue autohost
            if (config != null && config.MinToJuggle != null && SpawnConfig == null)
            {
                queue = new MatchMakerQueue(this);
            }

            
            Program.main.Downloader.PackagesChanged += Downloader_PackagesChanged;

            timer = new Timer(15000);
            timer.Elapsed += (s, e) =>
                {
                    try {
                        timer.Stop();
                        timerTick++;

                        // auto update engine branch
                        if (!String.IsNullOrEmpty(config.AutoUpdateSpringBranch) && timerTick%4 == 0) CheckEngineBranch();

                        // auto verify pw map
                        if (!spring.IsRunning && config.Mode != AutohostMode.None) if (SpawnConfig == null && config.Mode == AutohostMode.Planetwars) ServerVerifyMap(false);

                        // auto start split vote
                        if (!spring.IsRunning && config.SplitBiggerThan != null && tas.MyBattle != null && config.SplitBiggerThan < tas.MyBattle.NonSpectatorCount) {
                            if (DateTime.Now.Subtract(spring.GameExited).TotalSeconds >= GameExitSplitDelay) ComSplitPlayers(TasSayEventArgs.Default, new string[]{});
                            /*
                            int cnt = tas.MyBattle.NonSpectatorCount;
                            if (cnt > lastSplitPlayersCountCalled && cnt%2 == 0) {
                                StartVote(new VoteSplitPlayers(tas, spring, this), TasSayEventArgs.Default, new string[] { });
                                lastSplitPlayersCountCalled = cnt;
                            }*/
                        }

                        // auto rehost to latest mod version
                        if (!string.IsNullOrEmpty(config.AutoUpdateRapidTag) && SpawnConfig == null) UpdateRapidMod(config.AutoUpdateRapidTag);


                    } catch (Exception ex) {
                        Trace.TraceError(ex.ToString());
                    } finally {
                        timer.Start();
                    }
                };
            timer.Start();
           
        }
        public static void Main(string[] args) {
            try
            {
                //Stopwatch stopWatch = new Stopwatch(); stopWatch.Start();
                Trace.Listeners.Add(new ConsoleTraceListener());
                

                if (Environment.OSVersion.Platform != PlatformID.Unix)
                {
                    var ver = GetNetVersionFromRegistry();
                    if (ver < 378675)
                    {
                        MessageBox.Show(new Form { TopMost = true },
                            "Zero-K launcher needs Microsoft .NET framework 4.5.1\nPlease download and install it first",
                            "Program is unable to run",
                            MessageBoxButtons.OK,
                            MessageBoxIcon.Error);
                    }
                }

                Directory.SetCurrentDirectory(StartupPath);

                // extract fonts
                EmbeddedResourceExtractor.ExtractFile("ZeroKLobby.NativeLibs.SM.ttf", "SM.ttf");
                EmbeddedResourceExtractor.ExtractFile("ZeroKLobby.NativeLibs.OpenSans-Regular.ttf", "OpenSans-Regular.ttf");

                Conf = new Config();

                IsSteamFolder = File.Exists(Path.Combine(StartupPath, "steamfolder.txt"));

                SelfUpdater = new SelfUpdater("Zero-K");

                StartupArgs = args;

                try
                {
                    Application.EnableVisualStyles();
                    Application.SetCompatibleTextRenderingDefault(false);
                }
                catch (Exception ex)
                {
                    Trace.TraceWarning("Failed to set rendering compatibility: {0}", ex);
                }

                if (!Debugger.IsAttached)
                {
                    try
                    {
                        AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
                        Thread.GetDomain().UnhandledException += UnhandledException;
                        Application.ThreadException += Application_ThreadException;
                        Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
                    }
                    catch (Exception ex)
                    {
                        Trace.TraceWarning("Failed to set exception handling :{0}", ex);
                    }
                }




                //HttpWebRequest.DefaultCachePolicy = new RequestCachePolicy(RequestCacheLevel.NoCacheNoStore);
                Trace.TraceInformation("Starting with version {0}", SelfUpdater.CurrentVersion);

                WebRequest.DefaultWebProxy = null;
                ThreadPool.SetMaxThreads(500, 2000);
                ServicePointManager.Expect100Continue = false;
                LoadConfig();

            


                Trace.Listeners.Add(new LogTraceListener());
                if (Environment.OSVersion.Platform != PlatformID.Unix && !Conf.UseExternalBrowser) Utils.SetIeCompatibility(); //set to current IE version

                var contentDir = !string.IsNullOrEmpty(Conf.DataFolder) ? Conf.DataFolder : StartupPath;
                if (!Directory.Exists(contentDir) || !SpringPaths.IsDirectoryWritable(contentDir))
                {
                    var dc = new SelectWritableFolder { SelectedPath = SpringPaths.GetMySpringDocPath() };
                    if (dc.ShowDialog() != DialogResult.OK) return;
                    contentDir = dc.SelectedPath;
                }
                if (Conf.DataFolder != StartupPath) Conf.DataFolder = contentDir;
                else Conf.DataFolder = null;

                if (!SpringPaths.IsDirectoryWritable(StartupPath))
                {
                    var newTarget = Path.Combine(contentDir, "Zero-K.exe");
                    if (SelfUpdater.CheckForUpdate(newTarget, true))
                    {
                        Conf.Save(Path.Combine(contentDir, Config.ConfigFileName));
                        Process.Start(newTarget);
                        return;
                    } MessageBox.Show(new Form { TopMost = true }, "Move failed, please copy Zero-K.exe to a writable folder");
                    return;
                }

                

                SpringPaths = new SpringPaths(contentDir);

                if (
                MessageBox.Show(new Form() { TopMost = true },
                    "Would you like to try the new lobby program for Zero-K: Chobby?",
                    "New launcher option available",
                    MessageBoxButtons.YesNo,
                    MessageBoxIcon.Question) == DialogResult.Yes)
                {
                    var targetPath = Path.Combine(SpringPaths.WritableDirectory, "Chobby.exe");
                    if (!File.Exists(targetPath))
                    {
                        var wc = new WebClient();
                        wc.DownloadFile(GlobalConst.BaseSiteUrl + "/lobby/Chobby.exe", targetPath);
                    }
                    Process.Start(targetPath);
                    Environment.Exit(0);
                }

                // speed up spring start
                SpringPaths.SpringVersionChanged += (sender, engine) =>
                {
                    ZkData.Utils.StartAsync(
                        () =>
                        {
                            UnitSync unitSync = null;
                            try
                            {
                                unitSync = new UnitSync(SpringPaths, engine); // initialize unitsync to avoid slowdowns when starting

                                if (unitSync.UnitsyncWritableFolder != SpringPaths.WritableDirectory)
                                {
                                    // unitsync created its cache in different folder than is used to start spring -> move it
                                    var fi = ArchiveCache.GetCacheFile(unitSync.UnitsyncWritableFolder);
                                    if (fi != null) File.Copy(fi.FullName, Path.Combine(SpringPaths.WritableDirectory, "cache", fi.Name), true);
                                }
                            }
                            finally
                            {
                                unitSync?.Dispose();
                            }
                        });
                };

                SaveConfig();


                // write license files
                try
                {
                    var path = SpringPaths.WritableDirectory;
                    var pathGPL = Utils.MakePath(path, "license_GPLv3");
                    var gpl = Encoding.UTF8.GetString(License.GPLv3);
                    if (!File.Exists(pathGPL)) File.WriteAllText(pathGPL, gpl);
                    var pathMIT = Utils.MakePath(path, "license_MIT");
                    var mit = Encoding.UTF8.GetString(License.MITlicense);
                    if (!File.Exists(pathMIT)) File.WriteAllText(pathMIT, mit);
                }
                catch (Exception ex)
                {
                    Trace.TraceError(ex.ToString());
                }


                
                if (Conf.IsFirstRun)
                {
                    if (!IsSteamFolder)
                    {
                        Utils.CreateDesktopShortcut();
                    }
                    if (Environment.OSVersion.Platform != PlatformID.Unix) Utils.RegisterProtocol();
                }

                MetaData = new MetaDataCache(SpringPaths);
                AutoJoinManager = new AutoJoinManager();
                EngineConfigurator = new EngineConfigurator(SpringPaths.WritableDirectory);

                SpringScanner = new PlasmaResourceChecker(SpringPaths);
                SpringScanner.LocalResourceAdded += (s, e) => Trace.TraceInformation("New resource found: {0}", e.Item.InternalName);
                SpringScanner.LocalResourceRemoved += (s, e) => Trace.TraceInformation("Resource removed: {0}", e.Item.InternalName);
                Downloader = new PlasmaDownloader.PlasmaDownloader(SpringScanner, SpringPaths); //rapid
                Downloader.DownloadAdded += (s, e) => Trace.TraceInformation("Download started: {0}", e.Data.Name);
                //Downloader.GetResource(DownloadType.ENGINE, GlobalConst.DefaultEngineOverride);

                var isLinux = Environment.OSVersion.Platform == PlatformID.Unix;
                TasClient = new TasClient(string.Format("ZK {0}{1}", SelfUpdater.CurrentVersion, isLinux ? " linux" : ""));

                SayCommandHandler = new SayCommandHandler(TasClient);

                ServerImages = new ServerImagesHandler(SpringPaths, TasClient);


                // log, for debugging
                TasClient.Connected += (s, e) => Trace.TraceInformation("TASC connected");
                TasClient.LoginAccepted += (s, e) =>
                {
                    Trace.TraceInformation("TASC login accepted");
                    Trace.TraceInformation("Server is using Spring version {0}", TasClient.ServerSpringVersion);
                    if (Environment.OSVersion.Platform == PlatformID.Unix || Conf.UseExternalBrowser) if (MainWindow != null) MainWindow.navigationControl.Path = "battles";
                };

                TasClient.LoginDenied += (s, e) => Trace.TraceInformation("TASC login denied");
                TasClient.ChannelJoined += (s, e) => { Trace.TraceInformation("TASC channel joined: " + e.Name); };
                TasClient.ConnectionLost += (s, e) => Trace.TraceInformation("Connection lost");
                TasClient.WelcomeReceived += (s, e) =>
                {
                    Downloader.GetResource(DownloadType.ENGINE, e.Engine);
                    Downloader.GetResource(DownloadType.RAPID, e.Game);
                };

                Program.AreYouReadyDialog = new AreYouReadyDialog(TasClient);

                // special handling
                TasClient.PreviewSaid += (s, e) =>
                {
                    var tas = (TasClient)s;
                    User user = null;
                    if (e.Data.UserName != null)
                    {
                        tas.ExistingUsers.TryGetValue(e.Data.UserName, out user);
                        if ((user != null && user.BanMute) || TasClient.Ignores.Contains(e.Data.UserName)) e.Cancel = true;
                    }
                };

                TasClient.SiteToLobbyCommandReceived += (eventArgs, o) =>
                {
                    if (MainWindow != null)
                    {
                        MainWindow.navigationControl.Path = o.Command;
                        MainWindow.PopupSelf();
                    }
                };

                ModStore = new ModStore();

                ConnectBar = new ConnectBar(TasClient);
                ToolTip = new ToolTipHandler();
                BrowserInterop = new BrowserInterop(TasClient, Conf);
                BattleIconManager = new BattleIconManager();
                Application.AddMessageFilter(ToolTip);

                SteamHandler = new ZklSteamHandler(TasClient);

                MainWindow = new MainWindow();

                Application.AddMessageFilter(new ScrollMessageFilter());

                MainWindow.Size = new Size(
                    Math.Min(SystemInformation.VirtualScreen.Width - 30, MainWindow.Width),
                    Math.Min(SystemInformation.VirtualScreen.Height - 30, MainWindow.Height)); //in case user have less space than 1024x768

                BattleBar = new BattleBar();
                VoteBar = new VoteBar();
                PwBar = new PwBar();
                MatchMakerBar = new MatchMakerBar(TasClient);

                SelfUpdater.ProgramUpdated += s =>
                {
                    Program.MainWindow.InvokeFunc(
                        () => WarningBar.DisplayWarning($"New version of Zero-K launcher downloaded, restart it to apply changes", "Restart", Restart));
                };
                if (!Debugger.IsAttached && !Conf.DisableAutoUpdate && !IsSteamFolder) SelfUpdater.StartChecking();

                if (GlobalConst.Mode != ModeType.Local) SteamHandler.Connect();
                Application.Run(MainWindow);

                ShutDown();
            }
            catch (Exception ex)
            {
                ErrorHandling.HandleException(ex, true);
                if (Debugger.IsAttached) Debugger.Break();
            }
            finally
            {
                ShutDown();
            }
            if (ErrorHandling.HasFatalException && !CloseOnNext)
            {
                if (Debugger.IsAttached) Debugger.Break();
                Application.Restart();
            }
        }
        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\";

            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());
        }
        void PerformUnitSyncOperation(WorkItem workItem)
        {
            Trace.TraceInformation("PerformUnitSyncOperation");
            VerifyUnitSync();

            if (unitSync == null)
            {
                Trace.TraceError("Skipping file after unitsync loading errors: {0}", workItem.CacheItem.ShortPath);
                CacheMarkFailedUnitSync(workItem.CacheItem.ShortPath);
                return;
            }

            var info = GetUnitSyncData(workItem.CacheItem.FileName);

            UnInitUnitsync();

            if (info != null)
            {
                workItem.CacheItem.InternalName = info.Name;
                workItem.CacheItem.ResourceType = info is Map ? ResourceType.Map : ResourceType.Mod;

                CacheItemAdd(workItem.CacheItem);

                var args = new CancelEventArgs <IResourceInfo>(info);
                UploadUnitsyncData.Invoke(this, args);
                if (args.Cancel)
                {
                    return;
                }

                var serializedData = MetaDataCache.SerializeAndCompressMetaData(info);

                var    map       = info as Map;
                object userState = null;
                try
                {
                    var creator = new TorrentCreator();
                    creator.Path = GetFullPath(workItem);
                    var ms = new MemoryStream();
                    creator.Create(ms);

                    byte[] minimap   = null;
                    byte[] metalMap  = null;
                    byte[] heightMap = null;
                    if (map != null)
                    {
                        minimap   = map.Minimap.ToBytes(ImageSize);
                        metalMap  = map.Metalmap.ToBytes(ImageSize);
                        heightMap = map.Heightmap.ToBytes(ImageSize);
                        userState = new MapRegisteredEventArgs(info.Name, map, minimap, metalMap, heightMap, serializedData);
                    }
                    var mod = info as Mod;
                    if (mod != null)
                    {
                        userState = new KeyValuePair <Mod, byte[]>(mod, serializedData);
                    }

                    Trace.TraceInformation("uploading {0} to server", info.Name);
                    Task.Factory.StartNew(() => {
                        ReturnValue e;
                        try {
                            e = service.RegisterResource(PlasmaServiceVersion, springPaths.SpringVersion, workItem.CacheItem.Md5.ToString(),
                                                         workItem.CacheItem.Length, info is Map ? ResourceType.Map : ResourceType.Mod, workItem.CacheItem.FileName, info.Name,
                                                         serializedData, mod != null ? mod.Dependencies.ToList() : null, minimap, metalMap, heightMap,
                                                         ms.ToArray());
                        } catch (Exception ex) {
                            Trace.TraceError("Error uploading data to server: {0}", ex);
                            return;
                        } finally {
                            Interlocked.Decrement(ref itemsSending);
                        }

                        if (e != ReturnValue.Ok)
                        {
                            Trace.TraceWarning("Resource registering failed: {0}", e);
                            return;
                        }
                        var mapArgs = userState as MapRegisteredEventArgs;
                        if (mapArgs != null)
                        {
                            var mapName = mapArgs.MapName;
                            MetaData.SaveMinimap(mapName, mapArgs.Minimap);
                            MetaData.SaveMetalmap(mapName, mapArgs.MetalMap);
                            MetaData.SaveHeightmap(mapName, mapArgs.HeightMap);
                            MetaData.SaveMetadata(mapName, mapArgs.SerializedData);
                            MapRegistered(this, mapArgs);
                        }
                        else
                        {
                            var kvp               = (KeyValuePair <Mod, byte[]>)userState;
                            var modInfo           = kvp.Key;
                            var serializedDataRet = kvp.Value;
                            MetaData.SaveMetadata(modInfo.Name, serializedDataRet);
                            ModRegistered(this, new EventArgs <Mod>(mod));
                        }
                    });

                    Interlocked.Increment(ref itemsSending);
                }
                catch (Exception e)
                {
                    Trace.TraceError("Error registering new resource {0}: {1}", workItem.CacheItem.ShortPath, e);
                }
            }
            else
            {
                Trace.TraceError("Could not unitsync file {0}", workItem.CacheItem.ShortPath);
                CacheMarkFailedUnitSync(workItem.CacheItem.ShortPath);
            }
            return;
        }