Added Profiler for simple rough time measurement

This commit is contained in:
miku-666
2023-07-31 20:47:41 +02:00
parent 22eff0df73
commit c9c69a7ed8
9 changed files with 53 additions and 16 deletions

View File

@@ -0,0 +1,47 @@
/* Copyright (c) 2023-present miku-666, MattNL
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
**/
using System;
using System.IO;
using System.Reflection;
namespace PckStudio.Internal
{
static internal class ApplicationBuildInfo
{
// this is to specify which build release this is. This is manually updated for now
// TODO: add different chars for different configurations
private const string BuildType = "b";
private static System.Globalization.Calendar _buildCalendar;
private static DateTime date = new FileInfo(Assembly.GetExecutingAssembly().Location).LastWriteTime;
private static string _betaBuildVersion;
public static string BetaBuildVersion
{
get
{
// adopted Minecraft Java Edition Snapshot format (YYwWWn)
// to keep track of work in progress features and builds
_buildCalendar ??= new System.Globalization.CultureInfo("en-US").Calendar;
return _betaBuildVersion ??= string.Format("#{0}w{1}{2}",
date.ToString("yy"),
_buildCalendar.GetWeekOfYear(date, System.Globalization.CalendarWeekRule.FirstDay, DayOfWeek.Monday),
BuildType);
}
}
}
}

View File

@@ -0,0 +1,41 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using PckStudio.Classes.Misc;
using PckStudio.Forms.Utilities;
using PckStudio.Properties;
using PckStudio.Extensions;
using System.Globalization;
using System.ComponentModel;
using PckStudio.Internal;
namespace PckStudio
{
internal static class ApplicationScope
{
public static FileCacher DataCacher { get; private set; }
private static Image[] _entityImages;
public static Image[] EntityImages => _entityImages;
internal static void Initialize()
{
Profiler.Configure(Debug.Listeners[0]);
Profiler.Start();
{
_entityImages ??= Resources.entities_sheet.CreateImageList(32).ToArray();
DataCacher ??= new FileCacher(Program.AppDataCache);
_ = AnimationResources.JsonTileData;
_ = AnimationResources.ItemImageList;
_ = AnimationResources.BlockImageList;
SettingsManager.Initialize();
CultureInfo.CurrentCulture = CultureInfo.InvariantCulture;
}
Profiler.Stop();
}
}
}

View File

@@ -0,0 +1,50 @@
/* Copyright (c) 2023-present miku-666
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
**/
using System.Linq;
using System.Reflection;
namespace PckStudio.Internal
{
static internal class CommitInfo
{
private static string _branchName = null;
private static string _commitHash = null;
public static string BranchName
{
get
{
return _branchName ??= Assembly
.GetEntryAssembly()
.GetCustomAttributes<AssemblyMetadataAttribute>()
.FirstOrDefault(attr => attr.Key == "GitBranch")?.Value;
}
}
public static string CommitHash
{
get
{
return _commitHash ??= Assembly
.GetEntryAssembly()
.GetCustomAttributes<AssemblyMetadataAttribute>()
.FirstOrDefault(attr => attr.Key == "GitHash")?.Value;
}
}
}
}

View File

@@ -0,0 +1,38 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
namespace PckStudio.Internal
{
internal static class Profiler
{
private static Stopwatch _stopwatch = new Stopwatch();
private static TraceListener _listener;
[Conditional("DEBUG")]
internal static void Configure(TraceListener listener)
{
_listener = listener;
}
[Conditional("DEBUG")]
internal static void Start([CallerMemberName] string caller = default!, [CallerFilePath] string source = default!, [CallerLineNumber] int line = default!)
{
_listener?.WriteLine($"Stopwatch starts", category: nameof(Profiler));
_listener?.WriteLine($"{source}@{caller}:{line}", category: nameof(Profiler));
_stopwatch.Restart();
}
[Conditional("DEBUG")]
internal static void Stop([CallerMemberName] string caller = default!, [CallerFilePath] string source = default!, [CallerLineNumber] int line = default!)
{
_stopwatch.Stop();
_listener?.WriteLine($"{caller} took {_stopwatch.ElapsedMilliseconds}ms", category: nameof(Profiler));
}
}
}

View File

