Rewrite code to avoid usage of Dictionary

This commit is contained in:
UnknownShadow200 2017-09-15 17:38:33 +10:00
parent 7303e8c2e4
commit db4275f571
25 changed files with 300 additions and 361 deletions

View file

@ -1,79 +0,0 @@
// Copyright 2014-2017 ClassicalSharp | Licensed under BSD-3
#if ANDROID
using System;
using ClassicalSharp.GraphicsAPI;
using Android.Graphics;
using Android.Graphics.Drawables;
using System.Drawing;
namespace ClassicalSharp {
public sealed partial class CanvasDrawer2D {
Bitmap measuringBmp;
Canvas measuringC;
public CanvasDrawer2D(IGraphicsApi graphics) {
this.graphics = graphics;
measuringBmp = Bitmap.CreateBitmap(1, 1, Bitmap.Config.Argb8888);
measuringC = new Canvas(measuringBmp);
}
protected override void DrawSysText(ref DrawTextArgs args, int x, int y) {
if (!args.SkipPartsCheck)
GetTextParts(args.Text);
float textX = x;
Paint backBrush = GetOrCreateBrush(FastColour.Black);
for (int i = 0; i < parts.Count; i++) {
TextPart part = parts[i];
Paint foreBrush = GetOrCreateBrush(part.Col);
if (args.UseShadow)
c.DrawText(part.Text, textX + Offset, y + Offset, backBrush);
c.DrawText(part.Text, textX, y, foreBrush);
textX += foreBrush.MeasureText(part.Text);
}
}
public override void DrawClippedText(ref DrawTextArgs args, int x, int y, float maxWidth, float maxHeight) {
throw new NotImplementedException();
}
FastBitmap bitmapWrapper = new FastBitmap();
protected override void DrawBitmappedText(ref DrawTextArgs args, int x, int y) {
using (bitmapWrapper) {
bitmapWrapper.SetData(curBmp, true, false);
DrawBitmapTextImpl(bitmapWrapper, ref args, x, y);
}
}
protected override Size MeasureSysSize(ref DrawTextArgs args) {
GetTextParts(args.Text);
if (parts.Count == 0)
return Size.Empty;
SizeF total = SizeF.Empty;
for (int i = 0; i < parts.Count; i++) {
TextPart part = parts[i];
Paint textBrush = GetOrCreateBrush(part.Col);
total.Width += textBrush.MeasureText(part.Text);
}
total.Height = PtToPx(args.Font.Size);
if (args.UseShadow) {
total.Width += Offset; total.Height += Offset;
}
return Size.Ceiling(total);
}
int PtToPx(int point) {
return (int)Math.Ceiling((float)point / 72 * 96); // TODO: not sure if even right, non 96 dpi?
}
void DisposeText() {
measuringC.Dispose();
measuringBmp.Dispose();
}
}
}
#endif

View file

