Tooltip support & Bug fix

This commit is contained in:
BruceChen 2022-12-11 13:00:19 +08:00
parent 892999ac98
commit 5e11ed3896
40 changed files with 8409 additions and 1987 deletions

View file

@ -1,6 +1,4 @@
using System;
using Brigadier.NET;
using MinecraftClient.CommandHandler;
using MinecraftClient.Mapping;
using MinecraftClient.Scripting;
using Tomlet.Attributes;

View file

@ -1,7 +1,5 @@
using System;
using System.Collections.Generic;
using Brigadier.NET;
using MinecraftClient.CommandHandler;
using MinecraftClient.Mapping;
using MinecraftClient.Scripting;
using Tomlet.Attributes;

View file

@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Brigadier.NET;
using Brigadier.NET.Builder;
using MinecraftClient.CommandHandler;
using MinecraftClient.CommandHandler.Patch;

View file

@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Brigadier.NET;
using Brigadier.NET.Builder;
using MinecraftClient.CommandHandler;
using MinecraftClient.CommandHandler.Patch;

View file

@ -2,7 +2,6 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Brigadier.NET;
using Brigadier.NET.Builder;
using MinecraftClient.CommandHandler;
using MinecraftClient.CommandHandler.Patch;

View file

@ -1,6 +1,4 @@
using System;
using Brigadier.NET;
using MinecraftClient.CommandHandler;
using MinecraftClient.Scripting;
using Tomlet.Attributes;

View file

@ -4,10 +4,8 @@ using System.Globalization;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using Brigadier.NET;
using MinecraftClient.CommandHandler;
using MinecraftClient.Scripting;
using PInvoke;
using Tomlet.Attributes;
using static MinecraftClient.Settings;

View file

@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Brigadier.NET;
using Brigadier.NET.Builder;
using DSharpPlus;
using DSharpPlus.Entities;

View file

@ -5,7 +5,6 @@ using System.IO;
using System.Linq;
using Brigadier.NET;
using Brigadier.NET.Builder;
using MinecraftClient.CommandHandler;
using MinecraftClient.CommandHandler.Patch;
using MinecraftClient.Scripting;
using Tomlet.Attributes;

View file

@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using Brigadier.NET;
using Brigadier.NET.Builder;
using MinecraftClient.CommandHandler;
using MinecraftClient.CommandHandler.Patch;

View file

@ -5,8 +5,6 @@ using System.IO;
using System.Reflection;
using System.Text;
using System.Threading;
using Brigadier.NET;
using MinecraftClient.CommandHandler;
using MinecraftClient.Scripting;
namespace MinecraftClient.ChatBots

View file

@ -3,7 +3,6 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Brigadier.NET;
using Brigadier.NET.Builder;
using MinecraftClient.CommandHandler;
using MinecraftClient.CommandHandler.Patch;

View file

@ -23,8 +23,27 @@ namespace MinecraftClient.CommandHandler.ArgumentType
public override Task<Suggestions> ListSuggestions<TSource>(CommandContext<TSource> context, SuggestionsBuilder builder)
{
foreach (var result in Enum.GetNames(typeof(EntityType)))
builder.Suggest(result);
foreach (EntityType result in Enum.GetValues<EntityType>())
{
string name = result.ToString();
string localName = Entity.GetTypeString(result);
bool same = true;
for (int i = 0, j = 0; i < name.Length; ++i, ++j)
{
while (j < localName.Length && localName[j] == ' ')
++j;
if (j >= localName.Length || name[i] != localName[j])
{
same = false;
break;
}
}
if (same)
builder.Suggest(name);
else
builder.Suggest(name, new SuggestionTooltip(localName));
}
return builder.BuildFuture();
}
}

View file

@ -0,0 +1,43 @@
using System;
using System.Threading.Tasks;
using Brigadier.NET;
using Brigadier.NET.ArgumentTypes;
using Brigadier.NET.Context;
using Brigadier.NET.Suggestion;
namespace MinecraftClient.CommandHandler.ArgumentType
{
public class HotbarSlotArgumentType : ArgumentType<int>
{
public override int Parse(IStringReader reader)
{
reader.SkipWhitespace();
return reader.ReadInt();
}
public override Task<Suggestions> ListSuggestions<TSource>(CommandContext<TSource> context, SuggestionsBuilder builder)
{
McClient? client = CmdResult.client;
if (client != null)
{
Inventory.Container? inventory = client.GetInventory(0);
if (inventory != null)
{
for (int i = 1; i <= 9; ++i)
{
if (inventory.Items.TryGetValue(i - 1 + 36, out Inventory.Item? item))
{
string slotStr = i.ToString();
if (slotStr.StartsWith(builder.RemainingLowerCase, StringComparison.InvariantCultureIgnoreCase))
{
string itemDesc = item.Count == 1 ? item.GetTypeString() : string.Format("{0}x{1}", item.Count, item.GetTypeString());
builder.Suggest(slotStr, new SuggestionTooltip(itemDesc));
}
}
}
}
}
return builder.BuildFuture();
}
}
}

View file

@ -25,7 +25,13 @@ namespace MinecraftClient.CommandHandler.ArgumentType
{
string invName = inv.Key.ToString();
if (invName.StartsWith(builder.RemainingLowerCase, StringComparison.InvariantCultureIgnoreCase))
builder.Suggest(invName);
{
string? invTitle = inv.Value.Title;
if (!string.IsNullOrWhiteSpace(invTitle))
builder.Suggest(invName, new SuggestionTooltip(invTitle));
else
builder.Suggest(invName);
}
}
}
return builder.BuildFuture();

View file

