Skip to content

Commit

Permalink
✨ 实用工具
Browse files Browse the repository at this point in the history
你别管它实不实用 在终端中操作
你就说帅不帅就得了

Signed-off-by: 舰队的偶像-岛风酱! <[email protected]>
  • Loading branch information
frg2089 committed Jul 9, 2023
1 parent 34f156e commit 2f3c81c
Show file tree
Hide file tree
Showing 6 changed files with 250 additions and 0 deletions.
11 changes: 11 additions & 0 deletions app/Directory.Build.props
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<Project>

<Import Project="$(MSBuildThisFileDirectory)..\build\Common.props" />

<Import Project="$(MSBuildThisFileDirectory)..\build\NugetPackage.props" />

<Import Condition=" '$(MSBuildProjectExtension)' == '.csproj' "
Project="$(MSBuildThisFileDirectory)..\build\CSharp.props" />

</Project>
7 changes: 7 additions & 0 deletions app/Directory.Build.targets
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Project>

<Import Condition=" '$(MSBuildProjectExtension)' == '.csproj' "
Project="$(MSBuildThisFileDirectory)..\build\CSharp.targets" />

</Project>
28 changes: 28 additions & 0 deletions app/Shimakaze.Sdk.Vpl.Editor/ColorExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using Shimakaze.Sdk.Pal;

namespace Shimakaze.Sdk.Vpl.Editor;

/// <summary>
/// 颜色 扩展
/// </summary>
public static class ColorExtensions
{
/// <summary>
/// 转 ANSI Color 字符串 用于在终端显示颜色
/// </summary>
/// <param name="color">颜色</param>
/// <param name="isBackground">是否是背景色</param>
/// <returns></returns>
public static string GetANSIString(this in Color color, bool isBackground = false) => $"\x1B[{(isBackground ? 4 : 3)}8;2;{color.GetR5()};{color.GetG6()};{color.GetB5()}m";

/// <summary>
/// 反转颜色
/// </summary>
/// <param name="color">颜色</param>
/// <returns>被反转后的颜色</returns>
public static Color GetReverse(this in Color color) => new(
(byte)~color.Red,
(byte)~color.Green,
(byte)~color.Blue
);
}
31 changes: 31 additions & 0 deletions app/Shimakaze.Sdk.Vpl.Editor/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using Sharprompt;

using Shimakaze.Sdk.IO.Pal;
using Shimakaze.Sdk.IO.Vpl;
using Shimakaze.Sdk.Pal;
using Shimakaze.Sdk.Vpl;
using Shimakaze.Sdk.Vpl.Editor;

string vplPath = Prompt.Input<string>("What VPL File do you want edit?").Trim('"');
string palPath = Prompt.Input<string>("What PAL File do you want see?").Trim('"');

VoxelPalette vpl;
Palette pal;

await using (var vplStream = File.OpenRead(vplPath))
await using (VoxelPaletteReader vplReader = new(vplStream))
vpl = vplReader.Read();

await using (var palStream = File.OpenRead(palPath))
await using (PaletteReader palReader = new(palStream))
pal = palReader.Read();

VplEditor editor = new(vpl, pal, async (editor) =>
{
string path = Prompt.Input<string>("Where is your new VPL file save to?", vplPath);
await using var fs = File.Create(path);
await using VoxelPaletteWriter writer = new(fs);
writer.Write(editor.Vpl);
});

await editor.RunAsync();
14 changes: 14 additions & 0 deletions app/Shimakaze.Sdk.Vpl.Editor/Shimakaze.Sdk.Vpl.Editor.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<OutputType>Exe</OutputType>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\Shimakaze.Sdk.Vpl\Shimakaze.Sdk.Vpl.csproj" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Sharprompt" Version="3.0.0-preview2" />
</ItemGroup>
</Project>
159 changes: 159 additions & 0 deletions app/Shimakaze.Sdk.Vpl.Editor/VplEditor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
using Sharprompt;

using Shimakaze.Sdk.Pal;

namespace Shimakaze.Sdk.Vpl.Editor;