@@ -0,0 +1,65 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using PckStudio.Properties;
namespace PckStudio.Internal
{
internal static class SettingsManager
{
private static Dictionary<string, Action<object>> _registery = new Dictionary<string, Action<object>>();
private static object _newValue = null;
internal static void Initialize()
{
Settings.Default.PropertyChanged += PropertyChangedHandler;
Settings.Default.SettingChanging += SettingChangingHandler;
}
internal static bool RegisterPropertyChangedCallback<TSettingsType>(string propertyName, Action<TSettingsType> callback)
{
Type propertyType = Settings.Default[propertyName].GetType();
if (!propertyType.Equals(typeof(TSettingsType)))
{
return false;
}
return RegisterPropertyChangedCallback(propertyName, delegate (object obj) { callback((TSettingsType)obj); });
}
internal static bool RegisterPropertyChangedCallback(string propertyName, Action callback)
{
return RegisterPropertyChangedCallback(propertyName, delegate (object _) { callback(); });
}
private static bool RegisterPropertyChangedCallback(string propertyName, Action<object> callback)
{
if (_registery.ContainsKey(propertyName))
return false;
_registery.Add(propertyName, callback);
return true;
}
private static void PropertyChangedHandler(object sender, PropertyChangedEventArgs e)
{
if (_registery.ContainsKey(e.PropertyName))
{
_registery[e.PropertyName]?.Invoke(_newValue);
_newValue = null;
}
}
private static void SettingChangingHandler(object sender, SettingChangingEventArgs e)
{
if (_registery.ContainsKey(e.SettingName))
{
_newValue = e.NewValue;
}
}
}
}

View File

@@ -0,0 +1,158 @@
/* Copyright (c) 2022-present miku-666, MattNL
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
**/
using System;
using System.Text.RegularExpressions;
namespace PckStudio.Internal
{
/// <summary>
/// For usage see <see cref="SkinANIM"/>
/// </summary>
[Flags]
public enum SkinAnimFlag : int
{
NONE = 0, // 0x00
STATIC_ARMS = 1 << 0, // 0x01
ZOMBIE_ARMS = 1 << 1, // 0x02
STATIC_LEGS = 1 << 2, // 0x04
BAD_SANTA = 1 << 3, // 0x08
//
__BIT_4 = 1 << 4, // 0x10 - Unused??
SYNCED_LEGS = 1 << 5, // 0x20
SYNCED_ARMS = 1 << 6, // 0x40
STATUE_OF_LIBERTY = 1 << 7, // 0x80
ALL_ARMOR_DISABLED = 1 << 8, // 0x100
HEAD_BOBBING_DISABLED = 1 << 9, // 0x200
HEAD_DISABLED = 1 << 10, // 0x400
RIGHT_ARM_DISABLED = 1 << 11, // 0x800
LEFT_ARM_DISABLED = 1 << 12, // 0x1000
BODY_DISABLED = 1 << 13, // 0x2000
RIGHT_LEG_DISABLED = 1 << 14, // 0x4000
LEFT_LEG_DISABLED = 1 << 15, // 0x8000
HEAD_OVERLAY_DISABLED = 1 << 16, // 0x10000
DO_BACKWARDS_CROUCH = 1 << 17, // 0x20000
RESOLUTION_64x64 = 1 << 18, // 0x40000
SLIM_MODEL = 1 << 19, // 0x80000
LEFT_ARM_OVERLAY_DISABLED = 1 << 20, // 0x100000
RIGHT_ARM_OVERLAY_DISABLED = 1 << 21, // 0x200000
LEFT_LEG_OVERLAY_DISABLED = 1 << 22, // 0x400000
RIGHT_LEG_OVERLAY_DISABLED = 1 << 23, // 0x800000
BODY_OVERLAY_DISABLED = 1 << 24, // 0x1000000
FORCE_HEAD_ARMOR = 1 << 25, // 0x2000000
FORCE_RIGHT_ARM_ARMOR = 1 << 26, // 0x4000000
FORCE_LEFT_ARM_ARMOR = 1 << 27, // 0x8000000
FORCE_BODY_ARMOR = 1 << 28, // 0x10000000
FORCE_RIGHT_LEG_ARMOR = 1 << 29, // 0x20000000
FORCE_LEFT_LEG_ARMOR = 1 << 30, // 0x40000000
DINNERBONE = 1 << 31, // 0x80000000
}
/// <summary>
/// Represents a Skin Anim value where flags can be set
/// </summary>
public class SkinANIM : ICloneable, IEquatable<SkinANIM>, IEquatable<SkinAnimFlag>
{
public static readonly SkinANIM Empty = new SkinANIM();
private SkinAnimFlag _flags;
private static readonly Regex _validator = new Regex(@"^0x[0-9a-f]{1,8}\b", RegexOptions.IgnoreCase);
public SkinANIM()
: this(SkinAnimFlag.NONE)
{
}
public SkinANIM(SkinAnimFlag mask)
{
_flags = mask;
}
public override string ToString() => "0x" + ((int)_flags).ToString("x8");
public static bool IsValidANIM(string anim)
{
if (anim is not null)
return _validator.IsMatch(anim);
return false;
}
public static SkinANIM FromString(string value)
=> IsValidANIM(value)
? new SkinANIM((SkinAnimFlag)Convert.ToInt32(value.TrimEnd(' ', '\n', '\r'), 16))
: new SkinANIM();
public void SetMask(SkinAnimFlag mask) => _flags = mask;
public static SkinANIM operator |(SkinANIM _this, SkinANIM other) => new SkinANIM(_this._flags | other._flags);
public static SkinANIM operator |(SkinANIM _this, SkinAnimFlag mask) => new SkinANIM(_this._flags | mask);
public static implicit operator SkinANIM(SkinAnimFlag mask) => new SkinANIM(mask);
public static bool operator ==(SkinANIM _this, SkinAnimFlag mask) => _this.Equals(mask);
public static bool operator !=(SkinANIM _this, SkinAnimFlag mask) => !_this.Equals(mask);
public static bool operator ==(SkinANIM _this, SkinANIM other) => _this.Equals(other);
public static bool operator !=(SkinANIM _this, SkinANIM other) => !_this.Equals(other);
public bool Equals(SkinANIM other)
{
return _flags == other._flags;
}
public bool Equals(SkinAnimFlag other)
{
return _flags == other;
}
public override bool Equals(object obj) => obj is SkinANIM a && Equals(a);
public override int GetHashCode() => (int)_flags;
/// <summary>
/// Sets the desired flag in the bitfield
/// </summary>
/// <param name="flag">ANIM Flag to set</param>
/// <param name="state">State of the flag</param>
public void SetFlag(SkinAnimFlag flag, bool state)
{
if (state) _flags |= flag;
else _flags &= ~flag;
}
/// <summary>
/// Gets a desired flags state
/// </summary>
/// <param name="flag">Flag to check</param>
/// <returns>True if flag is set, otherwise false</returns>
public bool GetFlag(SkinAnimFlag flag)
{
return (_flags & flag) != 0;
}
public object Clone()
{
return MemberwiseClone();
}
}
}