@ -0,0 +1,55 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using Brigadier.NET;
using Brigadier.NET.ArgumentTypes;
using Brigadier.NET.Context;
using Brigadier.NET.Suggestion;
namespace MinecraftClient.CommandHandler.ArgumentType
{
public class InventorySlotArgumentType : ArgumentType<int>
{
public override int Parse(IStringReader reader)
{
reader.SkipWhitespace();
return reader.ReadInt();
}
public override Task<Suggestions> ListSuggestions<TSource>(CommandContext<TSource> context, SuggestionsBuilder builder)
{
McClient? client = CmdResult.client;
if (client != null && context.Nodes.Count >= 2)
{
string invName = context.Nodes[1].Range.Get(builder.Input);
if (!int.TryParse(invName, out int invId))
invId = invName switch
{
"creativegive" => 0,
"creativedelete" => 0,
"player" => 0,
"container" => client.GetInventories().Keys.ToList().Max(),
_ => -1,
};
Inventory.Container? inventory = client.GetInventory(invId);
if (inventory != null)
{
foreach ((int slot, Inventory.Item item) in inventory.Items)
{
if (item != null && item.Count > 0)
{
string slotStr = slot.ToString();
if (slotStr.StartsWith(builder.RemainingLowerCase, StringComparison.InvariantCultureIgnoreCase))
{
string itemDesc = item.Count == 1 ? item.GetTypeString() : string.Format("{0}x{1}", item.Count, item.GetTypeString());
builder.Suggest(slotStr, new SuggestionTooltip(itemDesc));
}
}
}
}
}
return builder.BuildFuture();
}
}
}

View file

@ -23,8 +23,29 @@ namespace MinecraftClient.CommandHandler.ArgumentType
public override Task<Suggestions> ListSuggestions<TSource>(CommandContext<TSource> context, SuggestionsBuilder builder)
{
foreach (var result in Enum.GetNames(typeof(ItemType)))
builder.Suggest(result);
foreach (ItemType result in Enum.GetValues<ItemType>())
{
if (result == ItemType.Unknown || result == ItemType.Null)
continue;
string name = result.ToString();
string localName = Item.GetTypeString(result);
bool same = true;
for (int i = 0, j = 0; i < name.Length; ++i, ++j)
{
while (j < localName.Length && localName[j] == ' ')
++j;
if (j >= localName.Length || name[i] != localName[j])
{
same = false;
break;
}
}
if (same)
builder.Suggest(name);
else
builder.Suggest(name, new SuggestionTooltip(localName));
}
return builder.BuildFuture();
}
}

View file

@ -71,6 +71,11 @@ namespace MinecraftClient.CommandHandler
return new InventoryActionArgumentType();
}
public static InventorySlotArgumentType InventorySlot()
{
return new InventorySlotArgumentType();
}
public static Inventory.WindowActionType GetInventoryAction<TSource>(CommandContext<TSource> context, string name)
{
return context.GetArgument<Inventory.WindowActionType>(name);
@ -100,5 +105,10 @@ namespace MinecraftClient.CommandHandler
{
return new MapBotMapIdArgumentType();
}
public static HotbarSlotArgumentType HotbarSlot()
{
return new HotbarSlotArgumentType();
}
}
}

View file

@ -18,19 +18,26 @@ namespace MinecraftClient.CommandHandler.Patch
public static string GetAllUsageString(this CommandDispatcher<CmdResult> commandDispatcher, string commandName, bool restricted)
{
char cmdChar = Settings.Config.Main.Advanced.InternalCmdChar.ToChar();
string[] usages = commandDispatcher.GetAllUsage(commandDispatcher.GetRoot().GetChild(commandName), new(), restricted);
StringBuilder sb = new();
sb.AppendLine("All Usages:");
foreach (var usage in usages)
try
{
sb.Append(cmdChar).Append(commandName).Append(' ');
if (usage.Length > 0 && usage[0] == '_')
sb.AppendLine(usage.Replace("_help -> ", $"_help -> {cmdChar}help "));
else
sb.AppendLine(usage);
string[] usages = commandDispatcher.GetAllUsage(commandDispatcher.GetRoot().GetChild(commandName), new(), restricted);
StringBuilder sb = new();
sb.AppendLine("All Usages:");
foreach (var usage in usages)
{
sb.Append(cmdChar).Append(commandName).Append(' ');
if (usage.Length > 0 && usage[0] == '_')
sb.AppendLine(usage.Replace("_help -> ", $"_help -> {cmdChar}help "));
else
sb.AppendLine(usage);
}
sb.Remove(sb.Length - 1, 1);
return sb.ToString();
}
catch
{
return string.Empty;
}
sb.Remove(sb.Length - 1, 1);
return sb.ToString();
}
}
}

View file

@ -0,0 +1,14 @@
using Brigadier.NET;
namespace MinecraftClient.CommandHandler
{
internal class SuggestionTooltip : IMessage
{
public SuggestionTooltip(string tooltip)
{
String = tooltip;
}
public string String { get; set; }
}
}

View file

@ -20,7 +20,7 @@ namespace MinecraftClient.Commands
);
dispatcher.Register(l => l.Literal(CmdName)
.Then(l => l.Argument("Slot", Arguments.Integer(1, 9))
.Then(l => l.Argument("Slot", MccArguments.HotbarSlot())
.Executes(r => DoChangeSlot(r.Source, handler, Arguments.GetInteger(r, "Slot"))))
.Then(l => l.Literal("_help")
.Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName)))

View file

