void LoadMod(MiniYaml yaml, string path = null, bool forceRegistration = false) { var mod = FieldLoader.Load<ExternalMod>(yaml); if (sheetBuilder != null) { var iconNode = yaml.Nodes.FirstOrDefault(n => n.Key == "Icon"); if (iconNode != null && !string.IsNullOrEmpty(iconNode.Value.Value)) using (var stream = new MemoryStream(Convert.FromBase64String(iconNode.Value.Value))) mod.Icon = sheetBuilder.Add(new Png(stream)); var icon2xNode = yaml.Nodes.FirstOrDefault(n => n.Key == "Icon2x"); if (icon2xNode != null && !string.IsNullOrEmpty(icon2xNode.Value.Value)) using (var stream = new MemoryStream(Convert.FromBase64String(icon2xNode.Value.Value))) mod.Icon2x = sheetBuilder.Add(new Png(stream), 1f / 2); var icon3xNode = yaml.Nodes.FirstOrDefault(n => n.Key == "Icon3x"); if (icon3xNode != null && !string.IsNullOrEmpty(icon3xNode.Value.Value)) using (var stream = new MemoryStream(Convert.FromBase64String(icon3xNode.Value.Value))) mod.Icon3x = sheetBuilder.Add(new Png(stream), 1f / 3); } // Avoid possibly overwriting a valid mod with an obviously bogus one var key = ExternalMod.MakeKey(mod); if ((forceRegistration || File.Exists(mod.LaunchPath)) && (path == null || Path.GetFileNameWithoutExtension(path) == key)) mods[key] = mod; }
public override void Init(ModData modData, Dictionary <string, string> info) { base.Init(modData, info); // Avoid standard loading mechanisms so we // can display the loadscreen as early as possible r = Game.Renderer; if (r == null) { return; } if (info.ContainsKey("Text")) { messages = info["Text"].Split(','); } if (info.ContainsKey("Palette")) { using (var stream = modData.DefaultFileSystem.Open(info["Palette"])) { palette = new ImmutablePalette(stream, new int[] { }); } hardwarePalette = new HardwarePalette(); hardwarePalette.AddPalette("loadscreen", palette, false); hardwarePalette.Initialize(); r.SetPalette(hardwarePalette); } if (info.ContainsKey("Image")) { using (var stream = modData.DefaultFileSystem.Open(info["Image"])) { CpsD2Loader loader = new CpsD2Loader(); if (!loader.TryParseSprite(stream, out frames)) { return; } } if (frames.Length == 0) { return; } sheetBuilder = new SheetBuilder(SheetType.Indexed, 512); logo = sheetBuilder.Add(frames[0]); logoPos = new float2((r.Resolution.Width - logo.Size.X) / 2, (r.Resolution.Height - logo.Size.Y) / 2); } }
void LoadMod(MiniYaml yaml) { var mod = FieldLoader.Load <ExternalMod>(yaml); var iconNode = yaml.Nodes.FirstOrDefault(n => n.Key == "Icon"); if (iconNode != null && !string.IsNullOrEmpty(iconNode.Value.Value)) { using (var stream = new MemoryStream(Convert.FromBase64String(iconNode.Value.Value))) using (var bitmap = new Bitmap(stream)) mod.Icon = sheetBuilder.Add(bitmap); } mods.Add(ExternalMod.MakeKey(mod), mod); }
Manifest LoadMod(string id, string path) { IReadOnlyPackage package = null; try { if (Directory.Exists(path)) { package = new Folder(path); } else { try { using (var fileStream = File.OpenRead(path)) package = new ZipFile(fileStream, path); } catch { throw new InvalidDataException(path + " is not a valid mod package"); } } if (!package.Contains("mod.yaml")) { throw new InvalidDataException(path + " is not a valid mod package"); } using (var stream = package.GetStream("icon.png")) if (stream != null) { using (var bitmap = new Bitmap(stream)) icons[id] = sheetBuilder.Add(bitmap); } // Mods in the support directory and oramod packages (which are listed later // in the CandidateMods list) override mods in the main install. return(new Manifest(id, package)); } catch (Exception) { if (package != null) { package.Dispose(); } return(null); } }
void LoadAsyncInternal() { Log.Write("debug", "MapCache.LoadAsyncInternal started"); // Milliseconds to wait on one loop when nothing to do var emptyDelay = 50; // Keep the thread alive for at least 5 seconds after the last minimap generation var maxKeepAlive = 5000 / emptyDelay; var keepAlive = maxKeepAlive; while (keepAlive-- > 0) { List <MapPreview> todo; lock (syncRoot) { todo = generateMinimap.Where(p => p.GetMinimap() == null).ToList(); generateMinimap.Clear(); } if (todo.Count == 0) { Thread.Sleep(emptyDelay); continue; } else { keepAlive = maxKeepAlive; } // Render the minimap into the shared sheet foreach (var p in todo) { // The rendering is thread safe because it only reads from the passed instances and writes to a new bitmap var bitmap = p.CustomPreview ?? Minimap.RenderMapPreview(modData.DefaultRules.TileSets[p.Map.Tileset], p.Map, modData.DefaultRules, true); // Note: this is not generally thread-safe, but it works here because: // (a) This worker is the only thread writing to this sheet // (b) The main thread is the only thread reading this sheet // (c) The sheet is marked dirty after the write is completed, // which causes the main thread to copy this to the texture during // the next render cycle. // (d) Any partially written bytes from the next minimap is in an // unallocated area, and will be committed in the next cycle. p.SetMinimap(sheetBuilder.Add(bitmap)); // Yuck... But this helps the UI Jank when opening the map selector significantly. Thread.Sleep(Environment.ProcessorCount == 1 ? 25 : 5); } } Log.Write("debug", "MapCache.LoadAsyncInternal ended"); }
Manifest LoadMod(string id, string path) { IReadOnlyPackage package = null; try { if (!Directory.Exists(path)) { Log.Write("debug", path + " is not a valid mod package"); return(null); } package = new Folder(path); if (package.Contains("mod.yaml")) { var manifest = new Manifest(id, package); if (package.Contains("icon.png")) { using (var stream = package.GetStream("icon.png")) if (stream != null) { using (var bitmap = new Bitmap(stream)) icons[id] = sheetBuilder.Add(bitmap); } } else if (!manifest.Metadata.Hidden) { Log.Write("debug", "Mod '{0}' is missing 'icon.png'.".F(path)); } return(manifest); } } catch (Exception e) { Log.Write("debug", "Load mod '{0}': {1}".F(path, e)); } if (package != null) { package.Dispose(); } return(null); }
static Sheet SpriteFrameToSheet(ISpriteFrame frame, PaletteReference p) { var size = Exts.NextPowerOf2(Math.Max(frame.FrameSize.Width, frame.FrameSize.Height)); SheetBuilder sheetBuilder = new SheetBuilder(SheetType.BGRA, size); byte[] data; if (frame.Type == SpriteFrameType.Indexed) { data = IndexedSpriteFrameToData(frame, p); } else { data = frame.Data; } var sprite = sheetBuilder.Add(data, frame.FrameSize); return(sprite.Sheet); }
void LoadMod(MiniYaml yaml, string path = null) { var mod = FieldLoader.Load <ExternalMod>(yaml); var iconNode = yaml.Nodes.FirstOrDefault(n => n.Key == "Icon"); if (iconNode != null && !string.IsNullOrEmpty(iconNode.Value.Value)) { using (var stream = new MemoryStream(Convert.FromBase64String(iconNode.Value.Value))) using (var bitmap = new Bitmap(stream)) mod.Icon = sheetBuilder.Add(bitmap); } // Avoid possibly overwriting a valid mod with an obviously bogus one var key = ExternalMod.MakeKey(mod); if (File.Exists(mod.LaunchPath) && (path == null || Path.GetFileNameWithoutExtension(path) == key)) { mods[key] = mod; } }
void LoadAsyncInternal() { for (;;) { MapPreview p; lock (syncRoot) { if (generateMinimap.Count == 0) { break; } p = generateMinimap.Peek(); // Preview already exists if (p.Minimap != null) { generateMinimap.Dequeue(); continue; } } // Render the minimap into the shared sheet // Note: this is not generally thread-safe, but it works here because: // (a) This worker is the only thread writing to this sheet // (b) The main thread is the only thread reading this sheet // (c) The sheet is marked dirty after the write is completed, // which causes the main thread to copy this to the texture during // the next render cycle. // (d) Any partially written bytes from the next minimap is in an // unallocated area, and will be committed in the next cycle. var bitmap = p.CustomPreview ?? Minimap.RenderMapPreview(modData.DefaultRules.TileSets[p.Map.Tileset], p.Map, modData.DefaultRules, true); p.Minimap = sheetBuilder.Add(bitmap); lock (syncRoot) generateMinimap.Dequeue(); // Yuck... But this helps the UI Jank when opening the map selector significantly. Thread.Sleep(50); } }
Manifest LoadMod(string id, string path) { IReadOnlyPackage package = null; try { if (!Directory.Exists(path)) { throw new InvalidDataException(path + " is not a valid mod package"); } package = new Folder(path); if (!package.Contains("mod.yaml")) { throw new InvalidDataException(path + " is not a valid mod package"); } using (var stream = package.GetStream("icon.png")) if (stream != null) { using (var bitmap = new Bitmap(stream)) icons[id] = sheetBuilder.Add(bitmap); } return(new Manifest(id, package)); } catch (Exception) { if (package != null) { package.Dispose(); } return(null); } }
public override void Draw() { if (video == null) { return; } var sheetBuilder = new SheetBuilder(SheetType.Indexed, 512); var videoSprite = sheetBuilder.Add(video.Frame); Game.Renderer.EnableScissor(RenderBounds); Game.Renderer.RgbaColorRenderer.FillRect( new float2(RenderBounds.Left, RenderBounds.Top), new float2(RenderBounds.Right, RenderBounds.Bottom), OpenRA.Primitives.Color.Black); Game.Renderer.DisableScissor(); Game.Renderer.SpriteRenderer.DrawSprite(videoSprite, videoOrigin, pr, videoSize); /* * Game.Renderer.RgbaSpriteRenderer.DrawSprite( * videoSprite, * videoOrigin, * videoSize); */ if (!stopped && !paused) { if (video.CurrentFrame >= video.Length - 1) { Stop(); return; } video.AdvanceFrame(); } }
public ModBrowserLogic(Widget widget) { var panel = widget; var loadButton = panel.Get <ButtonWidget>("LOAD_BUTTON"); loadButton.OnClick = () => LoadMod(selectedMod); loadButton.IsDisabled = () => selectedMod.Id == Game.ModData.Manifest.Mod.Id; panel.Get <ButtonWidget>("QUIT_BUTTON").OnClick = Game.Exit; modList = panel.Get("MOD_LIST"); modTemplate = modList.Get <ButtonWidget>("MOD_TEMPLATE"); panel.Get <LabelWidget>("MOD_DESC").GetText = () => selectedDescription; panel.Get <LabelWidget>("MOD_TITLE").GetText = () => selectedMod.Title; panel.Get <LabelWidget>("MOD_AUTHOR").GetText = () => selectedAuthor; panel.Get <LabelWidget>("MOD_VERSION").GetText = () => selectedMod.Version; var prevMod = panel.Get <ButtonWidget>("PREV_MOD"); prevMod.OnClick = () => { modOffset -= 1; RebuildModList(); }; prevMod.IsVisible = () => modOffset > 0; var nextMod = panel.Get <ButtonWidget>("NEXT_MOD"); nextMod.OnClick = () => { modOffset += 1; RebuildModList(); }; nextMod.IsVisible = () => modOffset + 5 < allMods.Length; panel.Get <RGBASpriteWidget>("MOD_PREVIEW").GetSprite = () => { Sprite ret = null; previews.TryGetValue(selectedMod.Id, out ret); return(ret); }; sheetBuilder = new SheetBuilder(SheetType.BGRA); allMods = ModMetadata.AllMods.Values.Where(m => !m.Hidden) .OrderBy(m => m.Title) .ToArray(); // Load preview images, and eat any errors foreach (var mod in allMods) { try { using (var preview = new Bitmap(Platform.ResolvePath(".", "mods", mod.Id, "preview.png"))) if (preview.Width == 296 && preview.Height == 196) { previews.Add(mod.Id, sheetBuilder.Add(preview)); } } catch (Exception) { } try { using (var logo = new Bitmap(Platform.ResolvePath(".", "mods", mod.Id, "logo.png"))) if (logo.Width == 96 && logo.Height == 96) { logos.Add(mod.Id, sheetBuilder.Add(logo)); } } catch (Exception) { } } ModMetadata initialMod = null; ModMetadata.AllMods.TryGetValue(Game.Settings.Game.PreviousMod, out initialMod); SelectMod(initialMod ?? ModMetadata.AllMods["ra"]); RebuildModList(); }
public ModBrowserLogic(Widget widget, ModData modData) { modInstallStatus = new Cache <ModMetadata, bool>(IsModInstalled); modPrerequisitesFulfilled = new Cache <string, bool>(Game.IsModInstalled); modChooserPanel = widget; loadButton = modChooserPanel.Get <ButtonWidget>("LOAD_BUTTON"); loadButton.OnClick = () => LoadMod(selectedMod); loadButton.IsDisabled = () => selectedMod.Id == modData.Manifest.Mod.Id; modChooserPanel.Get <ButtonWidget>("QUIT_BUTTON").OnClick = Game.Exit; modList = modChooserPanel.Get("MOD_LIST"); modTemplate = modList.Get <ButtonWidget>("MOD_TEMPLATE"); modChooserPanel.Get <LabelWidget>("MOD_DESC").GetText = () => selectedDescription; modChooserPanel.Get <LabelWidget>("MOD_TITLE").GetText = () => selectedMod.Title; modChooserPanel.Get <LabelWidget>("MOD_AUTHOR").GetText = () => selectedAuthor; modChooserPanel.Get <LabelWidget>("MOD_VERSION").GetText = () => selectedMod.Version; var prevMod = modChooserPanel.Get <ButtonWidget>("PREV_MOD"); prevMod.OnClick = () => { modOffset -= 1; RebuildModList(); }; prevMod.IsVisible = () => modOffset > 0; var nextMod = modChooserPanel.Get <ButtonWidget>("NEXT_MOD"); nextMod.OnClick = () => { modOffset += 1; RebuildModList(); }; nextMod.IsVisible = () => modOffset + 5 < allMods.Length; modChooserPanel.Get <RGBASpriteWidget>("MOD_PREVIEW").GetSprite = () => { Sprite ret = null; previews.TryGetValue(selectedMod.Id, out ret); return(ret); }; sheetBuilder = new SheetBuilder(SheetType.BGRA); allMods = ModMetadata.AllMods.Values.Where(m => !m.Hidden) .OrderBy(m => m.Title) .ToArray(); // Load preview images, and eat any errors foreach (var mod in allMods) { try { using (var stream = ModMetadata.AllMods[mod.Id].Package.GetStream("preview.png")) using (var preview = new Bitmap(stream)) if (preview.Width == 296 && preview.Height == 196) { previews.Add(mod.Id, sheetBuilder.Add(preview)); } } catch (Exception) { } try { using (var stream = ModMetadata.AllMods[mod.Id].Package.GetStream("logo.png")) using (var logo = new Bitmap(stream)) if (logo.Width == 96 && logo.Height == 96) { logos.Add(mod.Id, sheetBuilder.Add(logo)); } } catch (Exception) { } } ModMetadata initialMod; ModMetadata.AllMods.TryGetValue(Game.Settings.Game.PreviousMod, out initialMod); SelectMod(initialMod != null && initialMod.Id != "modchooser" ? initialMod : ModMetadata.AllMods["ra"]); RebuildModList(); }
void LoadAsyncInternal() { //Log.Write("debug", "MapCache.LoadAsyncInternal started"); // Milliseconds to wait on one loop when nothing to do var emptyDelay = 50; // Keep the thread alive for at least 5 seconds after the last minimap generation var maxKeepAlive = 5000 / emptyDelay; var keepAlive = maxKeepAlive; for (; ;) { List <MapPreview> todo; lock (syncRoot) { todo = generateMinimap.Where(p => p.GetMinimap() == null).ToList(); generateMinimap.Clear(); if (keepAlive > 0) { keepAlive--; } if (keepAlive == 0 && todo.Count == 0) { previewLoaderThreadShutDown = true; break; } } if (todo.Count == 0) { Thread.Sleep(emptyDelay); continue; } else { keepAlive = maxKeepAlive; } // Render the minimap into the shared sheet foreach (var p in todo) { if (p.Preview != null) { WarGame.RunAfterTick(() => { try { p.SetMinimap(sheetBuilder.Add(p.Preview)); } catch (Exception e) { //Log.Write("debug", "Failed to load minimap with exception: {0}", e); } }); } // Yuck... But this helps the UI Jank when opening the map selector significantly. Thread.Sleep(Environment.ProcessorCount == 1 ? 25 : 5); } } // The buffer is not fully reclaimed until changes are written out to the texture. // We will access the texture in order to force changes to be written out, allowing the buffer to be freed. WarGame.RunAfterTick(() => { sheetBuilder.Current.ReleaseBuffer(); sheetBuilder.Current.GetTexture(); }); //Log.Write("debug", "MapCache.LoadAsyncInternal ended"); }
public void Draw2() { //вызовы SetPalette в Draw для UI элементов, конкурируют с RefreshPalette в World.Draw. //Game.Renderer.SetPalette(hardwarePalette); //теперь не нужно, так как обнаружен файл palettes.yaml, в котором все палитры есть и сделано через него. if (String.IsNullOrEmpty(cachedVideo)) { return; } //if (video==null) //{ // return; //} //Game.RunTime MilliSeconds 1s=1000ms=50ms*20times var deltaScale = Game.RunTime - lastDrawTime; CountForWaitNextFrameMs += deltaScale; //if we need pause wait it if (CountForPause > PauseInSeconds * 1000) { if (VideoStackList != null) {//only move next, first video must be dequed from PlayVideoStack if (VideoStackList.Count > 0) { CountForPause = 0; CountForWaitNextFrameMs = 0; Load(VideoStackList.Dequeue()); lastDrawTime = Game.RunTime; stopped = paused = false; return; } //stop video } //нужно остановить медиа=сцену и передать контроль дальше cachedVideo = null; Exit(); return; } if (CountForWaitNextFrameMs < DrawPrevFrameEveryXMs) //code runs every tick before Next Video frame to fill the gap { if (prevSprite != null) { //just draw the same frame Game.Renderer.SpriteRenderer.DrawSprite(prevSprite, videoOrigin, pr, videoSize); } if (prevText != null) { DrawWsaText(prevText); } return; } else { if (video != null && prevSprite != null) { if (video.CurrentFrame >= video.Length - 1) //this code runs every DrawFrameEveryXMilliseconds when video is ended. { //on video last frame draw always last frame Game.Renderer.SpriteRenderer.DrawSprite(prevSprite, videoOrigin, pr, videoSize); CountForPause += deltaScale; //incerease CountForPause to enter at if (CountForPause > PauseInSeconds * 1000) lastDrawTime = Game.RunTime; if (prevText != null) { DrawWsaText(prevText); } return; } //if not last frame of video, move next frame video.AdvanceFrame(); } if (image != null && prevSprite != null) { Game.Renderer.SpriteRenderer.DrawSprite(prevSprite, videoOrigin, pr, videoSize); CountForPause += deltaScale; //incerease CountForPause to enter at if (CountForPause > PauseInSeconds * 1000) lastDrawTime = Game.RunTime; return; } if (prevText != null) { DrawWsaText(prevText); } //|| //\/ } if (video != null) { if (frameSoundLine == null) { } else { if (frameSoundLine.Contains(new FrameSoundLine() { WSAfilename = cachedVideo, FrameNumber = video.CurrentFrame })) { var vocfilename = frameSoundLine.Find(x => x.WSAfilename.Contains(cachedVideo) && x.FrameNumber == video.CurrentFrame).VOCfilename; if (vocfilename.Contains("ADL")) { IReadOnlyFileSystem fileSystem = Game.ModData.DefaultFileSystem; if (!fileSystem.Exists(vocfilename)) { Log.Write("sound", "LoadSound, file does not exist: {0}", vocfilename); } DuneMusic.Quit(); DuneMusic.Init(44100, "", DuneMusic.DuneMusicOplEmu.kOplEmuNuked); using (var stream = fileSystem.Open(vocfilename)) { DuneMusic.InsertMemoryFile("test", stream.ReadAllBytes()); byte[] temp = new byte[28106880]; UIntPtr temp3; temp3 = (UIntPtr)1000000; temp3 = DuneMusic.SynthesizeAudio("test", 52, -1, temp, (UIntPtr)temp.Length); ISoundSource soundSource; soundSource = Game.Sound.soundEngine.AddSoundSourceFromMemory(temp, 2, 16, 44100); ISound temp2 = Game.Sound.soundEngine.Play2D(Game.LocalTick, soundSource, false, true, WPos.Zero, 100, false); } } else { Game.Sound.Play(SoundType.UI, vocfilename); } } } if (frameTextLine == null) { prevText = new FrameTextLine() { Text = "" }; DrawWsaText(prevText); } else { if (frameTextLine.Contains(new FrameTextLine() { WSAfilename = cachedVideo, FrameNumber = video.CurrentFrame })) { FrameTextLine ft = frameTextLine.Find(x => x.WSAfilename.Contains(cachedVideo) && x.FrameNumber == video.CurrentFrame); DrawWsaText(ft); prevText = ft; } } } var sheetBuilder = new SheetBuilder(SheetType.Indexed, 512); //router for WSA frame or CPS frame Sprite videoSprite = null; if (cachedVideo.Contains("WSA")) { videoSprite = sheetBuilder.Add(video.Frame); } else { //videoSprite = new Sprite(sheetBuilder.Current, new Rectangle(0, 0, 320, 200), TextureChannel.RGBA); videoSprite = sheetBuilder.Add(imageSprite[0]); //дампинг ресурсов игры в png //videoSprite.Sheet.CreateBuffer(); //videoSprite.Sheet.ReleaseBuffer(); ////videoSprite.Sheet.AsPng().Save("VIRGIN.png"); //IPalette exppal; //try //{ // exppal = hardwarePalette.GetPalette(cachedVideo); //} //catch (Exception) //{ // exppal = null; //} //if (exppal==null) //{ // LoadPalette(); // videoSprite.Sheet.AsPng(TextureChannel.Blue, hardwarePalette.GetPalette("chrome")).Save(cachedVideo + ".png"); //} //else //{ // videoSprite.Sheet.AsPng(TextureChannel.Blue, exppal).Save(cachedVideo + ".png"); //} } prevSprite = videoSprite; Game.Renderer.SpriteRenderer.DrawSprite(videoSprite, videoOrigin, pr, videoSize); CountForWaitNextFrameMs = 0; lastDrawTime = Game.RunTime; }
public override void Init(ModData modData, Dictionary <string, string> info) { base.Init(modData, info); this.modData = modData; this.info = info; /* * Unpack files needed, because in some PAK files, some VOC files can have prefix 'Z' * Unpacking files will unpack such files and rename. so no modifications in yaml needed. * LoadScreen.Init, possibly not the best place to do this, but need to do that early, before * data will be used. and do this in LoadScreen.Init just works fine. */ if (D2UnpackContent.UnpackFiles(modData, info) > 0) { // Some files unpacked. need to reload mod packages modData.ModFiles.LoadFromManifest(modData.Manifest); } /* * Like for unpack files, OpenRA engine do not have proper place for import maps. * And can't import in LoadScreen.Init, because engine not ready. * but Game.OnShellmapLoaded just works. */ Game.OnShellmapLoaded += ImportOriginalMaps; // Avoid standard loading mechanisms so we // can display the loadscreen as early as possible r = Game.Renderer; if (r == null) { return; } if (info.ContainsKey("Text")) { messages = info["Text"].Split(','); } if (info.ContainsKey("Palette")) { using (var stream = modData.DefaultFileSystem.Open(info["Palette"])) palette = new ImmutablePalette(stream, new int[] { }); hardwarePalette = new HardwarePalette(); hardwarePalette.AddPalette("loadscreen", palette, false); hardwarePalette.Initialize(); r.SetPalette(hardwarePalette); var pal = hardwarePalette.GetPalette("loadscreen"); pr = new PaletteReference("loadscreenref", hardwarePalette.GetPaletteIndex("loadscreen"), pal, hardwarePalette); } if (info.ContainsKey("Image")) { using (var stream = modData.DefaultFileSystem.Open(info["Image"])) { CpsD2Loader loader = new CpsD2Loader(); TypeDictionary metadata; if (!loader.TryParseSprite(stream, out frames, out metadata)) { return; } } if (frames.Length == 0) { return; } sheetBuilder = new SheetBuilder(SheetType.Indexed, 512); logo = sheetBuilder.Add(frames[0]); logoPos = new float2((r.Resolution.Width - logo.Size.X) / 2, (r.Resolution.Height - logo.Size.Y) / 2); } }
void LoadAsyncInternal() { Log.Write("debug", "MapCache.LoadAsyncInternal started"); // Milliseconds to wait on one loop when nothing to do var emptyDelay = 50; // Keep the thread alive for at least 5 seconds after the last minimap generation var maxKeepAlive = 5000 / emptyDelay; var keepAlive = maxKeepAlive; for (;;) { List <MapPreview> todo; lock (syncRoot) { todo = generateMinimap.Where(p => p.GetMinimap() == null).ToList(); generateMinimap.Clear(); if (keepAlive > 0) { keepAlive--; } if (keepAlive == 0 && todo.Count == 0) { previewLoaderThreadShutDown = true; break; } } if (todo.Count == 0) { Thread.Sleep(emptyDelay); continue; } else { keepAlive = maxKeepAlive; } // Render the minimap into the shared sheet foreach (var p in todo) { // The rendering is thread safe because it only reads from the passed instances and writes to a new bitmap var createdPreview = false; var bitmap = p.CustomPreview; if (bitmap == null) { createdPreview = true; bitmap = Minimap.RenderMapPreview(modData.DefaultRules.TileSets[p.Map.Tileset], p.Map, modData.DefaultRules, true); } Game.RunAfterTick(() => { try { p.SetMinimap(sheetBuilder.Add(bitmap)); } finally { if (createdPreview) { bitmap.Dispose(); } } }); // Yuck... But this helps the UI Jank when opening the map selector significantly. Thread.Sleep(Environment.ProcessorCount == 1 ? 25 : 5); } } // The buffer is not fully reclaimed until changes are written out to the texture. // We will access the texture in order to force changes to be written out, allowing the buffer to be freed. Game.RunAfterTick(() => { sheetBuilder.Current.ReleaseBuffer(); sheetBuilder.Current.GetTexture(); }); Log.Write("debug", "MapCache.LoadAsyncInternal ended"); }
public ModBrowserLogic(Widget widget, ModData modData) { modChooserPanel = widget; loadButton = modChooserPanel.Get <ButtonWidget>("LOAD_BUTTON"); loadButton.OnClick = () => LoadMod(selectedMod); loadButton.IsDisabled = () => selectedMod.Id == modData.Manifest.Id; var contentButton = modChooserPanel.Get <ButtonWidget>("CONFIGURE_BUTTON"); contentButton.OnClick = () => { var widgetArgs = new WidgetArgs { { "mod", selectedMod }, { "content", content[selectedMod] }, { "onCancel", () => { } } }; Ui.OpenWindow("CONTENT_PANEL", widgetArgs); }; modChooserPanel.Get <ButtonWidget>("QUIT_BUTTON").OnClick = Game.Exit; modList = modChooserPanel.Get("MOD_LIST"); modTemplate = modList.Get <ButtonWidget>("MOD_TEMPLATE"); modChooserPanel.Get <LabelWidget>("MOD_DESC").GetText = () => selectedDescription; modChooserPanel.Get <LabelWidget>("MOD_TITLE").GetText = () => selectedMod.Metadata.Title; modChooserPanel.Get <LabelWidget>("MOD_AUTHOR").GetText = () => selectedAuthor; modChooserPanel.Get <LabelWidget>("MOD_VERSION").GetText = () => selectedMod.Metadata.Version; var prevMod = modChooserPanel.Get <ButtonWidget>("PREV_MOD"); prevMod.OnClick = () => { modOffset -= 1; RebuildModList(); }; prevMod.IsVisible = () => modOffset > 0; var nextMod = modChooserPanel.Get <ButtonWidget>("NEXT_MOD"); nextMod.OnClick = () => { modOffset += 1; RebuildModList(); }; nextMod.IsVisible = () => modOffset + 5 < allMods.Length; modChooserPanel.Get <RGBASpriteWidget>("MOD_PREVIEW").GetSprite = () => { Sprite ret = null; previews.TryGetValue(selectedMod.Id, out ret); return(ret); }; sheetBuilder = new SheetBuilder(SheetType.BGRA); allMods = Game.Mods.Values.Where(m => !m.Metadata.Hidden) .OrderBy(m => m.Metadata.Title) .ToArray(); // Load preview images, and eat any errors foreach (var mod in allMods) { try { using (var stream = mod.Package.GetStream("preview.png")) using (var preview = new Bitmap(stream)) if (preview.Width == 296 && preview.Height == 196) { previews.Add(mod.Id, sheetBuilder.Add(preview)); } } catch (Exception) { } try { using (var stream = mod.Package.GetStream("logo.png")) using (var logo = new Bitmap(stream)) if (logo.Width == 96 && logo.Height == 96) { logos.Add(mod.Id, sheetBuilder.Add(logo)); } } catch (Exception) { } } Manifest initialMod; Game.Mods.TryGetValue(Game.Settings.Game.PreviousMod, out initialMod); SelectMod(initialMod != null && initialMod.Id != "modchooser" ? initialMod : Game.Mods["ra"]); RebuildModList(); }
public DefaultTileCache(DefaultTerrain terrainInfo, Action <uint, string> onMissingImage = null) { var allocated = false; Func <Sheet> allocate = () => { if (allocated) { throw new SheetOverflowException("Terrain sheet overflow. Try increasing the tileset SheetSize parameter."); } allocated = true; return(new Sheet(SheetType.Indexed, new Size(terrainInfo.SheetSize, terrainInfo.SheetSize))); }; random = new MersenneTwister(); var frameCache = new FrameCache(Game.ModData.DefaultFileSystem, Game.ModData.SpriteLoaders); foreach (var t in terrainInfo.Templates) { var variants = new List <Sprite[]>(); var templateInfo = (DefaultTerrainTemplateInfo)t.Value; foreach (var i in templateInfo.Images) { ISpriteFrame[] allFrames; if (onMissingImage != null) { try { allFrames = frameCache[i]; } catch (FileNotFoundException) { onMissingImage(t.Key, i); continue; } } else { allFrames = frameCache[i]; } var frameCount = terrainInfo.EnableDepth ? allFrames.Length / 2 : allFrames.Length; var indices = templateInfo.Frames != null ? templateInfo.Frames : Exts.MakeArray(t.Value.TilesCount, j => j); var start = indices.Min(); var end = indices.Max(); if (start < 0 || end >= frameCount) { throw new YamlException("Template `{0}` uses frames [{1}..{2}] of {3}, but only [0..{4}] actually exist" .F(t.Key, start, end, i, frameCount - 1)); } variants.Add(indices.Select(j => { var f = allFrames[j]; var tile = t.Value.Contains(j) ? (DefaultTerrainTileInfo)t.Value[j] : null; // The internal z axis is inverted from expectation (negative is closer) var zOffset = tile != null ? -tile.ZOffset : 0; var zRamp = tile != null ? tile.ZRamp : 1f; var offset = new float3(f.Offset, zOffset); var type = SheetBuilder.FrameTypeToSheetType(f.Type); // Defer SheetBuilder creation until we know what type of frames we are loading! // TODO: Support mixed indexed and BGRA frames if (sheetBuilder == null) { sheetBuilder = new SheetBuilder(SheetBuilder.FrameTypeToSheetType(f.Type), allocate); } else if (type != sheetBuilder.Type) { throw new YamlException("Sprite type mismatch. Terrain sprites must all be either Indexed or RGBA."); } var s = sheetBuilder.Allocate(f.Size, zRamp, offset); OpenRA.Graphics.Util.FastCopyIntoChannel(s, f.Data, f.Type); if (terrainInfo.EnableDepth) { var depthFrame = allFrames[j + frameCount]; var ss = sheetBuilder.Allocate(f.Size, zRamp, offset); OpenRA.Graphics.Util.FastCopyIntoChannel(ss, depthFrame.Data, depthFrame.Type); // s and ss are guaranteed to use the same sheet // because of the custom terrain sheet allocation s = new SpriteWithSecondaryData(s, s.Sheet, ss.Bounds, ss.Channel); } return(s); }).ToArray()); } var allSprites = variants.SelectMany(s => s); // Ignore the offsets baked into R8 sprites if (terrainInfo.IgnoreTileSpriteOffsets) { allSprites = allSprites.Select(s => new Sprite(s.Sheet, s.Bounds, s.ZRamp, new float3(float2.Zero, s.Offset.Z), s.Channel, s.BlendMode)); } if (onMissingImage != null && !variants.Any()) { continue; } templates.Add(t.Value.Id, new TheaterTemplate(allSprites.ToArray(), variants.First().Count(), templateInfo.Images.Length)); } // 1x1px transparent tile if (sheetBuilder.Type == SheetType.BGRA) { missingTile = sheetBuilder.Add(new byte[4], SpriteFrameType.Bgra32, new Size(1, 1)); } else { missingTile = sheetBuilder.Add(new byte[1], SpriteFrameType.Indexed8, new Size(1, 1)); } Sheet.ReleaseBuffer(); }