internal sealed class VplEditor
{
private const int X_SECTION_OFFSET = 3 * 16 + 4;
private const int Y_OFFSET = 1;
private const int SIZE_OF_CELL = 3;
public readonly VoxelPalette Vpl;
private readonly Palette _pal;
private readonly Func<VplEditor, Task> _saver;
private bool _isEditing;
private (int X, int Y, int Section) _current;
private (int X, int Y) _editing;

public VplEditor(VoxelPalette vpl, Palette pal, Func<VplEditor, Task> saver)
{
Vpl = vpl;
_pal = pal;
_saver = saver;
}

public async Task RunAsync()
{
PrintColor();
while (true)
{
if (_isEditing)
Console.SetCursorPosition(_editing.X * SIZE_OF_CELL, Y_OFFSET + _editing.Y);
else
Console.SetCursorPosition(X_SECTION_OFFSET + _current.X * SIZE_OF_CELL, Y_OFFSET + _current.Y);

var key = Console.ReadKey(true);
switch (key.Key)
{
case ConsoleKey.Tab when !_isEditing && key.Modifiers is ConsoleModifiers.Shift && _current.Section > 0:
case ConsoleKey.N when !_isEditing && _current.Section > 0:
_current.Section--;
PrintColor();
break;
case ConsoleKey.Tab when !_isEditing && key.Modifiers is 0 && _current.Section + 1 < Vpl.Header.SectionCount:
case ConsoleKey.M when !_isEditing && _current.Section + 1 < Vpl.Header.SectionCount:
_current.Section++;
PrintColor();
break;
case ConsoleKey.LeftArrow when !_isEditing && _current.X > 0:
case ConsoleKey.H when !_isEditing && _current.X > 0:
_current.X--;
break;
case ConsoleKey.RightArrow when !_isEditing && _current.X < 15:
case ConsoleKey.L when !_isEditing && _current.X < 15:
_current.X++;
break;
case ConsoleKey.UpArrow when !_isEditing && _current.Y > 0:
case ConsoleKey.K when !_isEditing && _current.Y > 0:
_current.Y--;
break;
case ConsoleKey.DownArrow when !_isEditing && _current.Y < 15:
case ConsoleKey.J when !_isEditing && _current.Y < 15:
_current.Y++;
break;
case ConsoleKey.LeftArrow when _isEditing && _editing.X > 0:
case ConsoleKey.H when _isEditing && _editing.X > 0:
_editing.X--;
break;
case ConsoleKey.RightArrow when _isEditing && _editing.X < 15:
case ConsoleKey.L when _isEditing && _editing.X < 15:
_editing.X++;
break;
case ConsoleKey.UpArrow when _isEditing && _editing.Y > 0:
case ConsoleKey.K when _isEditing && _editing.Y > 0:
_editing.Y--;
break;
case ConsoleKey.DownArrow when _isEditing && _editing.Y < 15:
case ConsoleKey.J when _isEditing && _editing.Y < 15:
_editing.Y++;
break;
case ConsoleKey.Enter when !_isEditing:
case ConsoleKey.Spacebar when !_isEditing:
byte index = Vpl[_current.Section][(_current.Y * 16) + _current.X];
_editing.X = index % 16;
_editing.Y = index / 16;
_isEditing = true;
PrintColor();
break;
case ConsoleKey.Enter when _isEditing:
case ConsoleKey.Spacebar when _isEditing:
index = (byte)((_editing.Y * 16) + _editing.X);
{
var tmp = Vpl[_current.Section];
tmp[(_current.Y * 16) + _current.X] = index;
Vpl[_current.Section] = tmp;
}
_isEditing = false;
PrintColor();
break;
case ConsoleKey.Escape when _isEditing:
case ConsoleKey.Q when _isEditing:
_isEditing = false;
PrintColor();
break;
case ConsoleKey.Escape when !_isEditing:
case ConsoleKey.Q when !_isEditing:
Console.SetCursorPosition(0, Y_OFFSET + 16);
var isExit = Prompt.Confirm("Are you sure you want to exit? Your changed will NOT saved!", false);
if (isExit)
Environment.Exit(0);

PrintColor();
break;
case ConsoleKey.S:
Console.SetCursorPosition(0, Y_OFFSET + 16);
await _saver(this);
PrintColor();
break;
}
}
}

void PrintColor()
{
Console.CursorVisible = false;
Console.Clear();
Console.SetCursorPosition(0, 0);
Console.Write("色板:");
Console.SetCursorPosition(X_SECTION_OFFSET, 0);
Console.Write("Section: #");
Console.Write((_current.Section + 1).ToString("D2"));
Console.WriteLine("\x1B[0m");
for (int y = 0; y < 256 / 16; y++)
{
for (int x = 0; x < 16; x++)
{
Console.Write(_pal[(y * 16) + x].GetANSIString(true));
Console.Write(" ");
}

Console.Write("\x1B[0m ");

for (int x = 0; x < 16; x++)
{
Console.Write(_pal[Vpl[_current.Section][(y * 16) + x]].GetANSIString(true));
if (x == _current.X && y == _current.Y && _isEditing)
{
Console.Write(_pal[Vpl[_current.Section][(y * 16) + x]].GetReverse().GetANSIString(false));
Console.Write(" x ");
}
else
Console.Write(" ");
}

Console.WriteLine("\x1B[0m");
}
Console.CursorVisible = true;
}
}

0 comments on commit 2f3c81c

Please sign in to comment.