@ -2,16 +2,24 @@
#if ANDROID #if ANDROID
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using ClassicalSharp.GraphicsAPI;
using System.Drawing;
using Android.Graphics; using Android.Graphics;
using Android.Graphics.Drawables; using Android.Graphics.Drawables;
namespace ClassicalSharp { namespace ClassicalSharp {
public sealed partial class CanvasDrawer2D : IDrawer2D { public sealed class CanvasDrawer2D : IDrawer2D {
Dictionary<int, Paint> brushCache = new Dictionary<int, Paint>(16); Dictionary<int, Paint> brushCache = new Dictionary<int, Paint>(16);
Bitmap curBmp; Bitmap curBmp, measuringBmp;
Canvas c; Canvas c, measuringC;
public CanvasDrawer2D(IGraphicsApi graphics) {
this.graphics = graphics;
measuringBmp = Bitmap.CreateBitmap(1, 1, Bitmap.Config.Argb8888);
measuringC = new Canvas(measuringBmp);
}
public override void SetBitmap(Bitmap bmp) { public override void SetBitmap(Bitmap bmp) {
if (c != null) { if (c != null) {
@ -78,6 +86,62 @@ namespace ClassicalSharp {
brushCache[key] = brush; brushCache[key] = brush;
return brush; return brush;
} }
protected override void DrawSysText(ref DrawTextArgs args, int x, int y) {
if (!args.SkipPartsCheck)
GetTextParts(args.Text);
float textX = x;
Paint backBrush = GetOrCreateBrush(FastColour.Black);
for (int i = 0; i < parts.Count; i++) {
TextPart part = parts[i];
Paint foreBrush = GetOrCreateBrush(part.Col);
if (args.UseShadow)
c.DrawText(part.Text, textX + Offset, y + Offset, backBrush);
c.DrawText(part.Text, textX, y, foreBrush);
textX += foreBrush.MeasureText(part.Text);
}
}
public override void DrawClippedText(ref DrawTextArgs args, int x, int y, float maxWidth, float maxHeight) {
throw new NotImplementedException();
}
FastBitmap bitmapWrapper = new FastBitmap();
protected override void DrawBitmappedText(ref DrawTextArgs args, int x, int y) {
using (bitmapWrapper) {
bitmapWrapper.SetData(curBmp, true, false);
DrawBitmapTextImpl(bitmapWrapper, ref args, x, y);
}
}
protected override Size MeasureSysSize(ref DrawTextArgs args) {
GetTextParts(args.Text);
if (parts.Count == 0)
return Size.Empty;
SizeF total = SizeF.Empty;
for (int i = 0; i < parts.Count; i++) {
TextPart part = parts[i];
Paint textBrush = GetOrCreateBrush(part.Col);
total.Width += textBrush.MeasureText(part.Text);
}
total.Height = PtToPx(args.Font.Size);
if (args.UseShadow) {
total.Width += Offset; total.Height += Offset;
}
return Size.Ceiling(total);
}
int PtToPx(int point) {
return (int)Math.Ceiling((float)point / 72 * 96); // TODO: not sure if even right, non 96 dpi?
}
void DisposeText() {
measuringC.Dispose();
measuringBmp.Dispose();
}
} }
} }
#endif #endif

View file

@ -1,22 +0,0 @@
// Copyright 2014-2017 ClassicalSharp | Licensed under BSD-3
using System;
using System.Drawing;
namespace ClassicalSharp {
/// <summary> Contains arguments for measuring or drawing text. </summary>
public struct DrawTextArgs {
public string Text;
public Font Font;
public bool UseShadow;
public bool SkipPartsCheck;
public DrawTextArgs(string text, Font font, bool useShadow) {
Text = text;
Font = font;
UseShadow = useShadow;
SkipPartsCheck = false;
}
}
}

View file

@ -1,107 +0,0 @@
// Copyright 2014-2017 ClassicalSharp | Licensed under BSD-3
#if !ANDROID
using System;
using System.Drawing;
using System.Drawing.Text;
#if !LAUNCHER
using ClassicalSharp.GraphicsAPI;
#endif
namespace ClassicalSharp {
public sealed partial class GdiPlusDrawer2D {
StringFormat format;
Bitmap measuringBmp;
Graphics measuringGraphics;
#if !LAUNCHER
public GdiPlusDrawer2D(IGraphicsApi graphics) {
this.graphics = graphics;
#else
public GdiPlusDrawer2D() {
#endif
format = StringFormat.GenericTypographic;
format.FormatFlags |= StringFormatFlags.MeasureTrailingSpaces;
format.Trimming = StringTrimming.None;
//format.FormatFlags |= StringFormatFlags.NoWrap;
//format.FormatFlags |= StringFormatFlags.NoClip;
measuringBmp = new Bitmap(1, 1);
measuringGraphics = Graphics.FromImage(measuringBmp);
measuringGraphics.TextRenderingHint = TextRenderingHint.AntiAlias;
}
protected override void DrawSysText(ref DrawTextArgs args, int x, int y) {
if (!args.SkipPartsCheck)
GetTextParts(args.Text);
float textX = x;
Brush backBrush = GetOrCreateBrush(FastColour.Black);
for (int i = 0; i < parts.Count; i++) {
TextPart part = parts[i];
Brush foreBrush = GetOrCreateBrush(part.Col);
if (args.UseShadow)
g.DrawString(part.Text, args.Font, backBrush, textX + Offset, y + Offset, format);
g.DrawString(part.Text, args.Font, foreBrush, textX, y, format);
textX += g.MeasureString(part.Text, args.Font, Int32.MaxValue, format).Width;
}
}
public override void DrawClippedText(ref DrawTextArgs args, int x, int y, float maxWidth, float maxHeight) {
if (!args.SkipPartsCheck)
GetTextParts(args.Text);
Brush shadowBrush = GetOrCreateBrush(FastColour.Black);
StringFormatFlags flags = format.FormatFlags;
format.FormatFlags |= StringFormatFlags.NoWrap;
format.Trimming = StringTrimming.EllipsisCharacter;
float textX = x;
for (int i = 0; i < parts.Count; i++) {
TextPart part = parts[i];
Brush textBrush = GetOrCreateBrush(part.Col);
RectangleF rect = new RectangleF(textX + Offset, y + Offset, maxWidth, maxHeight);
if (args.UseShadow)
g.DrawString(part.Text, args.Font, shadowBrush, rect, format);
rect = new RectangleF(textX, y, maxWidth, maxHeight);
g.DrawString(part.Text, args.Font, textBrush, rect, format);
textX += g.MeasureString(part.Text, args.Font, Int32.MaxValue, format).Width;
}
format.Trimming = StringTrimming.None;
format.FormatFlags = flags;
}
FastBitmap bitmapWrapper = new FastBitmap();
protected override void DrawBitmappedText(ref DrawTextArgs args, int x, int y) {
using (bitmapWrapper) {
bitmapWrapper.SetData(curBmp, true, false);
DrawBitmapTextImpl(bitmapWrapper, ref args, x, y);
}
}
protected override Size MeasureSysSize(ref DrawTextArgs args) {
GetTextParts(args.Text);
int count = parts.Count;
if (count == 0) return Size.Empty;
float width = 0, height = 0;
for (int i = 0; i < count; i++) {
SizeF size = measuringGraphics.MeasureString(parts[i].Text, args.Font, Int32.MaxValue, format);
height = Math.Max(height, size.Height);
width += size.Width;
}
if (args.UseShadow) { width += Offset; height += Offset; }
return new Size((int)Math.Ceiling(width), (int)Math.Ceiling(height));
}
void DisposeText() {
measuringGraphics.Dispose();
measuringBmp.Dispose();
}
}
}
#endif

View file

@ -5,14 +5,36 @@ using System.Collections.Generic;
using System.Drawing; using System.Drawing;
using System.Drawing.Drawing2D; using System.Drawing.Drawing2D;
using System.Drawing.Text; using System.Drawing.Text;
#if !LAUNCHER
using ClassicalSharp.GraphicsAPI;
#endif
namespace ClassicalSharp { namespace ClassicalSharp {
public sealed partial class GdiPlusDrawer2D : IDrawer2D { public sealed class GdiPlusDrawer2D : IDrawer2D {
Dictionary<int, SolidBrush> brushCache = new Dictionary<int, SolidBrush>(16); struct CachedBrush { public int ARGB; public SolidBrush Brush; }
Graphics g; List<CachedBrush> brushes = new List<CachedBrush>(16);
Bitmap curBmp; Graphics g, measuringGraphics;
Bitmap curBmp, measuringBmp;
StringFormat format;
#if !LAUNCHER
public GdiPlusDrawer2D(IGraphicsApi graphics) {
this.graphics = graphics;
#else
public GdiPlusDrawer2D() {
#endif
format = StringFormat.GenericTypographic;
format.FormatFlags |= StringFormatFlags.MeasureTrailingSpaces;
format.Trimming = StringTrimming.None;
//format.FormatFlags |= StringFormatFlags.NoWrap;
//format.FormatFlags |= StringFormatFlags.NoClip;
measuringBmp = new Bitmap(1, 1);
measuringGraphics = Graphics.FromImage(measuringBmp);
measuringGraphics.TextRenderingHint = TextRenderingHint.AntiAlias;
}
public override void SetBitmap(Bitmap bmp) { public override void SetBitmap(Bitmap bmp) {
if (g != null) { if (g != null) {
@ -64,8 +86,8 @@ namespace ClassicalSharp {
} }
public override void DisposeInstance() { public override void DisposeInstance() {
foreach (KeyValuePair<int, SolidBrush> pair in brushCache) { for (int i = 0; i < brushes.Count; i++) {
pair.Value.Dispose(); brushes[i].Brush.Dispose();
} }
DisposeText(); DisposeText();
@ -73,14 +95,85 @@ namespace ClassicalSharp {
} }
SolidBrush GetOrCreateBrush(FastColour col) { SolidBrush GetOrCreateBrush(FastColour col) {
int key = col.ToArgb(); int argb = col.ToArgb();
SolidBrush brush; for (int i = 0; i < brushes.Count; i++) {
if (brushCache.TryGetValue(key, out brush)) if (brushes[i].ARGB == argb) return brushes[i].Brush;
return brush; }
brush = new SolidBrush(col); CachedBrush b; b.ARGB = argb; b.Brush = new SolidBrush(col);
brushCache[key] = brush; brushes.Add(b);
return brush; return b.Brush;
}
protected override void DrawSysText(ref DrawTextArgs args, int x, int y) {
if (!args.SkipPartsCheck)
GetTextParts(args.Text);
float textX = x;
Brush backBrush = GetOrCreateBrush(FastColour.Black);
for (int i = 0; i < parts.Count; i++) {
TextPart part = parts[i];
Brush foreBrush = GetOrCreateBrush(part.Col);
if (args.UseShadow)
g.DrawString(part.Text, args.Font, backBrush, textX + Offset, y + Offset, format);
g.DrawString(part.Text, args.Font, foreBrush, textX, y, format);
textX += g.MeasureString(part.Text, args.Font, Int32.MaxValue, format).Width;
}
}
public override void DrawClippedText(ref DrawTextArgs args, int x, int y, float maxWidth, float maxHeight) {
if (!args.SkipPartsCheck)
GetTextParts(args.Text);
Brush shadowBrush = GetOrCreateBrush(FastColour.Black);
StringFormatFlags flags = format.FormatFlags;
format.FormatFlags |= StringFormatFlags.NoWrap;
format.Trimming = StringTrimming.EllipsisCharacter;
float textX = x;
for (int i = 0; i < parts.Count; i++) {
TextPart part = parts[i];
Brush textBrush = GetOrCreateBrush(part.Col);
RectangleF rect = new RectangleF(textX + Offset, y + Offset, maxWidth, maxHeight);
if (args.UseShadow)
g.DrawString(part.Text, args.Font, shadowBrush, rect, format);
rect = new RectangleF(textX, y, maxWidth, maxHeight);
g.DrawString(part.Text, args.Font, textBrush, rect, format);
textX += g.MeasureString(part.Text, args.Font, Int32.MaxValue, format).Width;
}
format.Trimming = StringTrimming.None;
format.FormatFlags = flags;
}
FastBitmap bitmapWrapper = new FastBitmap();
protected override void DrawBitmappedText(ref DrawTextArgs args, int x, int y) {
using (bitmapWrapper) {
bitmapWrapper.SetData(curBmp, true, false);
DrawBitmapTextImpl(bitmapWrapper, ref args, x, y);
}
}
protected override Size MeasureSysSize(ref DrawTextArgs args) {
GetTextParts(args.Text);
int count = parts.Count;
if (count == 0) return Size.Empty;
float width = 0, height = 0;
for (int i = 0; i < count; i++) {
SizeF size = measuringGraphics.MeasureString(parts[i].Text, args.Font, Int32.MaxValue, format);
height = Math.Max(height, size.Height);
width += size.Width;
}
if (args.UseShadow) { width += Offset; height += Offset; }
return new Size((int)Math.Ceiling(width), (int)Math.Ceiling(height));
}
void DisposeText() {
measuringGraphics.Dispose();
measuringBmp.Dispose();
} }
} }
} }

View file

@ -10,6 +10,20 @@ using Android.Graphics;
#endif #endif
namespace ClassicalSharp { namespace ClassicalSharp {
/// <summary> Contains arguments for measuring or drawing text. </summary>
public struct DrawTextArgs {
public string Text;
public Font Font;
public bool UseShadow, SkipPartsCheck;
public DrawTextArgs(string text, Font font, bool useShadow) {
Text = text;
Font = font;
UseShadow = useShadow;
SkipPartsCheck = false;
}
}
/// <summary> Class responsible for performing drawing operations on bitmaps /// <summary> Class responsible for performing drawing operations on bitmaps
/// and for converting bitmaps into graphics api textures. </summary> /// and for converting bitmaps into graphics api textures. </summary>

View file

@ -142,13 +142,20 @@ namespace ClassicalSharp.Gui.Screens {
} }
public void SetBlockTo(BlockID block) { public void SetBlockTo(BlockID block) {
selIndex = Array.IndexOf<BlockID>(blocksTable, block); selIndex = IndexOfBlock(block);
scrollY = (selIndex / blocksPerRow) - (maxRows - 1); scrollY = (selIndex / blocksPerRow) - (maxRows - 1);
ClampScrollY(); ClampScrollY();
MoveCursorToSelected(); MoveCursorToSelected();
RecreateBlockInfoTexture(); RecreateBlockInfoTexture();
} }
int IndexOfBlock(BlockID block) {
for (int i = 0; i < blocksTable.Length; i++) {
if (blocksTable[i] == block) return i;
}
return -1;
}
void MoveCursorToSelected() { void MoveCursorToSelected() {
if (selIndex == -1) return; if (selIndex == -1) return;
game.DesktopCursorPos = GetMouseCoords(selIndex); game.DesktopCursorPos = GetMouseCoords(selIndex);

View file

@ -118,7 +118,7 @@ namespace ClassicalSharp.Gui.Screens {
void DefaultButtonClick(Game game, Widget widget, MouseButton btn, int x, int y) { void DefaultButtonClick(Game game, Widget widget, MouseButton btn, int x, int y) {
if (btn != MouseButton.Left) return; if (btn != MouseButton.Left) return;
int index = Array.IndexOf<Widget>(widgets, targetWidget); int index = IndexOfWidget(targetWidget);
string defValue = defaultValues[index]; string defValue = defaultValues[index];
input.Clear(); input.Clear();

View file

@ -80,7 +80,7 @@ namespace ClassicalSharp.Gui.Screens {
} }
void HandleFontChange() { void HandleFontChange() {
int selIndex = Array.IndexOf<Widget>(widgets, selectedWidget); int selIndex = IndexOfWidget(selectedWidget);
game.Events.RaiseChatFontChanged(); game.Events.RaiseChatFontChanged();
base.Dispose(); base.Dispose();
base.Init(); base.Init();

View file

@ -168,7 +168,7 @@ namespace ClassicalSharp.Gui.Screens {
void DefaultButtonClick(Game game, Widget widget, MouseButton btn, int x, int y) { void DefaultButtonClick(Game game, Widget widget, MouseButton btn, int x, int y) {
if (btn != MouseButton.Left) return; if (btn != MouseButton.Left) return;
int index = Array.IndexOf<Widget>(widgets, targetWidget); int index = IndexOfWidget(targetWidget);
string defValue = defaultValues[index]; string defValue = defaultValues[index];
input.Clear(); input.Clear();

View file

@ -90,19 +90,19 @@ namespace ClassicalSharp.Gui.Screens {
int index = 0; int index = 0;
if (btn == MouseButton.Right && (curWidget == null || curWidget == widget)) { if (btn == MouseButton.Right && (curWidget == null || curWidget == widget)) {
curWidget = (ButtonWidget)widget; curWidget = (ButtonWidget)widget;
index = Array.IndexOf<Widget>(widgets, curWidget) - 2; index = IndexOfWidget(curWidget) - 2;
KeyBind mapping = Get(index, left, right); KeyBind mapping = Get(index, left, right);
HandlesKeyDown(game.Input.Keys.GetDefault(mapping)); HandlesKeyDown(game.Input.Keys.GetDefault(mapping));
} }
if (btn != MouseButton.Left) return; if (btn != MouseButton.Left) return;
if (curWidget != null) { if (curWidget != null) {
index = Array.IndexOf<Widget>(widgets, curWidget) - 2; index = IndexOfWidget(curWidget) - 2;
curWidget.SetText(ButtonText(index)); curWidget.SetText(ButtonText(index));
curWidget = null; curWidget = null;
} }
index = Array.IndexOf<Widget>(widgets, widget) - 2; index = IndexOfWidget(widget) - 2;
string text = ButtonText(index); string text = ButtonText(index);
curWidget = (ButtonWidget)widget; curWidget = (ButtonWidget)widget;
curWidget.SetText("> " + text + " <"); curWidget.SetText("> " + text + " <");
@ -119,7 +119,7 @@ namespace ClassicalSharp.Gui.Screens {
if (key == Key.Escape) { if (key == Key.Escape) {
game.Gui.SetNewScreen(null); game.Gui.SetNewScreen(null);
} else if (curWidget != null) { } else if (curWidget != null) {
int index = Array.IndexOf<Widget>(widgets, curWidget) - 2; int index = IndexOfWidget(curWidget) - 2;
KeyBind mapping = Get(index, left, right); KeyBind mapping = Get(index, left, right);
game.Input.Keys[mapping] = key; game.Input.Keys[mapping] = key;
curWidget.SetText(ButtonText(index)); curWidget.SetText(ButtonText(index));

View file

@ -149,7 +149,7 @@ namespace ClassicalSharp.Gui.Screens {
bool canShow = input == null && selectedWidget != null && descriptions != null; bool canShow = input == null && selectedWidget != null && descriptions != null;
if (!canShow) return; if (!canShow) return;
int index = Array.IndexOf<Widget>(widgets, selectedWidget); int index = IndexOfWidget(selectedWidget);
if (index < 0 || index >= descriptions.Length) return; if (index < 0 || index >= descriptions.Length) return;
string[] desc = descriptions[index]; string[] desc = descriptions[index];
if (desc == null) return; if (desc == null) return;
@ -186,7 +186,7 @@ namespace ClassicalSharp.Gui.Screens {
if (button == null) return; if (button == null) return;
DisposeExtendedHelp(); DisposeExtendedHelp();
int index = Array.IndexOf<Widget>(widgets, button); int index = IndexOfWidget(button);
MenuInputValidator validator = validators[index]; MenuInputValidator validator = validators[index];
if (validator is BooleanValidator) { if (validator is BooleanValidator) {
string value = button.GetValue(game); string value = button.GetValue(game);

View file

@ -69,7 +69,7 @@ namespace ClassicalSharp.Gui.Screens {
if (descWidget != null) descWidget.Dispose(); if (descWidget != null) descWidget.Dispose();
if (button == null) return; if (button == null) return;
string text = descriptions[Array.IndexOf<Widget>(widgets, button)]; string text = descriptions[IndexOfWidget(button)];
MakeDescWidget(text); MakeDescWidget(text);
} }

View file

@ -14,6 +14,13 @@ namespace ClassicalSharp.Gui.Screens {
protected Font titleFont, regularFont; protected Font titleFont, regularFont;
protected FastColour backCol = new FastColour(60, 60, 60, 160); protected FastColour backCol = new FastColour(60, 60, 60, 160);
protected int IndexOfWidget(Widget w) {
for (int i = 0; i < widgets.Length; i++) {
if (widgets[i] == w) return i;
}
return -1;
}
protected void RenderMenuBounds() { protected void RenderMenuBounds() {
gfx.Draw2DQuad(0, 0, game.Width, game.Height, backCol); gfx.Draw2DQuad(0, 0, game.Width, game.Height, backCol);
} }

View file

@ -66,7 +66,7 @@ namespace ClassicalSharp.Gui.Screens {
void OnYesClick(Game g, Widget w, MouseButton btn, int x, int y) { void OnYesClick(Game g, Widget w, MouseButton btn, int x, int y) {
if (btn != MouseButton.Left) return; if (btn != MouseButton.Left) return;
bool always = Array.IndexOf<Widget>(widgets, w) >= alwaysIndex; bool always = IndexOfWidget(w) >= alwaysIndex;
if (yesClick != null) yesClick(this, always); if (yesClick != null) yesClick(this, always);
Dispose(); Dispose();
@ -75,7 +75,7 @@ namespace ClassicalSharp.Gui.Screens {
void OnNoClick(Game g, Widget w, MouseButton btn, int x, int y) { void OnNoClick(Game g, Widget w, MouseButton btn, int x, int y) {
if (btn != MouseButton.Left) return; if (btn != MouseButton.Left) return;
bool always = Array.IndexOf<Widget>(widgets, w) >= alwaysIndex; bool always = IndexOfWidget(w) >= alwaysIndex;
if (confirmNo && !confirmingMode) { if (confirmNo && !confirmingMode) {
confirmingMode = true; confirmingMode = true;

View file

@ -78,12 +78,9 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="2D\Drawing\CanvasDrawer2D.cs" /> <Compile Include="2D\Drawing\CanvasDrawer2D.cs" />
<Compile Include="2D\Drawing\CanvasDrawer2D.Text.cs" />
<Compile Include="2D\Drawing\GdiPlusDrawer2D.Text.cs" />
<Compile Include="2D\Drawing\IDrawer2D.TextMC.cs" /> <Compile Include="2D\Drawing\IDrawer2D.TextMC.cs" />
<Compile Include="2D\GuiElement.cs" /> <Compile Include="2D\GuiElement.cs" />
<Compile Include="2D\IsometricBlockDrawer.cs" /> <Compile Include="2D\IsometricBlockDrawer.cs" />
<Compile Include="2D\Drawing\DrawTextArgs.cs" />
<Compile Include="2D\Drawing\GdiPlusDrawer2D.cs" /> <Compile Include="2D\Drawing\GdiPlusDrawer2D.cs" />
<Compile Include="2D\Drawing\IDrawer2D.cs" /> <Compile Include="2D\Drawing\IDrawer2D.cs" />
<Compile Include="2D\Screens\ChatScreen.cs" /> <Compile Include="2D\Screens\ChatScreen.cs" />

View file

@ -119,7 +119,7 @@ namespace ClassicalSharp.Entities {
fetchedSkin = true; fetchedSkin = true;
} }
DownloadedItem item; Request item;
if (!game.AsyncDownloader.TryGetItem(SkinName, out item)) return; if (!game.AsyncDownloader.TryGetItem(SkinName, out item)) return;
if (item == null || item.Data == null) { SetSkinAll(true); return; } if (item == null || item.Data == null) { SetSkinAll(true); return; }

View file

@ -112,21 +112,24 @@ namespace ClassicalSharp.Map {
NbtList list = new NbtList(); NbtList list = new NbtList();
list.ChildTagId = (NbtTagType)reader.ReadByte(); list.ChildTagId = (NbtTagType)reader.ReadByte();
list.ChildrenValues = new object[ReadInt32()]; list.ChildrenValues = new object[ReadInt32()];
for (int i = 0; i < list.ChildrenValues.Length; i++) for (int i = 0; i < list.ChildrenValues.Length; i++) {
list.ChildrenValues[i] = ReadTag((byte)list.ChildTagId, false).Value; list.ChildrenValues[i] = ReadTag((byte)list.ChildTagId, false).Value;
}
tag.Value = list; break; tag.Value = list; break;
case NbtTagType.Compound: case NbtTagType.Compound:
Dictionary<string, NbtTag> children = new Dictionary<string, NbtTag>(); Dictionary<string, NbtTag> children = new Dictionary<string, NbtTag>();
NbtTag child; NbtTag child;
while ((child = ReadTag(reader.ReadByte(), true)).TagId != NbtTagType.Invalid) while ((child = ReadTag(reader.ReadByte(), true)).TagId != NbtTagType.Invalid) {
children[child.Name] = child; children[child.Name] = child;
}
tag.Value = children; break; tag.Value = children; break;
case NbtTagType.Int32Array: case NbtTagType.Int32Array:
int[] array = new int[ReadInt32()]; int[] array = new int[ReadInt32()];
for (int i = 0; i < array.Length; i++) for (int i = 0; i < array.Length; i++) {
array[i] = ReadInt32(); array[i] = ReadInt32();
}
tag.Value = array; break; tag.Value = array; break;
default: default:

View file

@ -61,7 +61,7 @@ namespace ClassicalSharp {
protected void WarningScreenTick(Overlay warning) { protected void WarningScreenTick(Overlay warning) {
string identifier = warning.Metadata; string identifier = warning.Metadata;
DownloadedItem item; Request item;
if (!game.AsyncDownloader.TryGetItem(identifier, out item) || item.Data == null) return; if (!game.AsyncDownloader.TryGetItem(identifier, out item) || item.Data == null) return;
long contentLength = (long)item.Data; long contentLength = (long)item.Data;
@ -130,7 +130,7 @@ namespace ClassicalSharp {
} }
protected void CheckAsyncResources() { protected void CheckAsyncResources() {
DownloadedItem item; Request item;
if (game.AsyncDownloader.TryGetItem("terrain", out item)) { if (game.AsyncDownloader.TryGetItem("terrain", out item)) {
TexturePack.ExtractTerrainPng(game, item); TexturePack.ExtractTerrainPng(game, item);
} }

View file

@ -16,7 +16,7 @@ namespace ClassicalSharp.Network.Protocols {
internal bool sendWomId = false, sentWomId = false; internal bool sendWomId = false, sentWomId = false;
public override void Tick() { public override void Tick() {
DownloadedItem item; Request item;
game.AsyncDownloader.TryGetItem(womEnvIdentifier, out item); game.AsyncDownloader.TryGetItem(womEnvIdentifier, out item);
if (item != null && item.Data != null) { if (item != null && item.Data != null) {
ParseWomConfig((string)item.Data); ParseWomConfig((string)item.Data);

View file

@ -22,10 +22,10 @@ namespace ClassicalSharp.Network {
EventWaitHandle handle = new EventWaitHandle(false, EventResetMode.AutoReset); EventWaitHandle handle = new EventWaitHandle(false, EventResetMode.AutoReset);
Thread worker; Thread worker;
readonly object requestLocker = new object(); readonly object pendingLocker = new object();
List<Request> requests = new List<Request>(); List<Request> pending = new List<Request>();
readonly object downloadedLocker = new object(); readonly object processedLocker = new object();
Dictionary<string, DownloadedItem> downloaded = new Dictionary<string, DownloadedItem>(); List<Request> processed = new List<Request>();
string skinServer = null; string skinServer = null;
readonly IDrawer2D drawer; readonly IDrawer2D drawer;
@ -38,8 +38,8 @@ namespace ClassicalSharp.Network {
public void Init(Game game) { Init(game.skinServer); } public void Init(Game game) { Init(game.skinServer); }
public void Ready(Game game) { } public void Ready(Game game) { }
public void Reset(Game game) { public void Reset(Game game) {
lock (requestLocker) lock (pendingLocker)
requests.Clear(); pending.Clear();
handle.Set(); handle.Set();
} }
@ -113,12 +113,12 @@ namespace ClassicalSharp.Network {
void AddRequest(string url, bool priority, string identifier, void AddRequest(string url, bool priority, string identifier,
RequestType type, DateTime lastModified, string etag) { RequestType type, DateTime lastModified, string etag) {
lock (requestLocker) { lock (pendingLocker) {
Request request = new Request(url, identifier, type, lastModified, etag); Request request = new Request(url, identifier, type, lastModified, etag);
if (priority) { if (priority) {
requests.Insert(0, request); pending.Insert(0, request);
} else { } else {
requests.Add(request); pending.Add(request);
} }
} }
handle.Set(); handle.Set();
@ -129,8 +129,8 @@ namespace ClassicalSharp.Network {
/// Note that this will *block** the calling thread as the method waits until the asynchronous /// Note that this will *block** the calling thread as the method waits until the asynchronous
/// thread has exited the for loop. </summary> /// thread has exited the for loop. </summary>
public void Dispose() { public void Dispose() {
lock (requestLocker) { lock (pendingLocker) {
requests.Insert(0, null); pending.Insert(0, null);
} }
handle.Set(); handle.Set();
@ -142,26 +142,14 @@ namespace ClassicalSharp.Network {
/// <summary> Removes older entries that were downloaded a certain time ago /// <summary> Removes older entries that were downloaded a certain time ago
/// but were never removed from the downloaded queue. </summary> /// but were never removed from the downloaded queue. </summary>
public void PurgeOldEntriesTask(ScheduledTask task) { public void PurgeOldEntriesTask(ScheduledTask task) {
const int seconds = 10; lock (processedLocker) {
lock (downloadedLocker) {
DateTime now = DateTime.UtcNow; DateTime now = DateTime.UtcNow;
List<string> itemsToRemove = new List<string>(downloaded.Count); for (int i = processed.Count - 1; i >= 0; i--) {
Request item = processed[i];
foreach (var item in downloaded) { if ((now - item.TimeDownloaded).TotalSeconds < 10) continue;
DateTime timestamp = item.Value.TimeDownloaded;
if ((now - timestamp).TotalSeconds > seconds) { item.Dispose();
itemsToRemove.Add(item.Key); processed.RemoveAt(i);
}
}
for (int i = 0; i < itemsToRemove.Count; i++) {
string key = itemsToRemove[i];
DownloadedItem item;
downloaded.TryGetValue(key, out item);
downloaded.Remove(key);
Bitmap bmp = item.Data as Bitmap;
if (bmp != null)
bmp.Dispose();
} }
} }
} }
@ -171,13 +159,12 @@ namespace ClassicalSharp.Network {
/// If it does, it removes the item from the queue and outputs it. </summary> /// If it does, it removes the item from the queue and outputs it. </summary>
/// <remarks> If the asynchronous thread failed to download the item, this method /// <remarks> If the asynchronous thread failed to download the item, this method
/// will return 'true' and 'item' will be set. However, the contents of the 'item' object will be null.</remarks> /// will return 'true' and 'item' will be set. However, the contents of the 'item' object will be null.</remarks>
public bool TryGetItem(string identifier, out DownloadedItem item) { public bool TryGetItem(string identifier, out Request item) {
bool success = false; bool success = false;
lock (downloadedLocker) { lock (processedLocker) {
success = downloaded.TryGetValue(identifier, out item); int i = FindRequest(identifier, out item);
if (success) { success = i >= 0;
downloaded.Remove(identifier); if (success) processed.RemoveAt(i);
}
} }
return success; return success;
} }
@ -185,14 +172,14 @@ namespace ClassicalSharp.Network {
void DownloadThreadWorker() { void DownloadThreadWorker() {
while (true) { while (true) {
Request request = null; Request request = null;
lock (requestLocker) { lock (pendingLocker) {
if (requests.Count > 0) { if (pending.Count > 0) {
request = requests[0]; request = pending[0];
requests.RemoveAt(0); pending.RemoveAt(0);
if (request == null) if (request == null) return;
return;
} }
} }
if (request != null) { if (request != null) {
CurrentItem = request; CurrentItem = request;
CurrentItemProgress = -2; CurrentItemProgress = -2;
@ -206,21 +193,30 @@ namespace ClassicalSharp.Network {
} }
} }
int FindRequest(string identifer, out Request item) {
item = null;
for (int i = 0; i < processed.Count; i++) {
if (processed[i].Identifier != identifer) continue;
item = processed[i];
return i;
}
return -1;
}
void ProcessRequest(Request request) { void ProcessRequest(Request request) {
string url = request.Url; string url = request.Url;
Utils.LogDebug("Downloading {0} from: {1}", request.Type, url); Utils.LogDebug("Downloading {0} from: {1}", request.Type, url);
object value = null;
HttpStatusCode status = HttpStatusCode.OK; HttpStatusCode status = HttpStatusCode.OK;
string etag = null; request.Data = null;
DateTime lastModified = DateTime.MinValue;
try { try {
HttpWebRequest req = MakeRequest(request); HttpWebRequest req = MakeRequest(request);
using (HttpWebResponse response = (HttpWebResponse)req.GetResponse()) { using (HttpWebResponse response = (HttpWebResponse)req.GetResponse()) {
etag = response.Headers[HttpResponseHeader.ETag]; request.ETag = response.Headers[HttpResponseHeader.ETag];
if (response.Headers[HttpResponseHeader.LastModified] != null) if (response.Headers[HttpResponseHeader.LastModified] != null) {
lastModified = response.LastModified; request.LastModified = response.LastModified;
value = DownloadContent(request, response); }
request.Data = DownloadContent(request, response);
} }
} catch (Exception ex) { } catch (Exception ex) {
if (!(ex is WebException || ex is ArgumentException || ex is UriFormatException || ex is IOException)) throw; if (!(ex is WebException || ex is ArgumentException || ex is UriFormatException || ex is IOException)) throw;
@ -239,24 +235,24 @@ namespace ClassicalSharp.Network {
Utils.LogDebug("Failed to download from: " + url); Utils.LogDebug("Failed to download from: " + url);
} }
} }
value = CheckIsValidImage(value, url);
request.Data = CheckIsValidImage(request.Data, url);
lock (downloadedLocker) { request.TimeDownloaded = DateTime.UtcNow;
DownloadedItem oldItem;
DownloadedItem newItem = new DownloadedItem(value, request.TimeAdded, url, lock (processedLocker) {
status, etag, lastModified); Request older;
int index = FindRequest(request.Identifier, out older);
if (downloaded.TryGetValue(request.Identifier, out oldItem)) { if (index >= 0) {
if (oldItem.TimeAdded > newItem.TimeAdded) { if (older.TimeAdded > request.TimeAdded) {
DownloadedItem old = oldItem; Request tmp = older; older = request; request = tmp;
oldItem = newItem;
newItem = old;
} }
Bitmap oldBmp = oldItem.Data as Bitmap; older.Dispose();
if (oldBmp != null) oldBmp.Dispose(); processed[index] = request;
} else {
processed.Add(request);
} }
downloaded[request.Identifier] = newItem;
} }
} }
@ -331,25 +327,25 @@ namespace ClassicalSharp.Network {
public sealed class Request { public sealed class Request {
/// <summary> Full url to GET from. </summary> /// <summary> Full url to GET from. </summary>
public string Url; public string Url;
/// <summary> Unique identifier for this request. </summary> /// <summary> Unique identifier for this request. </summary>
public string Identifier; public string Identifier;
/// <summary> Type of data to return for this request. </summary> /// <summary> Type of data to return for this request. </summary>
public RequestType Type; public RequestType Type;
/// <summary> Point in time this request was added to the fetch queue. </summary> /// <summary> Point in time this request was added to the fetch queue. </summary>
public DateTime TimeAdded; public DateTime TimeAdded;
/// <summary> Point in time the item was fully downloaded. </summary>
public DateTime TimeDownloaded;
/// <summary> Contents that were downloaded. </summary>
public object Data;
/// <summary> Point in time the item most recently cached. (if at all) </summary> /// <summary> Point in time the item most recently cached. (if at all) </summary>
public DateTime LastModified; public DateTime LastModified;
/// <summary> ETag of the item most recently cached. (if any) </summary> /// <summary> ETag of the item most recently cached. (if any) </summary>
public string ETag; public string ETag;
public Request(string url, string identifier, RequestType type, public Request(string url, string identifier, RequestType type, DateTime lastModified, string etag) {
DateTime lastModified, string etag) {
Url = url; Url = url;
Identifier = identifier; Identifier = identifier;
Type = type; Type = type;
@ -357,38 +353,10 @@ namespace ClassicalSharp.Network {
LastModified = lastModified; LastModified = lastModified;
ETag = etag; ETag = etag;
} }
}
/// <summary> Represents an item that was asynchronously downloaded. </summary>
public class DownloadedItem {
/// <summary> Contents that were downloaded. </summary> public void Dispose() {
public object Data; Bitmap bmp = Data as Bitmap;
if (bmp != null) bmp.Dispose();
/// <summary> Point in time the item was originally added to the download queue. </summary>
public DateTime TimeAdded;
/// <summary> Point in time the item was fully downloaded. </summary>
public DateTime TimeDownloaded;
/// <summary> Full URL this item was downloaded from. </summary>
public string Url;
/// <summary> Unique identifier assigned by the server to this item. </summary>
public string ETag;
/// <summary> Time the server indicates this item was last modified. </summary>
public DateTime LastModified;
public DownloadedItem(object data, DateTime timeAdded,
string url, HttpStatusCode code,
string etag, DateTime lastModified) {
Data = data;
TimeAdded = timeAdded;
TimeDownloaded = DateTime.UtcNow;
Url = url;
ETag = etag;
LastModified = lastModified;
} }
} }
} }

View file

@ -62,7 +62,7 @@ namespace ClassicalSharp.Textures {
} }
internal static void ExtractTerrainPng(Game game, DownloadedItem item) { internal static void ExtractTerrainPng(Game game, Request item) {
if (item.Data == null) return; if (item.Data == null) return;
game.World.TextureUrl = item.Url; game.World.TextureUrl = item.Url;
game.Events.RaiseTexturePackChanged(); game.Events.RaiseTexturePackChanged();
@ -101,7 +101,7 @@ namespace ClassicalSharp.Textures {
ms.Dispose(); ms.Dispose();
} }
internal static void ExtractTexturePack(Game game, DownloadedItem item) { internal static void ExtractTexturePack(Game game, Request item) {
if (item.Data == null) return; if (item.Data == null) return;
game.World.TextureUrl = item.Url; game.World.TextureUrl = item.Url;
byte[] data = (byte[])item.Data; byte[] data = (byte[])item.Data;

View file

@ -57,15 +57,9 @@
<Reference Include="System.Windows.Forms" /> <Reference Include="System.Windows.Forms" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="..\ClassicalSharp\2D\Drawing\DrawTextArgs.cs">
<Link>Shared\DrawTextArgs.cs</Link>
</Compile>
<Compile Include="..\ClassicalSharp\2D\Drawing\GdiPlusDrawer2D.cs"> <Compile Include="..\ClassicalSharp\2D\Drawing\GdiPlusDrawer2D.cs">
<Link>Shared\GdiPlusDrawer2D.cs</Link> <Link>Shared\GdiPlusDrawer2D.cs</Link>
</Compile> </Compile>
<Compile Include="..\ClassicalSharp\2D\Drawing\GdiPlusDrawer2D.Text.cs">
<Link>Shared\GdiPlusDrawer2D.Text.cs</Link>
</Compile>
<Compile Include="..\ClassicalSharp\2D\Drawing\IDrawer2D.cs"> <Compile Include="..\ClassicalSharp\2D\Drawing\IDrawer2D.cs">
<Link>Shared\IDrawer2D.cs</Link> <Link>Shared\IDrawer2D.cs</Link>
</Compile> </Compile>

View file

@ -91,7 +91,7 @@ namespace Launcher.Patcher {
} }
bool Download(string identifier, ref byte[] data, Action<string> setStatus) { bool Download(string identifier, ref byte[] data, Action<string> setStatus) {
DownloadedItem item; Request item;
if (downloader.TryGetItem(identifier, out item)) { if (downloader.TryGetItem(identifier, out item)) {
FilesToDownload.RemoveAt(0); FilesToDownload.RemoveAt(0);
Console.WriteLine("got resource " + identifier); Console.WriteLine("got resource " + identifier);

View file

@ -37,7 +37,7 @@ namespace Launcher.Patcher {
public bool CheckDownloaded(ResourceFetcher fetcher, Action<string> setStatus) { public bool CheckDownloaded(ResourceFetcher fetcher, Action<string> setStatus) {
if (Done) return true; if (Done) return true;
for (int i = 0; i < identifiers.Length; i++) { for (int i = 0; i < identifiers.Length; i++) {
DownloadedItem item; Request item;
if (fetcher.downloader.TryGetItem(identifiers[i], out item)) { if (fetcher.downloader.TryGetItem(identifiers[i], out item)) {
fetcher.FilesToDownload.RemoveAt(0); fetcher.FilesToDownload.RemoveAt(0);
Console.WriteLine("got sound " + identifiers[i]); Console.WriteLine("got sound " + identifiers[i]);