@ -44,12 +44,12 @@ namespace MinecraftClient.Commands
dispatcher.Register(l => l.Literal(CmdName)
.Executes(r => ListAllInventories(r.Source, handler))
.Then(l => l.Literal("creativegive")
.Then(l => l.Argument("Slot", Arguments.Integer(0, 89))
.Then(l => l.Argument("Slot", MccArguments.InventorySlot())
.Then(l => l.Argument("ItemType", MccArguments.ItemType())
.Then(l => l.Argument("Count", Arguments.Integer(min: 1))
.Executes(r => DoCreativeGive(r.Source, handler, Arguments.GetInteger(r, "Slot"), MccArguments.GetItemType(r, "ItemType"), Arguments.GetInteger(r, "Count")))))))
.Then(l => l.Literal("creativedelete")
.Then(l => l.Argument("Slot", Arguments.Integer(0, 89))
.Then(l => l.Argument("Slot", MccArguments.InventorySlot())
.Executes(r => DoCreativeDelete(r.Source, handler, Arguments.GetInteger(r, "Slot")))))
.Then(l => l.Literal("inventories")
.Executes(r => ListAvailableInventories(r.Source, handler)))
@ -64,12 +64,12 @@ namespace MinecraftClient.Commands
.Then(l => l.Literal("list")
.Executes(r => DoListAction(r.Source, handler, Arguments.GetInteger(r, "InventoryId"))))
.Then(l => l.Literal("click")
.Then(l => l.Argument("Slot", Arguments.Integer(0, 89))
.Then(l => l.Argument("Slot", MccArguments.InventorySlot())
.Executes(r => DoClickAction(r.Source, handler, Arguments.GetInteger(r, "InventoryId"), Arguments.GetInteger(r, "Slot"), WindowActionType.LeftClick))
.Then(l => l.Argument("Action", MccArguments.InventoryAction())
.Executes(r => DoClickAction(r.Source, handler, Arguments.GetInteger(r, "InventoryId"), Arguments.GetInteger(r, "Slot"), MccArguments.GetInventoryAction(r, "Action"))))))
.Then(l => l.Literal("drop")
.Then(l => l.Argument("Slot", Arguments.Integer(0, 89))
.Then(l => l.Argument("Slot", MccArguments.InventorySlot())
.Executes(r => DoDropAction(r.Source, handler, Arguments.GetInteger(r, "InventoryId"), Arguments.GetInteger(r, "Slot"), WindowActionType.DropItem))
.Then(l => l.Literal("all")
.Executes(r => DoDropAction(r.Source, handler, Arguments.GetInteger(r, "InventoryId"), Arguments.GetInteger(r, "Slot"), WindowActionType.DropItemStack))))))
@ -77,12 +77,12 @@ namespace MinecraftClient.Commands
.Then(l => l.Literal("list")
.Executes(r => DoListAction(r.Source, handler, inventoryId: 0)))
.Then(l => l.Literal("click")
.Then(l => l.Argument("Slot", Arguments.Integer(0, 45))
.Then(l => l.Argument("Slot", MccArguments.InventorySlot())
.Executes(r => DoClickAction(r.Source, handler, inventoryId: 0, Arguments.GetInteger(r, "Slot"), WindowActionType.LeftClick))
.Then(l => l.Argument("Action", MccArguments.InventoryAction())
.Executes(r => DoClickAction(r.Source, handler, inventoryId: 0, Arguments.GetInteger(r, "Slot"), MccArguments.GetInventoryAction(r, "Action"))))))
.Then(l => l.Literal("drop")
.Then(l => l.Argument("Slot", Arguments.Integer(0, 45))
.Then(l => l.Argument("Slot", MccArguments.InventorySlot())
.Executes(r => DoDropAction(r.Source, handler, inventoryId: 0, Arguments.GetInteger(r, "Slot"), WindowActionType.DropItem))
.Then(l => l.Literal("all")
.Executes(r => DoDropAction(r.Source, handler, inventoryId: 0, Arguments.GetInteger(r, "Slot"), WindowActionType.DropItemStack))))))
@ -92,12 +92,12 @@ namespace MinecraftClient.Commands
.Then(l => l.Literal("list")
.Executes(r => DoListAction(r.Source, handler, inventoryId: null)))
.Then(l => l.Literal("click")
.Then(l => l.Argument("Slot", Arguments.Integer(0, 89))
.Then(l => l.Argument("Slot", MccArguments.InventorySlot())
.Executes(r => DoClickAction(r.Source, handler, inventoryId: null, Arguments.GetInteger(r, "Slot"), WindowActionType.LeftClick))
.Then(l => l.Argument("Action", MccArguments.InventoryAction())
.Executes(r => DoClickAction(r.Source, handler, inventoryId: null, Arguments.GetInteger(r, "Slot"), MccArguments.GetInventoryAction(r, "Action"))))))
.Then(l => l.Literal("drop")
.Then(l => l.Argument("Slot", Arguments.Integer(0, 89))
.Then(l => l.Argument("Slot", MccArguments.InventorySlot())
.Executes(r => DoDropAction(r.Source, handler, inventoryId: null, Arguments.GetInteger(r, "Slot"), WindowActionType.DropItem))
.Then(l => l.Literal("all")
.Executes(r => DoDropAction(r.Source, handler, inventoryId: null, Arguments.GetInteger(r, "Slot"), WindowActionType.DropItemStack))))))

View file

@ -1,5 +1,4 @@
using System.Collections.Generic;
using Brigadier.NET;
using Brigadier.NET;
using Brigadier.NET.Builder;
using MinecraftClient.CommandHandler;
@ -11,7 +10,8 @@ namespace MinecraftClient.Commands
public override string CmdUsage { get { return "upgrade [-f|check|cancel|download]"; } }
public override string CmdDesc { get { return string.Empty; } }
public override void RegisterCommand(McClient handler, CommandDispatcher<CmdResult> dispatcher) {
public override void RegisterCommand(McClient handler, CommandDispatcher<CmdResult> dispatcher)
{
dispatcher.Register(l => l.Literal("help")
.Then(l => l.Literal(CmdName)
.Executes(r => GetUsage(r.Source, string.Empty))
@ -41,8 +41,10 @@ namespace MinecraftClient.Commands
);
}
private int GetUsage(CmdResult r, string? cmd) {
return r.SetAndReturn(cmd switch {
private int GetUsage(CmdResult r, string? cmd)
{
return r.SetAndReturn(cmd switch
{
#pragma warning disable format // @formatter:off
"cancel" => GetCmdDescTranslated(),
"check" => GetCmdDescTranslated(),

View file

@ -220,16 +220,19 @@ namespace MinecraftClient
string command = fullCommand[offset..];
if (command.Length == 0)
{
var childs = CmdResult.client!.dispatcher.GetRoot().Children;
int index = 0;
var sugList = new ConsoleInteractive.ConsoleSuggestion.Suggestion[childs.Count + Commands.Count + 1];
List<ConsoleInteractive.ConsoleSuggestion.Suggestion> sugList = new();
sugList.Add(new("/"));
var childs = CmdResult.client?.dispatcher.GetRoot().Children;
if (childs != null)
foreach (var child in childs)
sugList.Add(new(child.Name));
sugList[index++] = new("/");
foreach (var child in childs)
sugList[index++] = new(child.Name);
foreach (var cmd in Commands)
sugList[index++] = new(cmd);
ConsoleInteractive.ConsoleSuggestion.UpdateSuggestions(sugList, new(offset, offset));
sugList.Add(new(cmd));
ConsoleInteractive.ConsoleSuggestion.UpdateSuggestions(sugList.ToArray(), new(offset, offset));
}
else if (command.Length > 0 && command[0] == '/' && !command.Contains(' '))
{
@ -243,29 +246,37 @@ namespace MinecraftClient
}
else
{
var parse = CmdResult.client!.dispatcher.Parse(command, CmdResult.Empty);
CommandDispatcher<CmdResult>? dispatcher = CmdResult.client?.dispatcher;
if (dispatcher == null)
return;
var suggestion = await CmdResult.client!.dispatcher.GetCompletionSuggestions(parse, buffer.CursorPosition - offset);
ParseResults<CmdResult> parse = dispatcher.Parse(command, CmdResult.Empty);
int sugLen = suggestion.List.Count;
Brigadier.NET.Suggestion.Suggestions suggestions = await dispatcher.GetCompletionSuggestions(parse, buffer.CursorPosition - offset);
int sugLen = suggestions.List.Count;
if (sugLen == 0)
{
ConsoleInteractive.ConsoleSuggestion.ClearSuggestions();
return;
}
Dictionary<string, string?> dictionary = new();
foreach (var sug in suggestions.List)
dictionary.Add(sug.Text, sug.Tooltip?.String);
var sugList = new ConsoleInteractive.ConsoleSuggestion.Suggestion[sugLen];
if (cts.IsCancellationRequested)
return;
Tuple<int, int> range = new(suggestion.Range.Start + offset, suggestion.Range.End + offset);
var sorted = Process.ExtractSorted(fullCommand[range.Item1..range.Item2], suggestion.List.Select(_ => _.Text).ToList());
Tuple<int, int> range = new(suggestions.Range.Start + offset, suggestions.Range.End + offset);
var sorted = Process.ExtractSorted(fullCommand[range.Item1..range.Item2], dictionary.Keys);
if (cts.IsCancellationRequested)
return;
int index = 0;
foreach (var sug in sorted)
sugList[index++] = new(sug.Value);
sugList[index++] = new(sug.Value, dictionary[sug.Value] ?? string.Empty);
ConsoleInteractive.ConsoleSuggestion.UpdateSuggestions(sugList, range);
}
@ -283,7 +294,8 @@ namespace MinecraftClient
public static void AutocompleteHandler(object? sender, ConsoleInteractive.ConsoleReader.Buffer buffer)
{
MccAutocompleteHandler(buffer);
if (Settings.Config.Console.CommandSuggestion.Enable)
MccAutocompleteHandler(buffer);
}
public static void CancelAutocomplete()

View file

@ -156,11 +156,16 @@ namespace MinecraftClient.Mapping
Pitch = pitch * (1 / 256) * 360;
}
public string GetTypeString()
public static string GetTypeString(EntityType type)
{
string typeStr = Type.ToString();
string typeStr = type.ToString();
string? trans = ChatParser.TranslateString("entity.minecraft." + typeStr.ToUnderscoreCase());
return string.IsNullOrEmpty(trans) ? typeStr : trans;
}
public string GetTypeString()
{
return GetTypeString(Type);
}
}
}

View file

@ -150,7 +150,6 @@ namespace MinecraftClient
/// <param name="forgeInfo">ForgeInfo item stating that Forge is enabled</param>
public McClient(SessionToken session, PlayerKeyPair? playerKeyPair, string server_ip, ushort port, int protocolversion, ForgeInfo? forgeInfo)
{
dispatcher = new();
CmdResult.client = this;
terrainAndMovementsEnabled = Config.Main.Advanced.TerrainAndMovements;
inventoryHandlingEnabled = Config.Main.Advanced.InventoryHandling;
@ -1048,9 +1047,10 @@ namespace MinecraftClient
if (InvokeRequired)
return InvokeOnMainThread(() => GetInventory(inventoryID));
if (inventories.ContainsKey(inventoryID))
return inventories[inventoryID];
return null;
if (inventories.TryGetValue(inventoryID, out Container? inv))
return inv;
else
return null;
}
/// <summary>

View file

@ -85,6 +85,11 @@
<AutoGen>True</AutoGen>
<DependentUpon>ConfigComments.resx</DependentUpon>
</Compile>
<Compile Update="Resources\MinecraftAssets.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>MinecraftAssets.resx</DependentUpon>
</Compile>
<Compile Update="Resources\Translations\Translations.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
@ -102,6 +107,11 @@
<LastGenOutput>ConfigComments.Designer.cs</LastGenOutput>
<CustomToolNamespace>MinecraftClient</CustomToolNamespace>
</EmbeddedResource>
<EmbeddedResource Update="Resources\MinecraftAssets.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>MinecraftAssets.Designer.cs</LastGenOutput>
<CustomToolNamespace>MinecraftClient</CustomToolNamespace>
</EmbeddedResource>
<EmbeddedResource Update="Resources\Translations\Translations.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Translations.Designer.cs</LastGenOutput>

View file

@ -692,7 +692,7 @@ namespace MinecraftClient
{
WriteBackSettings(true);
ConsoleInteractive.ConsoleSuggestion.ClearSuggestions();
ConsoleIO.WriteLineFormatted(string.Format(Translations.config_saving, settingsIniPath));
ConsoleIO.WriteLineFormatted("§a" + string.Format(Translations.config_saving, settingsIniPath));
if (client != null) { client.Disconnect(); ConsoleIO.Reset(); }
if (offlinePrompt != null) { offlinePrompt.Item2.Cancel(); offlinePrompt.Item1.Join(); offlinePrompt = null; ConsoleIO.Reset(); }

View file

@ -1,8 +1,9 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using static MinecraftClient.Settings;
@ -186,7 +187,7 @@ namespace MinecraftClient.Protocol.Message
/// <summary>
/// Set of translation rules for formatting text
/// </summary>
private static readonly Dictionary<string, string> TranslationRules = new();
private static Dictionary<string, string> TranslationRules = new();
/// <summary>
/// Initialize translation rules.
@ -199,90 +200,85 @@ namespace MinecraftClient.Protocol.Message
/// </summary>
private static void InitRules()
{
//Small default dictionnary of translation rules
TranslationRules["chat.type.admin"] = "[%s: %s]";
TranslationRules["chat.type.announcement"] = "§d[%s] %s";
TranslationRules["chat.type.emote"] = " * %s %s";
TranslationRules["chat.type.text"] = "<%s> %s";
TranslationRules["multiplayer.player.joined"] = "§e%s joined the game.";
TranslationRules["multiplayer.player.left"] = "§e%s left the game.";
TranslationRules["commands.message.display.incoming"] = "§7%s whispers to you: %s";
TranslationRules["commands.message.display.outgoing"] = "§7You whisper to %s: %s";
if (Config.Main.Advanced.Language == "en_us")
{
TranslationRules = JsonSerializer.Deserialize<Dictionary<string, string>>((byte[])MinecraftAssets.ResourceManager.GetObject("en_us.json")!)!;
return;
}
//Language file in a subfolder, depending on the language setting
if (!Directory.Exists("lang"))
Directory.CreateDirectory("lang");
string Language_File = "lang" + Path.DirectorySeparatorChar + Config.Main.Advanced.Language + ".lang";
string languageFilePath = "lang" + Path.DirectorySeparatorChar + Config.Main.Advanced.Language + ".json";
//File not found? Try downloading language file from Mojang's servers?
if (!File.Exists(Language_File))
// Load the external dictionnary of translation rules or display an error message
if (File.Exists(languageFilePath))
{
ConsoleIO.WriteLineFormatted("§8" + string.Format(Translations.chat_download, Config.Main.Advanced.Language));
HttpClient httpClient = new();
try
{
Task<string> fetch_index = httpClient.GetStringAsync(TranslationsFile_Website_Index);
fetch_index.Wait();
string assets_index = fetch_index.Result;
fetch_index.Dispose();
TranslationRules = JsonSerializer.Deserialize<Dictionary<string, string>>(File.OpenRead(languageFilePath))!;
}
catch (IOException) { }
catch (JsonException) { }
}
string[] tmp = assets_index.Split(new string[] { "minecraft/lang/" + Config.Main.Advanced.Language.ToLower() + ".json" }, StringSplitOptions.None);
tmp = tmp[1].Split(new string[] { "hash\": \"" }, StringSplitOptions.None);
string hash = tmp[1].Split('"')[0]; //Translations file identifier on Mojang's servers
if (TranslationRules.TryGetValue("Version", out string? version) && version == Settings.TranslationsFile_Version)
{
if (Config.Logging.DebugMessages)
ConsoleIO.WriteLineFormatted(Translations.chat_loaded, acceptnewlines: true);
return;
}
// Try downloading language file from Mojang's servers?
ConsoleIO.WriteLineFormatted("§8" + string.Format(Translations.chat_download, Config.Main.Advanced.Language));
HttpClient httpClient = new();
try
{
Task<string> fetch_index = httpClient.GetStringAsync(TranslationsFile_Website_Index);
fetch_index.Wait();
Match match = Regex.Match(fetch_index.Result, $"minecraft/lang/{Config.Main.Advanced.Language}.json" + @""":\s\{""hash"":\s""([\d\w]{40})""");
fetch_index.Dispose();
if (match.Success && match.Groups.Count == 2)
{
string hash = match.Groups[1].Value;
string translation_file_location = TranslationsFile_Website_Download + '/' + hash[..2] + '/' + hash;
if (Config.Logging.DebugMessages)
ConsoleIO.WriteLineFormatted(string.Format(Translations.chat_request, translation_file_location));
Task<string> fetch_file = httpClient.GetStringAsync(translation_file_location);
Task<Stream> fetch_file = httpClient.GetStreamAsync(translation_file_location);
fetch_file.Wait();
string translation_file = fetch_file.Result;
TranslationRules = JsonSerializer.Deserialize<Dictionary<string, string>>(fetch_file.Result)!;
fetch_file.Dispose();
StringBuilder stringBuilder = new();
foreach (KeyValuePair<string, Json.JSONData> entry in Json.ParseJson(translation_file).Properties)
stringBuilder.Append(entry.Key).Append('=').Append(entry.Value.StringValue.Replace("\n", "\\n").Replace("\r", string.Empty)).Append(Environment.NewLine);
File.WriteAllText(Language_File, stringBuilder.ToString());
TranslationRules["Version"] = TranslationsFile_Version;
ConsoleIO.WriteLineFormatted("§8" + string.Format(Translations.chat_done, Language_File));
File.WriteAllText(languageFilePath, JsonSerializer.Serialize(TranslationRules, typeof(Dictionary<string, string>)), Encoding.UTF8);
ConsoleIO.WriteLineFormatted("§8" + string.Format(Translations.chat_done, languageFilePath));
return;
}
catch
else
{
ConsoleIO.WriteLineFormatted("§8" + Translations.chat_fail, acceptnewlines: true);
}
}
catch (HttpRequestException)
{
ConsoleIO.WriteLineFormatted("§8" + Translations.chat_fail, acceptnewlines: true);
}
catch (IOException)
{
ConsoleIO.WriteLineFormatted("§8" + string.Format(Translations.chat_save_fail, languageFilePath), acceptnewlines: true);
}
finally
{
httpClient.Dispose();
}
//Download Failed? Defaulting to en_GB.lang if the game is installed
if (!File.Exists(Language_File) //Try en_GB.lang
&& File.Exists(TranslationsFile_FromMCDir))
{
Language_File = TranslationsFile_FromMCDir;
ConsoleIO.WriteLineFormatted(Translations.chat_from_dir, acceptnewlines: true);
}
//Load the external dictionnary of translation rules or display an error message
if (File.Exists(Language_File))
{
foreach (var line in File.ReadLines(Language_File))
{
if (line.Length > 0)
{
string[] splitted = line.Split('=');
if (splitted.Length == 2)
{
TranslationRules[splitted[0]] = splitted[1];
}
}
}
if (Config.Logging.DebugMessages)
ConsoleIO.WriteLineFormatted(Translations.chat_loaded, acceptnewlines: true);
}
else //No external dictionnary found.
{
ConsoleIO.WriteLineFormatted("§8" + string.Format(Translations.chat_not_found, Language_File));
}
TranslationRules = JsonSerializer.Deserialize<Dictionary<string, string>>((byte[])MinecraftAssets.ResourceManager.GetObject("en_us.json")!)!;
ConsoleIO.WriteLine(Translations.chat_use_default);
}
public static string? TranslateString(string rulename)

View file

@ -1,9 +1,9 @@
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net.Security;
using System.Net.Sockets;
using System.Security.Authentication;
@ -193,7 +193,7 @@ namespace MinecraftClient.Protocol
response.Body = rbody ?? "";
response.StatusCode = statusCode;
response.Headers = headers;
try
{
stream.Close();

View file

@ -82,7 +82,7 @@ namespace MinecraftClient.Proxy
case Configs.ProxyType.SOCKS5: innerProxytype = ProxyType.Socks5; break;
}
if (!string.IsNullOrWhiteSpace(Config.Username)&& !string.IsNullOrWhiteSpace(Config.Password))
if (!string.IsNullOrWhiteSpace(Config.Username) && !string.IsNullOrWhiteSpace(Config.Password))
proxy = factory.CreateProxyClient(innerProxytype, Config.Server.Host, Config.Server.Port, Config.Username, Config.Password);
else
proxy = factory.CreateProxyClient(innerProxytype, Config.Server.Host, Config.Server.Port);

File diff suppressed because it is too large Load diff

View file

@ -535,6 +535,21 @@ When this happens, you'll need to configure chat format below, see https://mccte
<data name="ChatFormat.UserDefined" xml:space="preserve">
<value>Whether to use the custom regular expressions below for detection.</value>
</data>
<data name="Console" xml:space="preserve">
<value>Console-related settings.</value>
</data>
<data name="Console.CommandSuggestion" xml:space="preserve">
<value>The settings for command completion suggestions.</value>
</data>
<data name="Console.CommandSuggestion.Enable" xml:space="preserve">
<value>Whether to display command suggestions in the console.</value>
</data>
<data name="Console.Enable_Color" xml:space="preserve">
<value>If a garbled code like "←[0m" appears on the terminal, you can turn off this.</value>
</data>
<data name="Console.General.Display_Uesr_Input" xml:space="preserve">
<value>You can use "Ctrl+P" to print out the current input and cursor position.</value>
</data>
<data name="Head" xml:space="preserve">
<value>Startup Config File
Please do not record extraneous data in this file as it will be overwritten by MCC.

View file

@ -0,0 +1,73 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace MinecraftClient {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class MinecraftAssets {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal MinecraftAssets() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("MinecraftClient.Resources.MinecraftAssets", typeof(MinecraftAssets).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
internal static byte[] en_us_json {
get {
object obj = ResourceManager.GetObject("en_us.json", resourceCulture);
return ((byte[])(obj));
}
}
}
}

View file

@ -0,0 +1,124 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="en_us.json" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>en_us.json;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
</root>

View file

@ -2270,15 +2270,6 @@ namespace MinecraftClient {
}
}
/// <summary>
/// Looks up a localized string similar to Defaulting to en_GB.lang from your Minecraft directory..
/// </summary>
internal static string chat_from_dir {
get {
return ResourceManager.GetString("chat.from_dir", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Translations file loaded..
/// </summary>
@ -2316,6 +2307,24 @@ namespace MinecraftClient {
}
}
/// <summary>
/// Looks up a localized string similar to Failed to save the file {0}..
/// </summary>
internal static string chat_save_fail {
get {
return ResourceManager.GetString("chat.save_fail", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Switch to use Minecraft&apos;s default language resource &quot;en_us.json&quot;..
/// </summary>
internal static string chat_use_default {
get {
return ResourceManager.GetString("chat.use_default", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to [{0}] Disconnecting and Reconnecting to the Server.
/// </summary>
@ -4112,6 +4121,15 @@ namespace MinecraftClient {
}
}
/// <summary>
/// Looks up a localized string similar to The color code {1} in {0} is in illegal format and the default value has been restored..
/// </summary>
internal static string config_commandsuggestion_illegal_color {
get {
return ResourceManager.GetString("config.commandsuggestion.illegal_color", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Settings have been loaded from {0}.
/// </summary>

View file

@ -869,9 +869,6 @@ Add the ID of this chat to "Authorized_Chat_Ids" field in the configuration file
<data name="chat.fail" xml:space="preserve">
<value>Failed to download the file.</value>
</data>
<data name="chat.from_dir" xml:space="preserve">
<value>Defaulting to en_GB.lang from your Minecraft directory.</value>
</data>
<data name="chat.loaded" xml:space="preserve">
<value>Translations file loaded.</value>
</data>
@ -885,6 +882,12 @@ Some messages won't be properly printed without this file.</value>
<data name="chat.request" xml:space="preserve">
<value>Performing request to {0}</value>
</data>
<data name="chat.save_fail" xml:space="preserve">
<value>Failed to save the file {0}.</value>
</data>
<data name="chat.use_default" xml:space="preserve">
<value>Switch to use Minecraft's default language resource "en_us.json".</value>
</data>
<data name="chatbot.reconnect" xml:space="preserve">
<value>[{0}] Disconnecting and Reconnecting to the Server</value>
</data>
@ -1449,7 +1452,7 @@ You can use "/chunk status {0:0.0} {1:0.0} {2:0.0}" to check the chunk loading s
<value>set a custom %variable% randomly to a given value.</value>
</data>
<data name="cmd.setrnd.format" xml:space="preserve">
<value>setrnd variable -7to17 OR setrnd variable string1 "\"string2\" string3"</value>
<value>setrnd variable -7 to 17 OR setrnd variable string1 "\"string2\" string3"</value>
</data>
<data name="cmd.setrndnum.format" xml:space="preserve">
<value>setrnd variable -7 to 17</value>
@ -1487,6 +1490,9 @@ You can use "/chunk status {0:0.0} {1:0.0} {2:0.0}" to check the chunk loading s
<data name="config.backup.fail" xml:space="preserve">
<value>Failed to write to backup file {0}</value>
</data>
<data name="config.commandsuggestion.illegal_color" xml:space="preserve">
<value>The color code {1} in {0} is in illegal format and the default value has been restored.</value>
</data>
<data name="config.load" xml:space="preserve">
<value>Settings have been loaded from {0}</value>
</data>
@ -1991,9 +1997,6 @@ Switching to autodetection mode.</value>
<data name="mcc.update.progress" xml:space="preserve">
<value>Self-updating: {0:00.00}%, ETA {4}, Downloaded {1:00.0}MB of {2:00.0}MB, Avg {3:0.0}KB/s</value>
</data>
<data name="cmd.setrnd.format" xml:space="preserve">
<value>setrnd variable -7 to 17 OR setrnd variable string1 "\"string2\" string3"</value>
</data>
<data name="mcc.update.progress_type2" xml:space="preserve">
<value>Self-updating: Downloaded {0:00.0}MB, Avg {1:0.0}KB/s</value>
</data>
@ -2025,4 +2028,4 @@ Logging in...</value>
<data name="proxy.connected" xml:space="preserve">
<value>Connected to proxy {0}:{1}</value>
</data>
</root>
</root>

File diff suppressed because it is too large Load diff

View file

@ -16,6 +16,7 @@ using Tomlet.Models;
using static MinecraftClient.Settings.AppVarConfigHelper;
using static MinecraftClient.Settings.ChatBotConfigHealper;
using static MinecraftClient.Settings.ChatFormatConfigHelper;
using static MinecraftClient.Settings.ConsoleConfigHealper;
using static MinecraftClient.Settings.HeadCommentHealper;
using static MinecraftClient.Settings.LoggingConfigHealper;
using static MinecraftClient.Settings.MainConfigHealper;
@ -31,10 +32,10 @@ namespace MinecraftClient
private const int CommentsAlignPosition = 45;
private readonly static Regex CommentRegex = new(@"^(.*)\s?#\s\$([\w\.]+)\$\s*$$", RegexOptions.Compiled);
//Other Settings
public static string TranslationsFile_FromMCDir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + @"\.minecraft\assets\objects\48\482e0dae05abfa35ab5cb076e41fda77b4fb9a08"; //MC 1.19 en_GB.lang
public static string TranslationsFile_Website_Index = "https://piston-meta.mojang.com/v1/packages/b5c7548ddb9e584e84a5f762da5b78211c715a63/1.19.json";
public static string TranslationsFile_Website_Download = "http://resources.download.minecraft.net";
// Other Settings
public const string TranslationsFile_Version = "1.19.3";
public const string TranslationsFile_Website_Index = "https://piston-meta.mojang.com/v1/packages/c492375ded5da34b646b8c5c0842a0028bc69cec/2.json";
public const string TranslationsFile_Website_Download = "http://resources.download.minecraft.net";
public const string TranslationProjectUrl = "https://crwd.in/minecraft-console-client";
@ -90,6 +91,12 @@ namespace MinecraftClient
set { LoggingConfigHealper.Config = value; LoggingConfigHealper.Config.OnSettingUpdate(); }
}
public ConsoleConfig Console
{
get { return ConsoleConfigHealper.Config; }
set { ConsoleConfigHealper.Config = value; ConsoleConfigHealper.Config.OnSettingUpdate(); }
}
public AppVarConfig AppVar
{
get { return AppVarConfigHelper.Config; }
@ -345,12 +352,12 @@ namespace MinecraftClient
"hy_am", "id_id", "ig_ng", "io_en", "is_is", "isv", "it_it", "ja_jp",
"jbo_en", "ka_ge", "kk_kz", "kn_in", "ko_kr", "ksh", "kw_gb", "la_la",
"lb_lu", "li_li", "lmo", "lol_us", "lt_lt", "lv_lv", "lzh", "mk_mk",
"mn_mn", "ms_my", "mt_mt", "nds_de", "nl_be", "nl_nl", "nn_no", "no_no",
"oc_fr", "ovd", "pl_pl", "pt_br", "pt_pt", "qya_aa", "ro_ro", "rpr",
"ru_ru", "se_no", "sk_sk", "sl_si", "so_so", "sq_al", "sr_sp", "sv_se",
"sxu", "szl", "ta_in", "th_th", "tl_ph", "tlh_aa", "tok", "tr_tr",
"tt_ru", "uk_ua", "val_es", "vec_it", "vi_vn", "yi_de", "yo_ng", "zh_cn",
"zh_hk", "zh_tw", "zlm_arab"
"mn_mn", "ms_my", "mt_mt", "nah", "nds_de", "nl_be", "nl_nl", "nn_no",
"no_no", "oc_fr", "ovd", "pl_pl", "pt_br", "pt_pt", "qya_aa", "ro_ro",
"rpr", "ru_ru", "ry_ua", "se_no", "sk_sk", "sl_si", "so_so", "sq_al",
"sr_sp", "sv_se", "sxu", "szl", "ta_in", "th_th", "tl_ph", "tlh_aa",
"tok", "tr_tr", "tt_ru", "uk_ua", "val_es", "vec_it", "vi_vn", "yi_de",
"yo_ng", "zh_cn", "zh_hk", "zh_tw", "zlm_arab"
};
/// <summary>
@ -421,7 +428,7 @@ namespace MinecraftClient
if (!Advanced.LoadMccTranslation)
{
CultureInfo culture = CultureInfo.CreateSpecificCulture("en_gb");
CultureInfo culture = CultureInfo.CreateSpecificCulture("en-US");
CultureInfo.DefaultThreadCurrentCulture = culture;
CultureInfo.DefaultThreadCurrentUICulture = culture;
Program.ActualCulture = culture;
@ -491,7 +498,7 @@ namespace MinecraftClient
public class AdvancedConfig
{
[TomlInlineComment("$Main.Advanced.language$")]
public string Language = "en_gb";
public string Language = "en_us";
[TomlInlineComment("$Main.Advanced.LoadMccTrans$")]
public bool LoadMccTranslation = true;
@ -767,6 +774,139 @@ namespace MinecraftClient
}
}
public static class ConsoleConfigHealper
{
public static ConsoleConfig Config = new();
[TomlDoNotInlineObject]
public class ConsoleConfig
{
public MainConfig General = new();
[TomlPrecedingComment("$Console.CommandSuggestion$")]
public CommandSuggestionConfig CommandSuggestion = new();
public void OnSettingUpdate()
{
ConsoleInteractive.ConsoleWriter.EnableColor = General.Enable_Color;
ConsoleInteractive.ConsoleReader.DisplayUesrInput = General.Display_Uesr_Input;
ConsoleInteractive.ConsoleSuggestion.EnableColor = CommandSuggestion.Enable_Color;
CommandSuggestion.Max_Suggestion_Width =
ConsoleInteractive.ConsoleSuggestion.SetMaxSuggestionLength(CommandSuggestion.Max_Suggestion_Width);
CommandSuggestion.Max_Displayed_Suggestions =
ConsoleInteractive.ConsoleSuggestion.SetMaxSuggestionCount(CommandSuggestion.Max_Displayed_Suggestions);
// CommandSuggestion color settings
{
if (!CheckColorCode(CommandSuggestion.Text_Color))
{
ConsoleIO.WriteLine(string.Format(Translations.config_commandsuggestion_illegal_color, "CommandSuggestion.TextColor", CommandSuggestion.Text_Color));
CommandSuggestion.Text_Color = "#f8fafc";
}
if (!CheckColorCode(CommandSuggestion.Text_Background_Color))
{
ConsoleIO.WriteLine(string.Format(Translations.config_commandsuggestion_illegal_color, "CommandSuggestion.TextBackgroundColor", CommandSuggestion.Text_Background_Color));
CommandSuggestion.Text_Background_Color = "#64748b";
}
if (!CheckColorCode(CommandSuggestion.Highlight_Text_Color))
{
ConsoleIO.WriteLine(string.Format(Translations.config_commandsuggestion_illegal_color, "CommandSuggestion.HighlightTextColor", CommandSuggestion.Highlight_Text_Color));
CommandSuggestion.Highlight_Text_Color = "#334155";
}
if (!CheckColorCode(CommandSuggestion.Highlight_Text_Background_Color))
{
ConsoleIO.WriteLine(string.Format(Translations.config_commandsuggestion_illegal_color, "CommandSuggestion.HighlightTextBackgroundColor", CommandSuggestion.Highlight_Text_Background_Color));
CommandSuggestion.Highlight_Text_Background_Color = "#fde047";
}
if (!CheckColorCode(CommandSuggestion.Tooltip_Color))
{
ConsoleIO.WriteLine(string.Format(Translations.config_commandsuggestion_illegal_color, "CommandSuggestion.TooltipColor", CommandSuggestion.Tooltip_Color));
CommandSuggestion.Tooltip_Color = "#7dd3fc";
}
if (!CheckColorCode(CommandSuggestion.Highlight_Tooltip_Color))
{
ConsoleIO.WriteLine(string.Format(Translations.config_commandsuggestion_illegal_color, "CommandSuggestion.HighlightTooltipColor", CommandSuggestion.Highlight_Tooltip_Color));
CommandSuggestion.Highlight_Tooltip_Color = "#3b82f6";
}
if (!CheckColorCode(CommandSuggestion.Arrow_Symbol_Color))
{
ConsoleIO.WriteLine(string.Format(Translations.config_commandsuggestion_illegal_color, "CommandSuggestion.ArrowSymbolColor", CommandSuggestion.Arrow_Symbol_Color));
CommandSuggestion.Arrow_Symbol_Color = "#d1d5db";
}
ConsoleInteractive.ConsoleSuggestion.SetColors(
CommandSuggestion.Text_Color, CommandSuggestion.Text_Background_Color,
CommandSuggestion.Highlight_Text_Color, CommandSuggestion.Highlight_Text_Background_Color,
CommandSuggestion.Tooltip_Color, CommandSuggestion.Highlight_Tooltip_Color,
CommandSuggestion.Arrow_Symbol_Color);
}
}
private static bool CheckColorCode(string? input)
{
if (string.IsNullOrWhiteSpace(input))
return false;
if (input.Length < 6 || input.Length > 7)
return false;
if (input.Length == 6 && input[0] == '#')
return false;
if (input.Length == 7 && input[0] != '#')
return false;
try
{
Convert.ToInt32(input.Length == 7 ? input[1..] : input, 16);
return true;
}
catch
{
return false;
}
}
[TomlDoNotInlineObject]
public class MainConfig
{
[TomlInlineComment("$Console.Enable_Color$")]
public bool Enable_Color = true;
[TomlInlineComment("$Console.General.Display_Uesr_Input$")]
public bool Display_Uesr_Input = true;
}
[TomlDoNotInlineObject]
public class CommandSuggestionConfig
{
[TomlInlineComment("$Console.CommandSuggestion.Enable$")]
public bool Enable = true;
[TomlInlineComment("$Console.Enable_Color$")]
public bool Enable_Color = true;
public int Max_Suggestion_Width = 30;
public int Max_Displayed_Suggestions = 6;
public string Text_Color = "#f8fafc";
public string Text_Background_Color = "#64748b";
public string Highlight_Text_Color = "#334155";
public string Highlight_Text_Background_Color = "#fde047";
public string Tooltip_Color = "#7dd3fc";
public string Highlight_Tooltip_Color = "#3b82f6";
public string Arrow_Symbol_Color = "#d1d5db";
}
}
}
public static class AppVarConfigHelper
{
public static AppVarConfig Config = new();
@ -1238,7 +1378,7 @@ namespace MinecraftClient
public static string GetDefaultGameLanguage()
{
string gameLanguage = "en_gb";
string gameLanguage = "en_us";
string systemLanguage = string.IsNullOrWhiteSpace(Program.ActualCulture.Name)
? Program.ActualCulture.Parent.Name
: Program.ActualCulture.Name;
@ -1326,6 +1466,9 @@ namespace MinecraftClient
case "en-TT":
case "en-ZA":
case "en-ZW":
case "en-US":
gameLanguage = "en_us";
break;
case "en-GB":
gameLanguage = "en_gb";
break;
@ -1335,9 +1478,6 @@ namespace MinecraftClient
case "en-CA":
gameLanguage = "en_ca";
break;
case "en-US":
gameLanguage = "en_us";
break;
case "en-NZ":
gameLanguage = "en_nz";
break;

View file

@ -63,7 +63,7 @@ namespace MinecraftClient
{
string OSInfo = GetOSIdentifier();
if (Settings.Config.Logging.DebugMessages || string.IsNullOrEmpty(OSInfo))
ConsoleIO.WriteLine(string.Format("OS: {0}, Arch: {1}, Framework: {2}",
ConsoleIO.WriteLine(string.Format("OS: {0}, Arch: {1}, Framework: {2}",
RuntimeInformation.OSDescription, RuntimeInformation.ProcessArchitecture, RuntimeInformation.FrameworkDescription));
if (string.IsNullOrEmpty(OSInfo))
{
@ -308,7 +308,7 @@ namespace MinecraftClient
{
string proxyAddress;
if (!string.IsNullOrWhiteSpace(Settings.Config.Proxy.Username) && !string.IsNullOrWhiteSpace(Settings.Config.Proxy.Password))
proxyAddress = string.Format("{0}://{3}:{4}@{1}:{2}",
proxyAddress = string.Format("{0}://{3}:{4}@{1}:{2}",
Settings.Config.Proxy.Proxy_Type.ToString().ToLower(),
Settings.Config.Proxy.Server.Host,
Settings.Config.Proxy.Server.Port,