View File

@@ -0,0 +1,117 @@
/* Copyright (c) 2023-present miku-666, MattNL
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1.The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
**/
using System;
using System.Numerics;
namespace PckStudio.Internal
{
public class SkinBOX : ICloneable, IEquatable<SkinBOX>
{
public static readonly SkinBOX Empty = new SkinBOX("HEAD", new Vector3(-4, -8, -4), new Vector3(8), Vector2.Zero);
public string Type;
public Vector3 Pos;
public Vector3 Size;
public Vector2 UV;
public bool HideWithArmor;
public bool Mirror;
public float Scale;
public SkinBOX(string type, Vector3 pos, Vector3 size, Vector2 uv,
bool hideWithArmor = false, bool mirror = false, float scale = 0.0f)
{
Type = type;
Pos = pos;
Size = size;
UV = uv;
HideWithArmor = hideWithArmor;
Mirror = mirror;
Scale = scale;
}
public static SkinBOX FromString(string value)
{
var arguments = value.Split(' ');
if (arguments.Length < 9)
{
throw new ArgumentException("Arguments must have at least a length of 9");
}
var type = arguments[0];
var pos = TryGetVector3(arguments, 1);
var size = TryGetVector3(arguments, 4);
var uv = TryGetVector2(arguments, 7);
var skinBox = new SkinBOX(type, pos, size, uv);
if (arguments.Length >= 10)
skinBox.HideWithArmor = arguments[9] == "1";
if (arguments.Length >= 11)
skinBox.Mirror = arguments[10] == "1";
if (arguments.Length >= 12)
float.TryParse(arguments[11], out skinBox.Scale);
return skinBox;
}
public ValueTuple<string, string> ToProperty()
{
return new ValueTuple<string, string>("BOX", ToString());
}
public override string ToString()
{
return
$"{Type} {Pos.X} {Pos.Y} {Pos.Z} {Size.X} {Size.Y} {Size.Z} {UV.X} {UV.Y} {Convert.ToInt32(HideWithArmor)} {Convert.ToInt32(Mirror)} {Scale}"
.Replace(',', '.');
}
private static Vector2 TryGetVector2(string[] arguments, int startIndex)
{
float.TryParse(arguments[startIndex], out float x);
float.TryParse(arguments[startIndex + 1], out float y);
return new Vector2(x, y);
}
private static Vector3 TryGetVector3(string[] arguments, int startIndex)
{
var vec2 = TryGetVector2(arguments, startIndex);
float.TryParse(arguments[startIndex + 2], out float z);
return new Vector3(vec2, z);
}
public override int GetHashCode()
{
return Type.GetHashCode() % Pos.GetHashCode() * UV.GetHashCode() % Size.GetHashCode();
}
public override bool Equals(object obj)
{
return obj is SkinBOX box && Equals(box);
}
public bool Equals(SkinBOX other)
{
return Type.Equals(other.Type) &&
Pos.Equals(other.Pos) &&
Size.Equals(other.Size) &&
UV.Equals(other.UV);
}
public object Clone()
{
return new SkinBOX((string)Type.Clone(), Pos, Size, UV, HideWithArmor, Mirror, Scale);
}
}
}