Switching to TOML & Add AutoDig ChatBot

This commit is contained in:
BruceChen 2022-10-10 10:58:36 +08:00 committed by GitHub
commit b2514673bd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
82 changed files with 7913 additions and 3947 deletions

@ -1 +1 @@
Subproject commit 225b10ec96af5c8f179a008cc442b502d23bc601
Subproject commit 7acaa0ab31809f0f6512e6a76e53e15441de8e7c

View file

@ -1,5 +1,6 @@
using System;
using System.Linq;
using Tomlet.Attributes;
namespace MinecraftClient.ChatBots
{
@ -8,53 +9,103 @@ namespace MinecraftClient.ChatBots
/// </summary>
public class Alerts : ChatBot
{
private string[] dictionary = Array.Empty<string>();
private string[] excludelist = Array.Empty<string>();
private bool logToFile = false;
public static Configs Config = new();
[TomlDoNotInlineObject]
public class Configs
{
[NonSerialized]
private const string BotName = "Alerts";
public bool Enabled = false;
[TomlInlineComment("$config.ChatBot.Alerts.Beep_Enabled$")]
public bool Beep_Enabled = true;
[TomlInlineComment("$config.ChatBot.Alerts.Trigger_By_Words$")]
public bool Trigger_By_Words = false;
[TomlInlineComment("$config.ChatBot.Alerts.Trigger_By_Rain$")]
public bool Trigger_By_Rain = false;
[TomlInlineComment("$config.ChatBot.Alerts.Trigger_By_Thunderstorm$")]
public bool Trigger_By_Thunderstorm = false;
[TomlInlineComment("$config.ChatBot.Alerts.Log_To_File$")]
public bool Log_To_File = false;
[TomlInlineComment("$config.ChatBot.Alerts.Log_File$")]
public string Log_File = @"alerts-log.txt";
[TomlPrecedingComment("$config.ChatBot.Alerts.Matches$")]
public string[] Matches = new string[] { "Yourname", " whispers ", "-> me", "admin", ".com" };
[TomlPrecedingComment("$config.ChatBot.Alerts.Excludes$")]
public string[] Excludes = new string[] { "myserver.com", "Yourname>:", "Player Yourname", "Yourname joined", "Yourname left", "[Lockette] (Admin)", " Yourname:", "Yourname is" };
public void OnSettingUpdate()
{
Log_File ??= string.Empty;
if (!Enabled) return;
bool checkSuccessed = true;
if (Trigger_By_Words)
{
if (Log_To_File)
{
try
{
System.IO.File.AppendAllText(Log_File, string.Empty);
}
catch
{
checkSuccessed = false;
LogToConsole(BotName, "Can't write logs to " + System.IO.Path.GetFullPath(Log_File));
}
}
}
if (!checkSuccessed)
{
LogToConsole(BotName, Translations.TryGet("general.bot_unload"));
Enabled = false;
}
}
}
float curRainLevel = 0;
float curThunderLevel = 0;
const float threshold = 0.2f;
/// <summary>
/// Intitialize the Alerts bot
/// </summary>
public override void Initialize()
{
if (Settings.Alerts_Trigger_By_Words)
{
dictionary = LoadDistinctEntriesFromFile(Settings.Alerts_MatchesFile);
excludelist = LoadDistinctEntriesFromFile(Settings.Alerts_ExcludesFile);
logToFile = Settings.Alerts_File_Logging;
}
}
/// <summary>
/// Process text received from the server to display alerts
/// </summary>
/// <param name="text">Received text</param>
public override void GetText(string text)
{
if (Settings.Alerts_Trigger_By_Words)
if (Config.Trigger_By_Words)
{
//Remove color codes and convert to lowercase
text = GetVerbatim(text).ToLower();
//Proceed only if no exclusions are found in text
if (!excludelist.Any(exclusion => text.Contains(exclusion)))
if (!Config.Excludes.Any(exclusion => text.Contains(exclusion)))
{
//Show an alert for each alert item found in text, if any
foreach (string alert in dictionary.Where(alert => text.Contains(alert)))
foreach (string alert in Config.Matches.Where(alert => text.Contains(alert)))
{
if (Settings.Alerts_Beep_Enabled)
if (Config.Beep_Enabled)
Console.Beep(); //Text found !
ConsoleIO.WriteLine(text.Replace(alert, "§c" + alert + "§r"));
if (logToFile && Settings.Alerts_LogFile.Length > 0)
if (Config.Log_To_File && Config.Log_File.Length > 0)
{
DateTime now = DateTime.Now;
string TimeStamp = "[" + now.Year + '/' + now.Month + '/' + now.Day + ' ' + now.Hour + ':' + now.Minute + ']';
System.IO.File.AppendAllText(Settings.Alerts_LogFile, TimeStamp + " " + GetVerbatim(text) + "\n");
System.IO.File.AppendAllText(Config.Log_File, TimeStamp + " " + GetVerbatim(text) + "\n");
}
}
}
@ -65,9 +116,9 @@ namespace MinecraftClient.ChatBots
{
if (curRainLevel < threshold && level >= threshold)
{
if (Settings.Alerts_Trigger_By_Rain)
if (Config.Trigger_By_Rain)
{
if (Settings.Alerts_Beep_Enabled)
if (Config.Beep_Enabled)
{
Console.Beep();
Console.Beep();
@ -77,9 +128,9 @@ namespace MinecraftClient.ChatBots
}
else if (curRainLevel >= threshold && level < threshold)
{
if (Settings.Alerts_Trigger_By_Rain)
if (Config.Trigger_By_Rain)
{
if (Settings.Alerts_Beep_Enabled)
if (Config.Beep_Enabled)
{
Console.Beep();
}
@ -93,9 +144,9 @@ namespace MinecraftClient.ChatBots
{
if (curThunderLevel < threshold && level >= threshold)
{
if (Settings.Alerts_Trigger_By_Thunderstorm)
if (Config.Trigger_By_Thunderstorm)
{
if (Settings.Alerts_Beep_Enabled)
if (Config.Beep_Enabled)
{
Console.Beep();
Console.Beep();
@ -105,9 +156,9 @@ namespace MinecraftClient.ChatBots
}
else if (curThunderLevel >= threshold && level < threshold)
{
if (Settings.Alerts_Trigger_By_Thunderstorm)
if (Config.Trigger_By_Thunderstorm)
{
if (Settings.Alerts_Beep_Enabled)
if (Config.Beep_Enabled)
{
Console.Beep();
}

View file

@ -1,6 +1,6 @@
using System;
using System.Globalization;
using MinecraftClient.Mapping;
using Tomlet.Attributes;
namespace MinecraftClient.ChatBots
{
@ -10,104 +10,113 @@ namespace MinecraftClient.ChatBots
public class AntiAFK : ChatBot
{
private int count;
private readonly string pingparam;
private int timeping = 600;
private int timepingMax = -1;
private bool useTerrainHandling = false;
public static Configs Config = new();
[TomlDoNotInlineObject]
public class Configs
{
[NonSerialized]
private const string BotName = "AntiAFK";
public bool Enabled = false;
[TomlInlineComment("$config.ChatBot.AntiAfk.Delay$")]
public Range Delay = new(60);
[TomlInlineComment("$config.ChatBot.AntiAfk.Command$")]
public string Command = "/ping";
[TomlInlineComment("$config.ChatBot.AntiAfk.Use_Sneak$")]
public bool Use_Sneak = false;
[TomlInlineComment("$config.ChatBot.AntiAfk.Use_Terrain_Handling$")]
public bool Use_Terrain_Handling = false;
[TomlInlineComment("$config.ChatBot.AntiAfk.Walk_Range$")]
public int Walk_Range = 5;
[TomlInlineComment("$config.ChatBot.AntiAfk.Walk_Retries$")]
public int Walk_Retries = 20;
public void OnSettingUpdate()
{
if (Walk_Range <= 0)
{
Walk_Range = 5;
LogToConsole(BotName, Translations.TryGet("bot.antiafk.invalid_walk_range"));
}
Delay.min = Math.Max(1.0, Delay.min);
Delay.max = Math.Max(1.0, Delay.max);
Delay.min = Math.Min(int.MaxValue / 10, Delay.min);
Delay.max = Math.Min(int.MaxValue / 10, Delay.max);
if (Delay.min > Delay.max)
{
(Delay.min, Delay.max) = (Delay.max, Delay.min);
LogToConsole(BotName, Translations.TryGet("bot.antiafk.swapping"));
}
Command ??= string.Empty;
}
public struct Range
{
public double min, max;
public Range(int value)
{
min = max = value;
}
public Range(int min, int max)
{
this.min = min;
this.max = max;
}
}
}
private int count, nextrun = 50;
private bool previousSneakState = false;
private int walkRange = 5;
private readonly int walkRetries = 10;
private readonly Random random = new();
/// <summary>
/// This bot sends a /ping command every X seconds in order to stay non-afk.
/// </summary>
/// <param name="pingparam">Time amount between each ping (10 = 1s, 600 = 1 minute, etc.) Can be a range of numbers eg. 10-600</param>
public AntiAFK(string pingparam, bool useTerrainHandling, int walkRange, int walkRetries)
public AntiAFK()
{
count = 0;
this.pingparam = pingparam;
this.useTerrainHandling = useTerrainHandling;
this.walkRange = walkRange;
this.walkRetries = walkRetries;
}
public override void Initialize()
{
if (useTerrainHandling)
if (Config.Use_Terrain_Handling)
{
if (!GetTerrainEnabled())
{
useTerrainHandling = false;
LogToConsole(Translations.TryGet("bot.antiafk.not_using_terrain_handling"));
}
else
{
if (walkRange <= 0)
{
walkRange = 5;
LogToConsole(Translations.TryGet("bot.antiafk.invalid_walk_range"));
}
}
}
if (string.IsNullOrEmpty(pingparam))
LogToConsole(Translations.TryGet("bot.antiafk.invalid_time"));
else
{
// Handle the random range
if (pingparam.Contains('-'))
{
string[] parts = pingparam.Split("-");
if (parts.Length == 2)
{
if (int.TryParse(parts[0].Trim(), NumberStyles.Any, CultureInfo.CurrentCulture, out int firstTime))
{
timeping = firstTime;
if (int.TryParse(parts[1].Trim(), NumberStyles.Any, CultureInfo.CurrentCulture, out int secondTime))
timepingMax = secondTime;
else LogToConsole(Translations.TryGet("bot.antiafk.invalid_range_partial", timeping));
}
else LogToConsole(Translations.TryGet("bot.antiafk.invalid_range"));
}
else LogToConsole(Translations.TryGet("bot.antiafk.invalid_range"));
}
else
{
if (int.TryParse(pingparam.Trim(), NumberStyles.Any, CultureInfo.CurrentCulture, out int value))
timeping = value;
else LogToConsole(Translations.TryGet("bot.antiafk.invalid_value"));
}
}
if (timepingMax != -1 && timeping > timepingMax)
{
(timeping, timepingMax) = (timepingMax, timeping);
LogToConsole(Translations.TryGet("bot.antiafk.swapping"));
}
if (timeping < 10) { timeping = 10; } //To avoid flooding
}
public override void Update()
{
count++;
if ((timepingMax != -1 && count == random.Next(timeping, timepingMax)) || count == timeping)
if (count >= nextrun)
{
DoAntiAfkStuff();
count = 0;
nextrun = random.Next(Settings.DoubleToTick(Config.Delay.min), Settings.DoubleToTick(Config.Delay.max));
}
}
private void DoAntiAfkStuff()
{
if (useTerrainHandling)
if (Config.Use_Terrain_Handling && GetTerrainEnabled())
{
Location currentLocation = GetCurrentLocation();
Location goal;
@ -118,19 +127,19 @@ namespace MinecraftClient.ChatBots
while (!moved)
{
if (triesCounter++ >= walkRetries)
if (triesCounter++ >= Config.Walk_Retries)
{
useAlternativeMethod = true;
break;
}
goal = GetRandomLocationWithinRangeXZ(currentLocation, walkRange);
goal = GetRandomLocationWithinRangeXZ(currentLocation, Config.Walk_Range);
// Prevent getting the same location
while ((currentLocation.X == goal.X) && (currentLocation.Y == goal.Y) && (currentLocation.Z == goal.Z))
{
LogToConsole("Same location!, generating new one");
goal = GetRandomLocationWithinRangeXZ(currentLocation, walkRange);
goal = GetRandomLocationWithinRangeXZ(currentLocation, Config.Walk_Range);
}
if (!Movement.CheckChunkLoading(GetWorld(), currentLocation, goal))
@ -138,22 +147,27 @@ namespace MinecraftClient.ChatBots
useAlternativeMethod = true;
break;
}
else moved = MoveToLocation(goal, allowUnsafe: false, allowDirectTeleport: false);
else
{
moved = MoveToLocation(goal, allowUnsafe: false, allowDirectTeleport: false);
}
}
if (!useAlternativeMethod)
if (!useAlternativeMethod && Config.Use_Sneak)
{
// Solve the case when the bot was closed in 1x2, was sneaking, but then he was freed, this will make him not sneak anymore
previousSneakState = false;
Sneak(false);
return;
}
}
SendText(Settings.AntiAFK_Command);
Sneak(previousSneakState);
previousSneakState = !previousSneakState;
SendText(Config.Command);
if (Config.Use_Sneak)
{
Sneak(previousSneakState);
previousSneakState = !previousSneakState;
}
count = 0;
}

View file

@ -1,15 +1,89 @@
using System;
using System.Collections.Generic;
using System.IO;
using MinecraftClient.Mapping;
using Tomlet.Attributes;
namespace MinecraftClient.ChatBots
{
/// <summary>
/// The AutoAttack bot will automatically attack any hostile mob close to the player
/// </summary>
class AutoAttack : ChatBot
public class AutoAttack : ChatBot
{
public static Configs Config = new();
[TomlDoNotInlineObject]
public class Configs
{
[NonSerialized]
private const string BotName = "AutoAttack";
public bool Enabled = false;
[TomlInlineComment("$config.ChatBot.AutoAttack.Mode$")]
public AttackMode Mode = AttackMode.single;
[TomlInlineComment("$config.ChatBot.AutoAttack.Priority$")]
public PriorityType Priority = PriorityType.distance;
[TomlInlineComment("$config.ChatBot.AutoAttack.Cooldown_Time$")]
public CooldownConfig Cooldown_Time = new(false, 1.0);
[TomlInlineComment("$config.ChatBot.AutoAttack.Interaction$")]
public InteractType Interaction = InteractType.Attack;
[TomlInlineComment("$config.ChatBot.AutoAttack.Attack_Hostile$")]
public bool Attack_Hostile = true;
[TomlInlineComment("$config.ChatBot.AutoAttack.Attack_Passive$")]
public bool Attack_Passive = false;
[TomlInlineComment("$config.ChatBot.AutoAttack.List_Mode$")]
public ListType List_Mode = ListType.whitelist;
[TomlInlineComment("$config.ChatBot.AutoAttack.Entites_List$")]
public List<EntityType> Entites_List = new() { EntityType.Zombie, EntityType.Cow };
public void OnSettingUpdate()
{
if (Cooldown_Time.Custom && Cooldown_Time.value <= 0)
{
LogToConsole(BotName, Translations.TryGet("bot.autoAttack.invalidcooldown"));
Cooldown_Time.value = 1.0;
}
}
public enum AttackMode { single, multi };
public enum PriorityType { distance, health };
public enum ListType { blacklist, whitelist };
public struct CooldownConfig
{
public bool Custom;
public double value;
public CooldownConfig()
{
Custom = false;
value = 0;
}
public CooldownConfig(double value)
{
Custom = true;
this.value = value;
}
public CooldownConfig(bool Override, double value)
{
this.Custom = Override;
this.value = value;
}
}
}
private readonly Dictionary<int, Entity> entitiesToAttack = new(); // mobs within attack range
private int attackCooldown = 6;
private int attackCooldownCounter = 6;
@ -19,73 +93,20 @@ namespace MinecraftClient.ChatBots
private readonly int attackRange = 4;
private Double serverTPS;
private float health = 100;
private readonly bool singleMode = true;
private readonly bool priorityDistance = true;
private readonly InteractType interactMode;
private readonly bool attackHostile = true;
private readonly bool attackPassive = false;
private readonly string listMode = "blacklist";
private readonly List<EntityType> listedEntites = new();
public AutoAttack(
string mode, string priority, bool overrideAttackSpeed = false, double cooldownSeconds = 1, InteractType interaction = InteractType.Attack)
public AutoAttack()
{
if (mode == "single")
singleMode = true;
else if (mode == "multi")
singleMode = false;
else LogToConsoleTranslated("bot.autoAttack.mode", mode);
if (priority == "distance")
priorityDistance = true;
else if (priority == "health")
priorityDistance = false;
else LogToConsoleTranslated("bot.autoAttack.priority", priority);
interactMode = interaction;
if (overrideAttackSpeed)
overrideAttackSpeed = Config.Cooldown_Time.Custom;
if (Config.Cooldown_Time.Custom)
{
if (cooldownSeconds <= 0)
{
LogToConsoleTranslated("bot.autoAttack.invalidcooldown");
}
else
{
this.overrideAttackSpeed = overrideAttackSpeed;
attackCooldownSeconds = cooldownSeconds;
attackCooldown = Convert.ToInt32(Math.Truncate(attackCooldownSeconds / 0.1) + 1);
}
attackCooldownSeconds = Config.Cooldown_Time.value;
attackCooldown = Convert.ToInt32(Math.Truncate(attackCooldownSeconds / 0.1) + 1);
}
attackHostile = Settings.AutoAttack_Attack_Hostile;
attackPassive = Settings.AutoAttack_Attack_Passive;
if (Settings.AutoAttack_ListMode.Length > 0)
{
listMode = Settings.AutoAttack_ListMode.ToLower();
if (!(listMode.Equals("whitelist", StringComparison.OrdinalIgnoreCase) || listMode.Equals("blacklist", StringComparison.OrdinalIgnoreCase)))
{
LogToConsole(Translations.TryGet("bot.autoAttack.invalidlist"));
listMode = "blacklist";
}
}
else LogToConsole(Translations.TryGet("bot.autoAttack.invalidlist"));
if (File.Exists(Settings.AutoAttack_ListFile))
{
string[] entityList = LoadDistinctEntriesFromFile(Settings.AutoAttack_ListFile);
if (entityList.Length > 0)
{
foreach (var item in entityList)
{
if (Enum.TryParse(item, true, out EntityType resultingType))
listedEntites.Add(resultingType);
}
}
}
attackHostile = Config.Attack_Hostile;
attackPassive = Config.Attack_Passive;
}
public override void Initialize()
@ -108,10 +129,10 @@ namespace MinecraftClient.ChatBots
attackCooldownCounter = attackCooldown;
if (entitiesToAttack.Count > 0)
{
if (singleMode)
if (Config.Mode == Configs.AttackMode.single)
{
int priorityEntity = 0;
if (priorityDistance) // closest distance priority
if (Config.Priority == Configs.PriorityType.distance) // closest distance priority
{
double distance = 5;
foreach (var entity in entitiesToAttack)
@ -142,7 +163,7 @@ namespace MinecraftClient.ChatBots
// check entity distance and health again
if (ShouldAttackEntity(entitiesToAttack[priorityEntity]))
{
InteractEntity(priorityEntity, interactMode); // hit the entity!
InteractEntity(priorityEntity, Config.Interaction); // hit the entity!
SendAnimation(Inventory.Hand.MainHand); // Arm animation
}
}
@ -154,7 +175,7 @@ namespace MinecraftClient.ChatBots
// check that we are in range once again.
if (ShouldAttackEntity(entity.Value))
{
InteractEntity(entity.Key, interactMode); // hit the entity!
InteractEntity(entity.Key, Config.Interaction); // hit the entity!
}
}
SendAnimation(Inventory.Hand.MainHand); // Arm animation
@ -206,10 +227,13 @@ namespace MinecraftClient.ChatBots
if (attackPassive && entity.Type.IsPassive())
result = true;
if (listedEntites.Count > 0)
if (Config.Entites_List.Count > 0)
{
bool inList = listedEntites.Contains(entity.Type);
result = listMode.Equals("blacklist") ? (!inList && result) : (inList);
bool inList = Config.Entites_List.Contains(entity.Type);
if (Config.List_Mode == Configs.ListType.blacklist)
result = !inList && result;
else
result = inList;
}
return result;

View file

@ -1,14 +1,142 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using MinecraftClient.Inventory;
using MinecraftClient.Mapping;
using Tomlet.Attributes;
using static MinecraftClient.ChatBots.AutoCraft.Configs;
namespace MinecraftClient.ChatBots
{
class AutoCraft : ChatBot
public class AutoCraft : ChatBot
{
public static Configs Config = new();
[TomlDoNotInlineObject]
public class Configs
{
[NonSerialized]
private const string BotName = "AutoCraft";
public bool Enabled = false;
[TomlInlineComment("$config.ChatBot.AutoCraft.CraftingTable$")]
public LocationConfig CraftingTable = new(123, 65, 456);
[TomlInlineComment("$config.ChatBot.AutoCraft.OnFailure$")]
public OnFailConfig OnFailure = OnFailConfig.abort;
[TomlPrecedingComment("$config.ChatBot.AutoCraft.Recipes$")]
public RecipeConfig[] Recipes = new RecipeConfig[]
{
new RecipeConfig(
Name: "Recipe-Name-1",
Type: CraftTypeConfig.player,
Result: ItemType.StoneBricks,
Slots: new ItemType[4] { ItemType.Stone, ItemType.Stone, ItemType.Stone, ItemType.Stone }
),
new RecipeConfig(
Name: "Recipe-Name-2",
Type: CraftTypeConfig.table,
Result: ItemType.StoneBricks,
Slots: new ItemType[9] {
ItemType.Stone, ItemType.Stone, ItemType.Null,
ItemType.Stone, ItemType.Stone, ItemType.Null,
ItemType.Null, ItemType.Null, ItemType.Null,
}
),
};
[NonSerialized]
public Location _Table_Location = Location.Zero;
public void OnSettingUpdate()
{
_Table_Location = new Location(CraftingTable.X, CraftingTable.Y, CraftingTable.Z).ToFloor();
List<string> nameList = new();
foreach (RecipeConfig recipe in Recipes)
{
if (string.IsNullOrWhiteSpace(recipe.Name))
{
recipe.Name = new Random().NextInt64().ToString();
LogToConsole(BotName, Translations.TryGet("bot.autoCraft.exception.name_miss"));
}
if (nameList.Contains(recipe.Name))
{
LogToConsole(BotName, Translations.TryGet("bot.autoCraft.exception.duplicate", recipe.Name));
do
{
recipe.Name = new Random().NextInt64().ToString();
} while (nameList.Contains(recipe.Name));
}
nameList.Add(recipe.Name);
int fixLength = -1;
if (recipe.Type == CraftTypeConfig.player && recipe.Slots.Length != 4)
fixLength = 4;
else if (recipe.Type == CraftTypeConfig.table && recipe.Slots.Length != 9)
fixLength = 9;
if (fixLength > 0)
{
ItemType[] Slots = new ItemType[fixLength];
for (int i = 0; i < fixLength; ++i)
Slots[i] = (i < recipe.Slots.Length) ? recipe.Slots[i] : ItemType.Null;
recipe.Slots = Slots;
LogToConsole(BotName, Translations.TryGet("bot.autocraft.invaild_slots"));
}
if (recipe.Result == ItemType.Air || recipe.Result == ItemType.Null)
{
LogToConsole(BotName, Translations.TryGet("bot.autocraft.invaild_result"));
}
}
}
public struct LocationConfig
{
public double X, Y, Z;
public LocationConfig(double X, double Y, double Z)
{
this.X = X;
this.Y = Y;
this.Z = Z;
}
}
public enum OnFailConfig { abort, wait }
public class RecipeConfig
{
public string Name = "Recipe Name";
public CraftTypeConfig Type = CraftTypeConfig.player;
public ItemType Result = ItemType.Air;
public ItemType[] Slots = new ItemType[9] {
ItemType.Null, ItemType.Null, ItemType.Null,
ItemType.Null, ItemType.Null, ItemType.Null,
ItemType.Null, ItemType.Null, ItemType.Null,
};
public RecipeConfig() { }
public RecipeConfig(string Name, CraftTypeConfig Type, ItemType Result, ItemType[] Slots)
{
this.Name = Name;
this.Type = Type;
this.Result = Result;
this.Slots = Slots;
}
}
public enum CraftTypeConfig { player, table }
}
private bool waitingForMaterials = false;
private bool waitingForUpdate = false;
private bool waitingForTable = false;
@ -18,19 +146,12 @@ namespace MinecraftClient.ChatBots
private Recipe? recipeInUse;
private readonly List<ActionStep> actionSteps = new();
private Location tableLocation = new();
private bool abortOnFailure = true;
private int updateDebounceValue = 2;
private int updateDebounce = 0;
private readonly int updateTimeoutValue = 10;
private int updateTimeout = 0;
private string timeoutAction = "unspecified";
private readonly string configPath = @"autocraft\config.ini";
private string lastRecipe = ""; // Used in parsing recipe config
private readonly Dictionary<string, Recipe> recipes = new();
private void ResetVar()
{
craftingFailed = false;
@ -158,11 +279,6 @@ namespace MinecraftClient.ChatBots
}
}
public AutoCraft(string configPath = @"autocraft\config.ini")
{
this.configPath = configPath;
}
public override void Initialize()
{
if (!GetInventoryEnabled())
@ -174,7 +290,6 @@ namespace MinecraftClient.ChatBots
}
RegisterChatBotCommand("autocraft", Translations.Get("bot.autoCraft.cmd"), GetHelp(), CommandHandler);
RegisterChatBotCommand("ac", Translations.Get("bot.autoCraft.alias"), GetHelp(), CommandHandler);
LoadConfig();
}
public string CommandHandler(string cmd, string[] args)
@ -183,32 +298,39 @@ namespace MinecraftClient.ChatBots
{
switch (args[0])
{
case "load":
LoadConfig();
return "";
case "list":
string names = string.Join(", ", recipes.Keys.ToList());
return Translations.Get("bot.autoCraft.cmd.list", recipes.Count, names);
case "reload":
recipes.Clear();
LoadConfig();
return "";
case "resetcfg":
WriteDefaultConfig();
return Translations.Get("bot.autoCraft.cmd.resetcfg");
StringBuilder nameList = new();
foreach (RecipeConfig recipe in Config.Recipes)
nameList.Append(recipe.Name).Append(", ");
return Translations.Get("bot.autoCraft.cmd.list", Config.Recipes.Length, nameList.ToString());
case "start":
if (args.Length >= 2)
{
string name = args[1];
if (recipes.ContainsKey(name))
bool hasRecipe = false;
RecipeConfig? recipe = null;
foreach (RecipeConfig recipeConfig in Config.Recipes)
{
if (recipeConfig.Name == name)
{
hasRecipe = true;
recipe = recipeConfig;
break;
}
}
if (hasRecipe)
{
ResetVar();
PrepareCrafting(recipes[name]);
PrepareCrafting(recipe!);
return "";
}
else return Translations.Get("bot.autoCraft.recipe_not_exist");
else
return Translations.Get("bot.autoCraft.recipe_not_exist");
}
else return Translations.Get("bot.autoCraft.no_recipe_name");
else
return Translations.Get("bot.autoCraft.no_recipe_name");
case "stop":
StopCrafting();
return Translations.Get("bot.autoCraft.stop");
@ -243,220 +365,6 @@ namespace MinecraftClient.ChatBots
};
}
#region Config handling
public void LoadConfig()
{
if (!File.Exists(configPath))
{
if (!Directory.Exists(configPath))
{
Directory.CreateDirectory(@"autocraft");
}
WriteDefaultConfig();
LogDebugToConsoleTranslated("bot.autoCraft.debug.no_config");
}
try
{
ParseConfig();
LogToConsoleTranslated("bot.autoCraft.loaded");
}
catch (Exception e)
{
LogToConsoleTranslated("bot.autoCraft.error.config", "\n" + e.Message);
}
}
private void WriteDefaultConfig()
{
string[] content =
{
"[AutoCraft]",
"# A valid autocraft config must begin with [AutoCraft]",
"",
"tablelocation=0,65,0 # Location of the crafting table if you intended to use it. Terrain and movements must be enabled. Format: x,y,z",
"onfailure=abort # What to do on crafting failure, abort or wait",
"",
"# You can define multiple recipes in a single config file",
"# This is an example of how to define a recipe",
"[Recipe]",
"name=whatever # name could be whatever you like. This field must be defined first",
"type=player # crafting table type: player or table",
"result=StoneButton # the resulting item",
"",
"# define slots with their deserved item",
"slot1=Stone # slot start with 1, count from left to right, top to bottom",
"# For the naming of the items, please see",
"# https://github.com/MCCTeam/Minecraft-Console-Client/blob/master/MinecraftClient/Inventory/ItemType.cs"
};
File.WriteAllLines(configPath, content);
}
private void ParseConfig()
{
string[] content = File.ReadAllLines(configPath);
if (content.Length <= 0)
{
throw new Exception(Translations.Get("bot.autoCraft.exception.empty", configPath));
}
if (content[0].ToLower() != "[autocraft]")
{
throw new Exception(Translations.Get("bot.autoCraft.exception.invalid", configPath));
}
// local variable for use in parsing config
string section = "";
Dictionary<string, Recipe> recipes = new();
foreach (string l in content)
{
// ignore comment start with #
if (l.StartsWith("#"))
continue;
string line = l.Split('#')[0].Trim();
if (line.Length <= 0)
continue;
if (line[0] == '[' && line[^1] == ']')
{
section = line[1..^1].ToLower();
continue;
}
string key = line.Split('=')[0].ToLower();
if (!(line.Length > (key.Length + 1)))
continue;
string value = line[(key.Length + 1)..];
switch (section)
{
case "recipe": ParseRecipe(key, value); break;
case "autocraft": ParseMain(key, value); break;
}
}
// check and save recipe
foreach (var pair in recipes)
{
if ((pair.Value.CraftingAreaType == ContainerType.PlayerInventory
|| pair.Value.CraftingAreaType == ContainerType.Crafting)
&& (pair.Value.Materials != null
&& pair.Value.Materials.Count > 0)
&& pair.Value.ResultItem != ItemType.Air)
{
// checking pass
this.recipes.Add(pair.Key, pair.Value);
}
else
{
throw new Exception(Translations.Get("bot.autoCraft.exception.item_miss", pair.Key));
}
}
}
#region Method for parsing different section of config
private void ParseMain(string key, string value)
{
switch (key)
{
case "tablelocation":
string[] values = value.Split(',');
if (values.Length == 3)
{
tableLocation.X = Convert.ToInt32(values[0]);
tableLocation.Y = Convert.ToInt32(values[1]);
tableLocation.Z = Convert.ToInt32(values[2]);
}
else throw new Exception(Translations.Get("bot.autoCraft.exception.invalid_table", key));
break;
case "onfailure":
abortOnFailure = value.ToLower() == "abort";
break;
case "updatedebounce":
updateDebounceValue = Convert.ToInt32(value);
break;
}
}
private void ParseRecipe(string key, string value)
{
if (key.StartsWith("slot"))
{
int slot = Convert.ToInt32(key[^1].ToString());
if (slot > 0 && slot < 10)
{
if (recipes.ContainsKey(lastRecipe))
{
if (Enum.TryParse(value, true, out ItemType itemType))
{
Dictionary<int, ItemType>? materials = recipes[lastRecipe].Materials;
if (materials != null && materials.Count > 0)
{
materials.Add(slot, itemType);
}
else
{
recipes[lastRecipe].Materials = new Dictionary<int, ItemType>()
{
{ slot, itemType }
};
}
return;
}
else
{
throw new Exception(Translations.Get("bot.autoCraft.exception.item_name", lastRecipe, key));
}
}
else
{
throw new Exception(Translations.Get("bot.autoCraft.exception.name_miss"));
}
}
else
{
throw new Exception(Translations.Get("bot.autoCraft.exception.slot", key));
}
}
else
{
switch (key)
{
case "name":
if (!recipes.ContainsKey(value))
{
recipes.Add(value, new Recipe());
lastRecipe = value;
}
else
{
throw new Exception(Translations.Get("bot.autoCraft.exception.duplicate", value));
}
break;
case "type":
if (recipes.ContainsKey(lastRecipe))
{
recipes[lastRecipe].CraftingAreaType = value.ToLower() == "player" ? ContainerType.PlayerInventory : ContainerType.Crafting;
}
break;
case "result":
if (recipes.ContainsKey(lastRecipe))
{
if (Enum.TryParse(value, true, out ItemType itemType))
{
recipes[lastRecipe].ResultItem = itemType;
}
}
break;
}
}
}
#endregion
#endregion
#region Core part of auto-crafting
public override void OnInventoryUpdate(int inventoryId)
@ -525,9 +433,19 @@ namespace MinecraftClient.ChatBots
/// Prepare the crafting action steps by the given recipe name and start crafting
/// </summary>
/// <param name="recipe">Name of the recipe to craft</param>
private void PrepareCrafting(string name)
private void PrepareCrafting(RecipeConfig recipeConfig)
{
PrepareCrafting(recipes[name]);
Dictionary<int, ItemType> materials = new();
for (int i = 0; i < recipeConfig.Slots.Length; ++i)
if (recipeConfig.Slots[i] != ItemType.Null)
materials[i + 1] = recipeConfig.Slots[i];
ItemType ResultItem = recipeConfig.Result;
ContainerType CraftingAreaType =
(recipeConfig.Type == CraftTypeConfig.player) ? ContainerType.PlayerInventory : ContainerType.Crafting;
PrepareCrafting(new Recipe(materials, ResultItem, CraftingAreaType));
}
/// <summary>
@ -548,7 +466,7 @@ namespace MinecraftClient.ChatBots
if (inventoryInUse == -2)
{
// table required but not found. Try to open one
OpenTable(tableLocation);
OpenTable(Config._Table_Location);
waitingForTable = true;
SetTimeout(Translations.Get("bot.autoCraft.table_not_found"));
return;
@ -698,7 +616,7 @@ namespace MinecraftClient.ChatBots
// Inform user the missing meterial name
LogToConsoleTranslated("bot.autoCraft.missing_material", actionSteps[index - 1].ItemType.ToString());
}
if (abortOnFailure)
if (Config.OnFailure == OnFailConfig.abort)
{
StopCrafting();
LogToConsoleTranslated("bot.autoCraft.aborted");

View file

@ -0,0 +1,423 @@
using System;
using System.Collections.Generic;
using System.Linq;
using MinecraftClient.Mapping;
using Tomlet.Attributes;
namespace MinecraftClient.ChatBots
{
public class AutoDig : ChatBot
{
public static Configs Config = new();
[TomlDoNotInlineObject]
public class Configs
{
[NonSerialized]
private const string BotName = "AutoDig";
public bool Enabled = false;
[NonSerialized]
[TomlInlineComment("$config.ChatBot.AutoDig.Auto_Tool_Switch$")]
public bool Auto_Tool_Switch = false;
[NonSerialized]
[TomlInlineComment("$config.ChatBot.AutoDig.Durability_Limit$")]
public int Durability_Limit = 2;
[NonSerialized]
[TomlInlineComment("$config.ChatBot.AutoDig.Drop_Low_Durability_Tools$")]
public bool Drop_Low_Durability_Tools = false;
[TomlInlineComment("$config.ChatBot.AutoDig.Mode$")]
public ModeType Mode = ModeType.lookat;
[TomlInlineComment("$config.ChatBot.AutoDig.Locations$")]
public Coordination[] Locations = new Coordination[] { new(123.5, 64, 234.5), new(124.5, 63, 235.5) };
[TomlInlineComment("$config.ChatBot.AutoDig.Location_Order$")]
public OrderType Location_Order = OrderType.distance;
[TomlInlineComment("$config.ChatBot.AutoDig.Auto_Start_Delay$")]
public double Auto_Start_Delay = 3.0;
[TomlInlineComment("$config.ChatBot.AutoDig.Dig_Timeout$")]
public double Dig_Timeout = 60.0;
[TomlInlineComment("$config.ChatBot.AutoDig.Log_Block_Dig$")]
public bool Log_Block_Dig = true;
[TomlInlineComment("$config.ChatBot.AutoDig.List_Type$")]
public ListType List_Type = ListType.whitelist;
public List<Material> Blocks = new() { Material.Cobblestone, Material.Stone };
[NonSerialized]
public Location[] _Locations = Array.Empty<Location>();
public void OnSettingUpdate()
{
if (Auto_Start_Delay >= 0)
Auto_Start_Delay = Math.Max(0.1, Auto_Start_Delay);
if (Dig_Timeout >= 0)
Dig_Timeout = Math.Max(0.1, Dig_Timeout);
_Locations = new Location[Locations.Length];
for (int i = 0; i < Locations.Length; ++i)
_Locations[i] = new(Locations[i].x, Locations[i].y, Locations[i].z);
}
public enum ModeType { lookat, fixedpos, both };
public enum ListType { blacklist, whitelist };
public enum OrderType { distance, index };
public struct Coordination
{
public double x, y, z;
public Coordination(double x, double y, double z)
{
this.x = x; this.y = y; this.z = z;
}
}
}
private bool inventoryEnabled;
private int counter = 0;
private readonly object stateLock = new();
private State state = State.WaitJoinGame;
bool AlreadyWaitting = false;
private Location currentDig = Location.Zero;
private enum State
{
WaitJoinGame,
WaitingStart,
Digging,
Stopping,
}
public override void Initialize()
{
if (!GetTerrainEnabled())
{
LogToConsoleTranslated("extra.terrainandmovement_required");
LogToConsoleTranslated("general.bot_unload");
UnloadBot();
return;
}
inventoryEnabled = GetInventoryEnabled();
if (!inventoryEnabled && Config.Auto_Tool_Switch)
LogToConsoleTranslated("bot.autodig.no_inv_handle");
RegisterChatBotCommand("digbot", Translations.Get("bot.digbot.cmd"), GetHelp(), CommandHandler);
}
public string CommandHandler(string cmd, string[] args)
{
if (args.Length > 0)
{
switch (args[0])
{
case "start":
lock (stateLock)
{
counter = 0;
state = State.WaitingStart;
}
return Translations.Get("bot.autodig.start");
case "stop":
StopDigging();
return Translations.Get("bot.autodig.stop");
case "help":
return GetCommandHelp(args.Length >= 2 ? args[1] : "");
default:
return GetHelp();
}
}
else return GetHelp();
}
private void StartDigging()
{
if (Config.Auto_Start_Delay > 0)
{
double delay = Config.Auto_Start_Delay;
LogToConsole(Translations.Get("bot.autodig.start_delay", delay));
lock (stateLock)
{
counter = Settings.DoubleToTick(delay);
state = State.WaitingStart;
}
}
else
{
lock (stateLock)
{
state = State.WaitJoinGame;
}
}
}
private void StopDigging()
{
state = State.Stopping;
lock (stateLock)
{
state = State.Stopping;
}
}
public override void Update()
{
lock (stateLock)
{
switch (state)
{
case State.WaitJoinGame:
break;
case State.WaitingStart:
if (--counter < 0)
{
if (DoDigging())
{
AlreadyWaitting = false;
state = State.Digging;
}
else
{
counter = 0;
state = State.WaitingStart;
}
}
break;
case State.Digging:
if (++counter > Settings.DoubleToTick(Config.Dig_Timeout))
{
LogToConsole(GetTimestamp() + ": " + Translations.Get("bot.autodig.dig_timeout"));
state = State.WaitingStart;
counter = 0;
}
break;
case State.Stopping:
break;
}
}
}
private bool DoDigging()
{
if (Config.Mode == Configs.ModeType.lookat || Config.Mode == Configs.ModeType.both)
{
(bool hasBlock, Location blockLoc, Block block) = GetLookingBlock(4.5, false);
if (!hasBlock)
{
if (!AlreadyWaitting)
{
AlreadyWaitting = true;
if (Config.Log_Block_Dig)
LogToConsole(Translations.Get("cmd.dig.too_far"));
}
return false;
}
else if (block.Type == Material.Air)
{
if (!AlreadyWaitting)
{
AlreadyWaitting = true;
if (Config.Log_Block_Dig)
LogToConsole(Translations.Get("cmd.dig.no_block"));
}
return false;
}
else if ((Config.List_Type == Configs.ListType.whitelist && Config.Blocks.Contains(block.Type)) ||
(Config.List_Type == Configs.ListType.blacklist && !Config.Blocks.Contains(block.Type)))
{
if (Config.Mode == Configs.ModeType.lookat ||
(Config.Mode == Configs.ModeType.both && Config._Locations.Contains(blockLoc)))
{
if (DigBlock(blockLoc, lookAtBlock: false))
{
currentDig = blockLoc;
if (Config.Log_Block_Dig)
LogToConsole(Translations.Get("cmd.dig.dig", blockLoc.X, blockLoc.Y, blockLoc.Z, block.Type));
return true;
}
else
{
LogToConsole(Translations.Get("cmd.dig.fail"));
return false;
}
}
else
{
if (!AlreadyWaitting)
{
AlreadyWaitting = true;
if (Config.Log_Block_Dig)
LogToConsole(Translations.Get("bot.autodig.not_allow"));
}
return false;
}
}
else
{
if (!AlreadyWaitting)
{
AlreadyWaitting = true;
if (Config.Log_Block_Dig)
LogToConsole(Translations.Get("bot.autodig.not_allow"));
}
return false;
}
}
else if (Config.Mode == Configs.ModeType.fixedpos && Config.Location_Order == Configs.OrderType.distance)
{
Location current = GetCurrentLocation();
double minDistance = double.MaxValue;
Location target = Location.Zero;
Block targetBlock = Block.Air;
foreach (Location location in Config._Locations)
{
Block block = GetWorld().GetBlock(location);
if (block.Type != Material.Air &&
((Config.List_Type == Configs.ListType.whitelist && Config.Blocks.Contains(block.Type)) ||
(Config.List_Type == Configs.ListType.blacklist && !Config.Blocks.Contains(block.Type))))
{
double distance = current.Distance(location);
if (distance < minDistance)
{
minDistance = distance;
target = location;
targetBlock = block;
}
}
}
if (minDistance <= 6.0)
{
if (DigBlock(target, lookAtBlock: true))
{
currentDig = target;
if (Config.Log_Block_Dig)
LogToConsole(Translations.Get("cmd.dig.dig", target.X, target.Y, target.Z, targetBlock.Type));
return true;
}
else
{
LogToConsole(Translations.Get("cmd.dig.fail"));
return false;
}
}
else
{
if (!AlreadyWaitting)
{
AlreadyWaitting = true;
if (Config.Log_Block_Dig)
LogToConsole(Translations.Get("cmd.dig.no_block"));
}
return false;
}
}
else if (Config.Mode == Configs.ModeType.fixedpos && Config.Location_Order == Configs.OrderType.index)
{
for (int i = 0; i < Config._Locations.Length; ++i)
{
Location blockLoc = Config._Locations[i];
Block block = GetWorld().GetBlock(blockLoc);
if (block.Type != Material.Air &&
((Config.List_Type == Configs.ListType.whitelist && Config.Blocks.Contains(block.Type)) ||
(Config.List_Type == Configs.ListType.blacklist && !Config.Blocks.Contains(block.Type))))
{
if (DigBlock(blockLoc, lookAtBlock: true))
{
currentDig = blockLoc;
if (Config.Log_Block_Dig)
LogToConsole(Translations.Get("cmd.dig.dig", blockLoc.X, blockLoc.Y, blockLoc.Z, block.Type));
return true;
}
else
{
LogToConsole(Translations.Get("cmd.dig.fail"));
return false;
}
}
}
if (!AlreadyWaitting)
{
AlreadyWaitting = true;
if (Config.Log_Block_Dig)
LogToConsole(Translations.Get("cmd.dig.no_block"));
}
return false;
}
return false;
}
public override void OnBlockChange(Location location, Block block)
{
if (location == currentDig)
{
lock (stateLock)
{
if (state == State.Digging && location == currentDig)
{
currentDig = Location.Zero;
counter = 0;
state = State.WaitingStart;
}
}
}
}
public override void AfterGameJoined()
{
StartDigging();
}
public override void OnRespawn()
{
StartDigging();
}
public override void OnDeath()
{
StopDigging();
}
public override bool OnDisconnect(DisconnectReason reason, string message)
{
StopDigging();
return base.OnDisconnect(reason, message);
}
private static string GetHelp()
{
return Translations.Get("bot.autodig.available_cmd", "start, stop, help");
}
private string GetCommandHelp(string cmd)
{
return cmd.ToLower() switch
{
#pragma warning disable format // @formatter:off
"start" => Translations.Get("bot.autodig.help.start"),
"stop" => Translations.Get("bot.autodig.help.stop"),
"help" => Translations.Get("bot.autodig.help.help"),
_ => GetHelp(),
#pragma warning restore format // @formatter:on
};
}
}
}

View file

@ -2,51 +2,42 @@
using System.Collections.Generic;
using System.Linq;
using MinecraftClient.Inventory;
using Tomlet.Attributes;
using static MinecraftClient.ChatBots.AutoDrop.Configs;
namespace MinecraftClient.ChatBots
{
class AutoDrop : ChatBot
public class AutoDrop : ChatBot
{
private enum Mode
public static Configs Config = new();
[TomlDoNotInlineObject]
public class Configs
{
Include, // Items in list will be dropped
Exclude, // Items in list will be kept
Everything // Everything will be dropped
[NonSerialized]
private const string BotName = "AutoDrop";
public bool Enabled = false;
[TomlInlineComment("$config.ChatBot.AutoDrop.Mode$")]
public DropMode Mode = DropMode.include;
public List<ItemType> Items = new() { ItemType.Cobblestone, ItemType.Dirt };
public void OnSettingUpdate() { }
public enum DropMode
{
include, // Items in list will be dropped
exclude, // Items in list will be kept
everything // Everything will be dropped
}
}
private Mode dropMode = Mode.Include;
private bool enable = true;
private int updateDebounce = 0;
private readonly int updateDebounceValue = 2;
private int inventoryUpdated = -1;
private readonly List<ItemType> itemList = new();
public AutoDrop(string mode, string itemList)
{
if (!Enum.TryParse(mode, true, out dropMode))
{
LogToConsoleTranslated("bot.autoDrop.no_mode");
}
if (dropMode != Mode.Everything)
this.itemList = ItemListParser(itemList).ToList();
}
/// <summary>
/// Convert an item type string to item type array
/// </summary>
/// <param name="itemList">String to convert</param>
/// <returns>Item type array</returns>
private ItemType[] ItemListParser(string itemList)
{
string trimed = new(itemList.Where(c => !char.IsWhiteSpace(c)).ToArray());
List<ItemType> result = new();
foreach (string t in trimed.Split(','))
if (Enum.TryParse(t, true, out ItemType item))
result.Add(item);
return result.ToArray();
}
public string CommandHandler(string cmd, string[] args)
{
if (args.Length > 0)
@ -54,19 +45,19 @@ namespace MinecraftClient.ChatBots
switch (args[0].ToLower())
{
case "on":
enable = true;
Config.Enabled = true;
inventoryUpdated = 0;
OnUpdateFinish();
return Translations.Get("bot.autoDrop.on");
case "off":
enable = false;
Config.Enabled = false;
return Translations.Get("bot.autoDrop.off");
case "add":
if (args.Length >= 2)
{
if (Enum.TryParse(args[1], true, out ItemType item))
{
itemList.Add(item);
Config.Items.Add(item);
return Translations.Get("bot.autoDrop.added", item.ToString());
}
else
@ -83,9 +74,9 @@ namespace MinecraftClient.ChatBots
{
if (Enum.TryParse(args[1], true, out ItemType item))
{
if (itemList.Contains(item))
if (Config.Items.Contains(item))
{
itemList.Remove(item);
Config.Items.Remove(item);
return Translations.Get("bot.autoDrop.removed", item.ToString());
}
else
@ -103,9 +94,9 @@ namespace MinecraftClient.ChatBots
return Translations.Get("cmd.inventory.help.usage") + ": remove <item name>";
}
case "list":
if (itemList.Count > 0)
if (Config.Items.Count > 0)
{
return Translations.Get("bot.autoDrop.list", itemList.Count, string.Join("\n", itemList));
return Translations.Get("bot.autoDrop.list", Config.Items.Count, string.Join("\n", Config.Items));
}
else
{
@ -117,20 +108,20 @@ namespace MinecraftClient.ChatBots
switch (args[1].ToLower())
{
case "include":
dropMode = Mode.Include;
Config.Mode = DropMode.include;
break;
case "exclude":
dropMode = Mode.Exclude;
Config.Mode = DropMode.exclude;
break;
case "everything":
dropMode = Mode.Everything;
Config.Mode = DropMode.everything;
break;
default:
return Translations.Get("bot.autoDrop.unknown_mode"); // Unknwon mode. Available modes: Include, Exclude, Everything
}
inventoryUpdated = 0;
OnUpdateFinish();
return Translations.Get("bot.autoDrop.switched", dropMode.ToString()); // Switched to {0} mode.
return Translations.Get("bot.autoDrop.switched", Config.Mode.ToString()); // Switched to {0} mode.
}
else
{
@ -178,7 +169,7 @@ namespace MinecraftClient.ChatBots
public override void OnInventoryUpdate(int inventoryId)
{
if (enable)
if (Config.Enabled)
{
updateDebounce = updateDebounceValue;
// Always interact container if available (larger ID) because they included player inventory (ID 0)
@ -199,28 +190,28 @@ namespace MinecraftClient.ChatBots
}
var inventory = GetInventories()[inventoryUpdated];
var items = inventory.Items.ToDictionary(entry => entry.Key, entry => entry.Value);
if (dropMode == Mode.Include)
if (Config.Mode == DropMode.include)
{
foreach (var item in items)
{
// Ingore crafting result slot
if (item.Key == 0)
continue;
if (itemList.Contains(item.Value.Type))
if (Config.Items.Contains(item.Value.Type))
{
// Drop it !!
WindowAction(inventoryUpdated, item.Key, WindowActionType.DropItemStack);
}
}
}
else if (dropMode == Mode.Exclude)
else if (Config.Mode == DropMode.exclude)
{
foreach (var item in items)
{
// Ingore crafting result slot
if (item.Key == 0)
continue;
if (!itemList.Contains(item.Value.Type))
if (!Config.Items.Contains(item.Value.Type))
{
// Drop it !!
WindowAction(inventoryUpdated, item.Key, WindowActionType.DropItemStack);

View file

@ -1,19 +1,36 @@
using MinecraftClient.Inventory;
using System;
using MinecraftClient.Inventory;
using Tomlet.Attributes;
namespace MinecraftClient.ChatBots
{
class AutoEat : ChatBot
public class AutoEat : ChatBot
{
public static Configs Config = new();
[TomlDoNotInlineObject]
public class Configs
{
[NonSerialized]
private const string BotName = "AutoEat";
public bool Enabled = false;
public int Threshold = 6;
public void OnSettingUpdate()
{
if (Threshold > 20)
Threshold = 20;
else if (Threshold < 0)
Threshold = 0;
}
}
byte LastSlot = 0;
public static bool Eating = false;
private readonly int HungerThreshold = 6;
private int DelayCounter = 0;
public AutoEat(int Threshold)
{
HungerThreshold = Threshold;
}
public override void Update()
{
if (DelayCounter > 0)
@ -31,7 +48,7 @@ namespace MinecraftClient.ChatBots
public override void OnHealthUpdate(float health, int food)
{
if (health <= 0) return; // player dead
if (((food <= HungerThreshold) || (food < 20 && health < 20)) && !Eating)
if (((food <= Config.Threshold) || (food < 20 && health < 20)) && !Eating)
{
Eating = FindFoodAndEat();
if (!Eating)

View file

@ -1,6 +1,8 @@
using System;
using MinecraftClient.Inventory;
using MinecraftClient.Mapping;
using Tomlet.Attributes;
using static MinecraftClient.ChatBots.AutoFishing.Configs;
namespace MinecraftClient.ChatBots
{
@ -8,8 +10,130 @@ namespace MinecraftClient.ChatBots
/// The AutoFishing bot semi-automates fishing.
/// The player needs to have a fishing rod in hand, then manually send it using the UseItem command.
/// </summary>
class AutoFishing : ChatBot
public class AutoFishing : ChatBot
{
public static Configs Config = new();
[TomlDoNotInlineObject]
public class Configs
{
[NonSerialized]
private const string BotName = "AutoFishing";
public bool Enabled = false;
[TomlInlineComment("$config.ChatBot.AutoFishing.Antidespawn$")]
public bool Antidespawn = false;
[TomlInlineComment("$config.ChatBot.AutoFishing.Mainhand$")]
public bool Mainhand = true;
[TomlInlineComment("$config.ChatBot.AutoFishing.Auto_Start$")]
public bool Auto_Start = true;
[TomlInlineComment("$config.ChatBot.AutoFishing.Cast_Delay$")]
public double Cast_Delay = 0.4;
[TomlInlineComment("$config.ChatBot.AutoFishing.Fishing_Delay$")]
public double Fishing_Delay = 3.0;
[TomlInlineComment("$config.ChatBot.AutoFishing.Fishing_Timeout$")]
public double Fishing_Timeout = 300.0;
[TomlInlineComment("$config.ChatBot.AutoFishing.Durability_Limit$")]
public double Durability_Limit = 2;
[TomlInlineComment("$config.ChatBot.AutoFishing.Auto_Rod_Switch$")]
public bool Auto_Rod_Switch = true;
[TomlInlineComment("$config.ChatBot.AutoFishing.Stationary_Threshold$")]
public double Stationary_Threshold = 0.001;
[TomlInlineComment("$config.ChatBot.AutoFishing.Hook_Threshold$")]
public double Hook_Threshold = 0.2;
[TomlInlineComment("$config.ChatBot.AutoFishing.Log_Fish_Bobber$")]
public bool Log_Fish_Bobber = false;
[TomlInlineComment("$config.ChatBot.AutoFishing.Enable_Move$")]
public bool Enable_Move = false;
[TomlPrecedingComment("$config.ChatBot.AutoFishing.Movements$")]
public LocationConfig[] Movements = new LocationConfig[]
{
new LocationConfig(12.34, -23.45),
new LocationConfig(123.45, 64, -654.32, -25.14, 36.25),
new LocationConfig(-1245.63, 63.5, 1.2),
};
public void OnSettingUpdate()
{
if (Cast_Delay < 0)
Cast_Delay = 0;
if (Fishing_Delay < 0)
Fishing_Delay = 0;
if (Fishing_Timeout < 0)
Fishing_Timeout = 0;
if (Durability_Limit < 0)
Durability_Limit = 0;
else if (Durability_Limit > 64)
Durability_Limit = 64;
if (Stationary_Threshold < 0)
Stationary_Threshold = -Stationary_Threshold;
if (Hook_Threshold < 0)
Hook_Threshold = -Hook_Threshold;
}
public struct LocationConfig
{
public Coordination? XYZ;
public Facing? facing;
public LocationConfig(double yaw, double pitch)
{
this.XYZ = null;
this.facing = new(yaw, pitch);
}
public LocationConfig(double x, double y, double z)
{
this.XYZ = new(x, y, z);
this.facing = null;
}
public LocationConfig(double x, double y, double z, double yaw, double pitch)
{
this.XYZ = new(x, y, z);
this.facing = new(yaw, pitch);
}
public struct Coordination
{
public double x, y, z;
public Coordination(double x, double y, double z)
{
this.x = x; this.y = y; this.z = z;
}
}
public struct Facing
{
public double yaw, pitch;
public Facing(double yaw, double pitch)
{
this.yaw = yaw; this.pitch = pitch;
}
}
}
}
private int fishCount = 0;
private bool inventoryEnabled;
private int castTimeout = 12;
@ -54,13 +178,13 @@ namespace MinecraftClient.ChatBots
private void StartFishing()
{
isFishing = false;
if (Settings.AutoFishing_AutoStart)
if (Config.Auto_Start)
{
double delay = Settings.AutoFishing_FishingDelay;
double delay = Config.Fishing_Delay;
LogToConsole(Translations.Get("bot.autoFish.start", delay));
lock (stateLock)
{
counter = (int)(delay * 10);
counter = Settings.DoubleToTick(delay);
state = FishingState.StartMove;
}
}
@ -84,7 +208,7 @@ namespace MinecraftClient.ChatBots
private void UseFishRod()
{
if (Settings.AutoFishing_Mainhand)
if (Config.Mainhand)
UseItemInHand();
else
UseItemInLeftHand();
@ -100,7 +224,7 @@ namespace MinecraftClient.ChatBots
break;
case FishingState.WaitingToCast:
if (AutoEat.Eating)
counter = (int)(Settings.AutoFishing_CastDelay * 10);
counter = Settings.DoubleToTick(Config.Cast_Delay);
else if (--counter < 0)
state = FishingState.CastingRod;
break;
@ -116,28 +240,27 @@ namespace MinecraftClient.ChatBots
castTimeout *= 2; // Exponential backoff
LogToConsole(GetTimestamp() + ": " + Translations.Get("bot.autoFish.cast_timeout", castTimeout / 10.0));
counter = (int)(Settings.AutoFishing_CastDelay * 10);
counter = Settings.DoubleToTick(Config.Cast_Delay);
state = FishingState.WaitingToCast;
}
break;
case FishingState.WaitingFishToBite:
if (++counter > (int)(Settings.AutoFishing_FishingTimeout * 10))
if (++counter > Settings.DoubleToTick(Config.Fishing_Timeout))
{
LogToConsole(GetTimestamp() + ": " + Translations.Get("bot.autoFish.fishing_timeout"));
counter = (int)(Settings.AutoFishing_CastDelay * 10);
counter = Settings.DoubleToTick(Config.Cast_Delay);
state = FishingState.WaitingToCast;
}
break;
case FishingState.StartMove:
if (--counter < 0)
{
double[,]? locationList = Settings.AutoFishing_Location;
if (locationList != null)
if (Config.Enable_Move && Config.Movements.Length > 0)
{
if (GetTerrainEnabled())
{
UpdateLocation(locationList);
UpdateLocation(Config.Movements);
state = FishingState.WaitingMovement;
}
else
@ -148,7 +271,7 @@ namespace MinecraftClient.ChatBots
}
else
{
counter = (int)(Settings.AutoFishing_CastDelay * 10);
counter = Settings.DoubleToTick(Config.Cast_Delay);
state = FishingState.DurabilityCheck;
goto case FishingState.DurabilityCheck;
}
@ -167,7 +290,7 @@ namespace MinecraftClient.ChatBots
case FishingState.DurabilityCheck:
if (DurabilityCheck())
{
counter = (int)(Settings.AutoFishing_CastDelay * 10);
counter = Settings.DoubleToTick(Config.Cast_Delay);
state = FishingState.WaitingToCast;
}
break;
@ -181,7 +304,7 @@ namespace MinecraftClient.ChatBots
{
if (entity.Type == EntityType.FishingBobber && entity.ObjectData == GetPlayerEntityID())
{
if (Settings.AutoFishing_LogFishingBobber)
if (Config.Log_Fish_Bobber)
LogToConsole(string.Format("FishingBobber spawn at {0}, distance = {1:0.00}", entity.Location, GetCurrentLocation().Distance(entity.Location)));
LogToConsole(GetTimestamp() + ": " + Translations.Get("bot.autoFish.throw"));
@ -202,20 +325,20 @@ namespace MinecraftClient.ChatBots
{
if (entity != null && entity.Type == EntityType.FishingBobber && entity.ID == fishingBobber!.ID)
{
if (Settings.AutoFishing_LogFishingBobber)
if (Config.Log_Fish_Bobber)
LogToConsole(string.Format("FishingBobber despawn at {0}", entity.Location));
if (isFishing)
{
isFishing = false;
if (Settings.AutoFishing_Antidespawn)
if (Config.Antidespawn)
{
LogToConsoleTranslated("bot.autoFish.despawn");
lock (stateLock)
{
counter = (int)(Settings.AutoFishing_CastDelay * 10);
counter = Settings.DoubleToTick(Config.Cast_Delay);
state = FishingState.WaitingToCast;
}
}
@ -233,12 +356,12 @@ namespace MinecraftClient.ChatBots
double Dz = LastPos.Z - Pos.Z;
LastPos = Pos;
if (Settings.AutoFishing_LogFishingBobber)
if (Config.Log_Fish_Bobber)
LogToConsole(string.Format("FishingBobber {0} Dx={1:0.000000} Dy={2:0.000000} Dz={3:0.000000}", Pos, Dx, Math.Abs(Dy), Dz));
if (Math.Abs(Dx) < Math.Abs(Settings.AutoFishing_StationaryThreshold) &&
Math.Abs(Dz) < Math.Abs(Settings.AutoFishing_StationaryThreshold) &&
Math.Abs(Dy) > Math.Abs(Settings.AutoFishing_HookThreshold))
if (Math.Abs(Dx) < Math.Abs(Config.Stationary_Threshold) &&
Math.Abs(Dz) < Math.Abs(Config.Stationary_Threshold) &&
Math.Abs(Dy) > Math.Abs(Config.Hook_Threshold))
{
// prevent triggering multiple time
if ((DateTime.Now - CaughtTime).TotalSeconds > 1)
@ -283,7 +406,7 @@ namespace MinecraftClient.ChatBots
public void OnCaughtFish()
{
++fishCount;
if (Settings.AutoFishing_Location != null)
if (Config.Enable_Move && Config.Movements.Length > 0)
LogToConsole(GetTimestamp() + ": " + Translations.Get("bot.autoFish.caught_at",
fishingBobber!.Location.X, fishingBobber!.Location.Y, fishingBobber!.Location.Z, fishCount));
else
@ -298,47 +421,36 @@ namespace MinecraftClient.ChatBots
}
}
private void UpdateLocation(double[,] locationList)
private void UpdateLocation(LocationConfig[] locationList)
{
if (curLocationIdx >= locationList.GetLength(0))
if (curLocationIdx >= locationList.Length)
{
curLocationIdx = Math.Max(0, locationList.GetLength(0) - 2);
curLocationIdx = Math.Max(0, locationList.Length - 2);
moveDir = -1;
}
else if (curLocationIdx < 0)
{
curLocationIdx = Math.Min(locationList.GetLength(0) - 1, 1);
curLocationIdx = Math.Min(locationList.Length - 1, 1);
moveDir = 1;
}
int locationType = locationList.GetLength(1);
LocationConfig curConfig = locationList[curLocationIdx];
if (locationType == 2)
{
nextYaw = (float)locationList[curLocationIdx, 0];
nextPitch = (float)locationList[curLocationIdx, 1];
}
else if (locationType == 3)
{
nextYaw = GetYaw();
nextPitch = GetPitch();
}
else if (locationType == 5)
{
nextYaw = (float)locationList[curLocationIdx, 3];
nextPitch = (float)locationList[curLocationIdx, 4];
}
if (curConfig.facing != null)
(nextYaw, nextPitch) = ((float)curConfig.facing.Value.yaw, (float)curConfig.facing.Value.pitch);
else
(nextYaw, nextPitch) = (GetYaw(), GetPitch());
if (locationType == 3 || locationType == 5)
if (curConfig.XYZ != null)
{
Location current = GetCurrentLocation();
Location goal = new(locationList[curLocationIdx, 0], locationList[curLocationIdx, 1], locationList[curLocationIdx, 2]);
Location goal = new(curConfig.XYZ.Value.x, curConfig.XYZ.Value.y, curConfig.XYZ.Value.z);
bool isMoveSuccessed;
if (!Movement.CheckChunkLoading(GetWorld(), current, goal))
{
LogToConsole(Translations.Get("cmd.move.chunk_not_loaded", goal.X, goal.Y, goal.Z));
isMoveSuccessed = false;
LogToConsole(Translations.Get("cmd.move.chunk_not_loaded", goal.X, goal.Y, goal.Z));
}
else
{
@ -347,8 +459,7 @@ namespace MinecraftClient.ChatBots
if (!isMoveSuccessed)
{
nextYaw = GetYaw();
nextPitch = GetPitch();
(nextYaw, nextPitch) = (GetYaw(), GetPitch());
LogToConsole(Translations.Get("cmd.move.fail", goal));
}
else
@ -365,13 +476,13 @@ namespace MinecraftClient.ChatBots
if (!inventoryEnabled)
return true;
bool useMainHand = Settings.AutoFishing_Mainhand;
bool useMainHand = Config.Mainhand;
Container container = GetPlayerInventory();
int itemSolt = useMainHand ? GetCurrentSlot() + 36 : 45;
if (container.Items.TryGetValue(itemSolt, out Item? handItem) &&
handItem.Type == ItemType.FishingRod && (64 - handItem.Damage) >= Settings.AutoFishing_DurabilityLimit)
handItem.Type == ItemType.FishingRod && (64 - handItem.Damage) >= Config.Durability_Limit)
{
isWaitingRod = false;
return true;
@ -381,11 +492,11 @@ namespace MinecraftClient.ChatBots
if (!isWaitingRod)
LogToConsole(GetTimestamp() + ": " + Translations.Get("bot.autoFish.no_rod"));
if (Settings.AutoFishing_AutoRodSwitch)
if (Config.Auto_Rod_Switch)
{
foreach ((int slot, Item item) in container.Items)
{
if (item.Type == ItemType.FishingRod && (64 - item.Damage) >= Settings.AutoFishing_DurabilityLimit)
if (item.Type == ItemType.FishingRod && (64 - item.Damage) >= Config.Durability_Limit)
{
WindowAction(0, slot, WindowActionType.LeftClick);
WindowAction(0, itemSolt, WindowActionType.LeftClick);

View file

@ -1,5 +1,5 @@
using System;
using System.Text;
using Tomlet.Attributes;
namespace MinecraftClient.ChatBots
{
@ -8,11 +8,68 @@ namespace MinecraftClient.ChatBots
/// </summary>
public class AutoRelog : ChatBot
{
public static Configs Config = new();
[TomlDoNotInlineObject]
public class Configs
{
[NonSerialized]
private const string BotName = "AutoRelog";
public bool Enabled = false;
[TomlInlineComment("$config.ChatBot.AutoRelog.Delay$")]
public Range Delay = new(3);
[TomlInlineComment("$config.ChatBot.AutoRelog.Retries$")]
public int Retries = 3;
[TomlInlineComment("$config.ChatBot.AutoRelog.Ignore_Kick_Message$")]
public bool Ignore_Kick_Message = false;
[TomlPrecedingComment("$config.ChatBot.AutoRelog.Kick_Messages$")]
public string[] Kick_Messages = new string[] { "Connection has been lost", "Server is restarting", "Server is full", "Too Many people" };
[NonSerialized]
public static int _BotRecoAttempts = 0;
public void OnSettingUpdate()
{
Delay.min = Math.Max(0.1, Delay.min);
Delay.max = Math.Max(0.1, Delay.max);
Delay.min = Math.Min(int.MaxValue / 10, Delay.min);
Delay.max = Math.Min(int.MaxValue / 10, Delay.max);
if (Delay.min > Delay.max)
(Delay.min, Delay.max) = (Delay.max, Delay.min);
if (Retries == -1)
Retries = int.MaxValue;
if (Enabled)
for (int i = 0; i < Kick_Messages.Length; i++)
Kick_Messages[i] = Kick_Messages[i].ToLower();
}
public struct Range
{
public double min, max;
public Range(int value)
{
min = max = value;
}
public Range(int min, int max)
{
this.min = min;
this.max = max;
}
}
}
private static readonly Random random = new();
private string[] dictionary = Array.Empty<string>();
private readonly int attempts;
private readonly int delayMin;
private readonly int delayMax;
/// <summary>
/// This bot automatically re-join the server if kick message contains predefined string
@ -20,48 +77,18 @@ namespace MinecraftClient.ChatBots
/// <param name="DelayBeforeRelogMin">Minimum delay before re-joining the server (in seconds)</param>
/// <param name="DelayBeforeRelogMax">Maximum delay before re-joining the server (in seconds)</param>
/// <param name="retries">Number of retries if connection fails (-1 = infinite)</param>
public AutoRelog(int DelayBeforeRelogMin, int DelayBeforeRelogMax, int retries)
public AutoRelog()
{
attempts = retries;
if (attempts == -1) { attempts = int.MaxValue; }
McClient.ReconnectionAttemptsLeft = attempts;
delayMin = DelayBeforeRelogMin;
delayMax = DelayBeforeRelogMax;
if (delayMin < 1)
delayMin = 1;
if (delayMax < delayMin)
delayMax = delayMin;
LogDebugToConsoleTranslated("bot.autoRelog.launch", attempts);
LogDebugToConsoleTranslated("bot.autoRelog.launch", Config.Retries);
}
public override void Initialize()
{
McClient.ReconnectionAttemptsLeft = attempts;
if (Settings.AutoRelog_IgnoreKickMessage)
McClient.ReconnectionAttemptsLeft = Config.Retries;
if (Config.Ignore_Kick_Message)
{
LogDebugToConsoleTranslated("bot.autoRelog.no_kick_msg");
}
else
{
if (System.IO.File.Exists(Settings.AutoRelog_KickMessagesFile))
{
LogDebugToConsoleTranslated("bot.autoRelog.loading", System.IO.Path.GetFullPath(Settings.AutoRelog_KickMessagesFile));
dictionary = System.IO.File.ReadAllLines(Settings.AutoRelog_KickMessagesFile, Encoding.UTF8);
for (int i = 0; i < dictionary.Length; i++)
{
LogDebugToConsoleTranslated("bot.autoRelog.loaded", dictionary[i]);
dictionary[i] = dictionary[i].ToLower();
}
}
else
{
LogToConsoleTranslated("bot.autoRelog.not_found", System.IO.Path.GetFullPath(Settings.AutoRelog_KickMessagesFile));
LogDebugToConsoleTranslated("bot.autoRelog.curr_dir", System.IO.Directory.GetCurrentDirectory());
}
}
}
public override bool OnDisconnect(DisconnectReason reason, string message)
@ -70,23 +97,25 @@ namespace MinecraftClient.ChatBots
{
LogDebugToConsoleTranslated("bot.autoRelog.ignore_user_logout");
}
else
else if (Config.Retries < 0 || Configs._BotRecoAttempts < Config.Retries)
{
message = GetVerbatim(message);
string comp = message.ToLower();
LogDebugToConsoleTranslated("bot.autoRelog.disconnect_msg", message);
if (Settings.AutoRelog_IgnoreKickMessage)
if (Config.Ignore_Kick_Message)
{
Configs._BotRecoAttempts++;
LaunchDelayedReconnection(null);
return true;
}
foreach (string msg in dictionary)
foreach (string msg in Config.Kick_Messages)
{
if (comp.Contains(msg))
{
Configs._BotRecoAttempts++;
LaunchDelayedReconnection(msg);
return true;
}
@ -100,7 +129,7 @@ namespace MinecraftClient.ChatBots
private void LaunchDelayedReconnection(string? msg)
{
int delay = random.Next(delayMin, delayMax);
int delay = random.Next(Settings.DoubleToTick(Config.Delay.min), Settings.DoubleToTick(Config.Delay.max));
LogDebugToConsoleTranslated(String.IsNullOrEmpty(msg) ? "bot.autoRelog.reconnect_always" : "bot.autoRelog.reconnect", msg);
LogToConsoleTranslated("bot.autoRelog.wait", delay);
System.Threading.Thread.Sleep(delay * 1000);
@ -109,9 +138,9 @@ namespace MinecraftClient.ChatBots
public static bool OnDisconnectStatic(DisconnectReason reason, string message)
{
if (Settings.AutoRelog_Enabled)
if (Config.Enabled)
{
AutoRelog bot = new(Settings.AutoRelog_Delay_Min, Settings.AutoRelog_Delay_Max, Settings.AutoRelog_Retries);
AutoRelog bot = new();
bot.Initialize();
return bot.OnDisconnect(reason, message);
}

View file

@ -1,31 +1,52 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using Tomlet.Attributes;
using static MinecraftClient.Settings;
namespace MinecraftClient.ChatBots
{
/// <summary>
/// This bot automatically runs actions when a user sends a message matching a specified rule
/// </summary>
class AutoRespond : ChatBot
public class AutoRespond : ChatBot
{
private readonly string matchesFile;
private readonly bool matchColors;
public static Configs Config = new();
[TomlDoNotInlineObject]
public class Configs
{
[NonSerialized]
private const string BotName = "AutoRespond";
public bool Enabled = false;
public string Matches_File = @"matches.ini";
[TomlInlineComment("$config.ChatBot.AutoRespond.Match_Colors$")]
public bool Match_Colors = false;
public void OnSettingUpdate()
{
Matches_File ??= string.Empty;
if (!Enabled) return;
if (!File.Exists(Matches_File))
{
LogToConsole(BotName, Translations.TryGet("bot.autoRespond.file_not_found", Path.GetFullPath(Matches_File)));
LogToConsole(BotName, Translations.TryGet("general.bot_unload"));
Enabled = false;
}
}
}
private List<RespondRule>? respondRules;
private enum MessageType { Public, Private, Other };
/// <summary>
/// Create a new AutoRespond bot
/// </summary>
/// <param name="matchesFile">INI File to load matches from</param>
public AutoRespond(string matchesFile, bool matchColors)
{
this.matchesFile = matchesFile;
this.matchColors = matchColors;
}
/// <summary>
/// Describe a respond rule based on a simple match or a regex
/// </summary>
@ -96,7 +117,7 @@ namespace MinecraftClient.ChatBots
string? toSend = null;
if (ownersOnly && (String.IsNullOrEmpty(username) || !Settings.Bots_Owners.Contains(username.ToLower())))
if (ownersOnly && (String.IsNullOrEmpty(username) || !Settings.Config.Main.Advanced.BotOwners.Contains(username.ToLower())))
return null;
switch (msgType)
@ -164,7 +185,7 @@ namespace MinecraftClient.ChatBots
/// </summary>
public override void Initialize()
{
if (File.Exists(matchesFile))
if (File.Exists(Config.Matches_File))
{
Regex? matchRegex = null;
string? matchString = null;
@ -175,9 +196,9 @@ namespace MinecraftClient.ChatBots
TimeSpan cooldown = TimeSpan.Zero;
respondRules = new List<RespondRule>();
LogDebugToConsoleTranslated("bot.autoRespond.loading", System.IO.Path.GetFullPath(matchesFile));
LogDebugToConsoleTranslated("bot.autoRespond.loading", System.IO.Path.GetFullPath(Config.Matches_File));
foreach (string lineRAW in File.ReadAllLines(matchesFile, Encoding.UTF8))
foreach (string lineRAW in File.ReadAllLines(Config.Matches_File, Encoding.UTF8))
{
string line = lineRAW.Split('#')[0].Trim();
if (line.Length > 0)
@ -211,8 +232,8 @@ namespace MinecraftClient.ChatBots
case "action": matchAction = argValue; break;
case "actionprivate": matchActionPrivate = argValue; break;
case "actionother": matchActionOther = argValue; break;
case "ownersonly": ownersOnly = Settings.str2bool(argValue); break;
case "cooldown": cooldown = TimeSpan.FromSeconds(Settings.str2int(argValue)); break;
case "ownersonly": ownersOnly = bool.Parse(argValue); break;
case "cooldown": cooldown = TimeSpan.FromSeconds(int.Parse(argValue, NumberStyles.Any, CultureInfo.CurrentCulture)); break;
}
}
}
@ -222,7 +243,7 @@ namespace MinecraftClient.ChatBots
}
else
{
LogToConsoleTranslated("bot.autoRespond.file_not_found", System.IO.Path.GetFullPath(matchesFile));
LogToConsoleTranslated("bot.autoRespond.file_not_found", System.IO.Path.GetFullPath(Config.Matches_File));
UnloadBot(); //No need to keep the bot active
}
}
@ -264,7 +285,7 @@ namespace MinecraftClient.ChatBots
public override void GetText(string text)
{
//Remove colour codes
if (!matchColors)
if (!Config.Match_Colors)
text = GetVerbatim(text);
//Get Message type
@ -277,7 +298,7 @@ namespace MinecraftClient.ChatBots
else message = text;
//Do not process messages sent by the bot itself
if (msgType == MessageType.Other || sender != Settings.Username)
if (msgType == MessageType.Other || sender != InternalConfig.Username)
{
foreach (RespondRule rule in respondRules!)
{

View file

@ -1,5 +1,6 @@
using System;
using System.IO;
using Tomlet.Attributes;
namespace MinecraftClient.ChatBots
{
@ -9,13 +10,44 @@ namespace MinecraftClient.ChatBots
public class ChatLog : ChatBot
{
public enum MessageFilter { AllText, AllMessages, OnlyChat, OnlyWhispers, OnlyInternalCommands };
private readonly bool dateandtime;
private readonly bool saveOther = true;
private readonly bool saveChat = true;
private readonly bool savePrivate = true;
private readonly bool saveInternal = true;
private readonly string logfile;
public static Configs Config = new();
[TomlDoNotInlineObject]
public class Configs
{
[NonSerialized]
private const string BotName = "ChatLog";
public bool Enabled = false;
public bool Add_DateTime = true;
public string Log_File = @"chatlog-%username%-%serverip%.txt";
public MessageFilter Filter = MessageFilter.messages;
public void OnSettingUpdate()
{
Log_File ??= string.Empty;
if (!Enabled) return;
string Log_File_Full = Settings.Config.AppVar.ExpandVars(Log_File);
if (String.IsNullOrEmpty(Log_File_Full) || Log_File_Full.IndexOfAny(Path.GetInvalidPathChars()) >= 0)
{
LogToConsole(BotName, Translations.TryGet("bot.chatLog.invalid_file", Log_File_Full));
LogToConsole(BotName, Translations.TryGet("general.bot_unload"));
Enabled = false;
}
}
public enum MessageFilter { all, messages, chat, private_chat, internal_msg };
}
private bool saveOther = true;
private bool saveChat = true;
private bool savePrivate = true;
private bool saveInternal = true;
private readonly object logfileLock = new();
/// <summary>
@ -25,59 +57,42 @@ namespace MinecraftClient.ChatBots
/// <param name="filter">The kind of messages to save</param>
/// <param name="AddDateAndTime">Add a date and time before each message</param>
public ChatLog(string file, MessageFilter filter, bool AddDateAndTime)
public ChatLog()
{
UpdateFilter(Config.Filter);
}
public void UpdateFilter(Configs.MessageFilter filter)
{
dateandtime = AddDateAndTime;
logfile = file;
switch (filter)
{
case MessageFilter.AllText:
case Configs.MessageFilter.all:
saveOther = true;
savePrivate = true;
saveChat = true;
break;
case MessageFilter.AllMessages:
case Configs.MessageFilter.messages:
saveOther = false;
savePrivate = true;
saveChat = true;
break;
case MessageFilter.OnlyChat:
case Configs.MessageFilter.chat:
saveOther = false;
savePrivate = false;
saveChat = true;
break;
case MessageFilter.OnlyWhispers:
case Configs.MessageFilter.private_chat:
saveOther = false;
savePrivate = true;
saveChat = false;
break;
case MessageFilter.OnlyInternalCommands:
case Configs.MessageFilter.internal_msg:
saveOther = false;
savePrivate = false;
saveChat = false;
saveInternal = true;
break;
}
if (String.IsNullOrEmpty(file) || file.IndexOfAny(Path.GetInvalidPathChars()) >= 0)
{
LogToConsoleTranslated("bot.chatLog.invalid_file", file);
UnloadBot();
}
}
public static MessageFilter str2filter(string filtername)
{
return Settings.ToLowerIfNeed(filtername) switch
{
#pragma warning disable format // @formatter:off
"all" => MessageFilter.AllText,
"messages" => MessageFilter.AllMessages,
"chat" => MessageFilter.OnlyChat,
"private" => MessageFilter.OnlyWhispers,
"internal" => MessageFilter.OnlyInternalCommands,
_ => MessageFilter.AllText,
#pragma warning restore format // @formatter:on
};
}
public override void GetText(string text)
@ -110,14 +125,15 @@ namespace MinecraftClient.ChatBots
private void Save(string tosave)
{
if (dateandtime)
if (Config.Add_DateTime)
tosave = GetTimestamp() + ' ' + tosave;
string Log_File_Full = Settings.Config.AppVar.ExpandVars(Config.Log_File);
lock (logfileLock)
{
string? directory = Path.GetDirectoryName(logfile);
string? directory = Path.GetDirectoryName(Log_File_Full);
if (!String.IsNullOrEmpty(directory) && !Directory.Exists(directory))
Directory.CreateDirectory(directory);
FileStream stream = new(logfile, FileMode.OpenOrCreate);
FileStream stream = new(Log_File_Full, FileMode.OpenOrCreate);
StreamWriter writer = new(stream);
stream.Seek(0, SeekOrigin.End);
writer.WriteLine(tosave);

View file

@ -1,23 +1,42 @@
using System;
using System.Linq;
using MinecraftClient.Mapping;
using Tomlet.Attributes;
namespace MinecraftClient.ChatBots
{
public class FollowPlayer : ChatBot
{
public static Configs Config = new();
[TomlDoNotInlineObject]
public class Configs
{
[NonSerialized]
private const string BotName = "FollowPlayer";
public bool Enabled = false;
[TomlInlineComment("$config.ChatBot.FollowPlayer.Update_Limit$")]
public double Update_Limit = 1;
[TomlInlineComment("$config.ChatBot.FollowPlayer.Stop_At_Distance$")]
public double Stop_At_Distance = 3.0;
public void OnSettingUpdate()
{
if (Update_Limit < 0)
Update_Limit = 0;
if (Stop_At_Distance < 0)
Stop_At_Distance = 0;
}
}
private string? _playerToFollow = null;
private int _updateCounter = 0;
private readonly int _updateLimit;
private readonly int _stopAtDistance;
private bool _unsafeEnabled = false;
public FollowPlayer(int updateLimit = 15, int stopAtDistance = 3)
{
_updateLimit = updateLimit;
_stopAtDistance = stopAtDistance;
}
public override void Initialize()
{
if (!GetEntityHandlingEnabled())
@ -94,7 +113,7 @@ namespace MinecraftClient.ChatBots
public override void OnEntityMove(Entity entity)
{
if (_updateCounter < _updateLimit)
if (_updateCounter < Settings.DoubleToTick(Config.Update_Limit))
return;
_updateCounter = 0;
@ -114,7 +133,7 @@ namespace MinecraftClient.ChatBots
// Stop at specified distance from plater (prevents pushing player around)
double distance = entity.Location.Distance(GetCurrentLocation());
if (distance < _stopAtDistance)
if (distance < Config.Stop_At_Distance)
return;
MoveToLocation(entity.Location, _unsafeEnabled);

View file

@ -1,5 +1,6 @@
using System;
using System.Text;
using Tomlet.Attributes;
namespace MinecraftClient.ChatBots
{
@ -9,26 +10,37 @@ namespace MinecraftClient.ChatBots
public class HangmanGame : ChatBot
{
public static Configs Config = new();
[TomlDoNotInlineObject]
public class Configs
{
[NonSerialized]
private const string BotName = "HangmanGame";
public bool Enabled = false;
public bool English = true;
public string FileWords_EN = "hangman-en.txt";
public string FileWords_FR = "hangman-fr.txt";
public void OnSettingUpdate()
{
FileWords_EN ??= string.Empty;
FileWords_FR ??= string.Empty;
}
}
private int vie = 0;
private readonly int vie_param = 10;
private int compteur = 0;
private readonly int compteur_param = 3000; //5 minutes
private bool running = false;
private bool[] discovered;
private bool[] discovered = Array.Empty<bool>();
private string word = "";
private string letters = "";
private readonly bool English;
/// <summary>
/// Le jeu du Pendu / Hangman Game
/// </summary>
/// <param name="english">if true, the game will be in english. If false, the game will be in french.</param>
public HangmanGame(bool english)
{
English = english;
discovered = Array.Empty<bool>();
}
public override void Update()
{
@ -40,8 +52,8 @@ namespace MinecraftClient.ChatBots
}
else
{
SendText(English ? "You took too long to try a letter." : "Temps imparti écoulé !");
SendText(English ? "Game canceled." : "Partie annulée.");
SendText(Config.English ? "You took too long to try a letter." : "Temps imparti écoulé !");
SendText(Config.English ? "Game canceled." : "Partie annulée.");
running = false;
}
}
@ -55,7 +67,7 @@ namespace MinecraftClient.ChatBots
if (IsPrivateMessage(text, ref message, ref username))
{
if (Settings.Bots_Owners.Contains(username.ToLower()))
if (Settings.Config.Main.Advanced.BotOwners.Contains(username.ToLower()))
{
switch (message)
{
@ -81,7 +93,7 @@ namespace MinecraftClient.ChatBots
{
if (letters.Contains(letter))
{
SendText(English ? ("Letter " + letter + " has already been tried.") : ("Le " + letter + " a déjà été proposé."));
SendText(Config.English ? ("Letter " + letter + " has already been tried.") : ("Le " + letter + " a déjà été proposé."));
}
else
{
@ -91,29 +103,29 @@ namespace MinecraftClient.ChatBots
if (word.Contains(letter))
{
for (int i = 0; i < word.Length; i++) { if (word[i] == letter) { discovered[i] = true; } }
SendText(English ? ("Yes, the word contains a " + letter + '!') : ("Le " + letter + " figurait bien dans le mot :)"));
SendText(Config.English ? ("Yes, the word contains a " + letter + '!') : ("Le " + letter + " figurait bien dans le mot :)"));
}
else
{
vie--;
if (vie == 0)
{
SendText(English ? "Game Over! :]" : "Perdu ! Partie terminée :]");
SendText(English ? ("The word was: " + word) : ("Le mot était : " + word));
SendText(Config.English ? "Game Over! :]" : "Perdu ! Partie terminée :]");
SendText(Config.English ? ("The word was: " + word) : ("Le mot était : " + word));
running = false;
}
else SendText(English ? ("The " + letter + "? No.") : ("Le " + letter + " ? Non."));
else SendText(Config.English ? ("The " + letter + "? No.") : ("Le " + letter + " ? Non."));
}
if (running)
{
SendText(English ? ("Mysterious word: " + WordCached + " (lives : " + vie + ")")
SendText(Config.English ? ("Mysterious word: " + WordCached + " (lives : " + vie + ")")
: ("Mot mystère : " + WordCached + " (vie : " + vie + ")"));
}
if (Winner)
{
SendText(English ? ("Congrats, " + username + '!') : ("Félicitations, " + username + " !"));
SendText(Config.English ? ("Congrats, " + username + '!') : ("Félicitations, " + username + " !"));
running = false;
}
}
@ -132,23 +144,23 @@ namespace MinecraftClient.ChatBots
compteur = compteur_param;
discovered = new bool[word.Length];
SendText(English ? "Hangman v1.0 - By ORelio" : "Pendu v1.0 - Par ORelio");
SendText(English ? ("Mysterious word: " + WordCached + " (lives : " + vie + ")")
SendText(Config.English ? "Hangman v1.0 - By ORelio" : "Pendu v1.0 - Par ORelio");
SendText(Config.English ? ("Mysterious word: " + WordCached + " (lives : " + vie + ")")
: ("Mot mystère : " + WordCached + " (vie : " + vie + ")"));
SendText(English ? ("Try some letters ... :)") : ("Proposez une lettre ... :)"));
SendText(Config.English ? ("Try some letters ... :)") : ("Proposez une lettre ... :)"));
}
private string Chooseword()
{
if (System.IO.File.Exists(English ? Settings.Hangman_FileWords_EN : Settings.Hangman_FileWords_FR))
if (System.IO.File.Exists(Config.English ? Config.FileWords_EN : Config.FileWords_FR))
{
string[] dico = System.IO.File.ReadAllLines(English ? Settings.Hangman_FileWords_EN : Settings.Hangman_FileWords_FR, Encoding.UTF8);
string[] dico = System.IO.File.ReadAllLines(Config.English ? Config.FileWords_EN : Config.FileWords_FR, Encoding.UTF8);
return dico[new Random().Next(dico.Length)];
}
else
{
LogToConsole(English ? "File not found: " + Settings.Hangman_FileWords_EN : "Fichier introuvable : " + Settings.Hangman_FileWords_FR);
return English ? "WORDSAREMISSING" : "DICOMANQUANT";
LogToConsole(Config.English ? "File not found: " + Config.FileWords_EN : "Fichier introuvable : " + Config.FileWords_FR);
return Config.English ? "WORDSAREMISSING" : "DICOMANQUANT";
}
}

View file

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using Tomlet.Attributes;
namespace MinecraftClient.ChatBots
{
@ -11,6 +12,63 @@ namespace MinecraftClient.ChatBots
/// </summary>
public class Mailer : ChatBot
{
public static Configs Config = new();
[TomlDoNotInlineObject]
public class Configs
{
[NonSerialized]
private const string BotName = "Mailer";
public bool Enabled = false;
public string DatabaseFile = "MailerDatabase.ini";
public string IgnoreListFile = "MailerIgnoreList.ini";
public bool PublicInteractions = false;
public int MaxMailsPerPlayer = 10;
public int MaxDatabaseSize = 10000;
public int MailRetentionDays = 30;
public void OnSettingUpdate()
{
DatabaseFile ??= string.Empty;
IgnoreListFile ??= string.Empty;
if (!Enabled) return;
bool checkSuccessed = true;
if (Config.MaxDatabaseSize <= 0)
{
LogToConsole(BotName, Translations.TryGet("bot.mailer.init_fail.db_size"));
checkSuccessed = false;
}
if (Config.MaxMailsPerPlayer <= 0)
{
LogToConsole(BotName, Translations.TryGet("bot.mailer.init_fail.max_mails"));
checkSuccessed = false;
}
if (Config.MailRetentionDays <= 0)
{
LogToConsole(BotName, Translations.TryGet("bot.mailer.init_fail.mail_retention"));
checkSuccessed = false;
}
if (!checkSuccessed)
{
LogToConsole(BotName, Translations.TryGet("general.bot_unload"));
Enabled = false;
}
}
}
/// <summary>
/// Holds the list of ignored players
/// </summary>
@ -161,58 +219,37 @@ namespace MinecraftClient.ChatBots
public override void Initialize()
{
LogDebugToConsoleTranslated("bot.mailer.init");
LogDebugToConsoleTranslated("bot.mailer.init.db" + Settings.Mailer_DatabaseFile);
LogDebugToConsoleTranslated("bot.mailer.init.ignore" + Settings.Mailer_IgnoreListFile);
LogDebugToConsoleTranslated("bot.mailer.init.public" + Settings.Mailer_PublicInteractions);
LogDebugToConsoleTranslated("bot.mailer.init.max_mails" + Settings.Mailer_MaxMailsPerPlayer);
LogDebugToConsoleTranslated("bot.mailer.init.db_size" + Settings.Mailer_MaxDatabaseSize);
LogDebugToConsoleTranslated("bot.mailer.init.mail_retention" + Settings.Mailer_MailRetentionDays + " days");
LogDebugToConsoleTranslated("bot.mailer.init.db" + Config.DatabaseFile);
LogDebugToConsoleTranslated("bot.mailer.init.ignore" + Config.IgnoreListFile);
LogDebugToConsoleTranslated("bot.mailer.init.public" + Config.PublicInteractions);
LogDebugToConsoleTranslated("bot.mailer.init.max_mails" + Config.MaxMailsPerPlayer);
LogDebugToConsoleTranslated("bot.mailer.init.db_size" + Config.MaxDatabaseSize);
LogDebugToConsoleTranslated("bot.mailer.init.mail_retention" + Config.MailRetentionDays + " days");
if (Settings.Mailer_MaxDatabaseSize <= 0)
if (!File.Exists(Config.DatabaseFile))
{
LogToConsoleTranslated("bot.mailer.init_fail.db_size");
UnloadBot();
return;
LogToConsoleTranslated("bot.mailer.create.db", Path.GetFullPath(Config.DatabaseFile));
new MailDatabase().SaveToFile(Config.DatabaseFile);
}
if (Settings.Mailer_MaxMailsPerPlayer <= 0)
if (!File.Exists(Config.IgnoreListFile))
{
LogToConsoleTranslated("bot.mailer.init_fail.max_mails");
UnloadBot();
return;
}
if (Settings.Mailer_MailRetentionDays <= 0)
{
LogToConsoleTranslated("bot.mailer.init_fail.mail_retention");
UnloadBot();
return;
}
if (!File.Exists(Settings.Mailer_DatabaseFile))
{
LogToConsoleTranslated("bot.mailer.create.db", Path.GetFullPath(Settings.Mailer_DatabaseFile));
new MailDatabase().SaveToFile(Settings.Mailer_DatabaseFile);
}
if (!File.Exists(Settings.Mailer_IgnoreListFile))
{
LogToConsoleTranslated("bot.mailer.create.ignore", Path.GetFullPath(Settings.Mailer_IgnoreListFile));
new IgnoreList().SaveToFile(Settings.Mailer_IgnoreListFile);
LogToConsoleTranslated("bot.mailer.create.ignore", Path.GetFullPath(Config.IgnoreListFile));
new IgnoreList().SaveToFile(Config.IgnoreListFile);
}
lock (readWriteLock)
{
LogDebugToConsoleTranslated("bot.mailer.load.db", Path.GetFullPath(Settings.Mailer_DatabaseFile));
mailDatabase = MailDatabase.FromFile(Settings.Mailer_DatabaseFile);
LogDebugToConsoleTranslated("bot.mailer.load.db", Path.GetFullPath(Config.DatabaseFile));
mailDatabase = MailDatabase.FromFile(Config.DatabaseFile);
LogDebugToConsoleTranslated("bot.mailer.load.ignore", Path.GetFullPath(Settings.Mailer_IgnoreListFile));
ignoreList = IgnoreList.FromFile(Settings.Mailer_IgnoreListFile);
LogDebugToConsoleTranslated("bot.mailer.load.ignore", Path.GetFullPath(Config.IgnoreListFile));
ignoreList = IgnoreList.FromFile(Config.IgnoreListFile);
}
//Initialize file monitors. In case the bot needs to unload for some reason in the future, do not forget to .Dispose() them
mailDbFileMonitor = new FileMonitor(Path.GetDirectoryName(Settings.Mailer_DatabaseFile)!, Path.GetFileName(Settings.Mailer_DatabaseFile), FileMonitorCallback);
ignoreListFileMonitor = new FileMonitor(Path.GetDirectoryName(Settings.Mailer_IgnoreListFile)!, Path.GetFileName(Settings.Mailer_IgnoreListFile), FileMonitorCallback);
mailDbFileMonitor = new FileMonitor(Path.GetDirectoryName(Config.DatabaseFile)!, Path.GetFileName(Config.DatabaseFile), FileMonitorCallback);
ignoreListFileMonitor = new FileMonitor(Path.GetDirectoryName(Config.IgnoreListFile)!, Path.GetFileName(Config.IgnoreListFile), FileMonitorCallback);
RegisterChatBotCommand("mailer", Translations.Get("bot.mailer.cmd"), "mailer <getmails|addignored|getignored|removeignored>", ProcessInternalCommand);
}
@ -224,7 +261,7 @@ namespace MinecraftClient.ChatBots
{
maxMessageLength = GetMaxChatMessageLength()
- 44 // Deduct length of "/ 16CharPlayerName 16CharPlayerName mailed: "
- Settings.PrivateMsgsCmdName.Length; // Deduct length of "tell" command
- Settings.Config.Main.Advanced.PrivateMsgsCmdName.Length; // Deduct length of "tell" command
}
/// <summary>
@ -236,7 +273,7 @@ namespace MinecraftClient.ChatBots
string username = "";
text = GetVerbatim(text);
if (IsPrivateMessage(text, ref message, ref username) || (Settings.Mailer_PublicInteractions && IsChatMessage(text, ref message, ref username)))
if (IsPrivateMessage(text, ref message, ref username) || (Config.PublicInteractions && IsChatMessage(text, ref message, ref username)))
{
string usernameLower = username.ToLower();
if (!ignoreList.Contains(usernameLower))
@ -247,8 +284,8 @@ namespace MinecraftClient.ChatBots
case "mail":
case "tellonym":
if (usernameLower != GetUsername().ToLower()
&& mailDatabase.Count < Settings.Mailer_MaxDatabaseSize
&& mailDatabase.Where(mail => mail.SenderLowercase == usernameLower).Count() < Settings.Mailer_MaxMailsPerPlayer)
&& mailDatabase.Count < Config.MaxDatabaseSize
&& mailDatabase.Where(mail => mail.SenderLowercase == usernameLower).Count() < Config.MaxMailsPerPlayer)
{
Queue<string> args = new(Command.GetArgs(message));
if (args.Count >= 2)
@ -266,7 +303,7 @@ namespace MinecraftClient.ChatBots
lock (readWriteLock)
{
mailDatabase.Add(mail);
mailDatabase.SaveToFile(Settings.Mailer_DatabaseFile);
mailDatabase.SaveToFile(Config.DatabaseFile);
}
SendPrivateMessage(username, "Message saved!");
}
@ -307,8 +344,8 @@ namespace MinecraftClient.ChatBots
lock (readWriteLock)
{
mailDatabase.RemoveAll(mail => mail.Delivered);
mailDatabase.RemoveAll(mail => mail.DateSent.AddDays(Settings.Mailer_MailRetentionDays) < DateTime.Now);
mailDatabase.SaveToFile(Settings.Mailer_DatabaseFile);
mailDatabase.RemoveAll(mail => mail.DateSent.AddDays(Config.MailRetentionDays) < DateTime.Now);
mailDatabase.SaveToFile(Config.DatabaseFile);
}
nextMailSend = dateNow.AddSeconds(10);
@ -324,8 +361,8 @@ namespace MinecraftClient.ChatBots
{
lock (readWriteLock)
{
mailDatabase = MailDatabase.FromFile(Settings.Mailer_DatabaseFile);
ignoreList = IgnoreList.FromFile(Settings.Mailer_IgnoreListFile);
mailDatabase = MailDatabase.FromFile(Config.DatabaseFile);
ignoreList = IgnoreList.FromFile(Config.IgnoreListFile);
}
}
@ -357,7 +394,7 @@ namespace MinecraftClient.ChatBots
if (!ignoreList.Contains(username))
{
ignoreList.Add(username);
ignoreList.SaveToFile(Settings.Mailer_IgnoreListFile);
ignoreList.SaveToFile(Config.IgnoreListFile);
}
}
return Translations.Get("bot.mailer.cmd.ignore.added", args[1]);
@ -369,7 +406,7 @@ namespace MinecraftClient.ChatBots
if (ignoreList.Contains(username))
{
ignoreList.Remove(username);
ignoreList.SaveToFile(Settings.Mailer_IgnoreListFile);
ignoreList.SaveToFile(Config.IgnoreListFile);
}
}
return Translations.Get("bot.mailer.cmd.ignore.removed", args[1]);

View file

@ -3,43 +3,62 @@ using System.Collections.Generic;
using System.Drawing;
using System.Globalization;
using System.IO;
using System.Runtime.Versioning;
using MinecraftClient.Mapping;
using MinecraftClient.Protocol.Handlers;
using Tomlet.Attributes;
namespace MinecraftClient.ChatBots
{
class Map : ChatBot
public class Map : ChatBot
{
public static Configs Config = new();
[TomlDoNotInlineObject]
public class Configs
{
[NonSerialized]
private const string BotName = "Map";
public bool Enabled = false;
[TomlInlineComment("$config.ChatBot.Map.Should_Resize$")]
public bool Should_Resize = false;
[TomlInlineComment("$config.ChatBot.Map.Resize_To$")]
public int Resize_To = 256;
[TomlInlineComment("$config.ChatBot.Map.Auto_Render_On_Update$")]
public bool Auto_Render_On_Update = false;
[TomlInlineComment("$config.ChatBot.Map.Delete_All_On_Unload$")]
public bool Delete_All_On_Unload = true;
[TomlInlineComment("$config.ChatBot.Map.Notify_On_First_Update$")]
public bool Notify_On_First_Update = true;
public void OnSettingUpdate()
{
if (Resize_To < 128)
Resize_To = 128;
}
}
private readonly string baseDirectory = @"Rendered_Maps";
private readonly Dictionary<int, McMap> cachedMaps = new();
private bool shouldResize = true;
private int resizeTo = 256;
private bool autoRenderOnUpdate = true;
private bool deleteAllOnExit = true;
private bool notifyOnFirstUpdate = true;
public override void Initialize()
{
if (!Directory.Exists(baseDirectory))
Directory.CreateDirectory(baseDirectory);
shouldResize = Settings.Map_Should_Resize;
resizeTo = Settings.Map_Resize_To;
if (resizeTo < 128)
resizeTo = 128;
autoRenderOnUpdate = Settings.Map_Auto_Render_On_Update;
deleteAllOnExit = Settings.Map_Delete_All_On_Unload;
notifyOnFirstUpdate = Settings.Map_Notify_On_First_Update;
RegisterChatBotCommand("maps", "bot.map.cmd.desc", "maps list|render <id> or maps l|r <id>", OnMapCommand);
}
public override void OnUnload()
{
if (deleteAllOnExit)
if (Config.Delete_All_On_Unload)
{
DirectoryInfo di = new(baseDirectory);
FileInfo[] files = di.GetFiles();
@ -76,15 +95,22 @@ namespace MinecraftClient.ChatBots
if (!cachedMaps.ContainsKey(mapId))
return Translations.TryGet("bot.map.cmd.not_found", mapId);
try
if (OperatingSystem.IsWindows())
{
McMap map = cachedMaps[mapId];
GenerateMapImage(map);
try
{
McMap map = cachedMaps[mapId];
GenerateMapImage(map);
}
catch (Exception e)
{
LogDebugToConsole(e.StackTrace!);
return Translations.TryGet("bot.map.failed_to_render", mapId);
}
}
catch (Exception e)
else
{
LogDebugToConsole(e.StackTrace!);
return Translations.TryGet("bot.map.failed_to_render", mapId);
LogToConsoleTranslated("bot.map.windows_only");
}
return "";
@ -124,7 +150,7 @@ namespace MinecraftClient.ChatBots
{
cachedMaps.Add(mapid, map);
if (notifyOnFirstUpdate)
if (Config.Notify_On_First_Update)
LogToConsoleTranslated("bot.map.received_map", map.MapId);
}
else
@ -133,10 +159,16 @@ namespace MinecraftClient.ChatBots
cachedMaps.Add(mapid, map);
}
if (autoRenderOnUpdate)
GenerateMapImage(map);
if (Config.Auto_Render_On_Update)
{
if (OperatingSystem.IsWindows())
GenerateMapImage(map);
else
LogToConsoleTranslated("bot.map.windows_only");
}
}
[SupportedOSPlatform("windows")]
private void GenerateMapImage(McMap map)
{
string fileName = baseDirectory + "/Map_" + map.MapId + ".jpg";
@ -144,6 +176,8 @@ namespace MinecraftClient.ChatBots
if (File.Exists(fileName))
File.Delete(fileName);
/** Warning CA1416: Bitmap is only support Windows **/
/* https://learn.microsoft.com/en-us/dotnet/core/compatibility/core-libraries/6.0/system-drawing-common-windows-only */
Bitmap image = new(map.Width, map.Height);
for (int x = 0; x < map.Width; ++x)
@ -165,12 +199,14 @@ namespace MinecraftClient.ChatBots
// Resize, double the image
if (shouldResize)
image = ResizeBitmap(image, resizeTo, resizeTo);
if (Config.Should_Resize)
image = ResizeBitmap(image, Config.Resize_To, Config.Resize_To);
image.Save(fileName);
LogToConsole(Translations.TryGet("bot.map.rendered", map.MapId, fileName));
}
[SupportedOSPlatform("windows")]
private Bitmap ResizeBitmap(Bitmap sourceBMP, int width, int height)
{
Bitmap result = new(width, height);

View file

@ -1,6 +1,6 @@
using System;
using System.Linq;
using System.Text;
using Tomlet.Attributes;
namespace MinecraftClient.ChatBots
{
@ -10,28 +10,36 @@ namespace MinecraftClient.ChatBots
public class PlayerListLogger : ChatBot
{
private int count;
private readonly int timeping;
private readonly string file;
public static Configs Config = new();
/// <summary>
/// This bot sends a /list command every X seconds and save the result.
/// </summary>
/// <param name="pingparam">Time amount between each list ping (10 = 1s, 600 = 1 minute, etc.)</param>
public PlayerListLogger(int pingparam, string filetosavein)
[TomlDoNotInlineObject]
public class Configs
{
count = 0;
file = filetosavein;
timeping = pingparam;
if (timeping < 10) { timeping = 10; } //To avoid flooding
[NonSerialized]
private const string BotName = "PlayerListLogger";
public bool Enabled = false;
public string File = "playerlog.txt";
[TomlInlineComment("$config.ChatBot.PlayerListLogger.Delay$")]
public double Delay = 60;
public void OnSettingUpdate()
{
File ??= string.Empty;
if (Delay < 1.0)
Delay = 1.0;
}
}
private int count = 0;
public override void Update()
{
count++;
if (count == timeping)
if (count >= Settings.DoubleToTick(Config.Delay))
{
DateTime now = DateTime.Now;
@ -40,7 +48,7 @@ namespace MinecraftClient.ChatBots
StringBuilder sb = new();
sb.AppendLine(string.Format("[{0}/{1}/{2} {3}:{4}]", now.Year, now.Month, now.Day, now.Hour, now.Minute));
sb.AppendLine(string.Join(", ", GetOnlinePlayers())).AppendLine();
System.IO.File.AppendAllText(file, sb.ToString());
System.IO.File.AppendAllText(Settings.Config.AppVar.ExpandVars(Config.File), sb.ToString());
count = 0;
}

View file

@ -1,4 +1,5 @@
using System;
using Tomlet.Attributes;
namespace MinecraftClient.ChatBots
{
@ -8,11 +9,28 @@ namespace MinecraftClient.ChatBots
public class RemoteControl : ChatBot
{
public static Configs Config = new();
[TomlDoNotInlineObject]
public class Configs
{
[NonSerialized]
private const string BotName = "RemoteControl";
public bool Enabled = false;
public bool AutoTpaccept = true;
public bool AutoTpaccept_Everyone = false;
public void OnSettingUpdate() { }
}
public override void GetText(string text)
{
text = GetVerbatim(text).Trim();
string command = "", sender = "";
if (IsPrivateMessage(text, ref command, ref sender) && Settings.Bots_Owners.Contains(sender.ToLower().Trim()))
if (IsPrivateMessage(text, ref command, ref sender) && Settings.Config.Main.Advanced.BotOwners.Contains(sender.ToLower().Trim()))
{
string? response = "";
PerformInternalCommand(command, ref response);
@ -26,9 +44,9 @@ namespace MinecraftClient.ChatBots
SendPrivateMessage(sender, response);
}
}
else if (Settings.RemoteCtrl_AutoTpaccept
else if (Config.AutoTpaccept
&& IsTeleportRequest(text, ref sender)
&& (Settings.RemoteCtrl_AutoTpaccept_Everyone || Settings.Bots_Owners.Contains(sender.ToLower().Trim())))
&& (Config.AutoTpaccept_Everyone || Settings.Config.Main.Advanced.BotOwners.Contains(sender.ToLower().Trim())))
{
SendText("/tpaccept");
}

View file

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using MinecraftClient.Protocol;
using Tomlet.Attributes;
namespace MinecraftClient.ChatBots
{
@ -9,24 +10,35 @@ namespace MinecraftClient.ChatBots
/// </summary>
public class ReplayCapture : ChatBot
{
private ReplayHandler? replay;
private readonly int backupInterval = 3000; // Unit: second * 10
private int backupCounter = -1;
public static Configs Config = new();
public ReplayCapture(int backupInterval)
[TomlDoNotInlineObject]
public class Configs
{
if (backupInterval != -1)
this.backupInterval = backupInterval * 10;
else
this.backupInterval = -1;
[NonSerialized]
private const string BotName = "ReplayCapture";
public bool Enabled = false;
[TomlInlineComment("$config.ChatBot.ReplayCapture.Backup_Interval$")]
public int Backup_Interval = 3000;
public void OnSettingUpdate()
{
if (Backup_Interval < -1)
Backup_Interval = -1;
}
}
private ReplayHandler? replay;
private int backupCounter = -1;
public override void Initialize()
{
SetNetworkPacketEventEnabled(true);
replay = new ReplayHandler(GetProtocolVersion());
replay.MetaData.serverName = GetServerHost() + GetServerPort();
backupCounter = backupInterval;
backupCounter = Config.Backup_Interval * 10;
RegisterChatBotCommand("replay", Translations.Get("bot.replayCapture.cmd"), "replay <save|stop>", Command);
}
@ -38,12 +50,12 @@ namespace MinecraftClient.ChatBots
public override void Update()
{
if (backupInterval > 0 && replay!.RecordRunning)
if (Config.Backup_Interval > 0 && replay!.RecordRunning)
{
if (backupCounter <= 0)
{
replay.CreateBackupReplay(@"recording_cache\REPLAY_BACKUP.mcpr");
backupCounter = backupInterval;
backupCounter = Config.Backup_Interval * 10;
}
else backupCounter--;
}

View file

@ -107,7 +107,7 @@ namespace MinecraftClient.ChatBots
}
}
if (Settings.DebugMessages)
if (Settings.Config.Logging.DebugMessages)
{
string caller = "Script";
try
@ -195,7 +195,7 @@ namespace MinecraftClient.ChatBots
{
if (instruction_line[0] != '#' && instruction_line[0] != '/' && instruction_line[1] != '/')
{
instruction_line = Settings.ExpandVars(instruction_line, localVars);
instruction_line = Settings.Config.AppVar.ExpandVars(instruction_line, localVars);
string instruction_name = instruction_line.Split(' ')[0];
switch (instruction_name.ToLower())
{

View file

@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using Tomlet.Attributes;
using static MinecraftClient.ChatBots.ScriptScheduler.Configs;
namespace MinecraftClient.ChatBots
{
@ -11,143 +10,164 @@ namespace MinecraftClient.ChatBots
public class ScriptScheduler : ChatBot
{
private class TaskDesc
public static Configs Config = new();
[TomlDoNotInlineObject]
public class Configs
{
public string? action = null;
public bool triggerOnFirstLogin = false;
public bool triggerOnLogin = false;
public bool triggerOnTime = false;
public bool triggerOnInterval = false;
public int triggerOnInterval_Interval = 0;
public int triggerOnInterval_Interval_Max = 0;
public int triggerOnInterval_Interval_Countdown = 0;
public List<DateTime> triggerOnTime_Times = new();
public bool triggerOnTime_alreadyTriggered = false;
}
[NonSerialized]
private const string BotName = "ScriptScheduler";
private static bool firstlogin_done = false;
public bool Enabled = false;
private readonly string tasksfile;
private bool serverlogin_done;
private readonly List<TaskDesc> tasks = new();
private int verifytasks_timeleft = 10;
private readonly int verifytasks_delay = 10;
public TaskConfig[] TaskList = new TaskConfig[] {
new TaskConfig(
Task_Name: "Task Name 1",
Trigger_On_First_Login: false,
Trigger_On_Login: false,
Trigger_On_Times: new(true, new TimeSpan[] { new(14, 00, 00) }),
Trigger_On_Interval: new(true, 3.6, 4.8),
Action: "send /hello"
),
new TaskConfig(
Task_Name: "Task Name 2",
Trigger_On_First_Login: false,
Trigger_On_Login: true,
Trigger_On_Times: new(false, Array.Empty<TimeSpan>() ),
Trigger_On_Interval: new(false, 1, 10),
Action: "send /login pass"
),
};
public ScriptScheduler(string tasksfile)
{
this.tasksfile = tasksfile;
serverlogin_done = false;
}
public override void Initialize()
{
//Load the given file from the startup parameters
if (System.IO.File.Exists(tasksfile))
public void OnSettingUpdate()
{
LogDebugToConsoleTranslated("bot.scriptScheduler.loading", System.IO.Path.GetFullPath(tasksfile));
TaskDesc? current_task = null;
string[] lines = System.IO.File.ReadAllLines(tasksfile, Encoding.UTF8);
foreach (string lineRAW in lines)
foreach (TaskConfig task in TaskList)
{
string line = lineRAW.Split('#')[0].Trim();
if (line.Length > 0)
task.Trigger_On_Interval.MinTime = Math.Max(0.1, task.Trigger_On_Interval.MinTime);
task.Trigger_On_Interval.MaxTime = Math.Max(0.1, task.Trigger_On_Interval.MaxTime);
if (task.Trigger_On_Interval.MinTime > task.Trigger_On_Interval.MaxTime)
(task.Trigger_On_Interval.MinTime, task.Trigger_On_Interval.MaxTime) = (task.Trigger_On_Interval.MaxTime, task.Trigger_On_Interval.MinTime);
//Look for a valid action
if (!String.IsNullOrWhiteSpace(task.Action))
{
if (line[0] == '[' && line[^1] == ']')
//Look for a valid trigger
if (task.Trigger_On_Login
|| task.Trigger_On_First_Login
|| (task.Trigger_On_Times.Enable && task.Trigger_On_Times.Times.Length > 0)
|| (task.Trigger_On_Interval.Enable && task.Trigger_On_Interval.MinTime > 0))
{
switch (line[1..^1].ToLower())
{
case "task":
CheckAddTask(current_task);
current_task = new TaskDesc(); //Create a blank task
break;
}
if (Settings.Config.Logging.DebugMessages)
LogToConsole(BotName, Translations.TryGet("bot.scriptScheduler.loaded_task", Task2String(task)));
task.Trigger_On_Interval_Countdown = Settings.DoubleToTick(task.Trigger_On_Interval.MinTime); //Init countdown for interval
}
else if (current_task != null)
else
{
string argName = line.Split('=')[0];
if (line.Length > (argName.Length + 1))
{
string argValue = line[(argName.Length + 1)..];
switch (argName.ToLower())
{
case "triggeronfirstlogin": current_task.triggerOnFirstLogin = Settings.str2bool(argValue); break;
case "triggeronlogin": current_task.triggerOnLogin = Settings.str2bool(argValue); break;
case "triggerontime": current_task.triggerOnTime = Settings.str2bool(argValue); break;
case "triggeroninterval": current_task.triggerOnInterval = Settings.str2bool(argValue); break;
case "timevalue": try { current_task.triggerOnTime_Times.Add(DateTime.ParseExact(argValue, "HH:mm", CultureInfo.InvariantCulture)); } catch { } break;
case "timeinterval":
int interval;
int intervalMax = 0;
if (argValue.Contains('-'))
{
string[] parts = argValue.Split("-");
if (parts.Length == 2)
{
interval = int.Parse(parts[0].Trim(), NumberStyles.Any, CultureInfo.CurrentCulture);
intervalMax = int.Parse(parts[1].Trim(), NumberStyles.Any, CultureInfo.CurrentCulture);
}
else
{
interval = 1;
}
}
else
{
interval = int.Parse(argValue, NumberStyles.Any, CultureInfo.CurrentCulture);
}
current_task.triggerOnInterval_Interval = interval;
current_task.triggerOnInterval_Interval_Max = intervalMax;
break;
case "script": current_task.action = "script " + argValue; break; //backward compatibility with older tasks.ini
case "action": current_task.action = argValue; break;
}
}
if (Settings.Config.Logging.DebugMessages)
LogToConsole(BotName, Translations.TryGet("bot.scriptScheduler.no_trigger", Task2String(task)));
}
}
}
CheckAddTask(current_task);
}
else
{
LogToConsoleTranslated("bot.scriptScheduler.not_found", System.IO.Path.GetFullPath(tasksfile));
UnloadBot(); //No need to keep the bot active
}
}
private void CheckAddTask(TaskDesc? current_task)
{
//Check if we built a valid task before adding it
if (current_task != null)
{
//Look for a valid action
if (!String.IsNullOrWhiteSpace(current_task.action))
{
//Look for a valid trigger
if (current_task.triggerOnLogin
|| current_task.triggerOnFirstLogin
|| (current_task.triggerOnTime && current_task.triggerOnTime_Times.Count > 0)
|| (current_task.triggerOnInterval && current_task.triggerOnInterval_Interval > 0))
{
LogDebugToConsoleTranslated("bot.scriptScheduler.loaded_task", Task2String(current_task));
current_task.triggerOnInterval_Interval_Countdown = current_task.triggerOnInterval_Interval; //Init countdown for interval
tasks.Add(current_task);
}
else
{
LogDebugToConsoleTranslated("bot.scriptScheduler.no_trigger", Task2String(current_task));
task.Action ??= string.Empty;
if (Settings.Config.Logging.DebugMessages)
LogToConsole(BotName, Translations.TryGet("bot.scriptScheduler.no_action", Task2String(task)));
}
}
else
if (Enabled && TaskList.Length == 0)
{
LogDebugToConsoleTranslated("bot.scriptScheduler.no_action", Task2String(current_task));
LogToConsole(BotName, Translations.TryGet("general.bot_unload"));
Enabled = false;
}
}
public class TaskConfig
{
public string Task_Name = "Task Name (Can be empty)";
public bool Trigger_On_First_Login = false;
public bool Trigger_On_Login = false;
public TriggerOnTimeConfig Trigger_On_Times = new(false, new TimeSpan[] { new(23, 59, 59) });
public TriggerOnIntervalConfig Trigger_On_Interval = new(false, 1, 10);
public string Action = "send /hello";
[NonSerialized]
public bool Trigger_On_Time_Already_Triggered = false;
[NonSerialized]
public int Trigger_On_Interval_Countdown = 0;
public TaskConfig() { }
public TaskConfig(string Task_Name, bool Trigger_On_First_Login, bool Trigger_On_Login, TriggerOnTimeConfig Trigger_On_Times, TriggerOnIntervalConfig Trigger_On_Interval, string Action)
{
this.Task_Name = Task_Name;
this.Trigger_On_First_Login = Trigger_On_First_Login;
this.Trigger_On_Login = Trigger_On_Login;
this.Trigger_On_Times = Trigger_On_Times;
this.Trigger_On_Interval = Trigger_On_Interval;
this.Action = Action;
}
public struct TriggerOnTimeConfig
{
public bool Enable = false;
public TimeSpan[] Times;
public TriggerOnTimeConfig(bool Enable, TimeSpan[] Time)
{
this.Enable = Enable;
this.Times = Time;
}
public TriggerOnTimeConfig(TimeSpan[] Time)
{
this.Enable = true;
this.Times = Time;
}
}
public struct TriggerOnIntervalConfig
{
public bool Enable = false;
public double MinTime, MaxTime;
public TriggerOnIntervalConfig(double value)
{
this.Enable = true;
MinTime = MaxTime = value;
}
public TriggerOnIntervalConfig(bool Enable, double value)
{
this.Enable = Enable;
MinTime = MaxTime = value;
}
public TriggerOnIntervalConfig(double min, double max)
{
this.MinTime = min;
this.MaxTime = max;
}
public TriggerOnIntervalConfig(bool Enable, double min, double max)
{
this.Enable = Enable;
this.MinTime = min;
this.MaxTime = max;
}
}
}
}
private Random random = new();
private static bool firstlogin_done = false;
private bool serverlogin_done = false;
private int verifytasks_timeleft = 10;
private readonly int verifytasks_delay = 10;
public override void Update()
{
if (verifytasks_timeleft <= 0)
@ -155,55 +175,40 @@ namespace MinecraftClient.ChatBots
verifytasks_timeleft = verifytasks_delay;
if (serverlogin_done)
{
foreach (TaskDesc task in tasks)
foreach (TaskConfig task in Config.TaskList)
{
if (task.triggerOnTime)
if (task.Trigger_On_Times.Enable)
{
bool matching_time_found = false;
foreach (DateTime time in task.triggerOnTime_Times)
foreach (TimeSpan time in task.Trigger_On_Times.Times)
{
if (time.Hour == DateTime.Now.Hour && time.Minute == DateTime.Now.Minute)
if (time.Hours == DateTime.Now.Hour && time.Minutes == DateTime.Now.Minute)
{
matching_time_found = true;
if (!task.triggerOnTime_alreadyTriggered)
if (!task.Trigger_On_Time_Already_Triggered)
{
task.triggerOnTime_alreadyTriggered = true;
LogDebugToConsoleTranslated("bot.scriptScheduler.running_time", task.action);
PerformInternalCommand(task.action!);
task.Trigger_On_Time_Already_Triggered = true;
LogDebugToConsoleTranslated("bot.scriptScheduler.running_time", task.Action);
PerformInternalCommand(task.Action);
}
}
}
if (!matching_time_found)
task.triggerOnTime_alreadyTriggered = false;
task.Trigger_On_Time_Already_Triggered = false;
}
if (task.triggerOnInterval)
{
if (task.triggerOnInterval_Interval_Countdown == 0)
{
int time = task.triggerOnInterval_Interval;
if (task.triggerOnInterval_Interval_Max != 0)
time = new Random().Next(task.triggerOnInterval_Interval, task.triggerOnInterval_Interval_Max);
task.triggerOnInterval_Interval_Countdown = time;
LogDebugToConsoleTranslated("bot.scriptScheduler.running_inverval", task.action);
PerformInternalCommand(task.action!);
}
else task.triggerOnInterval_Interval_Countdown--;
}
}
}
else
{
foreach (TaskDesc task in tasks)
foreach (TaskConfig task in Config.TaskList)
{
if (task.triggerOnLogin || (firstlogin_done == false && task.triggerOnFirstLogin))
if (task.Trigger_On_Login || (firstlogin_done == false && task.Trigger_On_First_Login))
{
LogDebugToConsoleTranslated("bot.scriptScheduler.running_login", task.action);
PerformInternalCommand(task.action!);
LogDebugToConsoleTranslated("bot.scriptScheduler.running_login", task.Action);
PerformInternalCommand(task.Action);
}
}
@ -212,6 +217,22 @@ namespace MinecraftClient.ChatBots
}
}
else verifytasks_timeleft--;
foreach (TaskConfig task in Config.TaskList)
{
if (task.Trigger_On_Interval.Enable)
{
if (task.Trigger_On_Interval_Countdown == 0)
{
task.Trigger_On_Interval_Countdown = random.Next(
Settings.DoubleToTick(task.Trigger_On_Interval.MinTime), Settings.DoubleToTick(task.Trigger_On_Interval.MaxTime)
);
LogDebugToConsoleTranslated("bot.scriptScheduler.running_inverval", task.Action);
PerformInternalCommand(task.Action);
}
else task.Trigger_On_Interval_Countdown--;
}
}
}
public override bool OnDisconnect(DisconnectReason reason, string message)
@ -220,17 +241,17 @@ namespace MinecraftClient.ChatBots
return false;
}
private static string Task2String(TaskDesc task)
private static string Task2String(TaskConfig task)
{
return Translations.Get(
"bot.scriptScheduler.task",
task.triggerOnFirstLogin,
task.triggerOnLogin,
task.triggerOnTime,
task.triggerOnInterval,
String.Join(", ", task.triggerOnTime_Times),
task.triggerOnInterval_Interval,
task.action
task.Trigger_On_First_Login,
task.Trigger_On_Login,
task.Trigger_On_Times.Enable,
task.Trigger_On_Interval.Enable,
task.Trigger_On_Times.Times,
task.Trigger_On_Interval.MinTime + '-' + task.Trigger_On_Interval.MaxTime,
task.Action
);
}
}

View file

@ -32,16 +32,16 @@ namespace MinecraftClient.Commands
sb.Append(World.GetChunkLoadingStatus(handler.GetWorld()));
sb.Append('\n');
sb.Append(String.Format("Current location{0}, chunk: ({1}, {2}).\n", current, current.ChunkX, current.ChunkZ));
sb.AppendLine(Translations.Get("cmd.chunk.current", current, current.ChunkX, current.ChunkZ));
if (markedChunkPos != null)
{
sb.Append("Marked location: ");
sb.Append(Translations.Get("cmd.chunk.marked"));
if (args.Length == 1 + 3)
sb.Append(String.Format("X:{0:0.00} Y:{1:0.00} Z:{2:0.00}, ",
double.Parse(args[1], NumberStyles.Any, CultureInfo.CurrentCulture),
double.Parse(args[2], NumberStyles.Any, CultureInfo.CurrentCulture),
double.Parse(args[3], NumberStyles.Any, CultureInfo.CurrentCulture)));
sb.Append(String.Format("chunk: ({0}, {1}).\n", markChunkX, markChunkZ));
sb.AppendLine(Translations.Get("cmd.chunk.chunk_pos", markChunkX, markChunkZ));;
}
int consoleHeight = Math.Max(Console.BufferHeight - 2, 25);
@ -127,7 +127,7 @@ namespace MinecraftClient.Commands
if (markedChunkPos != null &&
(((Math.Max(bottomMost, markChunkZ) - Math.Min(topMost, markChunkZ) + 1) > consoleHeight) ||
((Math.Max(rightMost, markChunkX) - Math.Min(leftMost, markChunkX) + 1) > consoleWidth)))
sb.Append("§x§0Since the marked chunk is outside the graph, it will not be displayed!§r\n");
sb.AppendLine(Translations.Get("cmd.chunk.outside"));
else
{
topMost = Math.Min(topMost, markChunkZ);
@ -138,7 +138,7 @@ namespace MinecraftClient.Commands
// \ud83d\udd33: 🔳, \ud83d\udfe8: 🟨, \ud83d\udfe9: 🟩, \u25A1: □, \u25A3: ▣, \u25A0: ■
string[] chunkStatusStr = Settings.EnableEmoji ?
string[] chunkStatusStr = Settings.Config.Main.Advanced.EnableEmoji ?
new string[] { "\ud83d\udd33", "\ud83d\udfe8", "\ud83d\udfe9" } : new string[] { "\u25A1", "\u25A3", "\u25A0" };
// Output
@ -165,8 +165,7 @@ namespace MinecraftClient.Commands
sb.Append('\n');
}
sb.Append("Player:§z §r, MarkedChunk:§w §r, ");
sb.Append(string.Format("NotReceived:{0}, Loading:{1}, Loaded:{2}", chunkStatusStr[0], chunkStatusStr[1], chunkStatusStr[2]));
sb.AppendLine(Translations.Get("cmd.chunk.icon", "§z §r", "§w §r", chunkStatusStr[0], chunkStatusStr[1], chunkStatusStr[2]));
return sb.ToString();
}
else if (args[0] == "setloading") // For debugging
@ -174,7 +173,7 @@ namespace MinecraftClient.Commands
Tuple<int, int>? chunkPos = ParseChunkPos(args);
if (chunkPos != null)
{
handler.Log.Info("§x§0This command is used for debugging, make sure you know what you are doing.§r");
handler.Log.Info(Translations.Get("cmd.chunk.for_debug"));
World world = handler.GetWorld();
(int chunkX, int chunkZ) = chunkPos;
ChunkColumn? chunkColumn = world[chunkX, chunkZ];
@ -191,7 +190,7 @@ namespace MinecraftClient.Commands
Tuple<int, int>? chunkPos = ParseChunkPos(args);
if (chunkPos != null)
{
handler.Log.Info("§x§0This command is used for debugging, make sure you know what you are doing.§r");
handler.Log.Info(Translations.Get("cmd.chunk.for_debug"));
World world = handler.GetWorld();
(int chunkX, int chunkZ) = chunkPos;
ChunkColumn? chunkColumn = world[chunkX, chunkZ];
@ -208,7 +207,7 @@ namespace MinecraftClient.Commands
Tuple<int, int>? chunkPos = ParseChunkPos(args);
if (chunkPos != null)
{
handler.Log.Info("§x§0This command is used for debugging, make sure you know what you are doing.§r");
handler.Log.Info(Translations.Get("cmd.chunk.for_debug"));
World world = handler.GetWorld();
(int chunkX, int chunkZ) = chunkPos;
world[chunkX, chunkZ] = null;

View file

@ -15,13 +15,13 @@ namespace MinecraftClient.Commands
string[] args = GetArgs(command);
if (args.Length > 1)
{
if (!Settings.SetAccount(args[1]))
if (!Settings.Config.Main.Advanced.SetAccount(args[1]))
{
return Translations.Get("cmd.connect.unknown", args[1]);
}
}
if (Settings.SetServerIP(args[0]))
if (Settings.Config.Main.SetServerIP(new Settings.MainConfigHealper.MainConfig.ServerInfoConfig(args[0]), true))
{
Program.Restart();
return "";

View file

@ -11,11 +11,10 @@ namespace MinecraftClient.Commands
public override string Run(McClient handler, string command, Dictionary<string, object>? localVars)
{
if (HasArg(command))
{
Settings.DebugMessages = (GetArg(command).ToLower() == "on");
}
else Settings.DebugMessages = !Settings.DebugMessages;
return Translations.Get(Settings.DebugMessages ? "cmd.debug.state_on" : "cmd.debug.state_off");
Settings.Config.Logging.DebugMessages = (GetArg(command).ToLower() == "on");
else
Settings.Config.Logging.DebugMessages = !Settings.Config.Logging.DebugMessages;
return Translations.Get(Settings.Config.Logging.DebugMessages ? "cmd.debug.state_on" : "cmd.debug.state_off");
}
}
}

View file

@ -33,14 +33,17 @@ namespace MinecraftClient.Commands
try
{
Location current = handler.GetCurrentLocation();
Location blockToBreak = Location.Parse(current, args[0], args[1], args[2]);
Location blockToBreak = Location.Parse(current.ToFloor(), args[0], args[1], args[2]);
if (blockToBreak.DistanceSquared(current.EyesLocation()) > 25)
return Translations.Get("cmd.dig.too_far");
Block block = handler.GetWorld().GetBlock(blockToBreak);
if (block.Type == Material.Air)
return Translations.Get("cmd.dig.no_block");
else if (handler.DigBlock(blockToBreak))
{
blockToBreak = blockToBreak.ToCenter();
return Translations.Get("cmd.dig.dig", blockToBreak.X, blockToBreak.Y, blockToBreak.Z, block.Type);
}
else
return Translations.Get("cmd.dig.fail");
}

View file

@ -36,7 +36,7 @@ namespace MinecraftClient.Commands
var interpreter = new Interpreter();
interpreter.SetVariable("MCC", handler);
foreach (KeyValuePair<string, object> entry in Settings.GetVariables())
foreach (KeyValuePair<string, object> entry in Settings.Config.AppVar.GetVariables())
interpreter.SetVariable(entry.Key, entry.Value);
var result = interpreter.Eval<bool>(expressionText);

View file

@ -185,7 +185,7 @@ namespace MinecraftClient.Commands
response.AppendLine(String.Format(" #{0} - {1}§8", inventoryId, inventory.Title));
string? asciiArt = inventory.Type.GetAsciiArt();
if (asciiArt != null && Settings.DisplayInventoryLayout)
if (asciiArt != null && Settings.Config.Main.Advanced.ShowInventoryLayout)
response.AppendLine(asciiArt);
int selectedHotbar = handler.GetCurrentSlot() + 1;

View file

@ -45,8 +45,8 @@ namespace MinecraftClient.Commands
else if (args[0] == "gravity")
{
if (args.Count >= 2)
Settings.GravityEnabled = (args[1] == "on");
if (Settings.GravityEnabled)
Settings.InternalConfig.GravityEnabled = (args[1] == "on");
if (Settings.InternalConfig.GravityEnabled)
return Translations.Get("cmd.move.gravity.enabled");
else return Translations.Get("cmd.move.gravity.disabled");
}

View file

@ -13,7 +13,7 @@ namespace MinecraftClient.Commands
string[] args = GetArgs(command);
if (args.Length > 0)
{
if (!Settings.SetAccount(args[0]))
if (!Settings.Config.Main.Advanced.SetAccount(args[0]))
{
return Translations.Get("cmd.connect.unknown", args[0]);
}

View file

@ -15,15 +15,16 @@ namespace MinecraftClient.Commands
string[] temp = GetArg(command).Split('=');
if (temp.Length > 1)
{
if (Settings.SetVar(temp[0], GetArg(command).Substring(temp[0].Length + 1)))
{
if (Settings.Config.AppVar.SetVar(temp[0], GetArg(command).Substring(temp[0].Length + 1)))
return ""; //Success
}
else return Translations.Get("cmd.set.format");
else
return Translations.Get("cmd.set.format");
}
else return GetCmdDescTranslated();
else
return GetCmdDescTranslated();
}
else return GetCmdDescTranslated();
else
return GetCmdDescTranslated();
}
}
}

View file

@ -40,9 +40,9 @@ namespace MinecraftClient.Commands
(num2, num1) = (num1, num2);
// create a variable or set it to num1 <= varlue < num2
if (Settings.SetVar(args[0], rand.Next(num1, num2)))
if (Settings.Config.AppVar.SetVar(args[0], rand.Next(num1, num2)))
{
return string.Format("Set %{0}% to {1}.", args[0], Settings.GetVar(args[0])); //Success
return string.Format("Set %{0}% to {1}.", args[0], Settings.Config.AppVar.GetVar(args[0])); //Success
}
else return Translations.Get("cmd.setrndnum.format");
}
@ -55,9 +55,9 @@ namespace MinecraftClient.Commands
List<string> values = ParseCommandLine(argString);
// create a variable or set it to one of the values
if (values.Count > 0 && Settings.SetVar(args[0], values[rand.Next(0, values.Count)]))
if (values.Count > 0 && Settings.Config.AppVar.SetVar(args[0], values[rand.Next(0, values.Count)]))
{
return string.Format("Set %{0}% to {1}.", args[0], Settings.GetVar(args[0])); //Success
return string.Format("Set %{0}% to {1}.", args[0], Settings.Config.AppVar.GetVar(args[0])); //Success
}
else return Translations.Get("cmd.setrndstr.format");
}

View file

@ -18,7 +18,7 @@ namespace MinecraftClient.Commands
string[] args = GetArgs(command);
if (args.Length >= 3)
{
Location block = Location.Parse(handler.GetCurrentLocation(), args[0], args[1], args[2]).ToFloor();
Location block = Location.Parse(handler.GetCurrentLocation().ToFloor(), args[0], args[1], args[2]).ToFloor();
Location blockCenter = block.ToCenter();
bool res = handler.PlaceBlock(block, Direction.Down);
return Translations.Get("cmd.useblock.use", blockCenter.X, blockCenter.Y, blockCenter.Z, res ? "succeeded" : "failed");

View file

@ -8,11 +8,10 @@
// </auto-generated>
//------------------------------------------------------------------------------
namespace MinecraftClient
{
namespace MinecraftClient {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
@ -20,55 +19,47 @@ namespace MinecraftClient
// 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", "4.0.0.0")]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
public class DefaultConfigResource
{
internal class DefaultConfigResource {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal DefaultConfigResource()
{
internal DefaultConfigResource() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
public static global::System.Resources.ResourceManager ResourceManager
{
get
{
if (object.ReferenceEquals(resourceMan, null))
{
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("MinecraftClient.DefaultConfigResource", typeof(DefaultConfigResource).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)]
public static global::System.Globalization.CultureInfo Culture
{
get
{
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set
{
set {
resourceCulture = value;
}
}
/// <summary>
/// Looks up a localized string similar to ╔═════════════════════════════════════╗
///║ Brewing Stand ║
@ -82,16 +73,14 @@ namespace MinecraftClient
///║ Inventory ╚═══╝ ║
///║╔═══╦═══╦═══╦═══╦═══╦═══╦═══╦═══╦═══╗║
///║║ 5 ║ 6 ║ 7 ║ 8 ║ 9 ║10 ║11 ║12 ║13 ║║
///║╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬══ [rest of string was truncated]&quot;;.
///║╠═══╬═══╬═══╬═══╬══ [rest of string was truncated]&quot;;.
/// </summary>
public static string ContainerType_BrewingStand
{
get
{
internal static string ContainerType_BrewingStand {
get {
return ResourceManager.GetString("ContainerType_BrewingStand", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to ╔═════════════════════════════════════╗
///║ Crafting ║
@ -105,24 +94,35 @@ namespace MinecraftClient
///║ Inventory ║
///║╔═══╦═══╦═══╦═══╦═══╦═══╦═══╦═══╦═══╗║
///║║10 ║11 ║12 ║13 ║14 ║15 ║16 ║17 ║18 ║║
///║╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬══ [rest of string was truncated]&quot;;.
///║╠═══╬═══╬═══╬═══╬══ [rest of string was truncated]&quot;;.
/// </summary>
public static string ContainerType_Crafting
{
get
{
internal static string ContainerType_Crafting {
get {
return ResourceManager.GetString("ContainerType_Crafting", resourceCulture);
}
}
public static string ContainerType_Furnace
{
get
{
/// <summary>
/// Looks up a localized string similar to ╔═════════════════════════════════════╗
///║ Container ║
///║ ╔═══╗ ║
///║ ║ 0 ║ ║
///║ ╚═══╝ ╔═══╗ ║
///║ ⠂⡠⢂ ━━▶ ║ 2 ║ ║
///║ ⠂⡠⢂ ╚═══╝ ║
///║ ╔═══╗ ║
///║ ║ 1 ║ ║
///║ ╚═══╝ ║
///║ Inventory ║
///║╔═══╦═══╦═══╦═══╦═══╦═══╦═══╦═══╦═══╗║
///║║ 3 ║ 4 ║ 5 ║ 6 ║ 7 [rest of string was truncated]&quot;;.
/// </summary>
internal static string ContainerType_Furnace {
get {
return ResourceManager.GetString("ContainerType_Furnace", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to ╔═════════════════════════════════════╗
///║ Container ║
@ -136,19 +136,17 @@ namespace MinecraftClient
///║ Inventory ║
///║╔═══╦═══╦═══╦═══╦═══╦═══╦═══╦═══╦═══╗║
///║║ 9 ║10 ║11 ║12 ║13 ║14 ║15 ║16 ║17 ║║
///║╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬══ [rest of string was truncated]&quot;;.
///║╠═══╬═══╬═══╬═══╬══ [rest of string was truncated]&quot;;.
/// </summary>
public static string ContainerType_Generic_3x3
{
get
{
internal static string ContainerType_Generic_3x3 {
get {
return ResourceManager.GetString("ContainerType_Generic_3x3", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to ╔═════════════════════════════════════╗
///║ Chest
///║ Container
///║╔═══╦═══╦═══╦═══╦═══╦═══╦═══╦═══╦═══╗║
///║║ 0 ║ 1 ║ 2 ║ 3 ║ 4 ║ 5 ║ 6 ║ 7 ║ 8 ║║
///║╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣║
@ -159,19 +157,17 @@ namespace MinecraftClient
///║ Inventory ║
///║╔═══╦═══╦═══╦═══╦═══╦═══╦═══╦═══╦═══╗║
///║║27 ║28 ║29 ║30 ║31 ║32 ║33 ║34 ║35 ║║
///║╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬══ [rest of string was truncated]&quot;;.
///║╠═══╬═══╬═══╬═══╬══ [rest of string was truncated]&quot;;.
/// </summary>
public static string ContainerType_Generic_9x3
{
get
{
internal static string ContainerType_Generic_9x3 {
get {
return ResourceManager.GetString("ContainerType_Generic_9x3", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to ╔═════════════════════════════════════╗
///║ Large Container ║
///║ Container
///║╔═══╦═══╦═══╦═══╦═══╦═══╦═══╦═══╦═══╗║
///║║ 0 ║ 1 ║ 2 ║ 3 ║ 4 ║ 5 ║ 6 ║ 7 ║ 8 ║║
///║╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣║
@ -182,32 +178,56 @@ namespace MinecraftClient
///║║27 ║28 ║29 ║30 ║31 ║32 ║33 ║34 ║35 ║║
///║╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣║
///║║36 ║37 ║38 ║39 ║40 ║41 ║42 ║43 ║44 ║║
///║╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬══ [rest of string was truncated]&quot;;.
///║╠═══╬═══╬═══╬═══╬══ [rest of string was truncated]&quot;;.
/// </summary>
public static string ContainerType_Generic_9x6
{
get
{
internal static string ContainerType_Generic_9x6 {
get {
return ResourceManager.GetString("ContainerType_Generic_9x6", resourceCulture);
}
}
public static string ContainerType_Grindstone
{
get
{
/// <summary>
/// Looks up a localized string similar to ╔═════════════════════════════════════╗
///║ Repair &amp; Disenchant ║
///║ ╔═════════╗ ║
///║ ║ ╔═══╗ ║ ║
///║ ╔══║ ║ 0 ║ ║══╗ ║
///║ ║ ║ ╚═══╝ ║ ║ ║
///║ ║ ║ ╔═══╗ ║ ║ ╔═══╗ ║
///║ ║ ║ ║ 1 ║ ║ ║ ━━▶ ║ 2 ║ ║
///║ ║ ║ ╚═══╝ ║ ║ ╚═══╝ ║
///║ ║ ╠═════════╣ ║ ║
///║ ║ ║ ║ ║ ║
///║ ╚══╝ ╚══╝ ║
///║ [rest of string was truncated]&quot;;.
/// </summary>
internal static string ContainerType_Grindstone {
get {
return ResourceManager.GetString("ContainerType_Grindstone", resourceCulture);
}
}
public static string ContainerType_Hopper
{
get
{
/// <summary>
/// Looks up a localized string similar to ╔═════════════════════════════════════╗
///║ Container ║
///║ ╔═══╦═══╦═══╦═══╦═══╗ ║
///║ ║ 0 ║ 1 ║ 2 ║ 3 ║ 4 ║ ║
///║ ╚═══╩═══╩═══╩═══╩═══╝ ║
///║ Inventory ║
///║╔═══╦═══╦═══╦═══╦═══╦═══╦═══╦═══╦═══╗║
///║║ 5 ║ 6 ║ 7 ║ 8 ║ 9 ║10 ║11 ║12 ║13 ║║
///║╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣║
///║║14 ║15 ║16 ║17 ║18 ║19 ║20 ║21 ║22 ║║
///║╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣║
///║║23 ║24 ║25 ║26 ║27 ║28 ║29 ║30 ║31 ║║
///║╚═══╩═══╩═══╩═══╩══ [rest of string was truncated]&quot;;.
/// </summary>
internal static string ContainerType_Hopper {
get {
return ResourceManager.GetString("ContainerType_Hopper", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to ╔═════════════════════════════════════╗
///║╔═══╦═══════════╗ ║
@ -221,66 +241,168 @@ namespace MinecraftClient
///║╚═══╩═══════════╩═══╝ ║
///║╔═══╦═══╦═══╦═══╦═══╦═══╦═══╦═══╦═══╗║
///║║ 9 ║10 ║11 ║12 ║13 ║14 ║15 ║16 ║17 ║║
///║╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬══ [rest of string was truncated]&quot;;.
///║╠═══╬═══╬═══╬═══╬══ [rest of string was truncated]&quot;;.
/// </summary>
public static string ContainerType_PlayerInventory
{
get
{
internal static string ContainerType_PlayerInventory {
get {
return ResourceManager.GetString("ContainerType_PlayerInventory", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to # Startup Config File
///
///[Main]
///
///# General settings
///# Leave blank to prompt user on startup
///# Use &quot;-&quot; as password for offline mode
///
///login=
///password=
///serverip=
///type=mojang # Account type. mojang or microsoft
///method=mcc # Microsoft Account sign-in method. mcc OR browser
///
///# Advanced settings
///
///language=en_GB
///consoletitle=%username%@%serverip% - Minecraft Console Client
///internalcmdchar=slash # Use &apos;none&apos;, &apos;slash&apos; or &apos;backslash&apos;
///messagec [rest of string was truncated]&quot;;.
/// </summary>
public static string MinecraftClient
{
get
{
return ResourceManager.GetString("MinecraftClient", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to [mcc]
///# Messages from MCC itself
///mcc.help_us_translate=
///mcc.run_with_default_settings=
///mcc.settings_generated=
///mcc.has_update=
///mcc.login=Login :
///mcc.login_basic_io=Bitte gib einen Nutzernamen oder eine E-Mail deiner Wahl ein.
///mcc.password=Passwort :
///mcc.password_basic_io=Bitte gib das Passwort für {0} ein.
///mcc.password_hidden=Passwort : {0}
///mcc.offline=§8Das Programm läuft im Offline-Modus.
///mcc.session_invalid=§8Gespeicherte Session ungültig oder abgelaufen.
///mcc.session_valid=§8Gespeicherte Ses [rest of string was truncated]&quot;;.
/// </summary>
internal static string Translation_de {
get {
return ResourceManager.GetString("Translation_de", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to [mcc]
///# Messages from MCC itself
///mcc.help_us_translate=Help us translate MCC: {0}
///mcc.run_with_default_settings=\nMCC is running with default settings.
///mcc.settings_generated=§cSettings file MinecraftClient.ini has been generated.
///mcc.has_update=§eNew version of MCC available: {0}
///mcc.login=Login :
///mcc.login_basic_io=Please type the username or email of your choice.
///mcc.password=Password :
///mcc.password=Password:
///mcc.password_basic_io=Please type the password for {0}.
///mcc.password_hidden=Password : {0}
///mcc.offline=§8You chose to run in offline mode.
///mcc.session_invalid=§8Cached session is invalid or expired.
///mcc.session_valid=§8Cached session is still valid for {0}.
///mcc.connecting=Connecting to {0}...
///mcc.ip=Server IP :
///mcc.use_version=§8Using Minecraft version [rest of string was truncated]&quot;;.
///mcc.password_hidden=Password(invisible): {0}
///mcc.off [rest of string was truncated]&quot;;.
/// </summary>
public static string TranslationEnglish
{
get
{
return ResourceManager.GetString("TranslationEnglish", resourceCulture);
internal static string Translation_en {
get {
return ResourceManager.GetString("Translation_en", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to [mcc]
///# Messages from MCC itself
///mcc.help_us_translate=
///mcc.run_with_default_settings=
///mcc.settings_generated=
///mcc.has_update=
///mcc.login=Connexion :
///mcc.login_basic_io=Veuillez saisir un nom d&apos;utilisateur ou une adresse email.
///mcc.password=Mot de passe :
///mcc.password_basic_io=Saisissez le mot de passe pour {0}.
///mcc.password_hidden=Mot de passe : {0}
///mcc.offline=§8Vous avez choisi d&apos;utiliser le mode hors ligne.
///mcc.session_invalid=§8Le cache de la session est invalide ou a expiré.
///mcc.session_va [rest of string was truncated]&quot;;.
/// </summary>
internal static string Translation_fr {
get {
return ResourceManager.GetString("Translation_fr", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to [mcc]
///# Messages from MCC itself
///mcc.help_us_translate=
///mcc.run_with_default_settings=
///mcc.settings_generated=
///mcc.has_update=
///mcc.login=Логин :
///mcc.login_basic_io=Пожалуйста, введите имя пользователя или email по вашему выбору.
///mcc.password=Пароль:
///mcc.password_basic_io=Пожалуйста, введите пароль для {0}.
///mcc.password_hidden=Пароль: {0}
///mcc.offline=§8Вы выбрали запуск в автономном режиме.
///mcc.session_invalid=§8Кэшированная сессия недействительна или истекла.
///mcc.session_valid=§8Кэшированная се [rest of string was truncated]&quot;;.
/// </summary>
internal static string Translation_ru {
get {
return ResourceManager.GetString("Translation_ru", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to [mcc]
///# Messages from MCC itself
///mcc.help_us_translate=
///mcc.run_with_default_settings=
///mcc.settings_generated=
///mcc.has_update=
///mcc.login=Đăng nhập:
///mcc.login_basic_io=Hãy nhập địa chỉ email hoặc tên tài khoản của bạn:
///mcc.password=Mật khẩu:
///mcc.password_basic_io=Hãy nhập mật khẩu cho {0}.
///mcc.password_hidden=Password : {0}
///mcc.offline=§8Bạn chọn sử dụng chế độ ngoại tuyến.
///mcc.session_invalid=§8Phiên không hợp lệ hoặc đã hết hạn.
///mcc.session_valid=§8Phiên vẫn còn hợp lệ cho {0}.
///mcc.profile_ke [rest of string was truncated]&quot;;.
/// </summary>
internal static string Translation_vi {
get {
return ResourceManager.GetString("Translation_vi", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to [mcc]
///# Messages from MCC itself
///mcc.help_us_translate=帮助我们翻译MCC{0}
///mcc.run_with_default_settings=\nMCC正在使用默认配置运行。
///mcc.settings_generated=§c配置文件 MinecraftClient.ini 已经生成。
///mcc.has_update=§e新版本的MCC已经推出{0}
///mcc.login=账户名:
///mcc.login_basic_io=请输入用户名或邮箱。
///mcc.password=密码:
///mcc.password_basic_io=请输入用户 {0} 的密码。
///mcc.password_hidden=密码(不会显示){0}
///mcc.offline=§8您正在使用离线模式。
///mcc.session_invalid=§8会话缓存无效或已过期。
///mcc.session_valid=§8{0}的会话缓存仍然有效。
///mcc.profile_key_invalid=§8缓存的聊天签名密钥需要刷新。
///mcc.profile_key_valid=§8{0 [rest of string was truncated]&quot;;.
/// </summary>
internal static string Translation_zh_Hans {
get {
return ResourceManager.GetString("Translation_zh_Hans", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to [mcc]
///# Messages from MCC itself
///mcc.help_us_translate=幫助我們翻譯MCC{0}
///mcc.run_with_default_settings=\nMCC正在使用預設配置執行。
///mcc.settings_generated=§c配置檔案 MinecraftClient.ini 已經生成。
///mcc.has_update=§e新版本的MCC已經推出{0}
///mcc.login=賬戶名:
///mcc.login_basic_io=請輸入使用者名稱或郵箱。
///mcc.password=密碼:
///mcc.password_basic_io=請輸入使用者 {0} 的密碼。
///mcc.password_hidden=密碼(不會顯示){0}
///mcc.offline=§8您正在使用離線模式。
///mcc.session_invalid=§8會話快取無效或已過期。
///mcc.session_valid=§8{0}的會話快取仍然有效。
///mcc.profile_key_invalid=§8快取的聊天簽名金鑰需要重新整理。
///mcc.profile_key_valid [rest of string was truncated]&quot;;.
/// </summary>
internal static string Translation_zh_Hant {
get {
return ResourceManager.GetString("Translation_zh_Hant", resourceCulture);
}
}
}

View file

@ -145,10 +145,25 @@
<data name="ContainerType_PlayerInventory" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Resources\containers\ContainerType.PlayerInventory.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
<data name="MinecraftClient" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Resources\config\MinecraftClient.ini;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
<data name="Translation_de" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>resources\lang\de.ini;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
<data name="TranslationEnglish" type="System.Resources.ResXFileRef, System.Windows.Forms">
<data name="Translation_en" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Resources\lang\en.ini;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
<data name="Translation_fr" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>resources\lang\fr.ini;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
<data name="Translation_ru" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>resources\lang\ru.ini;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
<data name="Translation_vi" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>resources\lang\vi.ini;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
<data name="Translation_zh_Hans" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>resources\lang\zh-hans.ini;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
<data name="Translation_zh_Hant" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>resources\lang\zh-hant.ini;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
</root>

View file

@ -22,7 +22,7 @@ namespace MinecraftClient
/// <param name="handler">Callback for file changes</param>
public FileMonitor(string folder, string filename, FileSystemEventHandler handler)
{
if (Settings.DebugMessages)
if (Settings.Config.Logging.DebugMessages)
{
string callerClass = new System.Diagnostics.StackFrame(1).GetMethod()!.DeclaringType!.Name;
ConsoleIO.WriteLineFormatted(Translations.Get("filemonitor.init", callerClass, Path.Combine(folder, filename)));
@ -40,7 +40,7 @@ namespace MinecraftClient
}
catch
{
if (Settings.DebugMessages)
if (Settings.Config.Logging.DebugMessages)
{
string callerClass = new System.Diagnostics.StackFrame(1).GetMethod()!.DeclaringType!.Name;
ConsoleIO.WriteLineFormatted(Translations.Get("filemonitor.fail", callerClass));

View file

@ -1,8 +1,8 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
using System.Globalization;
using System.Linq;
using System.Text;
namespace MinecraftClient.Inventory
{

View file

@ -26,7 +26,7 @@ namespace MinecraftClient.Logger
{
try
{
if (!Settings.SaveColorCodes)
if (!Settings.Config.Logging.SaveColorCodes)
msg = ChatBot.GetVerbatim(msg);
if (prependTimestamp)
msg = GetTimestamp() + ' ' + msg;

View file

@ -1,4 +1,5 @@
using System.Text.RegularExpressions;
using static MinecraftClient.Settings;
namespace MinecraftClient.Logger
{
@ -8,19 +9,38 @@ namespace MinecraftClient.Logger
protected bool ShouldDisplay(FilterChannel channel, string msg)
{
if (Config.Logging.FilterMode == LoggingConfigHealper.LoggingConfig.FilterModeEnum.disable)
return true;
Regex? regexToUse = null;
// Convert to bool for XOR later. Whitelist = 0, Blacklist = 1
bool filterMode = Settings.FilterMode == Settings.FilterModeEnum.Blacklist;
switch (channel)
{
case FilterChannel.Chat: regexToUse = Settings.ChatFilter; break;
case FilterChannel.Debug: regexToUse = Settings.DebugFilter; break;
case FilterChannel.Chat:
string chat = Config.Logging.ChatFilterRegex;
if (string.IsNullOrEmpty(chat))
regexToUse = null;
else
regexToUse = new(chat);
break;
case FilterChannel.Debug:
string debug = Config.Logging.DebugFilterRegex;
if (string.IsNullOrEmpty(debug))
regexToUse = null;
else
regexToUse = new(debug);
break;
}
if (regexToUse != null)
{
// IsMatch and white/blacklist result can be represented using XOR
// e.g. matched(true) ^ blacklist(true) => shouldn't log(false)
return regexToUse.IsMatch(msg) ^ filterMode;
if (Config.Logging.FilterMode == LoggingConfigHealper.LoggingConfig.FilterModeEnum.blacklist)
return !regexToUse.IsMatch(msg);
else if (Config.Logging.FilterMode == LoggingConfigHealper.LoggingConfig.FilterModeEnum.whitelist)
return regexToUse.IsMatch(msg);
else
return true;
}
else return true;
}

View file

@ -21,7 +21,7 @@ namespace MinecraftClient.Mapping
/// <returns>Updated location after applying gravity</returns>
public static Location HandleGravity(World world, Location location, ref double motionY)
{
if (Settings.GravityEnabled)
if (Settings.InternalConfig.GravityEnabled)
{
Location onFoots = new(location.X, Math.Floor(location.Y), location.Z);
Location belowFoots = Move(location, Direction.Down);

View file

@ -1,10 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using MinecraftClient.Protocol;
namespace MinecraftClient.Mapping
{

View file

@ -14,6 +14,7 @@ using MinecraftClient.Protocol.Keys;
using MinecraftClient.Protocol.Message;
using MinecraftClient.Protocol.Session;
using MinecraftClient.Proxy;
using static MinecraftClient.Settings;
namespace MinecraftClient
{
@ -142,12 +143,11 @@ namespace MinecraftClient
/// <param name="port">The server port to use</param>
/// <param name="protocolversion">Minecraft protocol version to use</param>
/// <param name="forgeInfo">ForgeInfo item stating that Forge is enabled</param>
/// <param name="command">The text or command to send. Will only be sent if singlecommand is set to true.</param>
public McClient(SessionToken session, PlayerKeyPair? playerKeyPair, string server_ip, ushort port, int protocolversion, ForgeInfo? forgeInfo, string? command)
public McClient(SessionToken session, PlayerKeyPair? playerKeyPair, string server_ip, ushort port, int protocolversion, ForgeInfo? forgeInfo)
{
terrainAndMovementsEnabled = Settings.TerrainAndMovements;
inventoryHandlingEnabled = Settings.InventoryHandling;
entityHandlingEnabled = Settings.EntityHandling;
terrainAndMovementsEnabled = Config.Main.Advanced.TerrainAndMovements;
inventoryHandlingEnabled = Config.Main.Advanced.InventoryHandling;
entityHandlingEnabled = Config.Main.Advanced.EntityHandling;
sessionid = session.ID;
if (!Guid.TryParse(session.PlayerID, out uuid))
@ -159,64 +159,47 @@ namespace MinecraftClient
this.protocolversion = protocolversion;
this.playerKeyPair = playerKeyPair;
Log = Settings.LogToFile
? new FileLogLogger(Settings.ExpandVars(Settings.LogFile), Settings.PrependTimestamp)
Log = Settings.Config.Logging.LogToFile
? new FileLogLogger(Config.AppVar.ExpandVars(Settings.Config.Logging.LogFile), Settings.Config.Logging.PrependTimestamp)
: new FilteredLogger();
Log.DebugEnabled = Settings.DebugMessages;
Log.InfoEnabled = Settings.InfoMessages;
Log.ChatEnabled = Settings.ChatMessages;
Log.WarnEnabled = Settings.WarningMessages;
Log.ErrorEnabled = Settings.ErrorMessages;
Log.DebugEnabled = Config.Logging.DebugMessages;
Log.InfoEnabled = Config.Logging.InfoMessages;
Log.ChatEnabled = Config.Logging.ChatMessages;
Log.WarnEnabled = Config.Logging.WarningMessages;
Log.ErrorEnabled = Config.Logging.ErrorMessages;
if (command == null)
{
/* Load commands from Commands namespace */
LoadCommands();
/* Load commands from Commands namespace */
LoadCommands();
if (botsOnHold.Count == 0)
RegisterBots();
}
if (botsOnHold.Count == 0)
RegisterBots();
try
{
client = ProxyHandler.NewTcpClient(host, port);
client.ReceiveBufferSize = 1024 * 1024;
client.ReceiveTimeout = Settings.Timeout * 1000; // Default: 30 seconds
client.ReceiveTimeout = Config.Main.Advanced.TcpTimeout * 1000; // Default: 30 seconds
handler = Protocol.ProtocolHandler.GetProtocolHandler(client, protocolversion, forgeInfo, this);
Log.Info(Translations.Get("mcc.version_supported"));
if (command == null)
{
timeoutdetector = new(new Thread(new ParameterizedThreadStart(TimeoutDetector)), new CancellationTokenSource());
timeoutdetector.Item1.Name = "MCC Connection timeout detector";
timeoutdetector.Item1.Start(timeoutdetector.Item2.Token);
}
timeoutdetector = new(new Thread(new ParameterizedThreadStart(TimeoutDetector)), new CancellationTokenSource());
timeoutdetector.Item1.Name = "MCC Connection timeout detector";
timeoutdetector.Item1.Start(timeoutdetector.Item2.Token);
try
{
if (handler.Login(this.playerKeyPair, session))
{
if (command != null)
{
handler.SendChatMessage(command, playerKeyPair);
Log.Info(Translations.Get("mcc.single_cmd", command));
Thread.Sleep(5000);
handler.Disconnect();
Thread.Sleep(1000);
}
else
{
foreach (ChatBot bot in botsOnHold)
BotLoad(bot, false);
botsOnHold.Clear();
foreach (ChatBot bot in botsOnHold)
BotLoad(bot, false);
botsOnHold.Clear();
Log.Info(Translations.Get("mcc.joined", (Settings.internalCmdChar == ' ' ? "" : "" + Settings.internalCmdChar)));
Log.Info(Translations.Get("mcc.joined", Config.Main.Advanced.InternalCmdChar.ToLogString()));
cmdprompt = new CancellationTokenSource();
ConsoleInteractive.ConsoleReader.BeginReadThread(cmdprompt);
ConsoleInteractive.ConsoleReader.MessageReceived += ConsoleReaderOnMessageReceived;
ConsoleInteractive.ConsoleReader.OnKeyInput += ConsoleIO.AutocompleteHandler;
}
cmdprompt = new CancellationTokenSource();
ConsoleInteractive.ConsoleReader.BeginReadThread(cmdprompt);
ConsoleInteractive.ConsoleReader.MessageReceived += ConsoleReaderOnMessageReceived;
ConsoleInteractive.ConsoleReader.OnKeyInput += ConsoleIO.AutocompleteHandler;
}
else
{
@ -253,7 +236,7 @@ namespace MinecraftClient
ReconnectionAttemptsLeft--;
Program.Restart();
}
else if (command == null && Settings.interactiveMode)
else if (InternalConfig.InteractiveMode)
{
ConsoleInteractive.ConsoleReader.StopReadThread();
ConsoleInteractive.ConsoleReader.MessageReceived -= ConsoleReaderOnMessageReceived;
@ -269,25 +252,25 @@ namespace MinecraftClient
/// </summary>
private void RegisterBots(bool reload = false)
{
if (Settings.AntiAFK_Enabled) { BotLoad(new AntiAFK(Settings.AntiAFK_Delay, Settings.AntiAFK_UseTerrain_Handling, Settings.AntiAFK_Walk_Range, Settings.AntiAFK_Walk_Retries)); }
if (Settings.Hangman_Enabled) { BotLoad(new HangmanGame(Settings.Hangman_English)); }
if (Settings.Alerts_Enabled) { BotLoad(new Alerts()); }
if (Settings.ChatLog_Enabled) { BotLoad(new ChatLog(Settings.ExpandVars(Settings.ChatLog_File), Settings.ChatLog_Filter, Settings.ChatLog_DateTime)); }
if (Settings.PlayerLog_Enabled) { BotLoad(new PlayerListLogger(Settings.PlayerLog_Delay, Settings.ExpandVars(Settings.PlayerLog_File))); }
if (Settings.AutoRelog_Enabled) { BotLoad(new AutoRelog(Settings.AutoRelog_Delay_Min, Settings.AutoRelog_Delay_Max, Settings.AutoRelog_Retries)); }
if (Settings.ScriptScheduler_Enabled) { BotLoad(new ScriptScheduler(Settings.ExpandVars(Settings.ScriptScheduler_TasksFile))); }
if (Settings.RemoteCtrl_Enabled) { BotLoad(new RemoteControl()); }
if (Settings.AutoRespond_Enabled) { BotLoad(new AutoRespond(Settings.AutoRespond_Matches, Settings.AutoRespond_MatchColors)); }
if (Settings.AutoAttack_Enabled) { BotLoad(new AutoAttack(Settings.AutoAttack_Mode, Settings.AutoAttack_Priority, Settings.AutoAttack_OverrideAttackSpeed, Settings.AutoAttack_CooldownSeconds, Settings.AutoAttack_Interaction)); }
if (Settings.AutoFishing_Enabled) { BotLoad(new AutoFishing()); }
if (Settings.AutoEat_Enabled) { BotLoad(new AutoEat(Settings.AutoEat_hungerThreshold)); }
if (Settings.Mailer_Enabled) { BotLoad(new Mailer()); }
if (Settings.AutoCraft_Enabled) { BotLoad(new AutoCraft(Settings.AutoCraft_configFile)); }
if (Settings.AutoDrop_Enabled) { BotLoad(new AutoDrop(Settings.AutoDrop_Mode, Settings.AutoDrop_items)); }
if (Settings.ReplayMod_Enabled && reload) { BotLoad(new ReplayCapture(Settings.ReplayMod_BackupInterval)); }
if (Settings.FollowPlayer_Enabled) { BotLoad(new FollowPlayer(Settings.FollowPlayer_UpdateLimit, Settings.FollowPlayer_UpdateLimit)); }
if (Settings.Map_Enabled) { BotLoad(new Map()); }
if (Config.ChatBot.Alerts.Enabled) { BotLoad(new Alerts()); }
if (Config.ChatBot.AntiAFK.Enabled) { BotLoad(new AntiAFK()); }
if (Config.ChatBot.AutoAttack.Enabled) { BotLoad(new AutoAttack()); }
if (Config.ChatBot.AutoCraft.Enabled) { BotLoad(new AutoCraft()); }
if (Config.ChatBot.AutoDig.Enabled) { BotLoad(new AutoDig()); }
if (Config.ChatBot.AutoDrop.Enabled) { BotLoad(new AutoDrop()); }
if (Config.ChatBot.AutoEat.Enabled) { BotLoad(new AutoEat()); }
if (Config.ChatBot.AutoFishing.Enabled) { BotLoad(new AutoFishing()); }
if (Config.ChatBot.AutoRelog.Enabled) { BotLoad(new AutoRelog()); }
if (Config.ChatBot.AutoRespond.Enabled) { BotLoad(new AutoRespond()); }
if (Config.ChatBot.ChatLog.Enabled) { BotLoad(new ChatLog()); }
if (Config.ChatBot.FollowPlayer.Enabled) { BotLoad(new FollowPlayer()); }
if (Config.ChatBot.HangmanGame.Enabled) { BotLoad(new HangmanGame()); }
if (Config.ChatBot.Mailer.Enabled) { BotLoad(new Mailer()); }
if (Config.ChatBot.Map.Enabled) { BotLoad(new Map()); }
if (Config.ChatBot.PlayerListLogger.Enabled) { BotLoad(new PlayerListLogger()); }
if (Config.ChatBot.RemoteControl.Enabled) { BotLoad(new RemoteControl()); }
if (Config.ChatBot.ReplayCapture.Enabled && reload) { BotLoad(new ReplayCapture()); }
if (Config.ChatBot.ScriptScheduler.Enabled) { BotLoad(new ScriptScheduler()); }
//Add your ChatBot here by uncommenting and adapting
//BotLoad(new ChatBots.YourBot());
}
@ -302,7 +285,7 @@ namespace MinecraftClient
{
string text = chatQueue.Dequeue();
handler.SendChatMessage(text, playerKeyPair);
nextMessageSendTime = DateTime.Now + Settings.messageCooldown;
nextMessageSendTime = DateTime.Now + TimeSpan.FromSeconds(Config.Main.Advanced.MessageCooldown);
}
}
@ -336,7 +319,7 @@ namespace MinecraftClient
{
lock (locationLock)
{
for (int i = 0; i < Settings.MovementSpeed; i++) //Needs to run at 20 tps; MCC runs at 10 tps
for (int i = 0; i < Config.Main.Advanced.MovementSpeed; i++) //Needs to run at 20 tps; MCC runs at 10 tps
{
if (_yaw == null || _pitch == null)
{
@ -349,10 +332,8 @@ namespace MinecraftClient
Location next = path.Dequeue();
steps = Movement.Move2Steps(location, next, ref motionY);
if (Settings.MoveHeadWhileWalking) // Disable head movements to avoid anti-cheat triggers
{
if (Config.Main.Advanced.MoveHeadWhileWalking) // Disable head movements to avoid anti-cheat triggers
UpdateLocation(location, next + new Location(0, 1, 0)); // Update yaw and pitch to look at next step
}
}
else
{
@ -370,7 +351,7 @@ namespace MinecraftClient
}
}
if (Settings.AutoRespawn && respawnTicks > 0)
if (Config.Main.Advanced.AutoRespawn && respawnTicks > 0)
{
respawnTicks--;
if (respawnTicks == 0)
@ -404,7 +385,7 @@ namespace MinecraftClient
lock (lastKeepAliveLock)
{
if (lastKeepAlive.AddSeconds(Settings.Timeout) < DateTime.Now)
if (lastKeepAlive.AddSeconds(Config.Main.Advanced.TcpTimeout) < DateTime.Now)
{
if (((CancellationToken)o!).IsCancellationRequested)
return;
@ -471,7 +452,7 @@ namespace MinecraftClient
if (timeoutdetector != null)
{
if (Thread.CurrentThread != timeoutdetector.Item1)
if (timeoutdetector != null && Thread.CurrentThread != timeoutdetector.Item1)
timeoutdetector.Item2.Cancel();
timeoutdetector = null;
}
@ -572,11 +553,11 @@ namespace MinecraftClient
text = text.Trim();
if (text.Length > 0)
{
if (Settings.internalCmdChar == ' ' || text[0] == Settings.internalCmdChar)
if (Config.Main.Advanced.InternalCmdChar.ToChar() == ' ' || text[0] == Config.Main.Advanced.InternalCmdChar.ToChar())
{
string? response_msg = "";
string command = Settings.internalCmdChar == ' ' ? text : text[1..];
if (!PerformInternalCommand(Settings.ExpandVars(command), ref response_msg, Settings.GetVariables()) && Settings.internalCmdChar == '/')
string command = Config.Main.Advanced.InternalCmdChar.ToChar() == ' ' ? text : text[1..];
if (!PerformInternalCommand(Config.AppVar.ExpandVars(command), ref response_msg, Settings.Config.AppVar.GetVariables()) && Config.Main.Advanced.InternalCmdChar.ToChar() == '/')
{
SendText(text);
}
@ -659,7 +640,7 @@ namespace MinecraftClient
}
else response_msg = Translations.Get("icmd.unknown", command_name);
}
else response_msg = Translations.Get("icmd.list", String.Join(", ", cmd_names.ToArray()), Settings.internalCmdChar);
else response_msg = Translations.Get("icmd.list", String.Join(", ", cmd_names.ToArray()), Config.Main.Advanced.InternalCmdChar.ToChar());
}
else if (cmds.ContainsKey(command_name))
{
@ -845,7 +826,6 @@ namespace MinecraftClient
DispatchBotEvent(bot => bot.Initialize(), new ChatBot[] { b });
if (handler != null)
DispatchBotEvent(bot => bot.AfterGameJoined(), new ChatBot[] { b });
Settings.SingleCommand = "";
}
/// <summary>
@ -2395,18 +2375,19 @@ namespace MinecraftClient
/// </summary>
public void OnGameJoined()
{
if (!String.IsNullOrWhiteSpace(Settings.BrandInfo))
handler.SendBrandInfo(Settings.BrandInfo.Trim());
string? bandString = Config.Main.Advanced.BrandInfo.ToBrandString();
if (!String.IsNullOrWhiteSpace(bandString))
handler.SendBrandInfo(bandString.Trim());
if (Settings.MCSettings_Enabled)
if (Config.MCSettings.Enabled)
handler.SendClientSettings(
Settings.MCSettings_Locale,
Settings.MCSettings_RenderDistance,
Settings.MCSettings_Difficulty,
Settings.MCSettings_ChatMode,
Settings.MCSettings_ChatColors,
Settings.MCSettings_Skin_All,
Settings.MCSettings_MainHand);
Config.MCSettings.Locale,
Config.MCSettings.RenderDistance,
(byte)Config.MCSettings.Difficulty,
(byte)Config.MCSettings.ChatMode,
Config.MCSettings.ChatColors,
Config.MCSettings.Skin.GetByte(),
(byte)Config.MCSettings.MainHand);
if (inventoryHandlingRequested)
@ -2484,15 +2465,15 @@ namespace MinecraftClient
{
case MovementType.Sneak:
// https://minecraft.fandom.com/wiki/Sneaking#Effects - Sneaking 1.31m/s
Settings.MovementSpeed = 2;
Config.Main.Advanced.MovementSpeed = 2;
break;
case MovementType.Walk:
// https://minecraft.fandom.com/wiki/Walking#Usage - Walking 4.317 m/s
Settings.MovementSpeed = 4;
Config.Main.Advanced.MovementSpeed = 4;
break;
case MovementType.Sprint:
// https://minecraft.fandom.com/wiki/Sprinting#Usage - Sprinting 5.612 m/s
Settings.MovementSpeed = 5;
Config.Main.Advanced.MovementSpeed = 5;
break;
}
}
@ -2601,7 +2582,7 @@ namespace MinecraftClient
if (message.isSignedChat)
{
if (!Settings.ShowIllegalSignedChat && !message.isSystemChat && !(bool)message.isSignatureLegal!)
if (!Config.Signature.ShowIllegalSignedChat && !message.isSystemChat && !(bool)message.isSignatureLegal!)
return;
messageText = ChatParser.ParseSignedChat(message, links);
}
@ -2615,7 +2596,7 @@ namespace MinecraftClient
Log.Chat(messageText);
if (Settings.DisplayChatLinks)
if (Config.Main.Advanced.ShowChatLinks)
foreach (string link in links)
Log.Chat(Translations.Get("mcc.link", link));
@ -3024,14 +3005,14 @@ namespace MinecraftClient
if (health <= 0)
{
if (Settings.AutoRespawn)
if (Config.Main.Advanced.AutoRespawn)
{
Log.Info(Translations.Get("mcc.player_dead_respawn"));
respawnTicks = 10;
}
else
{
Log.Info(Translations.Get("mcc.player_dead", (Settings.internalCmdChar == ' ' ? "" : "" + Settings.internalCmdChar)));
Log.Info(Translations.Get("mcc.player_dead", Config.Main.Advanced.InternalCmdChar.ToLogString()));
}
DispatchBotEvent(bot => bot.OnDeath());
}
@ -3312,6 +3293,17 @@ namespace MinecraftClient
}
}
/// <summary>
/// Called when a block is changed.
/// </summary>
/// <param name="location">The location of the block.</param>
/// <param name="block">The block</param>
public void OnBlockChange(Location location, Block block)
{
world.SetBlock(location, block);
DispatchBotEvent(bot => bot.OnBlockChange(location, block));
}
#endregion
}
}

View file

@ -36,9 +36,10 @@
<PackageReference Include="DnsClient" Version="1.6.1" />
<PackageReference Include="DotNetZip" Version="1.16.0" />
<PackageReference Include="DynamicExpresso.Core" Version="2.13.0" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.3.0" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.3.1" />
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
<PackageReference Include="Microsoft.Windows.Compatibility" Version="5.0.2" />
<PackageReference Include="Microsoft.Windows.Compatibility" Version="6.0.0" />
<PackageReference Include="Samboy063.Tomlet" Version="5.0.0" />
<PackageReference Include="SingleFileExtractor.Core" Version="1.0.1" />
<PackageReference Include="starksoft.aspen" Version="1.1.8">
<NoWarn>NU1701</NoWarn>
@ -72,4 +73,9 @@
<ItemGroup>
<ProjectReference Include="..\ConsoleInteractive\ConsoleInteractive\ConsoleInteractive\ConsoleInteractive.csproj" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Update="DefaultConfigResource.resx">
<Generator></Generator>
</EmbeddedResource>
</ItemGroup>
</Project>

View file

@ -3,9 +3,10 @@ using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using MinecraftClient.Inventory.ItemPalettes;
@ -16,6 +17,10 @@ using MinecraftClient.Protocol.Handlers.Forge;
using MinecraftClient.Protocol.Keys;
using MinecraftClient.Protocol.Session;
using MinecraftClient.WinAPI;
using Tomlet;
using static MinecraftClient.Settings;
using static MinecraftClient.Settings.MainConfigHealper.MainConfig.AdvancedConfig;
using static MinecraftClient.Settings.MainConfigHealper.MainConfig.GeneralConfig;
namespace MinecraftClient
{
@ -37,6 +42,7 @@ namespace MinecraftClient
{
private static McClient? client;
public static string[]? startupargs;
public static readonly CultureInfo ActualCulture = CultureInfo.CurrentCulture;
public const string Version = MCHighestVersion;
public const string MCLowestVersion = "1.4.6";
@ -45,20 +51,25 @@ namespace MinecraftClient
private static Tuple<Thread, CancellationTokenSource>? offlinePrompt = null;
private static bool useMcVersionOnce = false;
private static string? settingsIniPath = null;
private static string settingsIniPath = "MinecraftClient.ini";
/// <summary>
/// The main entry point of Minecraft Console Client
/// </summary>
static void Main(string[] args)
{
new Thread(() =>
InitCulture();
Task.Run(() =>
{
// "ToLower" require "CultureInfo" to be initialized on first run, which can take a lot of time.
_ = "a".ToLower();
//Take advantage of Windows 10 / Mac / Linux UTF-8 console
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
if (OperatingSystem.IsWindows())
{
// If we're on windows, check if our version is Win10 or greater.
if (WindowsVersion.WinMajorVersion >= 10)
if (OperatingSystem.IsWindowsVersionAtLeast(10))
Console.OutputEncoding = Console.InputEncoding = Encoding.UTF8;
}
else
@ -69,10 +80,7 @@ namespace MinecraftClient
// Fix issue #2119
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
// "ToLower" require "CultureInfo" to be initialized on first run, which can take a lot of time.
_ = "a".ToLower();
}).Start();
});
//Setup ConsoleIO
ConsoleIO.LogPrefix = "§8[MCC] ";
@ -104,12 +112,11 @@ namespace MinecraftClient
ConsoleIO.DebugReadInput();
}
settingsIniPath = "MinecraftClient.ini";
//Process ini configuration file
if (args.Length >= 1 && System.IO.File.Exists(args[0]) && Settings.ToLowerIfNeed(Path.GetExtension(args[0])) == ".ini")
bool loadSucceed, needWriteDefaultSetting, newlyGenerated = false;
if (args.Length >= 1 && File.Exists(args[0]) && Settings.ToLowerIfNeed(Path.GetExtension(args[0])) == ".ini")
{
Settings.LoadFile(args[0]);
(loadSucceed, needWriteDefaultSetting) = Settings.LoadFromFile(args[0]);
settingsIniPath = args[0];
//remove ini configuration file from arguments array
@ -117,14 +124,81 @@ namespace MinecraftClient
args_tmp.RemoveAt(0);
args = args_tmp.ToArray();
}
else if (System.IO.File.Exists("MinecraftClient.ini"))
else if (File.Exists("MinecraftClient.ini"))
{
Settings.LoadFile("MinecraftClient.ini");
(loadSucceed, needWriteDefaultSetting) = Settings.LoadFromFile("MinecraftClient.ini");
}
else
{
loadSucceed = true;
needWriteDefaultSetting = true;
newlyGenerated = true;
}
else Settings.WriteDefaultSettings("MinecraftClient.ini");
//Load external translation file. Should be called AFTER settings loaded
Translations.LoadExternalTranslationFile(Settings.Language);
if (!loadSucceed)
{
ConsoleInteractive.ConsoleReader.StopReadThread();
string command = " ";
while (command.Length > 0)
{
ConsoleIO.WriteLine(string.Empty);
ConsoleIO.WriteLineFormatted(Translations.Get("mcc.invaild_config", Config.Main.Advanced.InternalCmdChar.ToLogString()));
Translations.WriteLineFormatted("mcc.press_exit");
command = ConsoleInteractive.ConsoleReader.RequestImmediateInput().Trim();
if (command.Length > 0)
{
if (Config.Main.Advanced.InternalCmdChar.ToChar() != ' '
&& command[0] == Config.Main.Advanced.InternalCmdChar.ToChar())
command = command[1..];
if (command.StartsWith("exit") || command.StartsWith("quit"))
{
return;
}
else if (command.StartsWith("new"))
{
(string gameLanguage, string[] langList) = Translations.GetTranslationPriority();
Config.Main.Advanced.Language = gameLanguage;
Translations.LoadTranslationFile(langList);
WriteBackSettings(true);
ConsoleIO.WriteLineFormatted(Translations.Get("mcc.gen_new_config", settingsIniPath));
return;
}
}
else
{
return;
}
}
return;
}
else if (needWriteDefaultSetting)
{
(string gameLanguage, string[] langList) = Translations.GetTranslationPriority();
Translations.LoadTranslationFile(langList);
Config.Main.Advanced.Language = gameLanguage;
WriteBackSettings(false);
if (newlyGenerated)
ConsoleIO.WriteLineFormatted(Translations.TryGet("mcc.settings_generated"));
ConsoleIO.WriteLine(Translations.TryGet("mcc.run_with_default_settings"));
}
else
{
//Load external translation file. Should be called AFTER settings loaded
Translations.LoadTranslationFile(Translations.GetTranslationPriority(Config.Main.Advanced.Language));
if (!Config.Main.Advanced.Language.StartsWith("en"))
ConsoleIO.WriteLine(Translations.TryGet("mcc.help_us_translate", Settings.TranslationDocUrl));
WriteBackSettings(true); // format
}
bool needPromptUpdate = true;
if (Settings.CheckUpdate(Config.Head.CurrentVersion, Config.Head.LatestVersion))
{
needPromptUpdate = false;
ConsoleIO.WriteLineFormatted(Translations.TryGet("mcc.has_update", Settings.GithubLatestReleaseUrl));
}
//Other command-line arguments
if (args.Length >= 1)
@ -140,6 +214,12 @@ namespace MinecraftClient
return;
}
if (args.Contains("--trim-translation"))
{
Translations.TrimAllTranslations();
return;
}
if (args.Contains("--generate"))
{
string dataGenerator = "";
@ -222,55 +302,92 @@ namespace MinecraftClient
}
catch (ArgumentException e)
{
Settings.interactiveMode = false;
InternalConfig.InteractiveMode = false;
HandleFailure(e.Message);
return;
}
}
if (Settings.ConsoleTitle != "")
// Check for updates
Task.Run(() =>
{
Settings.Username = "New Window";
Console.Title = Settings.ExpandVars(Settings.ConsoleTitle);
HttpClientHandler httpClientHandler = new() { AllowAutoRedirect = false };
HttpClient httpClient = new(httpClientHandler);
Task<HttpResponseMessage>? httpWebRequest = null;
try
{
httpWebRequest = httpClient.GetAsync(Settings.GithubLatestReleaseUrl, HttpCompletionOption.ResponseHeadersRead);
httpWebRequest.Wait();
HttpResponseMessage res = httpWebRequest.Result;
if (res.Headers.Location != null)
{
Match match = Regex.Match(res.Headers.Location.ToString(), Settings.GithubReleaseUrl + @"/tag/(\d{4})(\d{2})(\d{2})-(\d+)");
if (match.Success && match.Groups.Count == 5)
{
string year = match.Groups[1].Value, month = match.Groups[2].Value, day = match.Groups[3].Value, run = match.Groups[4].Value;
string latestVersion = string.Format("GitHub build {0}, built on {1}-{2}-{3}", run, year, month, day);
if (needPromptUpdate)
if (Settings.CheckUpdate(Config.Head.CurrentVersion, Config.Head.LatestVersion))
ConsoleIO.WriteLineFormatted(Translations.TryGet("mcc.has_update", Settings.GithubLatestReleaseUrl));
if (latestVersion != Config.Head.LatestVersion)
{
Config.Head.LatestVersion = latestVersion;
WriteBackSettings(false);
}
}
}
}
catch (Exception) { }
finally { httpWebRequest?.Dispose(); }
httpClient.Dispose();
httpClientHandler.Dispose();
});
if (Config.Main.Advanced.ConsoleTitle != "")
{
InternalConfig.Username = "New Window";
Console.Title = Config.AppVar.ExpandVars(Config.Main.Advanced.ConsoleTitle);
}
//Test line to troubleshoot invisible colors
if (Settings.DebugMessages)
if (Config.Logging.DebugMessages)
{
ConsoleIO.WriteLineFormatted(Translations.Get("debug.color_test", "[0123456789ABCDEF]: [§00§11§22§33§44§55§66§77§88§99§aA§bB§cC§dD§eE§fF§r]"));
}
//Load cached sessions from disk if necessary
if (Settings.SessionCaching == CacheType.Disk)
if (Config.Main.Advanced.SessionCache == CacheType.disk)
{
bool cacheLoaded = SessionCache.InitializeDiskCache();
if (Settings.DebugMessages)
if (Config.Logging.DebugMessages)
Translations.WriteLineFormatted(cacheLoaded ? "debug.session_cache_ok" : "debug.session_cache_fail");
}
// Setup exit cleaning code
ExitCleanUp.Add(() => { DoExit(0); });
//Asking the user to type in missing data such as Username and Password
bool useBrowser = Settings.AccountType == ProtocolHandler.AccountType.Microsoft && Settings.LoginMethod == "browser";
if (Settings.Login == "" && !useBrowser)
bool useBrowser = Config.Main.General.AccountType == LoginType.microsoft && Config.Main.General.Method == LoginMethod.browser;
if (string.IsNullOrEmpty(Config.Main.General.Account.Login) && !useBrowser)
{
ConsoleIO.WriteLine(ConsoleIO.BasicIO ? Translations.Get("mcc.login_basic_io") : Translations.Get("mcc.login"));
Settings.Login = ConsoleIO.ReadLine();
Config.Main.General.Account.Login = ConsoleIO.ReadLine().Trim();
if (string.IsNullOrEmpty(Config.Main.General.Account.Login))
{
HandleFailure(Translations.Get("error.login.blocked"), false, ChatBot.DisconnectReason.LoginRejected);
return;
}
}
if (Settings.Password == ""
&& (Settings.SessionCaching == CacheType.None || !SessionCache.Contains(Settings.ToLowerIfNeed(Settings.Login)))
&& !useBrowser)
InternalConfig.Username = Config.Main.General.Account.Login;
if (string.IsNullOrEmpty(Config.Main.General.Account.Password) && !useBrowser &&
(Config.Main.Advanced.SessionCache == CacheType.none || !SessionCache.Contains(Settings.ToLowerIfNeed(Config.Main.General.Account.Login))))
{
RequestPassword();
}
// Setup exit cleaning code
ExitCleanUp.Add(delegate ()
else
{
// Do NOT use Program.Exit() as creating new Thread cause program to freeze
if (client != null) { client.Disconnect(); ConsoleIO.Reset(); }
if (offlinePrompt != null) { offlinePrompt.Item2.Cancel(); offlinePrompt = null; ConsoleIO.Reset(); }
if (Settings.playerHeadAsIcon) { ConsoleIcon.RevertToMCCIcon(); }
});
InternalConfig.Password = Config.Main.General.Account.Password;
}
startupargs = args;
InitializeClient();
@ -281,10 +398,10 @@ namespace MinecraftClient
/// </summary>
private static void RequestPassword()
{
ConsoleIO.WriteLine(ConsoleIO.BasicIO ? Translations.Get("mcc.password_basic_io", Settings.Login) + "\n" : Translations.Get("mcc.password"));
ConsoleIO.WriteLine(ConsoleIO.BasicIO ? Translations.Get("mcc.password_basic_io", Config.Main.General.Account.Login) + "\n" : Translations.Get("mcc.password"));
string? password = ConsoleIO.BasicIO ? Console.ReadLine() : ConsoleIO.ReadPassword();
if (password == null || password == string.Empty) { password = "-"; }
Settings.Password = password;
InternalConfig.Password = password;
}
/// <summary>
@ -292,23 +409,25 @@ namespace MinecraftClient
/// </summary>
private static void InitializeClient()
{
InternalConfig.MinecraftVersion = Config.Main.Advanced.MinecraftVersion;
SessionToken session = new();
PlayerKeyPair? playerKeyPair = null;
ProtocolHandler.LoginResult result = ProtocolHandler.LoginResult.LoginRequired;
string loginLower = Settings.ToLowerIfNeed(Settings.Login);
if (Settings.Password == "-")
string loginLower = Settings.ToLowerIfNeed(Config.Main.General.Account.Login);
if (InternalConfig.Password == "-")
{
Translations.WriteLineFormatted("mcc.offline");
result = ProtocolHandler.LoginResult.Success;
session.PlayerID = "0";
session.PlayerName = Settings.Login;
session.PlayerName = InternalConfig.Username;
}
else
{
// Validate cached session or login new session.
if (Settings.SessionCaching != CacheType.None && SessionCache.Contains(loginLower))
if (Config.Main.Advanced.SessionCache != CacheType.none && SessionCache.Contains(loginLower))
{
session = SessionCache.Get(loginLower);
result = ProtocolHandler.GetTokenValidation(session);
@ -330,8 +449,8 @@ namespace MinecraftClient
}
if (result != ProtocolHandler.LoginResult.Success
&& Settings.Password == ""
&& Settings.AccountType == ProtocolHandler.AccountType.Mojang)
&& InternalConfig.Password == ""
&& Config.Main.General.AccountType == LoginType.mojang)
RequestPassword();
}
else ConsoleIO.WriteLineFormatted(Translations.Get("mcc.session_valid", session.PlayerName));
@ -339,72 +458,42 @@ namespace MinecraftClient
if (result != ProtocolHandler.LoginResult.Success)
{
Translations.WriteLine("mcc.connecting", Settings.AccountType == ProtocolHandler.AccountType.Mojang ? "Minecraft.net" : "Microsoft");
result = ProtocolHandler.GetLogin(Settings.Login, Settings.Password, Settings.AccountType, out session);
Translations.WriteLine("mcc.connecting", Config.Main.General.AccountType == LoginType.mojang ? "Minecraft.net" : "Microsoft");
result = ProtocolHandler.GetLogin(Config.Main.General.Account.Login, InternalConfig.Password, Config.Main.General.AccountType, out session);
}
if (result == ProtocolHandler.LoginResult.Success && Config.Main.Advanced.SessionCache != CacheType.none)
SessionCache.Store(loginLower, session);
if (result == ProtocolHandler.LoginResult.Success)
session.SessionPreCheckTask = Task.Factory.StartNew(() => session.SessionPreCheck());
}
if (result == ProtocolHandler.LoginResult.Success && Settings.SessionCaching != CacheType.None)
SessionCache.Store(loginLower, session);
if (result == ProtocolHandler.LoginResult.Success)
session.SessionPreCheckTask = Task.Factory.StartNew(() => session.SessionPreCheck());
if (result == ProtocolHandler.LoginResult.Success)
{
if (Settings.AccountType == ProtocolHandler.AccountType.Microsoft && Settings.Password != "-" && Settings.LoginWithSecureProfile)
{
// Load cached profile key from disk if necessary
if (Settings.ProfileKeyCaching == CacheType.Disk)
{
bool cacheKeyLoaded = KeysCache.InitializeDiskCache();
if (Settings.DebugMessages)
Translations.WriteLineFormatted(cacheKeyLoaded ? "debug.keys_cache_ok" : "debug.keys_cache_fail");
}
if (Settings.ProfileKeyCaching != CacheType.None && KeysCache.Contains(loginLower))
{
playerKeyPair = KeysCache.Get(loginLower);
if (playerKeyPair.NeedRefresh())
Translations.WriteLineFormatted("mcc.profile_key_invalid");
else
ConsoleIO.WriteLineFormatted(Translations.Get("mcc.profile_key_valid", session.PlayerName));
}
if (playerKeyPair == null || playerKeyPair.NeedRefresh())
{
Translations.WriteLineFormatted("mcc.fetching_key");
playerKeyPair = KeyUtils.GetNewProfileKeys(session.ID);
if (Settings.ProfileKeyCaching != CacheType.None && playerKeyPair != null)
{
KeysCache.Store(loginLower, playerKeyPair);
}
}
}
Settings.Username = session.PlayerName;
InternalConfig.Username = session.PlayerName;
bool isRealms = false;
if (Settings.ConsoleTitle != "")
Console.Title = Settings.ExpandVars(Settings.ConsoleTitle);
if (Config.Main.Advanced.ConsoleTitle != "")
Console.Title = Config.AppVar.ExpandVars(Config.Main.Advanced.ConsoleTitle);
if (Settings.playerHeadAsIcon)
ConsoleIcon.SetPlayerIconAsync(Settings.Username);
if (Config.Main.Advanced.PlayerHeadAsIcon && OperatingSystem.IsWindows())
ConsoleIcon.SetPlayerIconAsync(InternalConfig.Username);
if (Settings.DebugMessages)
if (Config.Logging.DebugMessages)
Translations.WriteLine("debug.session_id", session.ID);
List<string> availableWorlds = new();
if (Settings.MinecraftRealmsEnabled && !String.IsNullOrEmpty(session.ID))
availableWorlds = ProtocolHandler.RealmsListWorlds(Settings.Username, session.PlayerID, session.ID);
if (Config.Main.Advanced.MinecraftRealms && !String.IsNullOrEmpty(session.ID))
availableWorlds = ProtocolHandler.RealmsListWorlds(InternalConfig.Username, session.PlayerID, session.ID);
if (Settings.ServerIP == "")
if (InternalConfig.ServerIP == string.Empty)
{
Translations.Write("mcc.ip");
string addressInput = ConsoleIO.ReadLine();
if (addressInput.StartsWith("realms:"))
{
if (Settings.MinecraftRealmsEnabled)
if (Config.Main.Advanced.MinecraftRealms)
{
if (availableWorlds.Count == 0)
{
@ -416,12 +505,12 @@ namespace MinecraftClient
worldId = availableWorlds[worldIndex];
if (availableWorlds.Contains(worldId))
{
string RealmsAddress = ProtocolHandler.GetRealmsWorldServerAddress(worldId, Settings.Username, session.PlayerID, session.ID);
string RealmsAddress = ProtocolHandler.GetRealmsWorldServerAddress(worldId, InternalConfig.Username, session.PlayerID, session.ID);
if (RealmsAddress != "")
{
addressInput = RealmsAddress;
isRealms = true;
Settings.ServerVersion = MCHighestVersion;
InternalConfig.MinecraftVersion = MCHighestVersion;
}
else
{
@ -441,45 +530,76 @@ namespace MinecraftClient
return;
}
}
Settings.SetServerIP(addressInput);
Config.Main.SetServerIP(new MainConfigHealper.MainConfig.ServerInfoConfig(addressInput), true);
}
//Get server version
int protocolversion = 0;
ForgeInfo? forgeInfo = null;
if (Settings.ServerVersion != "" && Settings.ToLowerIfNeed(Settings.ServerVersion) != "auto")
if (InternalConfig.MinecraftVersion != "" && Settings.ToLowerIfNeed(InternalConfig.MinecraftVersion) != "auto")
{
protocolversion = Protocol.ProtocolHandler.MCVer2ProtocolVersion(Settings.ServerVersion);
protocolversion = Protocol.ProtocolHandler.MCVer2ProtocolVersion(InternalConfig.MinecraftVersion);
if (protocolversion != 0)
{
ConsoleIO.WriteLineFormatted(Translations.Get("mcc.use_version", Settings.ServerVersion, protocolversion));
}
else ConsoleIO.WriteLineFormatted(Translations.Get("mcc.unknown_version", Settings.ServerVersion));
ConsoleIO.WriteLineFormatted(Translations.Get("mcc.use_version", InternalConfig.MinecraftVersion, protocolversion));
else
ConsoleIO.WriteLineFormatted(Translations.Get("mcc.unknown_version", InternalConfig.MinecraftVersion));
if (useMcVersionOnce)
{
useMcVersionOnce = false;
Settings.ServerVersion = "";
InternalConfig.MinecraftVersion = "";
}
}
//Retrieve server info if version is not manually set OR if need to retrieve Forge information
if (!isRealms && (protocolversion == 0 || Settings.ServerAutodetectForge || (Settings.ServerForceForge && !ProtocolHandler.ProtocolMayForceForge(protocolversion))))
if (!isRealms && (protocolversion == 0 || (Config.Main.Advanced.EnableForge == ForgeConfigType.auto) ||
((Config.Main.Advanced.EnableForge == ForgeConfigType.force) && !ProtocolHandler.ProtocolMayForceForge(protocolversion))))
{
if (protocolversion != 0)
Translations.WriteLine("mcc.forge");
else Translations.WriteLine("mcc.retrieve");
if (!ProtocolHandler.GetServerInfo(Settings.ServerIP, Settings.ServerPort, ref protocolversion, ref forgeInfo))
if (!ProtocolHandler.GetServerInfo(InternalConfig.ServerIP, InternalConfig.ServerPort, ref protocolversion, ref forgeInfo))
{
HandleFailure(Translations.Get("error.ping"), true, ChatBots.AutoRelog.DisconnectReason.ConnectionLost);
return;
}
}
if (Config.Main.General.AccountType == LoginType.microsoft && InternalConfig.Password != "-" &&
Config.Signature.LoginWithSecureProfile && protocolversion >= 759 /* 1.19 and above */)
{
// Load cached profile key from disk if necessary
if (Config.Main.Advanced.ProfileKeyCache == CacheType.disk)
{
bool cacheKeyLoaded = KeysCache.InitializeDiskCache();
if (Config.Logging.DebugMessages)
Translations.WriteLineFormatted(cacheKeyLoaded ? "debug.keys_cache_ok" : "debug.keys_cache_fail");
}
if (Config.Main.Advanced.ProfileKeyCache != CacheType.none && KeysCache.Contains(loginLower))
{
playerKeyPair = KeysCache.Get(loginLower);
if (playerKeyPair.NeedRefresh())
Translations.WriteLineFormatted("mcc.profile_key_invalid");
else
ConsoleIO.WriteLineFormatted(Translations.Get("mcc.profile_key_valid", session.PlayerName));
}
if (playerKeyPair == null || playerKeyPair.NeedRefresh())
{
Translations.WriteLineFormatted("mcc.fetching_key");
playerKeyPair = KeyUtils.GetNewProfileKeys(session.ID);
if (Config.Main.Advanced.ProfileKeyCache != CacheType.none && playerKeyPair != null)
{
KeysCache.Store(loginLower, playerKeyPair);
}
}
}
//Force-enable Forge support?
if (!isRealms && Settings.ServerForceForge && forgeInfo == null)
if (!isRealms && (Config.Main.Advanced.EnableForge == ForgeConfigType.force) && forgeInfo == null)
{
if (ProtocolHandler.ProtocolMayForceForge(protocolversion))
{
@ -499,12 +619,11 @@ namespace MinecraftClient
try
{
//Start the main TCP client
string? command = String.IsNullOrEmpty(Settings.SingleCommand) ? null : Settings.SingleCommand;
client = new McClient(session, playerKeyPair, Settings.ServerIP, Settings.ServerPort, protocolversion, forgeInfo, command);
client = new McClient(session, playerKeyPair, InternalConfig.ServerIP, InternalConfig.ServerPort, protocolversion, forgeInfo);
//Update console title
if (Settings.ConsoleTitle != "")
Console.Title = Settings.ExpandVars(Settings.ConsoleTitle);
if (Config.Main.Advanced.ConsoleTitle != "")
Console.Title = Config.AppVar.ExpandVars(Config.Main.Advanced.ConsoleTitle);
}
catch (NotSupportedException)
{
@ -542,8 +661,16 @@ namespace MinecraftClient
/// </summary>
public static void ReloadSettings()
{
if (settingsIniPath != null)
Settings.LoadFile(settingsIniPath);
if(Settings.LoadFromFile(settingsIniPath).Item1)
ConsoleIO.WriteLine(Translations.TryGet("config.loading", settingsIniPath));
}
/// <summary>
/// Write-back settings
/// </summary>
public static void WriteBackSettings(bool enableBackup = true)
{
Settings.WriteToFile(settingsIniPath, enableBackup);
}
/// <summary>
@ -563,22 +690,28 @@ namespace MinecraftClient
System.Threading.Thread.Sleep(delaySeconds * 1000);
}
Translations.WriteLine("mcc.restart");
ReloadSettings();
InitializeClient();
})).Start();
}
public static void DoExit(int exitcode = 0)
{
WriteBackSettings(true);
ConsoleIO.WriteLineFormatted(Translations.TryGet("config.saving", settingsIniPath));
if (client != null) { client.Disconnect(); ConsoleIO.Reset(); }
if (offlinePrompt != null) { offlinePrompt.Item2.Cancel(); offlinePrompt.Item1.Join(); offlinePrompt = null; ConsoleIO.Reset(); }
if (Config.Main.Advanced.PlayerHeadAsIcon) { ConsoleIcon.RevertToMCCIcon(); }
Environment.Exit(exitcode);
}
/// <summary>
/// Disconnect the current client from the server and exit the app
/// </summary>
public static void Exit(int exitcode = 0)
{
new Thread(new ThreadStart(delegate
{
if (client != null) { client.Disconnect(); ConsoleIO.Reset(); }
if (offlinePrompt != null) { offlinePrompt.Item2.Cancel(); offlinePrompt.Item1.Join(); offlinePrompt = null; ConsoleIO.Reset(); }
if (Settings.playerHeadAsIcon) { ConsoleIcon.RevertToMCCIcon(); }
Environment.Exit(exitcode);
})).Start();
new Thread(new ThreadStart(() => { DoExit(exitcode); })).Start();
}
/// <summary>
@ -595,7 +728,7 @@ namespace MinecraftClient
ConsoleIO.Reset();
while (Console.KeyAvailable)
Console.ReadKey(true);
Console.WriteLine(errorMessage);
ConsoleIO.WriteLine(errorMessage);
if (disconnectReason.HasValue)
{
@ -604,13 +737,13 @@ namespace MinecraftClient
}
}
if (Settings.interactiveMode)
if (InternalConfig.InteractiveMode)
{
if (versionError)
{
Translations.Write("mcc.server_version");
Settings.ServerVersion = ConsoleInteractive.ConsoleReader.RequestImmediateInput();
if (Settings.ServerVersion != "")
InternalConfig.MinecraftVersion = ConsoleInteractive.ConsoleReader.RequestImmediateInput();
if (InternalConfig.MinecraftVersion != "")
{
useMcVersionOnce = true;
Restart();
@ -627,7 +760,8 @@ namespace MinecraftClient
{
bool exitThread = false;
string command = " ";
ConsoleIO.WriteLineFormatted(Translations.Get("mcc.disconnected", (Settings.internalCmdChar == ' ' ? "" : "" + Settings.internalCmdChar)));
ConsoleIO.WriteLine(string.Empty);
ConsoleIO.WriteLineFormatted(Translations.Get("mcc.disconnected", Config.Main.Advanced.InternalCmdChar.ToLogString()));
Translations.WriteLineFormatted("mcc.press_exit");
while (!cancellationTokenSource.IsCancellationRequested)
@ -645,13 +779,13 @@ namespace MinecraftClient
{
string message = "";
if (Settings.internalCmdChar != ' '
&& command[0] == Settings.internalCmdChar)
if (Config.Main.Advanced.InternalCmdChar.ToChar() != ' '
&& command[0] == Config.Main.Advanced.InternalCmdChar.ToChar())
command = command[1..];
if (command.StartsWith("reco"))
{
message = new Commands.Reco().Run(null, Settings.ExpandVars(command), null);
message = new Commands.Reco().Run(null, Config.AppVar.ExpandVars(command), null);
if (message == "")
{
exitThread = true;
@ -660,7 +794,7 @@ namespace MinecraftClient
}
else if (command.StartsWith("connect"))
{
message = new Commands.Connect().Run(null, Settings.ExpandVars(command), null);
message = new Commands.Connect().Run(null, Config.AppVar.ExpandVars(command), null);
if (message == "")
{
exitThread = true;
@ -669,31 +803,26 @@ namespace MinecraftClient
}
else if (command.StartsWith("exit") || command.StartsWith("quit"))
{
message = new Commands.Exit().Run(null, Settings.ExpandVars(command), null);
message = new Commands.Exit().Run(null, Config.AppVar.ExpandVars(command), null);
}
else if (command.StartsWith("help"))
{
ConsoleIO.WriteLineFormatted("§8MCC: " +
(Settings.internalCmdChar == ' '
? ""
: "" + Settings.internalCmdChar) +
Config.Main.Advanced.InternalCmdChar.ToLogString() +
new Commands.Reco().GetCmdDescTranslated());
ConsoleIO.WriteLineFormatted("§8MCC: " +
(Settings.internalCmdChar == ' '
? ""
: "" + Settings.internalCmdChar) +
Config.Main.Advanced.InternalCmdChar.ToLogString() +
new Commands.Connect().GetCmdDescTranslated());
}
else
ConsoleIO.WriteLineFormatted(Translations.Get("icmd.unknown",
command.Split(' ')[0]));
ConsoleIO.WriteLineFormatted(Translations.Get("icmd.unknown", command.Split(' ')[0]));
if (message != "")
ConsoleIO.WriteLineFormatted("§8MCC: " + message);
}
else
{
_ = new Commands.Exit().Run(null, Settings.ExpandVars(command), null);
_ = new Commands.Exit().Run(null, Config.AppVar.ExpandVars(command), null);
}
}
@ -732,6 +861,15 @@ namespace MinecraftClient
return assembly.GetTypes().Where(t => String.Equals(t.Namespace, nameSpace, StringComparison.Ordinal)).ToArray();
}
public static void InitCulture()
{
CultureInfo culture = CultureInfo.CreateSpecificCulture("en-US");
CultureInfo.DefaultThreadCurrentCulture = culture;
CultureInfo.DefaultThreadCurrentUICulture = culture;
Thread.CurrentThread.CurrentCulture = culture;
Thread.CurrentThread.CurrentUICulture = culture;
}
/// <summary>
/// Static initialization of build information, read from assembly information
/// </summary>

View file

@ -61,7 +61,7 @@ namespace MinecraftClient.Protocol.Handlers.PacketPalettes
}
else if (forgeEnabled)
{
if (Settings.DebugMessages)
if (Settings.Config.Logging.DebugMessages)
ConsoleIO.WriteLogLine("Ignoring unknown packet ID of 0x" + packetId.ToString("X2"));
return PacketTypesIn.Unknown;
}
@ -92,7 +92,7 @@ namespace MinecraftClient.Protocol.Handlers.PacketPalettes
}
else if (forgeEnabled)
{
if (Settings.DebugMessages)
if (Settings.Config.Logging.DebugMessages)
ConsoleIO.WriteLogLine("Ignoring unknown packet ID of 0x" + packetId.ToString("X2"));
return PacketTypesOut.Unknown;
}

View file

@ -13,6 +13,7 @@ using MinecraftClient.Protocol.Keys;
using MinecraftClient.Protocol.Message;
using MinecraftClient.Protocol.Session;
using MinecraftClient.Proxy;
using static MinecraftClient.Settings;
namespace MinecraftClient.Protocol.Handlers
{
@ -494,7 +495,7 @@ namespace MinecraftClient.Protocol.Handlers
if (serverID == "-")
Translations.WriteLineFormatted("mcc.server_offline");
else if (Settings.DebugMessages)
else if (Settings.Config.Logging.DebugMessages)
ConsoleIO.WriteLineFormatted(Translations.Get("mcc.handshake", serverID));
return StartEncryption(uuid, username, sessionID, token, serverID, PublicServerkey, session);
@ -511,7 +512,7 @@ namespace MinecraftClient.Protocol.Handlers
RSACryptoServiceProvider RSAService = CryptoHandler.DecodeRSAPublicKey(serverPublicKey)!;
byte[] secretKey = CryptoHandler.ClientAESPrivateKey ?? CryptoHandler.GenerateAESPrivateKey();
if (Settings.DebugMessages)
if (Settings.Config.Logging.DebugMessages)
Translations.WriteLineFormatted("debug.crypto");
if (serverIDhash != "-")
@ -534,7 +535,7 @@ namespace MinecraftClient.Protocol.Handlers
{
session.ServerIDhash = serverIDhash;
session.ServerPublicKey = serverPublicKey;
SessionCache.Store(Settings.Login.ToLower(), session);
SessionCache.Store(Config.Main.General.Account.Login.ToLower(), session);
}
else
{
@ -862,7 +863,7 @@ namespace MinecraftClient.Protocol.Handlers
Protocol16Handler ComTmp = new(tcp);
string result = ComTmp.ReadNextString();
if (Settings.DebugMessages)
if (Settings.Config.Logging.DebugMessages)
{
// May contain formatting codes, cannot use WriteLineFormatted
Console.ForegroundColor = ConsoleColor.DarkGray;

View file

@ -22,6 +22,7 @@ using MinecraftClient.Protocol.Keys;
using MinecraftClient.Protocol.Message;
using MinecraftClient.Protocol.Session;
using MinecraftClient.Proxy;
using static MinecraftClient.Settings;
namespace MinecraftClient.Protocol.Handlers
{
@ -242,6 +243,7 @@ namespace MinecraftClient.Protocol.Handlers
}
catch (ObjectDisposedException) { }
catch (OperationCanceledException) { }
catch (NullReferenceException) { }
if (cancelToken.IsCancellationRequested)
return;
@ -461,8 +463,8 @@ namespace MinecraftClient.Protocol.Handlers
{
//Hide system messages or xp bar messages?
messageType = dataTypes.ReadNextByte(packetData);
if ((messageType == 1 && !Settings.DisplaySystemMessages)
|| (messageType == 2 && !Settings.DisplayXPBarMessages))
if ((messageType == 1 && !Config.Main.Advanced.ShowSystemMessages)
|| (messageType == 2 && !Config.Main.Advanced.ShowSystemMessages))
break;
if (protocolVersion >= MC_1_16_5_Version)
@ -482,8 +484,8 @@ namespace MinecraftClient.Protocol.Handlers
string? unsignedChatContent = hasUnsignedChatContent ? dataTypes.ReadNextString(packetData) : null;
messageType = dataTypes.ReadNextVarInt(packetData);
if ((messageType == 1 && !Settings.DisplaySystemMessages)
|| (messageType == 2 && !Settings.DisplayXPBarMessages))
if ((messageType == 1 && !Config.Main.Advanced.ShowSystemMessages)
|| (messageType == 2 && !Config.Main.Advanced.ShowXPBarMessages))
break;
Guid senderUUID = dataTypes.ReadNextUUID(packetData);
@ -974,18 +976,20 @@ namespace MinecraftClient.Protocol.Handlers
int blocksSize = dataTypes.ReadNextVarInt(packetData);
for (int i = 0; i < blocksSize; i++)
{
ulong block = (ulong)dataTypes.ReadNextVarLong(packetData);
int blockId = (int)(block >> 12);
int localX = (int)((block >> 8) & 0x0F);
int localZ = (int)((block >> 4) & 0x0F);
int localY = (int)(block & 0x0F);
ulong chunkSectionPosition = (ulong)dataTypes.ReadNextVarLong(packetData);
int blockId = (int)(chunkSectionPosition >> 12);
int localX = (int)((chunkSectionPosition >> 8) & 0x0F);
int localZ = (int)((chunkSectionPosition >> 4) & 0x0F);
int localY = (int)(chunkSectionPosition & 0x0F);
Block b = new((ushort)blockId);
Block block = new((ushort)blockId);
int blockX = (sectionX * 16) + localX;
int blockY = (sectionY * 16) + localY;
int blockZ = (sectionZ * 16) + localZ;
var l = new Location(blockX, blockY, blockZ);
handler.GetWorld().SetBlock(l, b);
Location location = new(blockX, blockY, blockZ);
handler.OnBlockChange(location, block);
}
}
else
@ -1017,8 +1021,10 @@ namespace MinecraftClient.Protocol.Handlers
int blockX = locationXZ >> 4;
int blockZ = locationXZ & 0x0F;
Location location = new(chunkX, chunkZ, blockX, blockY, blockZ);
Block block = new(blockIdMeta);
handler.GetWorld().SetBlock(new Location(chunkX, chunkZ, blockX, blockY, blockZ), block);
handler.OnBlockChange(location, block);
}
}
}
@ -1048,11 +1054,16 @@ namespace MinecraftClient.Protocol.Handlers
int blockZ = dataTypes.ReadNextInt(packetData);
short blockId = (short)dataTypes.ReadNextVarInt(packetData);
byte blockMeta = dataTypes.ReadNextByte(packetData);
handler.GetWorld().SetBlock(new Location(blockX, blockY, blockZ), new Block(blockId, blockMeta));
Location location = new(blockX, blockY, blockZ);
Block block = new(blockId, blockMeta);
handler.OnBlockChange(location, block);
}
else
{
handler.GetWorld().SetBlock(dataTypes.ReadNextLocation(packetData), new Block((ushort)dataTypes.ReadNextVarInt(packetData)));
Location location = dataTypes.ReadNextLocation(packetData);
Block block = new((ushort)dataTypes.ReadNextVarInt(packetData));
handler.OnBlockChange(location, block);
}
}
break;
@ -1603,7 +1614,7 @@ namespace MinecraftClient.Protocol.Handlers
case PacketTypesIn.SystemChat:
string systemMessage = dataTypes.ReadNextString(packetData);
int msgType = dataTypes.ReadNextVarInt(packetData);
if ((msgType == 1 && !Settings.DisplaySystemMessages))
if ((msgType == 1 && !Config.Main.Advanced.ShowSystemMessages))
break;
handler.OnTextReceived(new(systemMessage, true, msgType, Guid.Empty, true));
break;
@ -1925,7 +1936,7 @@ namespace MinecraftClient.Protocol.Handlers
{
session.ServerIDhash = serverIDhash;
session.ServerPublicKey = serverPublicKey;
SessionCache.Store(Settings.Login.ToLower(), session);
SessionCache.Store(Config.Main.General.Account.Login.ToLower(), session);
}
else
{
@ -2119,7 +2130,7 @@ namespace MinecraftClient.Protocol.Handlers
{
string result = dataTypes.ReadNextString(packetData); //Get the Json data
if (Settings.DebugMessages)
if (Config.Logging.DebugMessages)
{
// May contain formatting codes, cannot use WriteLineFormatted
Console.ForegroundColor = ConsoleColor.DarkGray;
@ -2230,7 +2241,7 @@ namespace MinecraftClient.Protocol.Handlers
/// <returns> List< Argument Name, Argument Value > </returns>
private List<Tuple<string, string>>? CollectCommandArguments(string command)
{
if (!isOnlineMode || !Settings.SignMessageInCommand)
if (!isOnlineMode || !Config.Signature.SignMessageInCommand)
return null;
List<Tuple<string, string>> needSigned = new();
@ -2371,7 +2382,7 @@ namespace MinecraftClient.Protocol.Handlers
DateTimeOffset timeNow = DateTimeOffset.UtcNow;
fields.AddRange(dataTypes.GetLong(timeNow.ToUnixTimeMilliseconds()));
if (!isOnlineMode || playerKeyPair == null || !Settings.SignChat)
if (!isOnlineMode || playerKeyPair == null || !Config.Signature.SignChat)
{
fields.AddRange(dataTypes.GetLong(0)); // Salt: Long
fields.AddRange(dataTypes.GetVarInt(0)); // Signature Length: VarInt

View file

@ -130,7 +130,7 @@ namespace MinecraftClient.Protocol.Handlers
byte fmlProtocolVersion = dataTypes.ReadNextByte(packetData);
if (Settings.DebugMessages)
if (Settings.Config.Logging.DebugMessages)
ConsoleIO.WriteLineFormatted(Translations.Get("forge.version", fmlProtocolVersion));
if (fmlProtocolVersion >= 1)
@ -140,7 +140,7 @@ namespace MinecraftClient.Protocol.Handlers
SendForgeHandshakePacket(FMLHandshakeDiscriminator.ClientHello, new byte[] { fmlProtocolVersion });
// Then tell the server that we're running the same mods.
if (Settings.DebugMessages)
if (Settings.Config.Logging.DebugMessages)
Translations.WriteLineFormatted("forge.send_mod");
byte[][] mods = new byte[forgeInfo.Mods.Count][];
for (int i = 0; i < forgeInfo.Mods.Count; i++)
@ -160,7 +160,7 @@ namespace MinecraftClient.Protocol.Handlers
Thread.Sleep(2000);
if (Settings.DebugMessages)
if (Settings.Config.Logging.DebugMessages)
Translations.WriteLineFormatted("forge.accept");
// Tell the server that yes, we are OK with the mods it has
// even though we don't actually care what mods it has.
@ -182,7 +182,7 @@ namespace MinecraftClient.Protocol.Handlers
// with blocks and items.
int registrySize = dataTypes.ReadNextVarInt(packetData);
if (Settings.DebugMessages)
if (Settings.Config.Logging.DebugMessages)
ConsoleIO.WriteLineFormatted(Translations.Get("forge.registry", registrySize));
fmlHandshakeState = FMLHandshakeClientState.PENDINGCOMPLETE;
@ -194,7 +194,7 @@ namespace MinecraftClient.Protocol.Handlers
bool hasNextRegistry = dataTypes.ReadNextBool(packetData);
string registryName = dataTypes.ReadNextString(packetData);
int registrySize = dataTypes.ReadNextVarInt(packetData);
if (Settings.DebugMessages)
if (Settings.Config.Logging.DebugMessages)
ConsoleIO.WriteLineFormatted(Translations.Get("forge.registry_2", registryName, registrySize));
if (!hasNextRegistry)
fmlHandshakeState = FMLHandshakeClientState.PENDINGCOMPLETE;
@ -206,7 +206,7 @@ namespace MinecraftClient.Protocol.Handlers
// Just say yes.
if (discriminator != FMLHandshakeDiscriminator.HandshakeAck)
return false;
if (Settings.DebugMessages)
if (Settings.Config.Logging.DebugMessages)
Translations.WriteLineFormatted("forge.accept_registry");
SendForgeHandshakePacket(FMLHandshakeDiscriminator.HandshakeAck,
new byte[] { (byte)FMLHandshakeClientState.PENDINGCOMPLETE });
@ -220,7 +220,7 @@ namespace MinecraftClient.Protocol.Handlers
SendForgeHandshakePacket(FMLHandshakeDiscriminator.HandshakeAck,
new byte[] { (byte)FMLHandshakeClientState.COMPLETE });
if (Settings.DebugMessages)
if (Settings.Config.Logging.DebugMessages)
Translations.WriteLine("forge.complete");
fmlHandshakeState = FMLHandshakeClientState.DONE;
return true;
@ -300,7 +300,7 @@ namespace MinecraftClient.Protocol.Handlers
//
// [1]: Version is usually set to "FML2" for FML stuff and "1" for mods
if (Settings.DebugMessages)
if (Settings.Config.Logging.DebugMessages)
Translations.WriteLineFormatted("forge.fml2.mod");
List<string> mods = new();
@ -332,7 +332,7 @@ namespace MinecraftClient.Protocol.Handlers
// We are supposed to validate server info against our set of installed mods, then reply with our list
// In MCC, we just want to send a valid response so we'll reply back with data collected from the server.
if (Settings.DebugMessages)
if (Settings.Config.Logging.DebugMessages)
Translations.WriteLineFormatted("forge.fml2.mod_send");
// Packet ID 2: Client to Server Mod List
@ -368,7 +368,7 @@ namespace MinecraftClient.Protocol.Handlers
// Registry Snapshot: ForgeRegistry.java > Snapshot > read(PacketBuffer)
// Not documented yet. We're ignoring this packet in MCC
if (Settings.DebugMessages)
if (Settings.Config.Logging.DebugMessages)
{
string registryName = dataTypes.ReadNextString(packetData);
ConsoleIO.WriteLineFormatted(Translations.Get("forge.fml2.registry", registryName));
@ -387,7 +387,7 @@ namespace MinecraftClient.Protocol.Handlers
// [1] Config data may containt a standard Minecraft string readable with dataTypes.readNextString()
// We're ignoring this packet in MCC
if (Settings.DebugMessages)
if (Settings.Config.Logging.DebugMessages)
{
string configName = dataTypes.ReadNextString(packetData);
ConsoleIO.WriteLineFormatted(Translations.Get("forge.fml2.config", configName));
@ -398,7 +398,7 @@ namespace MinecraftClient.Protocol.Handlers
break;
default:
if (Settings.DebugMessages)
if (Settings.Config.Logging.DebugMessages)
ConsoleIO.WriteLineFormatted(Translations.Get("forge.fml2.unknown", packetID));
break;
}
@ -413,7 +413,7 @@ namespace MinecraftClient.Protocol.Handlers
return true;
}
}
else if (Settings.DebugMessages)
else if (Settings.Config.Logging.DebugMessages)
{
ConsoleIO.WriteLineFormatted(Translations.Get("forge.fml2.unknown_channel", fmlChannel));
}
@ -505,7 +505,7 @@ namespace MinecraftClient.Protocol.Handlers
if (forgeInfo.Mods.Any())
{
ConsoleIO.WriteLineFormatted(Translations.Get("forge.with_mod", forgeInfo.Mods.Count));
if (Settings.DebugMessages)
if (Settings.Config.Logging.DebugMessages)
{
Translations.WriteLineFormatted("forge.mod_list");
foreach (ForgeInfo.ForgeMod mod in forgeInfo.Mods)

View file

@ -432,5 +432,12 @@ namespace MinecraftClient.Protocol
/// <param name="reason">Event type</param>
/// <param name="value">Depends on Reason</param>
public void OnGameEvent(byte reason, float value);
/// <summary>
/// Called when a block is changed.
/// </summary>
/// <param name="location">The location of the block.</param>
/// <param name="block">The block</param>
public void OnBlockChange(Location location, Block block);
}
}

View file

@ -5,13 +5,13 @@ using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using MinecraftClient.Protocol.Message;
using static MinecraftClient.Settings;
namespace MinecraftClient.Protocol
{
/// <summary>
/// This class parses JSON chat data from MC 1.6+ and returns the appropriate string to be printed.
/// </summary>
static class ChatParser
{
public enum MessageType
@ -47,7 +47,7 @@ namespace MinecraftClient.Protocol
/// <returns>Returns the translated text</returns>
public static string ParseSignedChat(ChatMessage message, List<string>? links = null)
{
string chatContent = Settings.ShowModifiedChat && message.unsignedContent != null ? message.unsignedContent : message.content;
string chatContent = Config.Signature.ShowModifiedChat && message.unsignedContent != null ? message.unsignedContent : message.content;
string content = message.isJson ? ParseText(chatContent, links) : chatContent;
string sender = message.displayName!;
@ -107,27 +107,27 @@ namespace MinecraftClient.Protocol
string color = string.Empty;
if (message.isSystemChat)
{
if (Settings.MarkSystemMessage)
if (Config.Signature.MarkSystemMessage)
color = "§z §r "; // Custom color code §z : Background Gray
}
else
{
if ((bool)message.isSignatureLegal!)
{
if (Settings.ShowModifiedChat && message.unsignedContent != null)
if (Config.Signature.ShowModifiedChat && message.unsignedContent != null)
{
if (Settings.MarkModifiedMsg)
if (Config.Signature.MarkModifiedMsg)
color = "§x §r "; // Custom color code §x : Background Yellow
}
else
{
if (Settings.MarkLegallySignedMsg)
if (Config.Signature.MarkLegallySignedMsg)
color = "§y §r "; // Custom color code §y : Background Green
}
}
else
{
if (Settings.MarkIllegallySignedMsg)
if (Config.Signature.MarkIllegallySignedMsg)
color = "§w §r "; // Custom color code §w : Background Red
}
}
@ -203,12 +203,12 @@ namespace MinecraftClient.Protocol
if (!Directory.Exists("lang"))
Directory.CreateDirectory("lang");
string Language_File = "lang" + Path.DirectorySeparatorChar + Settings.Language + ".lang";
string Language_File = "lang" + Path.DirectorySeparatorChar + Config.Main.Advanced.Language + ".lang";
//File not found? Try downloading language file from Mojang's servers?
if (!File.Exists(Language_File))
{
ConsoleIO.WriteLineFormatted(Translations.Get("chat.download", Settings.Language));
ConsoleIO.WriteLineFormatted(Translations.Get("chat.download", Config.Main.Advanced.Language));
HttpClient httpClient = new();
try
{
@ -217,11 +217,11 @@ namespace MinecraftClient.Protocol
string assets_index = fetch_index.Result;
fetch_index.Dispose();
string[] tmp = assets_index.Split(new string[] { "minecraft/lang/" + Settings.Language.ToLower() + ".json" }, StringSplitOptions.None);
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
string translation_file_location = Settings.TranslationsFile_Website_Download + '/' + hash[..2] + '/' + hash;
if (Settings.DebugMessages)
if (Settings.Config.Logging.DebugMessages)
ConsoleIO.WriteLineFormatted(Translations.Get("chat.request", translation_file_location));
Task<string> fetch_file = httpClient.GetStringAsync(translation_file_location);
@ -266,7 +266,7 @@ namespace MinecraftClient.Protocol
}
}
if (Settings.DebugMessages)
if (Settings.Config.Logging.DebugMessages)
Translations.WriteLineFormatted("chat.loaded");
}
else //No external dictionnary found.

View file

@ -6,6 +6,8 @@ using System.Globalization;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
using static MinecraftClient.Settings;
using static MinecraftClient.Settings.MainConfigHealper.MainConfig.GeneralConfig;
namespace MinecraftClient.Protocol
{
@ -204,7 +206,7 @@ namespace MinecraftClient.Protocol
var response = request.Post("application/x-www-form-urlencoded", postData);
if (Settings.DebugMessages)
if (Settings.Config.Logging.DebugMessages)
{
ConsoleIO.WriteLine(response.ToString());
}
@ -271,7 +273,7 @@ namespace MinecraftClient.Protocol
request.Headers.Add("x-xbl-contract-version", "0");
var accessToken = loginResponse.AccessToken;
if (Settings.LoginMethod == "browser")
if (Config.Main.General.Method == LoginMethod.browser)
{
// Our own client ID must have d= in front of the token or HTTP status 400
// "Stolen" client ID must not have d= in front of the token or HTTP status 400
@ -288,7 +290,7 @@ namespace MinecraftClient.Protocol
+ "\"TokenType\": \"JWT\""
+ "}";
var response = request.Post("application/json", payload);
if (Settings.DebugMessages)
if (Settings.Config.Logging.DebugMessages)
{
ConsoleIO.WriteLine(response.ToString());
}
@ -338,7 +340,7 @@ namespace MinecraftClient.Protocol
+ "\"TokenType\": \"JWT\""
+ "}";
var response = request.Post("application/json", payload);
if (Settings.DebugMessages)
if (Settings.Config.Logging.DebugMessages)
{
ConsoleIO.WriteLine(response.ToString());
}
@ -418,7 +420,7 @@ namespace MinecraftClient.Protocol
string payload = "{\"identityToken\": \"XBL3.0 x=" + userHash + ";" + xstsToken + "\"}";
var response = request.Post("application/json", payload);
if (Settings.DebugMessages)
if (Settings.Config.Logging.DebugMessages)
{
ConsoleIO.WriteLine(response.ToString());
}
@ -440,7 +442,7 @@ namespace MinecraftClient.Protocol
request.Headers.Add("Authorization", string.Format("Bearer {0}", accessToken));
var response = request.Get();
if (Settings.DebugMessages)
if (Settings.Config.Logging.DebugMessages)
{
ConsoleIO.WriteLine(response.ToString());
}
@ -456,7 +458,7 @@ namespace MinecraftClient.Protocol
request.Headers.Add("Authorization", string.Format("Bearer {0}", accessToken));
var response = request.Get();
if (Settings.DebugMessages)
if (Settings.Config.Logging.DebugMessages)
{
ConsoleIO.WriteLine(response.ToString());
}

View file

@ -25,7 +25,7 @@ namespace MinecraftClient.Protocol.Keys
response = request.Post("application/json", "");
if (Settings.DebugMessages)
if (Settings.Config.Logging.DebugMessages)
{
ConsoleIO.WriteLine(response.Body.ToString());
}
@ -47,7 +47,7 @@ namespace MinecraftClient.Protocol.Keys
{
int code = (response == null) ? 0 : response.StatusCode;
ConsoleIO.WriteLineFormatted("§cFetch profile key failed: HttpCode = " + code + ", Error = " + e.Message);
if (Settings.DebugMessages)
if (Settings.Config.Logging.DebugMessages)
{
ConsoleIO.WriteLineFormatted("§c" + e.StackTrace);
}

View file

@ -3,7 +3,8 @@ using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Timers;
using MinecraftClient.Protocol.Session;
using static MinecraftClient.Settings;
using static MinecraftClient.Settings.MainConfigHealper.MainConfig.AdvancedConfig;
namespace MinecraftClient.Protocol.Keys
{
@ -46,11 +47,11 @@ namespace MinecraftClient.Protocol.Keys
keys.Add(login, playerKeyPair);
}
if (Settings.ProfileKeyCaching == CacheType.Disk && updatetimer.Enabled == true)
if (Config.Main.Advanced.ProfileKeyCache == CacheType.disk && updatetimer.Enabled == true)
{
pendingadds.Add(new KeyValuePair<string, PlayerKeyPair>(login, playerKeyPair));
}
else if (Settings.ProfileKeyCaching == CacheType.Disk)
else if (Config.Main.Advanced.ProfileKeyCache == CacheType.disk)
{
SaveToDisk();
}
@ -114,7 +115,7 @@ namespace MinecraftClient.Protocol.Keys
//User-editable keys cache file in text format
if (File.Exists(KeysCacheFilePlaintext))
{
if (Settings.DebugMessages)
if (Settings.Config.Logging.DebugMessages)
ConsoleIO.WriteLineFormatted(Translations.Get("cache.loading_keys", KeysCacheFilePlaintext));
try
@ -133,27 +134,27 @@ namespace MinecraftClient.Protocol.Keys
{
PlayerKeyPair playerKeyPair = PlayerKeyPair.FromString(value);
keys[login] = playerKeyPair;
if (Settings.DebugMessages)
if (Settings.Config.Logging.DebugMessages)
ConsoleIO.WriteLineFormatted(Translations.Get("cache.loaded_keys", playerKeyPair.ExpiresAt.ToString()));
}
catch (InvalidDataException e)
{
if (Settings.DebugMessages)
if (Settings.Config.Logging.DebugMessages)
ConsoleIO.WriteLineFormatted(Translations.Get("cache.ignore_string_keys", value, e.Message));
}
catch (FormatException e)
{
if (Settings.DebugMessages)
if (Settings.Config.Logging.DebugMessages)
ConsoleIO.WriteLineFormatted(Translations.Get("cache.ignore_string_keys", value, e.Message));
}
catch (ArgumentNullException e)
{
if (Settings.DebugMessages)
if (Settings.Config.Logging.DebugMessages)
ConsoleIO.WriteLineFormatted(Translations.Get("cache.ignore_string_keys", value, e.Message));
}
}
else if (Settings.DebugMessages)
else if (Settings.Config.Logging.DebugMessages)
{
ConsoleIO.WriteLineFormatted(Translations.Get("cache.ignore_line_keys", line));
}
@ -174,7 +175,7 @@ namespace MinecraftClient.Protocol.Keys
/// </summary>
private static void SaveToDisk()
{
if (Settings.DebugMessages)
if (Config.Logging.DebugMessages)
Translations.WriteLineFormatted("cache.saving_keys");
List<string> KeysCacheLines = new()

View file

@ -11,6 +11,8 @@ using MinecraftClient.Protocol.Handlers;
using MinecraftClient.Protocol.Handlers.Forge;
using MinecraftClient.Protocol.Session;
using MinecraftClient.Proxy;
using static MinecraftClient.Settings;
using static MinecraftClient.Settings.MainConfigHealper.MainConfig.GeneralConfig;
namespace MinecraftClient.Protocol
{
@ -64,7 +66,7 @@ namespace MinecraftClient.Protocol
{
ConsoleIO.WriteLineFormatted(Translations.Get("mcc.not_found", domainVal, e.GetType().FullName, e.Message));
}
}, TimeSpan.FromSeconds(Settings.ResolveSrvRecordsShortTimeout ? 10 : 30));
}, TimeSpan.FromSeconds(Config.Main.Advanced.ResolveSrvRecords == MainConfigHealper.MainConfig.AdvancedConfig.ResolveSrvRecordType.fast ? 10 : 30));
}
domain = domainVal;
@ -99,7 +101,7 @@ namespace MinecraftClient.Protocol
{
ConsoleIO.WriteLineFormatted(String.Format("§8{0}: {1}", e.GetType().FullName, e.Message));
}
}, TimeSpan.FromSeconds(Settings.ResolveSrvRecordsShortTimeout ? 10 : 30)))
}, TimeSpan.FromSeconds(Config.Main.Advanced.ResolveSrvRecords == MainConfigHealper.MainConfig.AdvancedConfig.ResolveSrvRecordType.fast ? 10 : 30)))
{
if (protocolversion != 0 && protocolversion != protocolversionTmp)
Translations.WriteLineFormatted("error.version_different");
@ -420,16 +422,16 @@ namespace MinecraftClient.Protocol
/// <param name="pass">Password</param>
/// <param name="session">In case of successful login, will contain session information for multiplayer</param>
/// <returns>Returns the status of the login (Success, Failure, etc.)</returns>
public static LoginResult GetLogin(string user, string pass, AccountType type, out SessionToken session)
public static LoginResult GetLogin(string user, string pass, LoginType type, out SessionToken session)
{
if (type == AccountType.Microsoft)
if (type == LoginType.microsoft)
{
if (Settings.LoginMethod == "mcc")
if (Config.Main.General.Method == LoginMethod.mcc)
return MicrosoftMCCLogin(user, pass, out session);
else
return MicrosoftBrowserLogin(out session, user);
}
else if (type == AccountType.Mojang)
else if (type == LoginType.mojang)
{
return MojangLogin(user, pass, out session);
}
@ -494,7 +496,7 @@ namespace MinecraftClient.Protocol
}
catch (System.Security.Authentication.AuthenticationException e)
{
if (Settings.DebugMessages)
if (Settings.Config.Logging.DebugMessages)
{
ConsoleIO.WriteLineFormatted("§8" + e.ToString());
}
@ -502,7 +504,7 @@ namespace MinecraftClient.Protocol
}
catch (System.IO.IOException e)
{
if (Settings.DebugMessages)
if (Settings.Config.Logging.DebugMessages)
{
ConsoleIO.WriteLineFormatted("§8" + e.ToString());
}
@ -514,7 +516,7 @@ namespace MinecraftClient.Protocol
}
catch (Exception e)
{
if (Settings.DebugMessages)
if (Settings.Config.Logging.DebugMessages)
{
ConsoleIO.WriteLineFormatted("§8" + e.ToString());
}
@ -543,7 +545,7 @@ namespace MinecraftClient.Protocol
{
session = new SessionToken() { ClientID = Guid.NewGuid().ToString().Replace("-", "") };
ConsoleIO.WriteLineFormatted("§cMicrosoft authenticate failed: " + e.Message);
if (Settings.DebugMessages)
if (Settings.Config.Logging.DebugMessages)
{
ConsoleIO.WriteLineFormatted("§c" + e.StackTrace);
}
@ -601,7 +603,7 @@ namespace MinecraftClient.Protocol
session.PlayerID = profile.UUID;
session.ID = accessToken;
session.RefreshToken = msaResponse.RefreshToken;
Settings.Login = msaResponse.Email;
Config.Main.General.Account.Login = msaResponse.Email;
return LoginResult.Success;
}
else
@ -612,7 +614,7 @@ namespace MinecraftClient.Protocol
catch (Exception e)
{
ConsoleIO.WriteLineFormatted("§cMicrosoft authenticate failed: " + e.Message);
if (Settings.DebugMessages)
if (Settings.Config.Logging.DebugMessages)
{
ConsoleIO.WriteLineFormatted("§c" + e.StackTrace);
}
@ -632,7 +634,7 @@ namespace MinecraftClient.Protocol
var expTimestamp = long.Parse(json.Properties["exp"].StringValue, NumberStyles.Any, CultureInfo.CurrentCulture);
var now = DateTime.Now;
var tokenExp = UnixTimeStampToDateTime(expTimestamp);
if (Settings.DebugMessages)
if (Settings.Config.Logging.DebugMessages)
{
ConsoleIO.WriteLine("Access token expiration time is " + tokenExp.ToString());
}
@ -772,7 +774,7 @@ namespace MinecraftClient.Protocol
catch (Exception e)
{
ConsoleIO.WriteLineFormatted("§8" + e.GetType().ToString() + ": " + e.Message);
if (Settings.DebugMessages)
if (Settings.Config.Logging.DebugMessages)
{
ConsoleIO.WriteLineFormatted("§8" + e.StackTrace);
}
@ -815,7 +817,7 @@ namespace MinecraftClient.Protocol
catch (Exception e)
{
ConsoleIO.WriteLineFormatted("§8" + e.GetType().ToString() + ": " + e.Message);
if (Settings.DebugMessages)
if (Settings.Config.Logging.DebugMessages)
{
ConsoleIO.WriteLineFormatted("§8" + e.StackTrace);
}
@ -890,14 +892,14 @@ namespace MinecraftClient.Protocol
{
try
{
if (Settings.DebugMessages)
if (Settings.Config.Logging.DebugMessages)
ConsoleIO.WriteLineFormatted(Translations.Get("debug.request", host));
TcpClient client = ProxyHandler.NewTcpClient(host, 443, true);
SslStream stream = new(client.GetStream());
stream.AuthenticateAsClient(host, null, SslProtocols.Tls12, true); // Enable TLS 1.2. Hotfix for #1780
if (Settings.DebugMessages)
if (Settings.Config.Logging.DebugMessages)
foreach (string line in headers)
ConsoleIO.WriteLineFormatted("§8> " + line);
@ -905,7 +907,7 @@ namespace MinecraftClient.Protocol
System.IO.StreamReader sr = new(stream);
string raw_result = sr.ReadToEnd();
if (Settings.DebugMessages)
if (Settings.Config.Logging.DebugMessages)
{
ConsoleIO.WriteLine("");
foreach (string line in raw_result.Split('\n'))
@ -915,7 +917,7 @@ namespace MinecraftClient.Protocol
if (raw_result.StartsWith("HTTP/1.1"))
{
postResult = raw_result[(raw_result.IndexOf("\r\n\r\n") + 4)..];
statusCode = Settings.str2int(raw_result.Split(' ')[1]);
statusCode = int.Parse(raw_result.Split(' ')[1], NumberStyles.Any, CultureInfo.CurrentCulture);
}
else statusCode = 520; //Web server is returning an unknown error
}

View file

@ -109,7 +109,7 @@ namespace MinecraftClient.Protocol
requestMessage.Add(body);
}
else requestMessage.Add(""); // <CR><LF>
if (Settings.DebugMessages)
if (Settings.Config.Logging.DebugMessages)
{
foreach (string l in requestMessage)
{

View file

@ -398,7 +398,7 @@ namespace MinecraftClient.Protocol
private static void WriteDebugLog(string t)
{
if (Settings.DebugMessages && logOutput)
if (Settings.Config.Logging.DebugMessages && logOutput)
WriteLog(t);
}

View file

@ -1,20 +0,0 @@
namespace MinecraftClient.Protocol.Session
{
public enum CacheType
{
/// <summary>
/// Do not perform any session caching, always perform login requests from scratch.
/// </summary>
None,
/// <summary>
/// Cache session information in memory to reuse session tokens across server joins.
/// </summary>
Memory,
/// <summary>
/// Cache session information in a SessionCache file to share session tokens between different MCC instances.
/// </summary>
Disk
};
}

View file

@ -4,6 +4,8 @@ using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Timers;
using static MinecraftClient.Settings;
using static MinecraftClient.Settings.MainConfigHealper.MainConfig.AdvancedConfig;
namespace MinecraftClient.Protocol.Session
{
@ -54,11 +56,11 @@ namespace MinecraftClient.Protocol.Session
sessions.Add(login, session);
}
if (Settings.SessionCaching == CacheType.Disk && updatetimer.Enabled == true)
if (Config.Main.Advanced.SessionCache == CacheType.disk && updatetimer.Enabled == true)
{
pendingadds.Add(new KeyValuePair<string, SessionToken>(login, session));
}
else if (Settings.SessionCaching == CacheType.Disk)
else if (Config.Main.Advanced.SessionCache == CacheType.disk)
{
SaveToDisk();
}
@ -122,7 +124,7 @@ namespace MinecraftClient.Protocol.Session
//Grab sessions in the Minecraft directory
if (File.Exists(SessionCacheFileMinecraft))
{
if (Settings.DebugMessages)
if (Config.Logging.DebugMessages)
ConsoleIO.WriteLineFormatted(Translations.Get("cache.loading", Path.GetFileName(SessionCacheFileMinecraft)));
Json.JSONData mcSession = new(Json.JSONData.DataType.String);
try
@ -155,7 +157,7 @@ namespace MinecraftClient.Protocol.Session
sessionItem["uuid"].StringValue.Replace("-", ""),
clientID
));
if (Settings.DebugMessages)
if (Config.Logging.DebugMessages)
ConsoleIO.WriteLineFormatted(Translations.Get("cache.loaded", login, session.ID));
sessions[login] = session;
}
@ -169,7 +171,7 @@ namespace MinecraftClient.Protocol.Session
//Serialized session cache file in binary format
if (File.Exists(SessionCacheFileSerialized))
{
if (Settings.DebugMessages)
if (Config.Logging.DebugMessages)
ConsoleIO.WriteLineFormatted(Translations.Get("cache.converting", SessionCacheFileSerialized));
try
@ -181,7 +183,7 @@ namespace MinecraftClient.Protocol.Session
#pragma warning restore SYSLIB0011 // BinaryFormatter.Deserialize() is obsolete
foreach (KeyValuePair<string, SessionToken> item in sessionsTemp)
{
if (Settings.DebugMessages)
if (Config.Logging.DebugMessages)
ConsoleIO.WriteLineFormatted(Translations.Get("cache.loaded", item.Key, item.Value.ID));
sessions[item.Key] = item.Value;
}
@ -199,7 +201,7 @@ namespace MinecraftClient.Protocol.Session
//User-editable session cache file in text format
if (File.Exists(SessionCacheFilePlaintext))
{
if (Settings.DebugMessages)
if (Config.Logging.DebugMessages)
ConsoleIO.WriteLineFormatted(Translations.Get("cache.loading_session", SessionCacheFilePlaintext));
try
@ -215,17 +217,17 @@ namespace MinecraftClient.Protocol.Session
{
string login = Settings.ToLowerIfNeed(keyValue[0]);
SessionToken session = SessionToken.FromString(keyValue[1]);
if (Settings.DebugMessages)
if (Config.Logging.DebugMessages)
ConsoleIO.WriteLineFormatted(Translations.Get("cache.loaded", login, session.ID));
sessions[login] = session;
}
catch (InvalidDataException e)
{
if (Settings.DebugMessages)
if (Config.Logging.DebugMessages)
ConsoleIO.WriteLineFormatted(Translations.Get("cache.ignore_string", keyValue[1], e.Message));
}
}
else if (Settings.DebugMessages)
else if (Config.Logging.DebugMessages)
{
ConsoleIO.WriteLineFormatted(Translations.Get("cache.ignore_line", line));
}
@ -246,7 +248,7 @@ namespace MinecraftClient.Protocol.Session
/// </summary>
private static void SaveToDisk()
{
if (Settings.DebugMessages)
if (Config.Logging.DebugMessages)
Translations.WriteLineFormatted("cache.saving");
List<string> sessionCacheLines = new()

View file

@ -1,5 +1,6 @@
using System.Net.Sockets;
using Starksoft.Aspen.Proxy;
using Tomlet.Attributes;
namespace MinecraftClient.Proxy
{
@ -11,7 +12,45 @@ namespace MinecraftClient.Proxy
public static class ProxyHandler
{
public enum Type { HTTP, SOCKS4, SOCKS4a, SOCKS5 };
public static Configs Config = new();
[TomlDoNotInlineObject]
public class Configs
{
[TomlInlineComment("$config.Proxy.Enabled_Login$")]
public bool Enabled_Login = false;
[TomlInlineComment("$config.Proxy.Enabled_Ingame$")]
public bool Enabled_Ingame = false;
[TomlInlineComment("$config.Proxy.Server$")]
public ProxyInfoConfig Server = new("0.0.0.0", 8080);
[TomlInlineComment("$config.Proxy.Proxy_Type$")]
public ProxyType Proxy_Type = ProxyType.HTTP;
[TomlInlineComment("$config.Proxy.Username$")]
public string Username = "";
[TomlInlineComment("$config.Proxy.Password$")]
public string Password = "";
public void OnSettingUpdate() { }
public struct ProxyInfoConfig
{
public string Host;
public ushort Port;
public ProxyInfoConfig(string host, ushort port)
{
Host = host;
Port = port;
}
}
public enum ProxyType { HTTP, SOCKS4, SOCKS4a, SOCKS5 };
}
private static readonly ProxyClientFactory factory = new();
private static IProxyClient? proxy;
@ -28,27 +67,26 @@ namespace MinecraftClient.Proxy
{
try
{
if (login ? Settings.ProxyEnabledLogin : Settings.ProxyEnabledIngame)
if (login ? Config.Enabled_Login : Config.Enabled_Ingame)
{
ProxyType innerProxytype = ProxyType.Http;
switch (Settings.proxyType)
switch (Config.Proxy_Type)
{
case Type.HTTP: innerProxytype = ProxyType.Http; break;
case Type.SOCKS4: innerProxytype = ProxyType.Socks4; break;
case Type.SOCKS4a: innerProxytype = ProxyType.Socks4a; break;
case Type.SOCKS5: innerProxytype = ProxyType.Socks5; break;
case Configs.ProxyType.HTTP: innerProxytype = ProxyType.Http; break;
case Configs.ProxyType.SOCKS4: innerProxytype = ProxyType.Socks4; break;
case Configs.ProxyType.SOCKS4a: innerProxytype = ProxyType.Socks4a; break;
case Configs.ProxyType.SOCKS5: innerProxytype = ProxyType.Socks5; break;
}
if (Settings.ProxyUsername != "" && Settings.ProxyPassword != "")
{
proxy = factory.CreateProxyClient(innerProxytype, Settings.ProxyHost, Settings.ProxyPort, Settings.ProxyUsername, Settings.ProxyPassword);
}
else proxy = factory.CreateProxyClient(innerProxytype, Settings.ProxyHost, Settings.ProxyPort);
if (Config.Username != "" && 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);
if (!proxy_ok)
{
ConsoleIO.WriteLineFormatted(Translations.Get("proxy.connected", Settings.ProxyHost, Settings.ProxyPort));
ConsoleIO.WriteLineFormatted(Translations.Get("proxy.connected", Config.Server.Host, Config.Server.Port));
proxy_ok = true;
}

View file

@ -1,319 +0,0 @@
# Startup Config File
# New to Minecraft Console Client? See README and sample configuration files here:
# https://github.com/MCCTeam/Minecraft-Console-Client/tree/master/MinecraftClient/config
# Want to upgrade to a newer version? See https://github.com/MCCTeam/Minecraft-Console-Client/#download
# Some settings missing here after an upgrade? Try to delete this file and relaunch MCC to generate a new one
[Main]
# General settings
# Leave blank to prompt user on startup
# Use "-" as password for offline mode
login=
password=
serverip=
type=microsoft # Account type. mojang or microsoft. Also affects interactive login in console.
method=mcc # Microsoft Account sign-in method. mcc OR browser
# Advanced settings
# Make sure you understand what each setting does before changing anything!
language=en_GB
consoletitle=%username%@%serverip% - Minecraft Console Client
internalcmdchar=slash # Use 'none', 'slash' or 'backslash'
messagecooldown=1 # Minimum delay in seconds between messages to avoid being kicked for spam.
botowners=Player1,Player2,Player3 # Name list or myfile.txt, one name per line. /!\ Server admins can impersonate owners!
mcversion=auto # Use 'auto' or '1.X.X' values. Allows to skip server info retrieval.
mcforge=auto # Use 'auto', 'false' or 'true'. Force-enabling only works for MC 1.13+.
brandinfo=mcc # Use 'mcc', 'vanilla', or 'none'. This is how MCC identifies itself to the server.
chatbotlogfile= # Leave empty for no logfile
privatemsgscmdname=tell # Used by RemoteControl bot
showsystemmessages=true # System messages for server ops
showxpbarmessages=true # Messages displayed above xp bar, set this to false in case of xp bar spam
showchatlinks=true # Decode links embedded in chat messages and show them in console
showinventorylayout=true # Show inventory layout as ASCII art in inventory command
terrainandmovements=false # Uses more ram, cpu, bandwidth but allows you to move around
inventoryhandling=false # Toggle inventory handling (beta)
entityhandling=false # Toggle entity handling (beta)
sessioncache=disk # How to retain session tokens. Use 'none', 'memory' or 'disk'
profilekeycache=disk # How to retain profile key. Use 'none', 'memory' or 'disk'
resolvesrvrecords=fast # Use 'false', 'fast' (5s timeout), or 'true'. Required for joining some servers.
accountlist=accounts.txt # See README > 'Servers and Accounts file' for more info about this file
serverlist=servers.txt # See README > 'Servers and Accounts file' for more info about this file
playerheadicon=true # Only works on Windows XP-8 or Windows 10 with old console
exitonfailure=false # Disable pauses on error, for using MCC in non-interactive scripts
scriptcache=true # Cache compiled scripts for faster load on low-end devices
timestamps=false # Prepend timestamps to chat messages
autorespawn=false # Toggle auto respawn if client player was dead (make sure your spawn point is safe)
minecraftrealms=false # Enable support for joining Minecraft Realms worlds
moveheadwhilewalking=true # Enable head movement while walking to avoid anti-cheat triggers
timeout=30 # Set a custom timeout in seconds (Default: 30). Use only if you know what you're doing.
enableemoji=true # If turned off, the emoji will be replaced with a simpler character (for /chunk status)
movementspeed=2 # A movement speed higher than 2 may be considered cheating.
[Signature]
# Chat settings (affects minecraft 1.19+)
login_with_secure_profile=true # Microsoft accounts only. If disabled, will not be able to sign chat and join servers configured with "enforce-secure-profile=true"
sign_chat=true # Whether to sign the chat send from MCC
sign_message_in_command=true # Whether to sign the messages contained in the commands sent by MCC. For example, the message in "/msg" and "/me"
mark_legally_signed_msg=false # Use green color block to mark chat with legitimate signatures
mark_modified_msg=true # Use yellow color block to mark chat that have been modified by the server.
mark_illegally_signed_msg=true # Use red color block to mark chat without legitimate signature
mark_system_message=false # Use gray color block to mark system message (always without signature)
show_modified_chat=true # Set to true to display messages modified by the server, false to display the original signed messages
show_illegal_signed_chat=true # Whether to display chat and messages in commands without legal signatures
[Logging]
# Only affect the messages on console.
debugmessages=false # Please enable this before submitting bug reports. Thanks!
chatmessages=true # Show server chat messages
warningmessages=true # Show warning messages
errormessages=true # Show error messages
infomessages=true # Informative messages (i.e Most of the message from MCC)
#chatfilter= # Regex for filtering chat message
#debugfilter= # Regex for filtering debug message
filtermode=blacklist # blacklist OR whitelist. Blacklist hide message match regex. Whitelist show message match regex
logtofile=false # Write log messages to file
logfile=console-log-%username%-%serverip%.txt # Log file name
prependtimestamp=false # Prepend timestamp to messages in log file
savecolorcodes=false # Keep color codes in the saved text (§b)
[AppVars]
# yourvar=yourvalue
# can be used in some other fields as %yourvar%
# %username% and %serverip% are reserved variables.
[Proxy]
# Connect to a server via a proxy instead of connecting directly
# If Mojang session services are blocked on your network, set enabled=login to login using proxy but connect directly to the server
# If connecting to port 25565 (Minecraft) is blocked on your network, set enabled=true to login & connect using the proxy
# /!\ Make sure your server rules allow Proxies or VPNs before setting enabled=true, or you may face consequences!
enabled=false # Use 'false', 'true', or 'login' for login only
type=HTTP # Supported types: HTTP, SOCKS4, SOCKS4a, SOCKS5
server=0.0.0.0:0000 # Proxy server must allow HTTPS for login, and non-443 ports for playing
username= # Only required for password-protected proxies
password= # Only required for password-protected proxies
[ChatFormat]
# MCC does it best to detect chat messages, but some server have unusual chat formats
# When this happens, you'll need to configure chat format below, see README > 'Detecting chat messages'
# Do not forget to uncomment (remove '#') these settings if modifying them
builtins=true # MCC support for common message formats. Set "false" to avoid conflicts with custom formats.
# public=^<([a-zA-Z0-9_]+)> (.+)$
# private=^([a-zA-Z0-9_]+) whispers to you: (.+)$
# tprequest=^([a-zA-Z0-9_]+) has requested (?:to|that you) teleport to (?:you|them)\.$
[MCSettings]
# Settings below are sent to the server and only affect server-side things like your skin
enabled=true # If disabled, settings below are not sent to the server
locale=en_US # Use any language implemented in Minecraft
renderdistance=medium # Use tiny, short, medium, far, or chunk amount [0 - 255]
difficulty=normal # MC 1.7- difficulty. peaceful, easy, normal, difficult
chatmode=enabled # Use 'enabled', 'commands', or 'disabled'. Allows to mute yourself...
chatcolors=true # Allows disabling chat colors server-side
main_hand=left # MC 1.9+ main hand. left or right
skin_cape=true
skin_hat=true
skin_jacket=false
skin_sleeve_left=false
skin_sleeve_right=false
skin_pants_left=false
skin_pants_right=false
# =============================== #
# Minecraft Console Client Bots #
# =============================== #
# Although Minecraft Console Client is only a Chat client by default, it can also do many more things
# Below you will find configuration sections to enable Bots that can automatically perform tasks for you
# BY ENABLING BOTS, YOU AGREE TO COMPLY WITH SERVER RULES, AND FACE CONSEQUENCES FROM SERVER STAFF IF YOU DON'T
[Alerts]
# Get alerted when specified words are detected in chat
# Useful for moderating your server or detecting when someone is talking to you
enabled=false
trigger_by_words=false # Triggers an alert after receiving a specified keyword.
trigger_by_rain=false # Trigger alerts when it rains and when it stops.
trigger_by_thunderstorm=false # Triggers alerts at the beginning and end of thunderstorms.
alertsfile=alerts.txt # List of words/strings to alert you on, e.g. "Yourname"
excludesfile=alerts-exclude.txt # List of words/strings to NOT alert you on, e.g. "<Yourname>"
beeponalert=true # Play a beep sound when a word is detected in addition to highlighting
logtofile=false # Log alerts info a file
logfile=alerts-log.txt # The name of a file where alers logs will be written
[AntiAFK]
# Send a command on a regular or random basis or make the bot walk around randomly to avoid automatic AFK disconnection
# /!\ Make sure your server rules do not forbid anti-AFK mechanisms!
# /!\ Make sure you keep the bot in an enclosure to prevent it wandering off if you're using terrain handling! (Recommended size 5x5x5)
enabled=false
delay=600 # 10 = 1s (Can also be a random number between 2 numbers, example: 50-600) (Default: 600)
command=/ping # Command to send to the server
use_terrain_handling=false # Use terrain handling to enable the bot to move around
walk_range=5 # The range the bot can move around randomly (Note: the bigger the range, the slower the bot will be)
walk_retries=20 # How many timec can the bot fail trying to move before using the command method
[AutoRelog]
# Automatically relog when disconnected by server, for example because the server is restating
# Put keywords/strings such as "Server is restarting" in kick messages file to relog when the message is seen
# /!\ Use ignorekickmessage=true at own risk! Server staff might not appreciate if you auto-relog on manual kicks
enabled=false
delay=10 # use 10 for 10 seconds, 10-60 for a random delay between 10 and 60 seconds
retries=3 # retries when failing to relog to the server. use -1 for unlimited retries
kickmessagesfile=kickmessages.txt # file with list of matches in kick messages that will trigger autorelog
ignorekickmessage=false # when set to true, autorelog will reconnect regardless of kick messages
[ChatLog]
# Logs chat messages in a file on disk
enabled=false
timestamps=true
filter=messages
logfile=chatlog-%username%-%serverip%.txt
[Hangman]
# A small game to demonstrate chat interactions. Players can guess mystery words one letter at a time.
# You need to have ChatFormat working correctly and add yourself in botowners to start the game with /tell <bot username> start
# /!\ This bot may get a bit spammy if many players are interacting with it
enabled=false
english=true
wordsfile=hangman-en.txt
fichiermots=hangman-fr.txt
[ScriptScheduler]
# Schedule commands and scripts to launch on various events such as server join, date/time or time interval
# See README > 'Using the Script Scheduler' for more info
enabled=false
tasksfile=tasks.ini
[RemoteControl]
# Send MCC console commands to your bot through server PMs (/tell)
# You need to have ChatFormat working correctly and add yourself in botowners to use the bot
# /!\ Server admins can spoof PMs (/tellraw, /nick) so enable RemoteControl only if you trust server admins
enabled=false
autotpaccept=true
tpaccepteveryone=false
[AutoRespond]
# Run commands or send messages automatically when a specified pattern is detected in chat
# /!\ Server admins can spoof chat messages (/nick, /tellraw) so keep this in mind when implementing AutoRespond rules
# /!\ This bot may get spammy depending on your rules, although the global messagecooldown setting can help you avoiding accidental spam
enabled=false
matchesfile=matches.ini
matchcolors=false # Do not remove colors from text (Note: Your matches will have to include color codes (ones using the § character) in order to work)
[AutoAttack]
# Automatically attack hostile mobs around you
# You need to enable Entity Handling to use this bot
# /!\ Make sure server rules allow your planned use of AutoAttack
# /!\ SERVER PLUGINS may consider AutoAttack to be a CHEAT MOD and TAKE ACTION AGAINST YOUR ACCOUNT so DOUBLE CHECK WITH SERVER RULES!
enabled=false
mode=single # single or multi. single target one mob per attack. multi target all mobs in range per attack
priority=distance # health or distance. Only needed when using single mode
cooldownseconds=auto # How long to wait between each attack. Use auto to let MCC calculate it
interaction=Attack # Possible values: Interact, Attack (default), InteractAt (Interact and Attack)
attackhostile=true # Allow attacking hostile mobs
attackpassive=false # Allow attacking passive mobs
listmode=blacklist # Wether to treat the list from the file bellow as a whitelist or as a blacklist
# A path to the file which contains blacklisted or whitelisted entities, entity types are written on a new line
# All entity types can be found here: https://bit.ly/3Rg68lp
# The file is not created by default.
listfile=autoattack-list.txt
[AutoFishing]
# Automatically catch fish using a fishing rod
# Guide: https://mccteam.github.io/guide/chat-bots.html#auto-fishing
# /!\ Make sure server rules allow automated farming before using this bot
enabled=false
antidespawn=false
main_hand=true # Use the main hand or the off hand to hold the rod.
auto_start=true # Whether to start fishing automatically after entering a world.
cast_delay=0.4 # How soon to re-cast after successful fishing.
fishing_delay=3.0 # How long after entering the game to start fishing (seconds).
fishing_timeout=300.0 # Fishing timeout (seconds). Timeout will trigger a re-cast.
durability_limit=2 # Will not use rods with less durability than this (full durability is 64). Set to zero to disable this feature.
auto_rod_switch=true # Switch to a new rod from inventory after the current rod is unavailable.
stationary_threshold=0.001 # Hooks moving in the X and Z axes below this threshold will be considered stationary.
hook_threshold=0.2 # A stationary hook moving on the Y-axis above this threshold will be considered to have caught a fish.
log_fishing_bobber=false # For debugging purposes, you can use this log to adjust the two thresholds mentioned above.
location= # Some plugins do not allow the player to fish in one place. This allows the player to change position/angle after each fish caught.
# Floating-point numbers can be used for both coordinates and angles. Leave blank to disable this function.
# Change the angle only (recommended): location=yaw_1, pitch_1; yaw_2, pitch_2; ...; yaw_n, pitch_n
# Change position only: location=x1, y1, z1; x2, y2, z2; ...; xn, yn, zn
# Change both angle and position: location=x1, y1, z1, yaw_1, pitch_1; x2, y2, z2, yaw_2, pitch_2; ... ;xn, yn, zn, yaw_n, pitch_n
[AutoEat]
# Automatically eat food when your Hunger value is low
# You need to enable Inventory Handling to use this bot
enabled=false
threshold=6
[AutoCraft]
# Automatically craft items in your inventory
# See README > 'Using the AutoCraft bot' for how to use
# You need to enable Inventory Handling to use this bot
# You should also enable Terrain and Movements if you need to use a crafting table
enabled=false
configfile=autocraft\config.ini
[Mailer]
# Relay messages between players and servers, like a mail plugin
# This bot can store messages when the recipients are offline, and send them when they join the server
# /!\ Server admins can spoof PMs (/tellraw, /nick) so enable this bot only if you trust server admins
enabled=false
database=MailerDatabase.ini
ignorelist=MailerIgnoreList.ini
publicinteractions=false
maxmailsperplayer=10
maxdatabasesize=10000
retentiondays=30
[AutoDrop]
# Automatically drop items in inventory
# You need to enable Inventory Handling to use this bot
enabled=false
mode=include # include, exclude or everything. Include: drop item IN the list. Exclude: drop item NOT IN the list
items= # separate each item name with a comma ',': ItemOne,ItemTwo
# See this file for an up-to-date list of item types you can use with this bot:
# https://github.com/MCCTeam/Minecraft-Console-Client/blob/master/MinecraftClient/Inventory/ItemType.cs
[ReplayMod]
# Enable recording of the game (/replay start) and replay it later using the Replay Mod (https://www.replaymod.com/)
# Please note that due to technical limitations, the client player (you) will not be shown in the replay file
# /!\ You SHOULD use /replay stop or exit the program gracefully with /quit OR THE REPLAY FILE MAY GET CORRUPT!
enabled=false
backupinterval=300 # How long should replay file be auto-saved, in seconds. Use -1 to disable
[FollowPlayer]
# Enabled you to make the bot follow you
# NOTE: This is an experimental feature, the bot can be slow at times, you need to walk with a normal speed and to sometimes stop for it to be able to keep up with you
# It's similar to making animals follow you when you're holding food in your hand.
# This is due to a slow pathfinding algorithm, we're working on getting a better one
# You can tweak the update limit and find what works best for you. (NOTE: Do not but a very low one, because you might achieve the opposite,
# this might clog the thread for terain handling) and thus slow the bot even more.
# /!\ Make sure server rules allow an option like this in the rules of the server before using this bot
enabled=false
update_limit=10 # The rate at which the bot does calculations (10 = 1s) (Default: 5) (You can tweak this if you feel the bot is too slow)
stop_at_distance=3 # Do not follow the player if he is in the range of 3 blocks (prevents the bot from pushing a player in an infinite loop)
[PlayerListLogger]
# Log the list of players periodically into a textual file
enabled=false
log_file=playerlog.txt
log_delay=600 # 10 = 1s
[Map]
# Allows you to render maps into .jpg images
# This is useful for solving captchas which use maps
# The maps are rendered into Rendered_Maps folder.
# NOTE:
# This feature is currently only useful for solving captchas which use maps.
# If some servers have a very short time for solving captchas, enabe auto_render_on_update and prepare to open the file quickly.
# On linux you can use FTP to access generated files.
# In the future it might will be possible to display maps directly in the console with a separate command.
# /!\ Make sure server rules allow bots to be used on the server, or you risk being punished.
enabled=false
resize_map=false # Should the map be resized? (Default one is small 128x128)
resize_to=256 # The size to resize the map to (Note: the bigger it is, the lower the quallity is)
auto_render_on_update=false # Automatically render the map once it's received or updated from/by the server
delete_rendered_on_unload=true # Delete all rendered maps on unload/reload (Does not delete the images if you exit the client)
notify_on_first_update=false # Get a notification when you have gotten a map from the server for the first time
# Note: Will be printed for each map in vicinity, could cause spam if there are a lot of maps

View file

@ -1,15 +1,22 @@
[mcc]
# Messages from MCC itself
mcc.help_us_translate=
mcc.run_with_default_settings=
mcc.settings_generated=
mcc.has_update=
mcc.login=Login :
mcc.login_basic_io=Bitte gib einen Nutzernamen oder eine E-Mail deiner Wahl ein.
mcc.password=Passwort :
mcc.password=Passwort :
mcc.password_basic_io=Bitte gib das Passwort für {0} ein.
mcc.password_hidden=Passwort : {0}
mcc.offline=§8Das Programm läuft im Offline-Modus.
mcc.session_invalid=§8Gespeicherte Session ungültig oder abgelaufen.
mcc.session_valid=§8Gespeicherte Session gültig für {0}.
mcc.profile_key_invalid=
mcc.profile_key_valid=
mcc.connecting=Verbinde zu {0}...
mcc.ip=Server-IP :
mcc.fetching_key=
mcc.ip=Server-IP :
mcc.use_version=§8Benutze Minecraft-Version {0} (protocol v{1})
mcc.unknown_version=§8Unbekannte oder nicht unterstützte MC-Version {0}.\nWechsele in den Autodetection-Modus.
mcc.forge=Prüfe, ob der Server Forge benutzt...
@ -20,7 +27,7 @@ mcc.not_found=§8SRV-Lookup fehlgeschlagen für {0}\n{1}: {2}
mcc.retrieve=Erhalte Server-Info...
mcc.restart=Starte Minecraft Console Client neu...
mcc.restart_delay=Warte {0} Sekunden vor Neustart...
mcc.server_version=Server-Version :
mcc.server_version=Server-Version :
mcc.disconnected=Mit keinem Server verbunden. Schreibe '{0}help' für weitere Hilfe.
mcc.press_exit=Oder drücke Enter, um den Minecraft Console Client zu verlassen.
mcc.version_supported=Version wird unterstützt.\nMelde an...
@ -41,13 +48,16 @@ mcc.with_forge=, mit Forge
mcc.handshake=§8Handshake erfolgreich. (Server ID: {0})
mcc.realms_available=Du hast Zugang zu den folgenden Realms-Welten
mcc.realms_join=Nutze realms:index als Server-IP, um der Realms-Welt beizutreten
mcc.generator.generating=
mcc.generator.done=
[debug]
# Messages from MCC Debug Mode
debug.color_test=Farbtest: Dein Terminal sollte {0} anzeigen.
debug.session_cache_ok=§8Sitzungsdaten wurden erfolgreich vom Speicher geladen.
debug.session_cache_fail=§8Es konnten keine Sitzungsdaten vom Speicher geladen werden.
debug.keys_cache_ok=
debug.keys_cache_fail=
debug.session_id=Erfolgreich. (session ID: {0})
debug.crypto=§8Crypto-Schlüssel & -Hash wurden generiert.
debug.request=§8Starte Anfrage zu {0}
@ -58,7 +68,7 @@ error.ping=Ping an IP fehlgeschlagen.
error.unsupported=Kann nicht zum Server verbinden : Diese Version wird nicht unterstützt !
error.determine=Konnte Server-Version nicht bestimmen.
error.forgeforce=Der zwangshafte Forge-Support wird für diese Minecraft-Version nicht unterstützt!
error.login=Minecraft Login fehlgeschlagen :
error.login=Minecraft Login fehlgeschlagen :
error.login.migrated=Account wurde migriert, benutze eine E-Mail als Nutzername.
error.login.server=Login-Server nicht erreichbar. Bitte versuche es später erneut.
error.login.blocked=Falsches Passwort, gesperrte IP oder zu viele Logins.
@ -67,7 +77,6 @@ error.login.premium=Dies ist kein Premium-Benutzer.
error.login.network=Netzwerkfehler.
error.login.ssl=SSL-Fehler.
error.login.unknown=Unbekannter Fehler.
error.login.ssl_help=§8Anscheinend hast du dieses Programm mit MONO gestartet.\nBeim ersten Mal musst du HTTPS-Zertifikate mit folgendem Befehl importieren:\nmozroots --import --ask-remove
error.login.cancel=Benutzer gecancelled.
error.login_failed=Nutzer konnte auf diesem Server nicht angemeldet werden.
error.join=Konnte dem Server nicht beitreten.
@ -81,10 +90,7 @@ error.no_version_report=§8Server gibt keine Protokoll-Version an, Autodetection
error.connection_timeout=§8Es gab einen Timeout während des Verbindungsaufbaus zu dieser IP.
error.forge=§8Forge Login Handshake konnte nicht erfolgreich abgeschlossen werden.
error.forge_encrypt=§8Forge StartEncryption Handshake konnte nicht erfolgreich abgeschlossen werden.
error.setting.str2int=Konnte '{0}' nicht in einen Int umwandeln. Bitte überprüfe die Einstellungen.
error.setting.argument_syntax={0}: Invalid syntax, expecting --argname=value or --section.argname=value
error.setting.unknown_section={0}: Unknown setting section '{1}'
error.setting.unknown_or_invalid={0}: Unknown setting or invalid value
error.http_code=§8Es gab einen Fehlercode vom Server: {0}
error.auth=§8Es gab einen Fehlercode vom Server, während die Authentication erneuert wurde: {0}
error.realms.ip_error=Konnte die Server-IP deiner Realms-Welt nicht abfragen
@ -92,6 +98,11 @@ error.realms.access_denied=Diese Realms-Welt existiert nicht oder der Zugang wur
error.realms.server_unavailable=Der Realms-Server braucht ein wenig Zeit zum starten. Bitte versuche es später erneut.
error.realms.server_id=Invalid or unknown Realms server ID.
error.realms.disabled=Versuche der Realms-Welt beizutreten, allerdings wurde der Realms-Support in der Config deaktiviert
error.missing.argument=
error.usage=
error.generator.invalid=
error.generator.path=
error.generator.json=
[internal command]
# MCC internal help command
@ -173,6 +184,14 @@ cache.ignore_line=§8Ignoriere ungültigen Sitzungstoken Zeile: {0}
cache.read_fail_plain=§8Konnte Sitzungscache nicht vom Speicher lesen: {0}
cache.saving=§8Speichere Sitzungscache auf Festplatte
cache.save_fail=§8Konnte Sitzungscache auf keine Festplatte schreiben: {0}
# Profile Key Cache
cache.loading_keys=
cache.loaded_keys=
cache.ignore_string_keys=
cache.ignore_line_keys=
cache.read_fail_plain_keys=
cache.saving_keys=
cache.save_fail_keys=
[proxy]
proxy.connected=§8Verbunden mit Proxy {0}:{1}
@ -186,6 +205,7 @@ chat.fail=§8Konnte Datei nicht herunterladen.
chat.from_dir=§8Nutze en_GB.lang als Standard von deinem Minecraft-Pfad.
chat.loaded=§8Übersetzungsdatei geladen.
chat.not_found=§8Übersetzungsdatei konnte nicht gefunden werden: '{0}'\nEinige Nachrichten können ohne diese Datei nicht korrekt angezeigt werden.
chat.message_chain_broken=
[general]
# General message/information (i.e. Done)
@ -201,12 +221,23 @@ general.available_cmd=Verfügbare Befehle: {0}
# Animation
cmd.animation.desc=Schwinge deinen Arm.
# Bots
cmd.bots.desc=
cmd.bots.list=
cmd.bots.notfound=
cmd.bots.noloaded=
cmd.bots.unloaded=
cmd.bots.unloaded_all=
# ChangeSlot
cmd.changeSlot.desc=Ändere deine Hotbar
cmd.changeSlot.nan=Konnte Slot nicht ändern: Dies ist keine Nummer.
cmd.changeSlot.changed=Slot geändert auf {0}
cmd.changeSlot.fail=Konnte Slot nicht ändern.
# Chunk
cmd.chunk.desc=
# Connect
cmd.connect.desc=Verbinde zum angegebenen Server.
cmd.connect.unknown=Unbekannter Account '{0}'.
@ -248,6 +279,19 @@ cmd.entityCmd.distance=Entfernung
cmd.entityCmd.location=Position
cmd.entityCmd.type=Typ
# Exec If
cmd.execif.desc=
cmd.execif.executed=
cmd.execif.executed_no_output=
cmd.execif.error_occured=
cmd.execif.error=
# Exec Multi
cmd.execmulti.desc=
cmd.execmulti.executed=
cmd.execmulti.result=
cmd.execmulti.no_result=
# Exit
cmd.exit.desc=Verbindung zum Server verloren.
@ -267,12 +311,15 @@ cmd.inventory.close_fail=Konnte das Inventar #{0} nicht schließen
cmd.inventory.not_exist=Inventar #{0} existiert nicht.
cmd.inventory.inventory=Inventar
cmd.inventory.inventories=Inventare
cmd.inventory.inventories_available=
cmd.inventory.hotbar=Deine ausgewählte Hotbar ist {0}
cmd.inventory.damage=Schaden
cmd.inventory.left=Links
cmd.inventory.right=Rechts
cmd.inventory.middle=Mittel
cmd.inventory.clicking={0} klicke Slote {1} im Fenster #{2}
cmd.inventory.shiftclick=
cmd.inventory.shiftclick_fail=
cmd.inventory.no_item=Kein Item im Slot #{0}
cmd.inventory.drop=Droppe 1 Item aus Slot #{0}
cmd.inventory.drop_stack=Droppe ganzen Item Stack aus Slot #{0}
@ -284,10 +331,29 @@ cmd.inventory.help.usage=Benutzung
cmd.inventory.help.list=Liste deine Inventare auf.
cmd.inventory.help.close=Schließe einen offenen Container.
cmd.inventory.help.click=Klicke auf ein Item.
cmd.inventory.help.shiftclick=
cmd.inventory.help.drop=Werfe ein Item aus deinem Inventar.
cmd.inventory.help.creativegive=Gebe dir ein Item im Kreativmodus.
cmd.inventory.help.creativedelete=Leere Slot im Kreativmodus.
cmd.inventory.help.unknown=Unbekannte Aktion.
cmd.inventory.help.inventories=
cmd.inventory.help.search=
cmd.inventory.help.unknown=Unbekannte Aktion.
cmd.inventory.found_items=
cmd.inventory.no_found_items=
# Leave bed
cmd.bed.desc=
cmd.bed.leaving=
cmd.bed.trying_to_use=
cmd.bed.in=
cmd.bed.not_in=
cmd.bed.not_a_bed=
cmd.bed.searching=
cmd.bed.bed_not_found=
cmd.bed.found_a_bed_at=
cmd.bed.cant_reach_safely=
cmd.bed.moving=
cmd.bed.failed_to_reach_in_time=
# List
cmd.list.desc=Liste alle Spieler auf.
@ -301,6 +367,8 @@ cmd.look.desc=Schaue in eine Richtung oder auf Koordinaten.
cmd.look.unknown=Unbekannte Richtung '{0}'
cmd.look.at=Schaue nach YAW: {0} PITCH: {1}
cmd.look.block=Schaue auf {0}
cmd.look.inspection=
cmd.look.noinspection=
# Move
cmd.move.desc=Laufe oder fange an zu laufen.
@ -313,11 +381,21 @@ cmd.move.fail=Konnte Pfad nach {0} nicht berechnen.
cmd.move.suggestforce=Weg nach {0} konnte nicht berechnet werden. Benutze den -f Parameter, um unsichere Wege zu aktivieren.
cmd.move.gravity.enabled=Gravitation ist aktiv.
cmd.move.gravity.disabled=Gravitation ist deaktiviert.
cmd.move.chunk_loading_status=
cmd.move.chunk_not_loaded=
# Reco
cmd.reco.desc=Starte neu und verbinde erneut zum Server.
# Reload
cmd.reload.started=
cmd.reload.warning1=
cmd.reload.warning2=
cmd.reload.warning3=
cmd.reload.warning4=
cmd.reload.finished=
cmd.reload.desc=
# Respawn
cmd.respawn.desc=Benutze dies, um nach deinem Tod zu respawnen.
cmd.respawn.done=Du wurdest respawned.
@ -353,6 +431,7 @@ cmd.tps.current=Aktuelle TPS
# Useblock
cmd.useblock.desc=Plaziere einen Block oder öffne eine Kiste
cmd.useblock.use=
# Useitem
cmd.useitem.desc=Benutze (links klick) ein Item auf der Hand
@ -362,9 +441,18 @@ cmd.useitem.use=Item wurde benutzt.
[bot]
# ChatBots. Naming style: bot.<className>.<msg...>
# Alerts
bot.alerts.start_rain=
bot.alerts.end_rain=
bot.alerts.start_thunderstorm=
bot.alerts.end_thunderstorm=
# Anti AFK
bot.antiafk.not_using_terrain_handling=
bot.antiafk.swapping=
bot.antiafk.invalid_walk_range=
# AutoAttack
bot.autoAttack.mode=Unbekannter Angriffsmodus: {0}. Benutze Einfach als Standard.
bot.autoAttack.priority=Unbekannte Priorität: {0}. Benutze Entfernung als Standard.
bot.autoAttack.invalidcooldown=Angriffscooldown kann nicht kleiner als 0 sein. Benutze Auto als Standard.
# AutoCraft
@ -393,15 +481,11 @@ bot.autoCraft.aborted=Crafting abgebrochen! Überprüfe die vorhandenen Material
bot.autoCraft.craft_fail=Crafting fehlgeschlagen! Warte auf weitere Materialien...
bot.autoCraft.timeout=Aktion timeout! Grund: {0}
bot.autoCraft.error.config=Fehler bei der Übergabe der Config: {0}
bot.autoCraft.exception.empty=Leere Konfigurationsdatei: {0}
bot.autoCraft.exception.invalid=Ungültige Konfigurationsdatei: {0}
bot.autoCraft.exception.item_miss=Fehlendes Item in Rezept: {0}
bot.autoCraft.exception.invalid_table=Ungültiges tablelocation Format: {0}
bot.autoCraft.exception.item_name=Ungültiger Itemname im Rezept {0} bei {1}
bot.autoCraft.exception.name_miss=Fehlender Rezeptname während der Rezeptübergabe
bot.autoCraft.exception.slot=Ungültiges Slot-Feld im Rezept: {0}
bot.autoCraft.exception.duplicate=Doppelter Rezeptname angegeben: {0}
bot.autoCraft.debug.no_config=Keine Config-Datei gefunden. Schreibe eine neue...
bot.autocraft.invaild_slots=
bot.autocraft.invaild_invaild_result=
# AutoDrop
bot.autoDrop.cmd=AutoDrop ChatBot Befehl
@ -420,9 +504,17 @@ bot.autoDrop.no_mode=Kann drop Modus nicht aus Config Datei lesen. Benutze inclu
bot.autoDrop.no_inventory=Konnte Inventar nicht finden {0}!
# AutoFish
bot.autoFish.no_inv_handle=
bot.autoFish.start=
bot.autoFish.throw=Angel ausgeworfen!
bot.autoFish.caught=Fisch gefangen!
bot.autoFish.caught_at=
bot.autoFish.no_rod=Keine Angelrute in der Hand. Ist sie kaputt?
bot.autoFish.despawn=
bot.autoFish.fishing_timeout=
bot.autoFish.cast_timeout=
bot.autoFish.update_lookat=
bot.autoFish.switch=
# AutoRelog
bot.autoRelog.launch=Starte mit {0} reconnect Versuchen
@ -466,7 +558,7 @@ bot.mailer.init_fail.mail_retention=Konnte Mailer nicht aktivieren: Die Auslaufz
bot.mailer.create.db=Erstelle neue Datenbank: {0}
bot.mailer.create.ignore=Erstelle neue Ignore-Liste: {0}
bot.mailer.load.db=Lade Datenbank-Datei: {0}
bot.mailer.load.ignore=Lade Ignore-Liste:
bot.mailer.load.ignore=Lade Ignore-Liste:
bot.mailer.cmd=Mailer-Befehl
@ -482,12 +574,43 @@ bot.mailer.cmd.ignore.removed=Entferne {0} von der Ignore Liste!
bot.mailer.cmd.ignore.invalid=Fehlender oder ungültiger Name. Benutzung: {0} <username>
bot.mailer.cmd.help=Siehe Benutzung
# Maps
bot.map.cmd.desc=
bot.map.cmd.not_found=
bot.map.cmd.invalid_id=
bot.map.received=
bot.map.no_maps=
bot.map.received_map=
bot.map.rendered=
bot.map.failed_to_render=
bot.map.list_item=
# ReplayCapture
bot.replayCapture.cmd=replay Befehl
bot.replayCapture.created=Replay-Datei erstellt.
bot.replayCapture.stopped=Record angehalten.
bot.replayCapture.restart=Aufnahme wurde angehalten. Starte das Programm neu um eine neue Aufnahme zu erstellen.
# Follow player
cmd.follow.desc=
cmd.follow.usage=
cmd.follow.already_stopped=
cmd.follow.stopping=
cmd.follow.invalid_name=
cmd.follow.invalid_player=
cmd.follow.cant_reach_player=
cmd.follow.already_following=
cmd.follow.switched=
cmd.follow.started=
cmd.follow.unsafe_enabled=
cmd.follow.note=
cmd.follow.player_came_to_the_range=
cmd.follow.resuming=
cmd.follow.player_left_the_range=
cmd.follow.pausing=
cmd.follow.player_left=
cmd.follow.stopping=
# Script
bot.script.not_found=§8[MCC] [{0}] Konnte Skriptdatei nicht finden: {1}
bot.script.file_not_found=Datei nicht gefunden: '{0}'
@ -495,8 +618,6 @@ bot.script.fail=Konnte Skript '{0}' nicht starten ({1}).
bot.script.pm.loaded=Skript '{0}' geladen.
# ScriptScheduler
bot.scriptScheduler.loading=Lade Aufgaben von '{0}'
bot.scriptScheduler.not_found=Datei nicht gefunden: '{0}'
bot.scriptScheduler.loaded_task=Lade Aufgabe:\n{0}
bot.scriptScheduler.no_trigger=Diese Aufgabe wird niemals ausgelöst:\n{0}
bot.scriptScheduler.no_action=Keine Aktion für diese Aufgabe:\n{0}
@ -508,3 +629,220 @@ bot.scriptScheduler.task=triggeronfirstlogin: {0}\n triggeronlogin: {1}\n trigge
# TestBot
bot.testBot.told=Bot: {0} told me : {1}
bot.testBot.said=Bot: {0} said : {1}
[config]
config.load=
config.load.fail=
config.write.fail=
config.backup.fail=
config.saving=
# Head
config.Head=
# Main.General
config.Main.General.account=
config.Main.General.login=
config.Main.General.server_info=
config.Main.General.method=
# Main.Advanced
config.Main.Advanced=
config.Main.Advanced.language=
config.Main.Advanced.internal_cmd_char=
config.Main.Advanced.message_cooldown=
config.Main.Advanced.bot_owners=
config.Main.Advanced.mc_version=
config.Main.Advanced.mc_forge=
config.Main.Advanced.brand_info=
config.Main.Advanced.chatbot_log_file=
config.Main.Advanced.private_msgs_cmd_name=
config.Main.Advanced.show_system_messages=
config.Main.Advanced.show_xpbar_messages=
config.Main.Advanced.show_chat_links=
config.Main.Advanced.show_inventory_layout=
config.Main.Advanced.terrain_and_movements=
config.Main.Advanced.inventory_handling=
config.Main.Advanced.entity_handling=
config.Main.Advanced.session_cache=
config.Main.Advanced.profilekey_cache=
config.Main.Advanced.resolve_srv_records=
config.Main.Advanced.account_list=
config.Main.Advanced.server_list=
config.Main.Advanced.player_head_icon=
config.Main.Advanced.exit_on_failure=
config.Main.Advanced.script_cache=
config.Main.Advanced.timestamps=
config.Main.Advanced.auto_respawn=
config.Main.Advanced.minecraft_realms=
config.Main.Advanced.move_head_while_walking=
config.Main.Advanced.timeout=
config.Main.Advanced.enable_emoji=
config.Main.Advanced.movement_speed=
config.Main.Advanced.language.invaild=
# Signature
config.Signature=
config.Signature.LoginWithSecureProfile=
config.Signature.SignChat=
config.Signature.SignMessageInCommand=
config.Signature.MarkLegallySignedMsg=
config.Signature.MarkModifiedMsg=
config.Signature.MarkIllegallySignedMsg=
config.Signature.MarkSystemMessage=
config.Signature.ShowModifiedChat=
config.Signature.ShowIllegalSignedChat=
# Logging
config.Logging=
config.Logging.DebugMessages=
config.Logging.ChatMessages=
config.Logging.InfoMessages=
config.Logging.WarningMessages=
config.Logging.ErrorMessages=
config.Logging.ChatFilter=
config.Logging.DebugFilter=
config.Logging.FilterMode=
config.Logging.LogToFile=
config.Logging.LogFile=
config.Logging.PrependTimestamp=
config.Logging.SaveColorCodes=
# AppVars
config.AppVars.Variables=
# Proxy
config.Proxy=
config.Proxy.Enabled_Login=
config.Proxy.Enabled_Ingame=
config.Proxy.Server=
config.Proxy.Proxy_Type=
config.Proxy.Username=
config.Proxy.Password=
# ChatFormat
config.ChatFormat=
config.ChatFormat.Builtins=
config.ChatFormat.UserDefined=
# MCSettings
config.MCSettings=
config.MCSettings.Enabled=
config.MCSettings.Locale=
config.MCSettings.RenderDistance=
config.MCSettings.Difficulty=
config.MCSettings.ChatMode=
config.MCSettings.ChatColors=
config.MCSettings.MainHand=
# ChatBot
config.ChatBot=
# ChatBot.Alerts
config.ChatBot.Alerts=
config.ChatBot.Alerts.Beep_Enabled=
config.ChatBot.Alerts.Trigger_By_Words=
config.ChatBot.Alerts.Trigger_By_Rain=
config.ChatBot.Alerts.Trigger_By_Thunderstorm=
config.ChatBot.Alerts.Matches=
config.ChatBot.Alerts.Excludes=
config.ChatBot.Alerts.Log_To_File=
config.ChatBot.Alerts.Log_File=
# ChatBot.AntiAFK
config.ChatBot.AntiAfk=
config.ChatBot.AntiAfk.Delay=
config.ChatBot.AntiAfk.Command=
config.ChatBot.AntiAfk.Use_Terrain_Handling=
config.ChatBot.AntiAfk.Walk_Range=
config.ChatBot.AntiAfk.Walk_Retries=
# ChatBot.AutoAttack
config.ChatBot.AutoAttack=
config.ChatBot.AutoAttack.Mode=
config.ChatBot.AutoAttack.Priority=
config.ChatBot.AutoAttack.Cooldown_Time=
config.ChatBot.AutoAttack.Interaction=
config.ChatBot.AutoAttack.Attack_Hostile=
config.ChatBot.AutoAttack.Attack_Passive=
config.ChatBot.AutoAttack.List_Mode=
config.ChatBot.AutoAttack.Entites_List=
# ChatBot.AutoCraft
config.ChatBot.AutoCraft=
config.ChatBot.AutoCraft.CraftingTable=
config.ChatBot.AutoCraft.OnFailure=
config.ChatBot.AutoCraft.Recipes=
# ChatBot.AutoDrop
config.ChatBot.AutoDrop=
config.ChatBot.AutoDrop.Mode=
# ChatBot.AutoEat
config.ChatBot.AutoEat=
# ChatBot.AutoFishing
config.ChatBot.AutoFishing=
config.ChatBot.AutoFishing.Antidespawn=
config.ChatBot.AutoFishing.Mainhand=
config.ChatBot.AutoFishing.Auto_Start=
config.ChatBot.AutoFishing.Cast_Delay=
config.ChatBot.AutoFishing.Fishing_Delay=
config.ChatBot.AutoFishing.Fishing_Timeout=
config.ChatBot.AutoFishing.Durability_Limit=
config.ChatBot.AutoFishing.Auto_Rod_Switch=
config.ChatBot.AutoFishing.Stationary_Threshold=
config.ChatBot.AutoFishing.Hook_Threshold=
config.ChatBot.AutoFishing.Log_Fish_Bobber=
config.ChatBot.AutoFishing.Enable_Move=
config.ChatBot.AutoFishing.Movements=
# ChatBot.AutoRelog
config.ChatBot.AutoRelog=
config.ChatBot.AutoRelog.Delay=
config.ChatBot.AutoRelog.Retries=
config.ChatBot.AutoRelog.Ignore_Kick_Message=
config.ChatBot.AutoRelog.Kick_Messages=
# ChatBot.AutoRespond
config.ChatBot.AutoRespond=
config.ChatBot.AutoRespond.Match_Colors=
# ChatBot.ChatLog
config.ChatBot.ChatLog=
# ChatBot.FollowPlayer
config.ChatBot.FollowPlayer=
config.ChatBot.FollowPlayer.Update_Limit=
config.ChatBot.FollowPlayer.Stop_At_Distance=
# ChatBot.HangmanGame
config.ChatBot.HangmanGame=
# ChatBot.Mailer
config.ChatBot.Mailer=
# ChatBot.Map
config.ChatBot.Map=
config.ChatBot.Map.Should_Resize=
config.ChatBot.Map.Resize_To=
config.ChatBot.Map.Auto_Render_On_Update=
config.ChatBot.Map.Delete_All_On_Unload=
config.ChatBot.Map.Notify_On_First_Update=
# ChatBot.PlayerListLogger
config.ChatBot.PlayerListLogger=
config.ChatBot.PlayerListLogger.Delay=
# ChatBot.RemoteControl
config.ChatBot.RemoteControl=
# ChatBot.ReplayCapture
config.ChatBot.ReplayCapture=
config.ChatBot.ReplayCapture.Backup_Interval=
# ChatBot.ScriptScheduler
config.ChatBot.ScriptScheduler=

View file

@ -1,10 +1,14 @@
[mcc]
# Messages from MCC itself
mcc.help_us_translate=Help us translate MCC: {0}
mcc.run_with_default_settings=\nMCC is running with default settings.
mcc.settings_generated=§cSettings file MinecraftClient.ini has been generated.
mcc.has_update=§eNew version of MCC available: {0}
mcc.login=Login :
mcc.login_basic_io=Please type the username or email of your choice.
mcc.password=Password :
mcc.password=Password:
mcc.password_basic_io=Please type the password for {0}.
mcc.password_hidden=Password : {0}
mcc.password_hidden=Password(invisible): {0}
mcc.offline=§8You chose to run in offline mode.
mcc.session_invalid=§8Cached session is invalid or expired.
mcc.session_valid=§8Cached session is still valid for {0}.
@ -46,6 +50,8 @@ mcc.realms_available=You have access to the following Realms worlds
mcc.realms_join=Use realms:<index> as server IP to join a Realms world
mcc.generator.generating=Generating {0} palette using the dataset: {1}
mcc.generator.done=Succesfully generated {0} palette using the dataset: {1}
mcc.invaild_config=Failed to parse the settings file, enter "{0}new" to generate a new configuration.
mcc.gen_new_config=New configuration file "{0}" is generated.
[debug]
# Messages from MCC Debug Mode
@ -67,13 +73,12 @@ error.forgeforce=Cannot force Forge support for this Minecraft version!
error.login=Login failed :
error.login.migrated=Account migrated, use e-mail as username.
error.login.server=Login servers are unavailable. Please try again later.
error.login.blocked=Incorrect password, blacklisted IP or too many logins.
error.login.blocked=Incorrect username/password, blacklisted IP or too many logins.
error.login.response=Invalid server response.
error.login.premium=User not premium.
error.login.network=Network error.
error.login.ssl=SSL Error.
error.login.unknown=Unknown Error.
error.login.ssl_help=§8It appears that you are using Mono to run this program.\nThe first time, you have to import HTTPS certificates using:\nmozroots --import --ask-remove
error.login.cancel=User cancelled.
error.login_failed=Failed to login to this server.
error.join=An error occured when attempting to join this server.
@ -87,13 +92,7 @@ error.no_version_report=§8Server does not report its protocol version, autodete
error.connection_timeout=§8A timeout occured while attempting to connect to this IP.
error.forge=§8Forge Login Handshake did not complete successfully
error.forge_encrypt=§8Forge StartEncryption Handshake did not complete successfully
error.setting.str2int=Failed to convert '{0}' into an integer. Please check your settings.
error.setting.str2double=Failed to convert '{0}' to a floating-point number. Please check your settings.
error.setting.str2locationList.convert_fail=Failed to convert '{0}' to a floating point number. Please check your settings.
error.setting.str2locationList.format_err=Wrong format, can't parse '{0}' into position data.. Please check your settings.
error.setting.argument_syntax={0}: Invalid syntax, expecting --argname=value or --section.argname=value
error.setting.unknown_section={0}: Unknown setting section '{1}'
error.setting.unknown_or_invalid={0}: Unknown setting or invalid value
error.http_code=§8Got error code from server: {0}
error.auth=§8Got error code from server while refreshing authentication: {0}
error.realms.ip_error=Cannot retrieve the server IP of your Realms world
@ -239,7 +238,13 @@ cmd.changeSlot.changed=Changed to slot {0}
cmd.changeSlot.fail=Could not change slot
# Chunk
cmd.chunk.desc=Displays the chunk loading status.\nChange enableemoji=false in the settings if the display is confusing.
cmd.chunk.desc=Displays the chunk loading status.\nChange EnableEmoji=false in the settings if the display is confusing.
cmd.chunk.current=Current location{0}, chunk: ({1}, {2}).
cmd.chunk.marked=Marked location:
cmd.chunk.chunk_pos=chunk: ({0}, {1}).
cmd.chunk.outside=§x§0Since the marked chunk is outside the graph, it will not be displayed!§r
cmd.chunk.icon=Player:{0}, MarkedChunk:{1}, NotReceived:{2}, Loading:{3}, Loaded:{4}
cmd.chunk.for_debug=§x§0This command is used for debugging, make sure you know what you are doing.§r
# Connect
cmd.connect.desc=connect to the specified server.
@ -421,7 +426,7 @@ cmd.setrndstr.format=setrnd variable string1 "\"string2\" string3"
# Sneak
cmd.sneak.desc=Toggles sneaking
cmd.sneak.on=You are sneaking now
cmd.sneak.off=You aren't sneaking anymore
cmd.sneak.off=You are not sneaking anymore
# DropItem
cmd.dropItem.desc=Drop specified type of items from player inventory or opened container
@ -434,7 +439,7 @@ cmd.tps.current=Current tps
# Useblock
cmd.useblock.desc=Place a block or open chest
cmd.useblock.use=Useblock at ({0:0.0}, {1:0.0}, {2:0.0}) {3}
cmd.useblock.use=Useblock at ({0:0.0}, {1:0.0}, {2:0.0}) {3}.
# Useitem
cmd.useitem.desc=Use (left click) an item on the hand
@ -445,23 +450,18 @@ cmd.useitem.use=Used an item
# ChatBots. Naming style: bot.<className>.<msg...>
# Alerts
bot.alerts.start_rain=§cWeather change: It's raining now.§r
bot.alerts.end_rain=§cWeather change: It's no longer raining.§r
bot.alerts.start_thunderstorm=§cWeather change: It's a thunderstorm.§r
bot.alerts.end_thunderstorm=§cWeather change: It's no longer a thunderstorm.§r
bot.alerts.start_rain=§cWeather change: It is raining now.§r
bot.alerts.end_rain=§cWeather change: It is no longer raining.§r
bot.alerts.start_thunderstorm=§cWeather change: It is a thunderstorm.§r
bot.alerts.end_thunderstorm=§cWeather change: It is no longer a thunderstorm.§r
# Anti AFK
bot.antiafk.not_using_terrain_handling=The terrain handling is not enabled in the settings of the client, enable it if you want to use it with this bot. Using alternative (command) method.
bot.antiafk.invalid_range_partial=Invalid time range provided, using the first part of the range {0} as the time!
bot.antiafk.invalid_range=Invalid time range provided, using default time of 600!
bot.antiafk.invalid_value=Invalid time provided, using default time of 600!
bot.antiafk.swapping=The time range begins with a bigger value, swapped them around.
bot.antiafk.invalid_walk_range=Invalid walk range provided, must be a positive integer greater than 0, using default value of 5!
# AutoAttack
bot.autoAttack.mode=Unknown attack mode: {0}. Using single mode as default.
bot.autoAttack.priority=Unknown priority: {0}. Using distance priority as default.
bot.autoAttack.invalidcooldown=Attack cooldown value cannot be smaller than 0. Using auto as default
bot.autoAttack.invalidcooldown=Attack cooldown value cannot be smaller than 0.
# AutoCraft
bot.autoCraft.cmd=Auto-crafting ChatBot command
@ -489,15 +489,23 @@ bot.autoCraft.aborted=Crafting aborted! Check your available materials.
bot.autoCraft.craft_fail=Crafting failed! Waiting for more materials
bot.autoCraft.timeout=Action timeout! Reason: {0}
bot.autoCraft.error.config=Error while parsing config: {0}
bot.autoCraft.exception.empty=Empty configuration file: {0}
bot.autoCraft.exception.invalid=Invalid configuration file: {0}
bot.autoCraft.exception.item_miss=Missing item in recipe: {0}
bot.autoCraft.exception.invalid_table=Invalid tablelocation format: {0}
bot.autoCraft.exception.item_name=Invalid item name in recipe {0} at {1}
bot.autoCraft.exception.name_miss=Missing recipe name while parsing a recipe
bot.autoCraft.exception.slot=Invalid slot field in recipe: {0}
bot.autoCraft.exception.duplicate=Duplicate recipe name specified: {0}
bot.autoCraft.debug.no_config=No config found. Writing a new one.
bot.autocraft.invaild_slots=The number of slots does not match and has been adjusted automatically.
bot.autocraft.invaild_invaild_result=Invalid result item!
# AutoDig
bot.autodig.start_delay=Digging will start in {0:0.0} second(s).
bot.autodig.dig_timeout=Digging block timeout, retry.
bot.autodig.not_allow=The block currently pointed to is not in the allowed list.
bot.autodig.cmd=Auto-digging ChatBot command
bot.autodig.available_cmd=Available commands: {0}. Use /digbot help <cmd name> for more information.
bot.autodig.start=Automatic digging has started.
bot.autodig.stop=Auto-digging has been stopped.
bot.autodig.help.start=Start the automatic digging bot.
bot.autodig.help.stop=Deactivate the automatic digging bot.
bot.autodig.help.help=Get the command description. Usage: /digbot help <command name>
# AutoDrop
bot.autoDrop.cmd=AutoDrop ChatBot command
@ -596,6 +604,7 @@ bot.map.received_map=Received a new Map, with Id: {0}
bot.map.rendered=Succesfully rendered a map with id '{0}' to: '{1}'
bot.map.failed_to_render=Failed to render the map with id: '{0}'
bot.map.list_item=- Map id: {0} (Last Updated: {1})
bot.map.windows_only=Save to file is currently only available for the windows platform.
# ReplayCapture
bot.replayCapture.cmd=replay command
@ -610,7 +619,7 @@ cmd.follow.already_stopped=Already stopped
cmd.follow.stopping=Stopped following!
cmd.follow.invalid_name=Invalid or empty player name provided!
cmd.follow.invalid_player=The specified player is either not connected out out of the range!
cmd.follow.cant_reach_player=Can\'t reach the player, he is either in chunks that are not loaded, too far away or not reachable by a bot due to obstacles like gaps or water bodies!
cmd.follow.cant_reach_player=Can not reach the player, he is either in chunks that are not loaded, too far away or not reachable by a bot due to obstacles like gaps or water bodies!
cmd.follow.already_following=Already following {0}!
cmd.follow.switched=Switched to following {0}!
cmd.follow.started=Started following {0}!
@ -630,8 +639,6 @@ bot.script.fail=Script '{0}' failed to run ({1}).
bot.script.pm.loaded=Script '{0}' loaded.
# ScriptScheduler
bot.scriptScheduler.loading=Loading tasks from '{0}'
bot.scriptScheduler.not_found=File not found: '{0}'
bot.scriptScheduler.loaded_task=Loaded task:\n{0}
bot.scriptScheduler.no_trigger=This task will never trigger:\n{0}
bot.scriptScheduler.no_action=No action for task:\n{0}
@ -643,3 +650,233 @@ bot.scriptScheduler.task=triggeronfirstlogin: {0}\n triggeronlogin: {1}\n trigge
# TestBot
bot.testBot.told=Bot: {0} told me : {1}
bot.testBot.said=Bot: {0} said : {1}
[config]
config.load=Settings have been loaded from {0}
config.load.fail=§cFailed to load settings:§r
config.write.fail=§cFailed to write to settings file {0}§r
config.backup.fail=§cFailed to write to backup file {0}§r
config.saving=§aThe current setting is saved as {0}
# Head
config.Head=Startup Config File\n# Please do not record extraneous data in this file as it will be overwritten by MCC.\n\n# New to Minecraft Console Client? Check out this document: https://mccteam.github.io/guide/configuration.html\n# Want to upgrade to a newer version? See https://github.com/MCCTeam/Minecraft-Console-Client/#download
# Main.General
config.Main.General.account=Login=Email or Name. Use "-" as password for offline mode. Leave blank to prompt user on startup.
config.Main.General.login=The address of the game server, "Host" can be filled in with domain name or IP address. (The "Port" field can be deleted, it will be resolved automatically)
config.Main.General.server_info=Account type: "mojang" OR "microsoft". Also affects interactive login in console.
config.Main.General.method=Microsoft Account sign-in method: "mcc" OR "browser". If the login always fails, please try to use the "browser" once.
# Main.Advanced
config.Main.Advanced=Make sure you understand what each setting does before changing anything!
config.Main.Advanced.language=Fill in with in-game locale code, check https://github.com/MCCTeam/Minecraft-Console-Client/discussions/2239
config.Main.Advanced.internal_cmd_char=Use "none", "slash"(/) or "backslash"(\).
config.Main.Advanced.message_cooldown=Controls the minimum interval (in seconds) between sending each message to the server.
config.Main.Advanced.bot_owners=Set the owner of the bot. /!\ Server admins can impersonate owners!
config.Main.Advanced.mc_version=Use "auto" or "1.X.X" values. Allows to skip server info retrieval.
config.Main.Advanced.mc_forge=Use "auto", "no" or "force". Force-enabling only works for MC 1.13+.
config.Main.Advanced.brand_info=Use "mcc", "vanilla" or "none". This is how MCC identifies itself to the server.
config.Main.Advanced.chatbot_log_file=Leave empty for no logfile.
config.Main.Advanced.private_msgs_cmd_name=For remote control of the bot.
config.Main.Advanced.show_system_messages=System messages for server ops.
config.Main.Advanced.show_xpbar_messages=Messages displayed above xp bar, set this to false in case of xp bar spam.
config.Main.Advanced.show_chat_links=Decode links embedded in chat messages and show them in console.
config.Main.Advanced.show_inventory_layout=Show inventory layout as ASCII art in inventory command.
config.Main.Advanced.terrain_and_movements=Uses more ram, cpu, bandwidth but allows you to move around.
config.Main.Advanced.inventory_handling=Toggle inventory handling.
config.Main.Advanced.entity_handling=Toggle entity handling.
config.Main.Advanced.session_cache=How to retain session tokens. Use "none", "memory" or "disk".
config.Main.Advanced.profilekey_cache=How to retain profile key. Use "none", "memory" or "disk".
config.Main.Advanced.resolve_srv_records=Use "no", "fast" (5s timeout), or "yes". Required for joining some servers.
config.Main.Advanced.account_list=AccountList: It allows a fast account switching without directly using the credentials\n# Usage examples: "/tell <mybot> reco Player2", "/connect <serverip> Player1"
config.Main.Advanced.server_list=ServerList: It allows an easier and faster server switching with short aliases instead of full server IP\n# Aliases cannot contain dots or spaces, and the name "localhost" cannot be used as an alias.\n# Usage examples: "/tell <mybot> connect Server1", "/connect Server2"
config.Main.Advanced.player_head_icon=Only works on Windows XP-8 or Windows 10 with old console.
config.Main.Advanced.exit_on_failure=Whether to exit directly when an error occurs, for using MCC in non-interactive scripts.
config.Main.Advanced.script_cache=Cache compiled scripts for faster load on low-end devices.
config.Main.Advanced.timestamps=Prepend timestamps to chat messages.
config.Main.Advanced.auto_respawn=Toggle auto respawn if client player was dead (make sure your spawn point is safe).
config.Main.Advanced.minecraft_realms=Enable support for joining Minecraft Realms worlds.
config.Main.Advanced.move_head_while_walking=Enable head movement while walking to avoid anti-cheat triggers.
config.Main.Advanced.timeout=Customize the TCP connection timeout with the server. (in seconds)
config.Main.Advanced.enable_emoji=If turned off, the emoji will be replaced with a simpler character (for /chunk status).
config.Main.Advanced.movement_speed=A movement speed higher than 2 may be considered cheating.
config.Main.Advanced.language.invaild=The language code is invalid!
# Signature
config.Signature=Chat signature related settings (affects minecraft 1.19+)
config.Signature.LoginWithSecureProfile=Microsoft accounts only. If disabled, will not be able to sign chat and join servers configured with "enforce-secure-profile=true"
config.Signature.SignChat=Whether to sign the chat send from MCC
config.Signature.SignMessageInCommand=Whether to sign the messages contained in the commands sent by MCC. For example, the message in "/msg" and "/me"
config.Signature.MarkLegallySignedMsg=Use green color block to mark chat with legitimate signatures
config.Signature.MarkModifiedMsg=Use yellow color block to mark chat that have been modified by the server.
config.Signature.MarkIllegallySignedMsg=Use red color block to mark chat without legitimate signature
config.Signature.MarkSystemMessage=Use gray color block to mark system message (always without signature)
config.Signature.ShowModifiedChat=Set to true to display messages modified by the server, false to display the original signed messages
config.Signature.ShowIllegalSignedChat=Whether to display chat and messages in commands without legal signatures
# Logging
config.Logging=This setting affects only the messages in the console.
config.Logging.DebugMessages=Please enable this before submitting bug reports. Thanks!
config.Logging.ChatMessages=Show server chat messages.
config.Logging.InfoMessages=Informative messages. (i.e Most of the message from MCC)
config.Logging.WarningMessages=Show warning messages.
config.Logging.ErrorMessages=Show error messages.
config.Logging.ChatFilter=Regex for filtering chat message.
config.Logging.DebugFilter=Regex for filtering debug message.
config.Logging.FilterMode="disable" or "blacklist" OR "whitelist". Blacklist hide message match regex. Whitelist show message match regex.
config.Logging.LogToFile=Write log messages to file.
config.Logging.LogFile=Log file name.
config.Logging.PrependTimestamp=Prepend timestamp to messages in log file.
config.Logging.SaveColorCodes=Keep color codes in the saved text.(look like "§b")
# AppVars
config.AppVars.Variables=can be used in some other fields as %yourvar%\n# %username% and %serverip% are reserved variables.
# Proxy
config.Proxy=Connect to a server via a proxy instead of connecting directly\n# If Mojang session services are blocked on your network, set Enabled_Login=true to login using proxy.\n# If the connection to the Minecraft game server is blocked by the firewall, set Enabled_Ingame=true to use a proxy to connect to the game server.\n# /!\ Make sure your server rules allow Proxies or VPNs before setting enabled=true, or you may face consequences!
config.Proxy.Enabled_Login=Whether to connect to the login server through a proxy.
config.Proxy.Enabled_Ingame=Whether to connect to the game server through a proxy.
config.Proxy.Server=Proxy server must allow HTTPS for login, and non-443 ports for playing.
config.Proxy.Proxy_Type=Supported types: "HTTP", "SOCKS4", "SOCKS4a", "SOCKS5".
config.Proxy.Username=Only required for password-protected proxies.
config.Proxy.Password=Only required for password-protected proxies.
# ChatFormat
config.ChatFormat=MCC does it best to detect chat messages, but some server have unusual chat formats\n# When this happens, you'll need to configure chat format below, see https://mccteam.github.io/guide/configuration.html#chat-format
config.ChatFormat.Builtins=MCC support for common message formats. Set "false" to avoid conflicts with custom formats.
config.ChatFormat.UserDefined=Whether to use the custom regular expressions below for detection.
# MCSettings
config.MCSettings=Settings below are sent to the server and only affect server-side things like your skin.
config.MCSettings.Enabled=If disabled, settings below are not sent to the server.
config.MCSettings.Locale=Use any language implemented in Minecraft.
config.MCSettings.RenderDistance=Value range: [0 - 255].
config.MCSettings.Difficulty=MC 1.7- difficulty. "peaceful", "easy", "normal", "difficult".
config.MCSettings.ChatMode=Use "enabled", "commands", or "disabled". Allows to mute yourself...
config.MCSettings.ChatColors=Allows disabling chat colors server-side.
config.MCSettings.MainHand=MC 1.9+ main hand. "left" or "right".
# ChatBot
config.ChatBot================================ #\n# Minecraft Console Client Bots #\n# =============================== #
# ChatBot.Alerts
config.ChatBot.Alerts=Get alerted when specified words are detected in chat\n# Useful for moderating your server or detecting when someone is talking to you
config.ChatBot.Alerts.Beep_Enabled=Play a beep sound when a word is detected in addition to highlighting.
config.ChatBot.Alerts.Trigger_By_Words=Triggers an alert after receiving a specified keyword.
config.ChatBot.Alerts.Trigger_By_Rain=Trigger alerts when it rains and when it stops.
config.ChatBot.Alerts.Trigger_By_Thunderstorm=Triggers alerts at the beginning and end of thunderstorms.
config.ChatBot.Alerts.Matches=List of words/strings to alert you on.
config.ChatBot.Alerts.Excludes=List of words/strings to NOT alert you on.
config.ChatBot.Alerts.Log_To_File=Log alerts info a file.
config.ChatBot.Alerts.Log_File=The name of a file where alers logs will be written.
# ChatBot.AntiAFK
config.ChatBot.AntiAfk=Send a command on a regular or random basis or make the bot walk around randomly to avoid automatic AFK disconnection\n# /!\ Make sure your server rules do not forbid anti-AFK mechanisms!\n# /!\ Make sure you keep the bot in an enclosure to prevent it wandering off if you're using terrain handling! (Recommended size 5x5x5)
config.ChatBot.AntiAfk.Delay=The time interval for execution. (in seconds)
config.ChatBot.AntiAfk.Command=Command to send to the server.
config.ChatBot.AntiAfk.Use_Sneak=Whether to sneak when sending the command.
config.ChatBot.AntiAfk.Use_Terrain_Handling=Use terrain handling to enable the bot to move around.
config.ChatBot.AntiAfk.Walk_Range=The range the bot can move around randomly (Note: the bigger the range, the slower the bot will be)
config.ChatBot.AntiAfk.Walk_Retries=How many times can the bot fail trying to move before using the command method.
# ChatBot.AutoAttack
config.ChatBot.AutoAttack=Automatically attack hostile mobs around you\n# You need to enable Entity Handling to use this bot\n# /!\ Make sure server rules allow your planned use of AutoAttack\n# /!\ SERVER PLUGINS may consider AutoAttack to be a CHEAT MOD and TAKE ACTION AGAINST YOUR ACCOUNT so DOUBLE CHECK WITH SERVER RULES!
config.ChatBot.AutoAttack.Mode="single" or "multi". single target one mob per attack. multi target all mobs in range per attack
config.ChatBot.AutoAttack.Priority="health" or "distance". Only needed when using single mode
config.ChatBot.AutoAttack.Cooldown_Time=How long to wait between each attack. Set "Custom = false" to let MCC calculate it.
config.ChatBot.AutoAttack.Interaction=Possible values: "Interact", "Attack" (default), "InteractAt" (Interact and Attack).
config.ChatBot.AutoAttack.Attack_Hostile=Allow attacking hostile mobs.
config.ChatBot.AutoAttack.Attack_Passive=Allow attacking passive mobs.
config.ChatBot.AutoAttack.List_Mode=Wether to treat the entities list as a "whitelist" or as a "blacklist".
config.ChatBot.AutoAttack.Entites_List=All entity types can be found here: https://bit.ly/3Rg68lp
# ChatBot.AutoCraft
config.ChatBot.AutoCraft=Automatically craft items in your inventory\n# See https://mccteam.github.io/guide/chat-bots.html#auto-craft for how to use\n# You need to enable Inventory Handling to use this bot\n# You should also enable Terrain and Movements if you need to use a crafting table
config.ChatBot.AutoCraft.CraftingTable=Location of the crafting table if you intended to use it. Terrain and movements must be enabled.
config.ChatBot.AutoCraft.OnFailure=What to do on crafting failure, "abort" or "wait".
config.ChatBot.AutoCraft.Recipes=Recipes.Name: The name can be whatever you like and it is used to represent the recipe.\n# Recipes.Type: crafting table type: "player" or "table"\n# Recipes.Result: the resulting item\n# Recipes.Slots: All slots, counting from left to right, top to bottom. Please fill in "Null" for empty slots.\n# For the naming of the items, please see:\n# https://github.com/MCCTeam/Minecraft-Console-Client/blob/master/MinecraftClient/Inventory/ItemType.cs
# AutoDig
config.ChatBot.AutoDig=Auto-digging blocks.\n# You can use "/digbot start" and "/digbot stop" to control the start and stop of AutoDig.\n# Since MCC does not yet support accurate calculation of the collision volume of blocks, all blocks are considered as complete cubes when obtaining the position of the lookahead.\n# For the naming of the block, please see https://github.com/MCCTeam/Minecraft-Console-Client/blob/master/MinecraftClient/Mapping/Material.cs
config.ChatBot.AutoDig.Auto_Tool_Switch=Automatically switch to the appropriate tool.
config.ChatBot.AutoDig.Durability_Limit=Will not use tools with less durability than this. Set to zero to disable this feature.
config.ChatBot.AutoDig.Drop_Low_Durability_Tools=Whether to drop the current tool when its durability is too low.
config.ChatBot.AutoDig.Mode="lookat", "fixedpos" or "both". Digging the block being looked at, the block in a fixed position, or the block that needs to be all met.
config.ChatBot.AutoDig.Locations=The position of the blocks when using "fixedpos" or "both" mode.
config.ChatBot.AutoDig.Location_Order="distance" or "index", When using the "fixedpos" mode, the blocks are determined by distance to the player, or by the order in the list.
config.ChatBot.AutoDig.Auto_Start_Delay=How many seconds to wait after entering the game to start digging automatically, set to -1 to disable automatic start.
config.ChatBot.AutoDig.Dig_Timeout=Mining a block for more than "Dig_Timeout" seconds will be considered a timeout.
config.ChatBot.AutoDig.Log_Block_Dig=Whether to output logs when digging blocks.
config.ChatBot.AutoDig.List_Type=Wether to treat the blocks list as a "whitelist" or as a "blacklist".
# ChatBot.AutoDrop
config.ChatBot.AutoDrop=Automatically drop items in inventory\n# You need to enable Inventory Handling to use this bot\n# See this file for an up-to-date list of item types you can use with this bot:\n# https://github.com/MCCTeam/Minecraft-Console-Client/blob/master/MinecraftClient/Inventory/ItemType.cs
config.ChatBot.AutoDrop.Mode="include", "exclude" or "everything". Include: drop item IN the list. Exclude: drop item NOT IN the list
# ChatBot.AutoEat
config.ChatBot.AutoEat=Automatically eat food when your Hunger value is low\n# You need to enable Inventory Handling to use this bot
# ChatBot.AutoFishing
config.ChatBot.AutoFishing=Automatically catch fish using a fishing rod\n# Guide: https://mccteam.github.io/guide/chat-bots.html#auto-fishing\n# /!\ Make sure server rules allow automated farming before using this bot
config.ChatBot.AutoFishing.Antidespawn=Keep it as false if you have not changed it before.
config.ChatBot.AutoFishing.Mainhand=Use the mainhand or the offhand to hold the rod.
config.ChatBot.AutoFishing.Auto_Start=Whether to start fishing automatically after entering a world.
config.ChatBot.AutoFishing.Cast_Delay=How soon to re-cast after successful fishing.
config.ChatBot.AutoFishing.Fishing_Delay=How long after entering the game to start fishing (seconds).
config.ChatBot.AutoFishing.Fishing_Timeout=Fishing timeout (seconds). Timeout will trigger a re-cast.
config.ChatBot.AutoFishing.Durability_Limit=Will not use rods with less durability than this (full durability is 64). Set to zero to disable this feature.
config.ChatBot.AutoFishing.Auto_Rod_Switch=Switch to a new rod from inventory after the current rod is unavailable.
config.ChatBot.AutoFishing.Stationary_Threshold=Hook movement in the X and Z axis less than this value will be considered stationary.
config.ChatBot.AutoFishing.Hook_Threshold=A "stationary" hook that moves above this threshold in the Y-axis will be considered to have caught a fish.
config.ChatBot.AutoFishing.Log_Fish_Bobber=Used to adjust the above two thresholds, which when enabled will print the change in the position of the fishhook entity upon receipt of its movement packet.
config.ChatBot.AutoFishing.Enable_Move=This allows the player to change position/facing after each fish caught.
config.ChatBot.AutoFishing.Movements=It will move in order "1->2->3->4->3->2->1->2->..." and can change position or facing or both each time. It is recommended to change the facing only.
# ChatBot.AutoRelog
config.ChatBot.AutoRelog=Automatically relog when disconnected by server, for example because the server is restating\n# /!\ Use Ignore_Kick_Message=true at own risk! Server staff might not appreciate if you auto-relog on manual kicks
config.ChatBot.AutoRelog.Delay=The delay time before joining the server. (in seconds)
config.ChatBot.AutoRelog.Retries=Retries when failing to relog to the server. use -1 for unlimited retries.
config.ChatBot.AutoRelog.Ignore_Kick_Message=When set to true, autorelog will reconnect regardless of kick messages.
config.ChatBot.AutoRelog.Kick_Messages=If the kickout message matches any of the strings, then autorelog will be triggered.
# ChatBot.AutoRespond
config.ChatBot.AutoRespond=Run commands or send messages automatically when a specified pattern is detected in chat\n# /!\ Server admins can spoof chat messages (/nick, /tellraw) so keep this in mind when implementing AutoRespond rules\n# /!\ This bot may get spammy depending on your rules, although the global messagecooldown setting can help you avoiding accidental spam
config.ChatBot.AutoRespond.Match_Colors=Do not remove colors from text (Note: Your matches will have to include color codes (ones using the § character) in order to work)
# ChatBot.ChatLog
config.ChatBot.ChatLog=Logs chat messages in a file on disk.
# ChatBot.FollowPlayer
config.ChatBot.FollowPlayer=Enabled you to make the bot follow you\n# NOTE: This is an experimental feature, the bot can be slow at times, you need to walk with a normal speed and to sometimes stop for it to be able to keep up with you\n# It's similar to making animals follow you when you're holding food in your hand.\n# This is due to a slow pathfinding algorithm, we're working on getting a better one\n# You can tweak the update limit and find what works best for you. (NOTE: Do not but a very low one, because you might achieve the opposite,\n# this might clog the thread for terain handling) and thus slow the bot even more.\n# /!\ Make sure server rules allow an option like this in the rules of the server before using this bot
config.ChatBot.FollowPlayer.Update_Limit=The rate at which the bot does calculations (in seconds) (You can tweak this if you feel the bot is too slow)
config.ChatBot.FollowPlayer.Stop_At_Distance=Do not follow the player if he is in the range of 3 blocks (prevents the bot from pushing a player in an infinite loop)
# ChatBot.HangmanGame
config.ChatBot.HangmanGame=A small game to demonstrate chat interactions. Players can guess mystery words one letter at a time.\n# You need to have ChatFormat working correctly and add yourself in botowners to start the game with /tell <bot username> start\n# /!\ This bot may get a bit spammy if many players are interacting with it
# ChatBot.Mailer
config.ChatBot.Mailer=Relay messages between players and servers, like a mail plugin\n# This bot can store messages when the recipients are offline, and send them when they join the server\n# /!\ Server admins can spoof PMs (/tellraw, /nick) so enable this bot only if you trust server admins
# ChatBot.Map
config.ChatBot.Map=Allows you to render maps into .jpg images\n# This is useful for solving captchas which use maps\n# The maps are rendered into Rendered_Maps folder.\n# NOTE:\n# This feature is currently only useful for solving captchas which use maps.\n# If some servers have a very short time for solving captchas, enabe Auto_Render_On_Update and prepare to open the file quickly.\n# On linux you can use FTP to access generated files.\n# In the future it might will be possible to display maps directly in the console with a separate command.\n# /!\ Make sure server rules allow bots to be used on the server, or you risk being punished.
config.ChatBot.Map.Should_Resize=Should the map be resized? (Default one is small 128x128)
config.ChatBot.Map.Resize_To=The size to resize the map to (Note: the bigger it is, the lower the quallity is)
config.ChatBot.Map.Auto_Render_On_Update=Automatically render the map once it is received or updated from/by the server
config.ChatBot.Map.Delete_All_On_Unload=Delete all rendered maps on unload/reload (Does not delete the images if you exit the client)
config.ChatBot.Map.Notify_On_First_Update=Get a notification when you have gotten a map from the server for the first time
# ChatBot.PlayerListLogger
config.ChatBot.PlayerListLogger=Log the list of players periodically into a textual file.
config.ChatBot.PlayerListLogger.Delay=(In seconds)
# ChatBot.RemoteControl
config.ChatBot.RemoteControl=Send MCC console commands to your bot through server PMs (/tell)\n# You need to have ChatFormat working correctly and add yourself in botowners to use the bot\n# /!\ Server admins can spoof PMs (/tellraw, /nick) so enable RemoteControl only if you trust server admins
# ChatBot.ReplayCapture
config.ChatBot.ReplayCapture=Enable recording of the game (/replay start) and replay it later using the Replay Mod (https://www.replaymod.com/)\n# Please note that due to technical limitations, the client player (you) will not be shown in the replay file\n# /!\ You SHOULD use /replay stop or exit the program gracefully with /quit OR THE REPLAY FILE MAY GET CORRUPT!
config.ChatBot.ReplayCapture.Backup_Interval=How long should replay file be auto-saved, in seconds. Use -1 to disable.
# ChatBot.ScriptScheduler
config.ChatBot.ScriptScheduler=Schedule commands and scripts to launch on various events such as server join, date/time or time interval\n# See https://mccteam.github.io/guide/chat-bots.html#script-scheduler for more info

View file

@ -1,15 +1,22 @@
[mcc]
# Messages from MCC itself
mcc.help_us_translate=
mcc.run_with_default_settings=
mcc.settings_generated=
mcc.has_update=
mcc.login=Connexion :
mcc.login_basic_io=Veuillez saisir un nom d'utilisateur ou une adresse email.
mcc.password=Mot de passe :
mcc.password=Mot de passe :
mcc.password_basic_io=Saisissez le mot de passe pour {0}.
mcc.password_hidden=Mot de passe : {0}
mcc.offline=§8Vous avez choisi d'utiliser le mode hors ligne.
mcc.session_invalid=§8Le cache de la session est invalide ou a expiré.
mcc.session_valid=§8Le cache de la session est encore valable pendant {0}.
mcc.profile_key_invalid=
mcc.profile_key_valid=
mcc.connecting=Connexion à {0}...
mcc.ip=Adresse IP du Serveur :
mcc.fetching_key=
mcc.ip=Adresse IP du Serveur :
mcc.use_version=§8Utilisation de la version {0} de Minecraft (protocole v{1})
mcc.unknown_version=§8Version MC non connue ou non supportée. {0}.\nPassage en mode autodétection.
mcc.forge=Vérification si le serveur utilise Forge...
@ -20,7 +27,7 @@ mcc.not_found=§8Échec de la résolution SRV pour {0}\n{1} : {2}
mcc.retrieve=Récupération des informations du serveur...
mcc.restart=Redémarrage de Minecraft Console Client...
mcc.restart_delay=Attente de {0} secondes avant de redémarrer...
mcc.server_version=Version du serveur :
mcc.server_version=Version du serveur :
mcc.disconnected=Actuellement non connecté à un serveur. Utilisez '{0}help' pour obtenir de l'aide.
mcc.press_exit=Ou appuyez sur la touche Entrer pour quitter Minecraft Console Client.
mcc.version_supported=La version est prise en charge.\nConnexion...
@ -41,13 +48,16 @@ mcc.with_forge=, avec Forge
mcc.handshake=§8Handshake réussi. (ID Serveur : {0})
mcc.realms_available=Vous avez accès aux mondes Realms suivants
mcc.realms_join=Utilisez realms:<index> comme ip de serveur pour rejoindre un monde Realms
mcc.generator.generating=
mcc.generator.done=
[debug]
# Messages from MCC Debug Mode
debug.color_test=Test des couleurs : Votre terminal devrait afficher {0}
debug.session_cache_ok=§8Informations de Session chargées depuis le disque avec succès.
debug.session_cache_fail=§8Aucune session n'a pu être chargé depuis le disque
debug.keys_cache_ok=
debug.keys_cache_fail=
debug.session_id=Succès. (ID de Session : {0})
debug.crypto=§8Clé de chiffrement & hash générés.
debug.request=§8Envoi d'une requête à {0}
@ -58,7 +68,7 @@ error.ping=Échec du ping sur l'IP.
error.unsupported=Impossible de se connecter au serveur : Cette version n'est pas prise en charge !
error.determine=La version du serveur n'a pas pu être déterminée.
error.forgeforce=Impossible de forcer le support de Forge sur cette version de Minecraft !
error.login=Échec d'authentification :
error.login=Échec d'authentification :
error.login.migrated=Compte migré, utiliser l'email à la place du nom d'utilisateur.
error.login.server=Serveur d'authentification indisponible. Veuillez réessayer ultérieurement.
error.login.blocked=Mot de passe incorrect, IP bannie ou trop de connexions.
@ -67,7 +77,6 @@ error.login.premium=L'utilisateur n'est pas premium.
error.login.network=Erreur réseau.
error.login.ssl=Erreur SSL.
error.login.unknown=Erreur inconnue.
error.login.ssl_help=§8Il semblerait que vous utilisez Mono pour lancer ce programme.\nLa première fois, vous devez importer les certificats HTTPS en utilisant :\nmozroots --import --ask-remove
error.login.cancel=Annulé par l'utilisateur.
error.login_failed=Échec de la connexion au serveur.
error.join=Une erreur est survenue lors de la connexion au serveur.
@ -81,10 +90,7 @@ error.no_version_report=§8Le serveur n'indique pas la version de son protocole.
error.connection_timeout=§8La connexion à cette adresse IP n'a pas abouti (timeout).
error.forge=§8Le Handshake Forge (Login) n'a pas réussi
error.forge_encrypt=§8Le Handshake Forge (StartEncryption) n'a pas réussi
error.setting.str2int=Échec de la conversion '{0}' en nombre entier. Veuillez vérifier la configuration.
error.setting.argument_syntax={0} : Syntaxe invalide, --argname=value ou --section.argname=value attendu
error.setting.unknown_section={0} : Section de configuration '{1}' inconnue
error.setting.unknown_or_invalid={0} : Paramètre inconnu ou valeur invalide
error.http_code=§8Code d'erreur indiqué par le serveur : {0}
error.auth=§8Le serveur a retourné un code d'erreur lors du rafraichissement de l'authentification : {0}
error.realms.ip_error=Impossible de déterminer l'IP du serveur de votre monde Realms
@ -92,6 +98,11 @@ error.realms.access_denied=Ce monde Realms n'existe pas ou l'accès a été refu
error.realms.server_unavailable=Le serveur peut nécessiter un peu de temps pour démarrer. Veuillez réessayer plus tard.
error.realms.server_id=ID Realms invalide ou inconnu.
error.realms.disabled=Tentative de connexion à un monde Realms mais le support Realms est désactivé dans la configuration
error.missing.argument=
error.usage=
error.generator.invalid=
error.generator.path=
error.generator.json=
[internal command]
# MCC internal help command
@ -173,6 +184,14 @@ cache.ignore_line=§8Ignoré une ligne de jeton de session invalide : {0}
cache.read_fail_plain=§8Échec de la lecture ddu fichier de cache de sessions : {0}
cache.saving=§8Sauvegarde du cache de sessions sur le disque
cache.save_fail=§8Échec d'écriture du fichier de cache de sessions : {0}
# Profile Key Cache
cache.loading_keys=
cache.loaded_keys=
cache.ignore_string_keys=
cache.ignore_line_keys=
cache.read_fail_plain_keys=
cache.saving_keys=
cache.save_fail_keys=
[proxy]
proxy.connected=§8Connecté au proxy {0}:{1}
@ -186,6 +205,7 @@ chat.fail=§8Échec de téléchargement du fichier.
chat.from_dir=§8Utilisation à la place de en_GB.lang depuis votre jeu Minecraft.
chat.loaded=§8Fichier de traductions chargé.
chat.not_found=§8Fichier de traductions non trouvé : '{0}'\nCertains messages ne seront pas affichés correctement sans ce fichier.
chat.message_chain_broken=
[general]
# General message/information (i.e. Done)
@ -201,12 +221,23 @@ general.available_cmd=Commandes disponibles : {0}
# Animation
cmd.animation.desc=Balancer le bras.
# Bots
cmd.bots.desc=
cmd.bots.list=
cmd.bots.notfound=
cmd.bots.noloaded=
cmd.bots.unloaded=
cmd.bots.unloaded_all=
# ChangeSlot
cmd.changeSlot.desc=Changer de slot (emplacement) dans la hotbar
cmd.changeSlot.nan=Le slot n'a pas pu être changé : Numéro invalide
cmd.changeSlot.changed=Slot sélectionné : {0}
cmd.changeSlot.fail=Le slot n'a pas pu être sélectionné
# Chunk
cmd.chunk.desc=
# Connect
cmd.connect.desc=Se connecter au serveur spécifié
cmd.connect.unknown=Compte '{0}' inconnu.
@ -248,6 +279,19 @@ cmd.entityCmd.distance=Distance
cmd.entityCmd.location=Emplacement
cmd.entityCmd.type=Type
# Exec If
cmd.execif.desc=
cmd.execif.executed=
cmd.execif.executed_no_output=
cmd.execif.error_occured=
cmd.execif.error=
# Exec Multi
cmd.execmulti.desc=
cmd.execmulti.executed=
cmd.execmulti.result=
cmd.execmulti.no_result=
# Exit
cmd.exit.desc=Se déconnecter du serveur.
@ -267,15 +311,18 @@ cmd.inventory.close_fail=Impossible de fermer l'inventaire #{0}
cmd.inventory.not_exist=L'inventaire #{0} n'existe pas
cmd.inventory.inventory=Inventaire
cmd.inventory.inventories=Inventaires
cmd.inventory.inventories_available=
cmd.inventory.hotbar=Votre sélection dans la horbar : {0}
cmd.inventory.damage=Dommage
cmd.inventory.left=gauche
cmd.inventory.right=droit
cmd.inventory.middle=du milieu
cmd.inventory.clicking=Clic {0} sur le slot {1} dans la fenêtre #{2}
cmd.inventory.shiftclick=
cmd.inventory.shiftclick_fail=
cmd.inventory.no_item=Aucun objet dans le slot #{0}
cmd.inventory.drop=Lâché 1 objet depuis le slot #{0}
cmd.inventory.drop_stack=Lâché tous les objets du slot #{0}
cmd.inventory.drop_stack=Lâché tous les objets du slot #{0}
# Inventory Help
cmd.inventory.help.basic=Utilisation de base
cmd.inventory.help.available=Actions possibles
@ -284,10 +331,29 @@ cmd.inventory.help.usage=Utilisation
cmd.inventory.help.list=Lister votre inventaire.
cmd.inventory.help.close=Fermer un conteneur ouvert.
cmd.inventory.help.click=Cliquer sur un objet.
cmd.inventory.help.shiftclick=
cmd.inventory.help.drop=Lâcher un objet de votre inventaire.
cmd.inventory.help.creativegive=Se donner un objet en mode créatif.
cmd.inventory.help.creativedelete=Vider un slot en mode créatif.
cmd.inventory.help.unknown=Action inconnue.
cmd.inventory.help.inventories=
cmd.inventory.help.search=
cmd.inventory.help.unknown=Action inconnue.
cmd.inventory.found_items=
cmd.inventory.no_found_items=
# Leave bed
cmd.bed.desc=
cmd.bed.leaving=
cmd.bed.trying_to_use=
cmd.bed.in=
cmd.bed.not_in=
cmd.bed.not_a_bed=
cmd.bed.searching=
cmd.bed.bed_not_found=
cmd.bed.found_a_bed_at=
cmd.bed.cant_reach_safely=
cmd.bed.moving=
cmd.bed.failed_to_reach_in_time=
# List
cmd.list.desc=Lister les joueurs connectés.
@ -301,6 +367,8 @@ cmd.look.desc=Regarder dans une direction ou des coordonnées.
cmd.look.unknown=Direction inconnue : '{0}'
cmd.look.at=Rotation de la tête (YAW:{0}, PITCH:{1})
cmd.look.block=Rotation de la tête vers : {0}
cmd.look.inspection=
cmd.look.noinspection=
# Move
cmd.move.desc=Marcher ou commencer à marcher.
@ -313,10 +381,21 @@ cmd.move.fail=Échec de calcul du chemin vers {0}
cmd.move.suggestforce=Échec de calcul du chemin vers {0}. Utilisez -f pour autoriser les mouvements risqués.
cmd.move.gravity.enabled=La gravité est activée.
cmd.move.gravity.disabled=La gravité est désactivée.
cmd.move.chunk_loading_status=
cmd.move.chunk_not_loaded=
# Reco
cmd.reco.desc=Relancer le programme et se reconnecter au serveur
# Reload
cmd.reload.started=
cmd.reload.warning1=
cmd.reload.warning2=
cmd.reload.warning3=
cmd.reload.warning4=
cmd.reload.finished=
cmd.reload.desc=
# Respawn
cmd.respawn.desc=Réapparaitre sur le serveur si vous êtes mort.
cmd.respawn.done=Vous êtes réapparu.
@ -352,6 +431,7 @@ cmd.tps.current=TPS actuel
# Useblock
cmd.useblock.desc=Placer un bloc ou ouvrir un coffre
cmd.useblock.use=
# Useitem
cmd.useitem.desc=Utiliser (clic gauche) un objet dans la main
@ -361,9 +441,18 @@ cmd.useitem.use=Objet utilisé
[bot]
# ChatBots. Naming style: bot.<className>.<msg...>
# Alerts
bot.alerts.start_rain=
bot.alerts.end_rain=
bot.alerts.start_thunderstorm=
bot.alerts.end_thunderstorm=
# Anti AFK
bot.antiafk.not_using_terrain_handling=
bot.antiafk.swapping=
bot.antiafk.invalid_walk_range=
# AutoAttack
bot.autoAttack.mode=Mode d'attaque inconnu : {0}. Utilisation du mode par défaut (single).
bot.autoAttack.priority=Priorité inconnue : {0}. Utilisation du mode par défaut (privilégier la distance).
bot.autoAttack.invalidcooldown=La valeur du Cooldown d'attaque ne peut pas être plus faible que 0. Utilisation du mode par défaut (distance automatique).
# AutoCraft
@ -392,15 +481,11 @@ bot.autoCraft.aborted=Fabrication interrompue ! Vérifiez vos matériaux disponi
bot.autoCraft.craft_fail=Échec de la fabrication ! Attente de plus de matériaux
bot.autoCraft.timeout=Le délai d'attente de l'action expiré ! Raison : {0}
bot.autoCraft.error.config=Erreur de traitement de la configuration : {0}
bot.autoCraft.exception.empty=Fichier de configuration vide : {0}
bot.autoCraft.exception.invalid=Fichier de configuration invalide : {0}
bot.autoCraft.exception.item_miss=Objet manquant dans la recette : {0}
bot.autoCraft.exception.invalid_table=Le format du lieu de l'établi est invalide : {0}
bot.autoCraft.exception.item_name=Nom d'objet invalide dans la recette {0} à {1}
bot.autoCraft.exception.name_miss=Nom manquant lors du chargement d'une recette
bot.autoCraft.exception.slot=Slot invalide dans la recette : {0}
bot.autoCraft.exception.duplicate=Nom de recette spécifié en double : {0}
bot.autoCraft.debug.no_config=Fichier de configuration introuvable. Création d'un nouveau fichier.
bot.autocraft.invaild_slots=
bot.autocraft.invaild_invaild_result=
# AutoDrop
bot.autoDrop.cmd=Commande du ChatBot AutoDrop
@ -419,9 +504,17 @@ bot.autoDrop.no_mode=Impossible de lire le mode de Drop dans la configuration. U
bot.autoDrop.no_inventory=Impossible de trouver l'inventaire {0} !
# AutoFish
bot.autoFish.no_inv_handle=
bot.autoFish.start=
bot.autoFish.throw=Canne à pêche lancée
bot.autoFish.caught=Poisson attrapé !
bot.autoFish.caught_at=
bot.autoFish.no_rod=Pas de canne a pêche dans la main. Peut-être a-t-elle cassé ?
bot.autoFish.despawn=
bot.autoFish.fishing_timeout=
bot.autoFish.cast_timeout=
bot.autoFish.update_lookat=
bot.autoFish.switch=
# AutoRelog
bot.autoRelog.launch=Lancement avec {0} tentatives de reconnexion
@ -465,7 +558,7 @@ bot.mailer.init_fail.mail_retention=Impossible d'activer le Mailer : La rétenti
bot.mailer.create.db=Création d'un nouveau fichier de base de données : {0}
bot.mailer.create.ignore=Création d'une nouvelle liste d'exclusions : {0}
bot.mailer.load.db=Chargement de la base de données : {0}
bot.mailer.load.ignore=Chargement de la liste d'exclusions :
bot.mailer.load.ignore=Chargement de la liste d'exclusions :
bot.mailer.cmd=Commande du Mailer
@ -481,12 +574,43 @@ bot.mailer.cmd.ignore.removed=Retrait de {0} de la liste d'exclusions !
bot.mailer.cmd.ignore.invalid=Nom manquant ou invalide. Utilisation : {0} <pseudo>
bot.mailer.cmd.help=Voir l'utilisation
# Maps
bot.map.cmd.desc=
bot.map.cmd.not_found=
bot.map.cmd.invalid_id=
bot.map.received=
bot.map.no_maps=
bot.map.received_map=
bot.map.rendered=
bot.map.failed_to_render=
bot.map.list_item=
# ReplayCapture
bot.replayCapture.cmd=Commande de Replay
bot.replayCapture.created=Fichier de Replay créé.
bot.replayCapture.stopped=Enregistrement arrêté.
bot.replayCapture.restart=L'enregistrement a été stoppé. Redémarrez le programme pour commencer un nouvel enregistrement.
# Follow player
cmd.follow.desc=
cmd.follow.usage=
cmd.follow.already_stopped=
cmd.follow.stopping=
cmd.follow.invalid_name=
cmd.follow.invalid_player=
cmd.follow.cant_reach_player=
cmd.follow.already_following=
cmd.follow.switched=
cmd.follow.started=
cmd.follow.unsafe_enabled=
cmd.follow.note=
cmd.follow.player_came_to_the_range=
cmd.follow.resuming=
cmd.follow.player_left_the_range=
cmd.follow.pausing=
cmd.follow.player_left=
cmd.follow.stopping=
# Script
bot.script.not_found=§8[MCC] [{0}] Impossible de trouver le fichier de script : {1}
bot.script.file_not_found=Fichier non trouvé : '{0}'
@ -494,8 +618,6 @@ bot.script.fail=Le script '{0}' n'a pas pu être lancé ({1}).
bot.script.pm.loaded=Script '{0}' chargé.
# ScriptScheduler
bot.scriptScheduler.loading=Chargement des tâches depuis '{0}'
bot.scriptScheduler.not_found=Fichier non trouvé : '{0}'
bot.scriptScheduler.loaded_task=Tâche chargée :\n{0}
bot.scriptScheduler.no_trigger=Cette tâche ne sera jamais déclenchée :\n{0}
bot.scriptScheduler.no_action=Aucune action pour cette tâche :\n{0}
@ -507,3 +629,220 @@ bot.scriptScheduler.task=triggeronfirstlogin : {0}\n triggeronlogin : {1}\n trig
# TestBot
bot.testBot.told=Bot : {0} m'a dit : {1}
bot.testBot.said=Bot : {0} a dit : {1}
[config]
config.load=
config.load.fail=
config.write.fail=
config.backup.fail=
config.saving=
# Head
config.Head=
# Main.General
config.Main.General.account=
config.Main.General.login=
config.Main.General.server_info=
config.Main.General.method=
# Main.Advanced
config.Main.Advanced=
config.Main.Advanced.language=
config.Main.Advanced.internal_cmd_char=
config.Main.Advanced.message_cooldown=
config.Main.Advanced.bot_owners=
config.Main.Advanced.mc_version=
config.Main.Advanced.mc_forge=
config.Main.Advanced.brand_info=
config.Main.Advanced.chatbot_log_file=
config.Main.Advanced.private_msgs_cmd_name=
config.Main.Advanced.show_system_messages=
config.Main.Advanced.show_xpbar_messages=
config.Main.Advanced.show_chat_links=
config.Main.Advanced.show_inventory_layout=
config.Main.Advanced.terrain_and_movements=
config.Main.Advanced.inventory_handling=
config.Main.Advanced.entity_handling=
config.Main.Advanced.session_cache=
config.Main.Advanced.profilekey_cache=
config.Main.Advanced.resolve_srv_records=
config.Main.Advanced.account_list=
config.Main.Advanced.server_list=
config.Main.Advanced.player_head_icon=
config.Main.Advanced.exit_on_failure=
config.Main.Advanced.script_cache=
config.Main.Advanced.timestamps=
config.Main.Advanced.auto_respawn=
config.Main.Advanced.minecraft_realms=
config.Main.Advanced.move_head_while_walking=
config.Main.Advanced.timeout=
config.Main.Advanced.enable_emoji=
config.Main.Advanced.movement_speed=
config.Main.Advanced.language.invaild=
# Signature
config.Signature=
config.Signature.LoginWithSecureProfile=
config.Signature.SignChat=
config.Signature.SignMessageInCommand=
config.Signature.MarkLegallySignedMsg=
config.Signature.MarkModifiedMsg=
config.Signature.MarkIllegallySignedMsg=
config.Signature.MarkSystemMessage=
config.Signature.ShowModifiedChat=
config.Signature.ShowIllegalSignedChat=
# Logging
config.Logging=
config.Logging.DebugMessages=
config.Logging.ChatMessages=
config.Logging.InfoMessages=
config.Logging.WarningMessages=
config.Logging.ErrorMessages=
config.Logging.ChatFilter=
config.Logging.DebugFilter=
config.Logging.FilterMode=
config.Logging.LogToFile=
config.Logging.LogFile=
config.Logging.PrependTimestamp=
config.Logging.SaveColorCodes=
# AppVars
config.AppVars.Variables=
# Proxy
config.Proxy=
config.Proxy.Enabled_Login=
config.Proxy.Enabled_Ingame=
config.Proxy.Server=
config.Proxy.Proxy_Type=
config.Proxy.Username=
config.Proxy.Password=
# ChatFormat
config.ChatFormat=
config.ChatFormat.Builtins=
config.ChatFormat.UserDefined=
# MCSettings
config.MCSettings=
config.MCSettings.Enabled=
config.MCSettings.Locale=
config.MCSettings.RenderDistance=
config.MCSettings.Difficulty=
config.MCSettings.ChatMode=
config.MCSettings.ChatColors=
config.MCSettings.MainHand=
# ChatBot
config.ChatBot=
# ChatBot.Alerts
config.ChatBot.Alerts=
config.ChatBot.Alerts.Beep_Enabled=
config.ChatBot.Alerts.Trigger_By_Words=
config.ChatBot.Alerts.Trigger_By_Rain=
config.ChatBot.Alerts.Trigger_By_Thunderstorm=
config.ChatBot.Alerts.Matches=
config.ChatBot.Alerts.Excludes=
config.ChatBot.Alerts.Log_To_File=
config.ChatBot.Alerts.Log_File=
# ChatBot.AntiAFK
config.ChatBot.AntiAfk=
config.ChatBot.AntiAfk.Delay=
config.ChatBot.AntiAfk.Command=
config.ChatBot.AntiAfk.Use_Terrain_Handling=
config.ChatBot.AntiAfk.Walk_Range=
config.ChatBot.AntiAfk.Walk_Retries=
# ChatBot.AutoAttack
config.ChatBot.AutoAttack=
config.ChatBot.AutoAttack.Mode=
config.ChatBot.AutoAttack.Priority=
config.ChatBot.AutoAttack.Cooldown_Time=
config.ChatBot.AutoAttack.Interaction=
config.ChatBot.AutoAttack.Attack_Hostile=
config.ChatBot.AutoAttack.Attack_Passive=
config.ChatBot.AutoAttack.List_Mode=
config.ChatBot.AutoAttack.Entites_List=
# ChatBot.AutoCraft
config.ChatBot.AutoCraft=
config.ChatBot.AutoCraft.CraftingTable=
config.ChatBot.AutoCraft.OnFailure=
config.ChatBot.AutoCraft.Recipes=
# ChatBot.AutoDrop
config.ChatBot.AutoDrop=
config.ChatBot.AutoDrop.Mode=
# ChatBot.AutoEat
config.ChatBot.AutoEat=
# ChatBot.AutoFishing
config.ChatBot.AutoFishing=
config.ChatBot.AutoFishing.Antidespawn=
config.ChatBot.AutoFishing.Mainhand=
config.ChatBot.AutoFishing.Auto_Start=
config.ChatBot.AutoFishing.Cast_Delay=
config.ChatBot.AutoFishing.Fishing_Delay=
config.ChatBot.AutoFishing.Fishing_Timeout=
config.ChatBot.AutoFishing.Durability_Limit=
config.ChatBot.AutoFishing.Auto_Rod_Switch=
config.ChatBot.AutoFishing.Stationary_Threshold=
config.ChatBot.AutoFishing.Hook_Threshold=
config.ChatBot.AutoFishing.Log_Fish_Bobber=
config.ChatBot.AutoFishing.Enable_Move=
config.ChatBot.AutoFishing.Movements=
# ChatBot.AutoRelog
config.ChatBot.AutoRelog=
config.ChatBot.AutoRelog.Delay=
config.ChatBot.AutoRelog.Retries=
config.ChatBot.AutoRelog.Ignore_Kick_Message=
config.ChatBot.AutoRelog.Kick_Messages=
# ChatBot.AutoRespond
config.ChatBot.AutoRespond=
config.ChatBot.AutoRespond.Match_Colors=
# ChatBot.ChatLog
config.ChatBot.ChatLog=
# ChatBot.FollowPlayer
config.ChatBot.FollowPlayer=
config.ChatBot.FollowPlayer.Update_Limit=
config.ChatBot.FollowPlayer.Stop_At_Distance=
# ChatBot.HangmanGame
config.ChatBot.HangmanGame=
# ChatBot.Mailer
config.ChatBot.Mailer=
# ChatBot.Map
config.ChatBot.Map=
config.ChatBot.Map.Should_Resize=
config.ChatBot.Map.Resize_To=
config.ChatBot.Map.Auto_Render_On_Update=
config.ChatBot.Map.Delete_All_On_Unload=
config.ChatBot.Map.Notify_On_First_Update=
# ChatBot.PlayerListLogger
config.ChatBot.PlayerListLogger=
config.ChatBot.PlayerListLogger.Delay=
# ChatBot.RemoteControl
config.ChatBot.RemoteControl=
# ChatBot.ReplayCapture
config.ChatBot.ReplayCapture=
config.ChatBot.ReplayCapture.Backup_Interval=
# ChatBot.ScriptScheduler
config.ChatBot.ScriptScheduler=

View file

@ -1,15 +1,22 @@
[mcc]
# Messages from MCC itself
mcc.help_us_translate=
mcc.run_with_default_settings=
mcc.settings_generated=
mcc.has_update=
mcc.login=Логин :
mcc.login_basic_io=Пожалуйста, введите имя пользователя или email по вашему выбору.
mcc.password=Пароль:
mcc.password=Пароль:
mcc.password_basic_io=Пожалуйста, введите пароль для {0}.
mcc.password_hidden=Пароль: {0}
mcc.offline=§8Вы выбрали запуск в автономном режиме.
mcc.session_invalid=§8Кэшированная сессия недействительна или истекла.
mcc.session_valid=§8Кэшированная сессия все еще действительна для {0}.
mcc.profile_key_invalid=
mcc.profile_key_valid=
mcc.connecting=Подключение к {0}...
mcc.ip=IP сервера:
mcc.fetching_key=
mcc.ip=IP сервера:
mcc.use_version=§8Используется Minecraft версии {0} (протокол v{1})
mcc.unknown_version=§8Неизвестная или не поддерживаемая версия MC {0}.\nПереключение в режим автоопределения.
mcc.forge=Проверка, запущен ли на сервере Forge...
@ -20,7 +27,7 @@ mcc.not_found=§8Failed to perform SRV lookup for {0}\n{1}: {2}
mcc.retrieve=Получение информации о сервере...
mcc.restart=Перезапуск консольного клиента Minecraft...
mcc.restart_delay=Ожидание {0} секунд перед перезапуском...
mcc.server_version=Версия сервера:
mcc.server_version=Версия сервера:
mcc.disconnected=Не подключен ни к одному серверу. Используйте '{0}help' для получения справки.
mcc.press_exit=Нажмите Enter, чтобы выйти из консольного клиента Minecraft.
mcc.version_supported=Версия поддерживается.\nВойти в игру...
@ -41,13 +48,16 @@ mcc.with_forge=, с Forge
mcc.handshake=§8Handshake successful. (ID сервера: {0})
mcc.realms_available=У вас есть доступ к следующим мирам Realms
mcc.realms_join=Используйте realms:index как IP сервера, чтобы присоединиться к миру Realms
mcc.generator.generating=
mcc.generator.done=
[debug]
# Messages from MCC Debug Mode
debug.color_test=Цветовой тест: В вашем терминале должно отображаться {0}
debug.session_cache_ok=§8Данные сессии успешно загружены с диска.
debug.session_cache_fail=§8Ни одна сессия не могла быть загружена с диска
debug.keys_cache_ok=
debug.keys_cache_fail=
debug.session_id=Успех. (ID сессии: {0})
debug.crypto=§8Сгенерированы криптографические ключи и хэш.
debug.request=§8Выполнение запроса к {0}
@ -58,7 +68,7 @@ error.ping=Не удалось выполнить ping этого IP.
error.unsupported=Не удается подключиться к серверу: эта версия не поддерживается!
error.determine=Не удалось определить версию сервера.
error.forgeforce=Не удается принудительно включить поддержку Forge для этой версии Minecraft!
error.login=Не удалось войти в систему Minecraft :
error.login=Не удалось войти в систему Minecraft :
error.login.migrated=Аккаунт перенесен, используйте e-mail в качестве имени пользователя.
error.login.server=Серверы входа недоступны. Пожалуйста, повторите попытку позже.
error.login.blocked=Неправильный пароль, IP из черного списка или слишком много логинов.
@ -67,7 +77,6 @@ error.login.premium=Пользователь не премиум-класса.
error.login.network=Ошибка сети.
error.login.ssl=Ошибка SSL.
error.login.unknown=Неизвестная ошибка.
error.login.ssl_help=§8Похоже, что вы используете Mono для запуска этой программы.\nВ первый раз, вы должны импортировать HTTPS сертификаты, используя:\nmozroots --import --ask-remove
error.login.cancel=Пользователь отменен.
error.login_failed=Не удалось войти на этот сервер.
error.join=Не удалось подключиться к этому серверу.
@ -81,10 +90,7 @@ error.no_version_report=§8Сервер не сообщает версию св
error.connection_timeout=§8При попытке подключения к этому IP произошел тайм-аут.
error.forge=§8Forge Login Handshake не завершилось успешно
error.forge_encrypt=§8Forge StartEncryption Handshake не завершилось успешно
error.setting.str2int=Не удалось преобразовать '{0}' в int. Проверьте свои настройки.
error.setting.argument_syntax={0}: Неверный синтаксис, ожидается --argname=value или --section.argname=value
error.setting.unknown_section={0}: Неизвестный раздел настройки '{1}'
error.setting.unknown_or_invalid={0}: Неизвестная настройка или недопустимое значение
error.http_code=§8Получен код ошибки от сервера: {0}
error.auth=§8Получили код ошибки от сервера при обновлении аутентификации: {0}
error.realms.ip_error=Невозможно получить IP-адрес сервера вашего мира Realms
@ -92,6 +98,11 @@ error.realms.access_denied=Этот мир Realms не существует ил
error.realms.server_unavailable=Серверу Realms может потребоваться некоторое время для запуска. Пожалуйста, повторите попытку позже.
error.realms.server_id=Неверный или неизвестный идентификатор сервера Realms.
error.realms.disabled=Попытка присоединиться к миру Realms, но поддержка Realms отключена в конфигурации
error.missing.argument=
error.usage=
error.generator.invalid=
error.generator.path=
error.generator.json=
[internal command]
# MCC internal help command
@ -114,7 +125,7 @@ exception.chatbot.init= Методы ChatBot НЕ должны вызывать
exception.csrunner.invalid_head=Предоставленный скрипт не имеет действительного заголовка MCCScript
[chatbot]
# API ChatBot
# ChatBot API
chatbot.reconnect=[{0}] Отключение и повторное подключение к серверу
[filemonitor]
@ -173,6 +184,14 @@ cache.ignore_line=§8Игнорирование недопустимой стр
cache.read_fail_plain=§8Не удалось прочитать кэш сессии с диска: {0}
cache.saving=§8Сохранение кэша сессии на диск
cache.save_fail=§8Не удалось записать кэш сессии на диск: {0}
# Profile Key Cache
cache.loading_keys=
cache.loaded_keys=
cache.ignore_string_keys=
cache.ignore_line_keys=
cache.read_fail_plain_keys=
cache.saving_keys=
cache.save_fail_keys=
[proxy]
proxy.connected=§8Подключен к прокси {0}:{1}
@ -186,6 +205,7 @@ chat.fail=§8Не удалось загрузить файл.
chat.from_dir=§8Дополнительно к en_GB.lang из вашей директории Minecraft.
chat.loaded=§8Файл переводов загружен.
chat.not_found=§8Файл переводов не найден: '{0}'\nНекоторые сообщения не будут правильно печататься без этого файла.
chat.message_chain_broken=
[general]
# General message/information (i.e. Done)
@ -201,12 +221,23 @@ general.available_cmd=Доступные команды: {0}
# Animation
cmd.animation.desc=Взмах руки.
# Bots
cmd.bots.desc=
cmd.bots.list=
cmd.bots.notfound=
cmd.bots.noloaded=
cmd.bots.unloaded=
cmd.bots.unloaded_all=
# ChangeSlot
cmd.changeSlot.desc=Изменить горячую панель
cmd.changeSlot.nan=Не удалось изменить слот: Not a Number
cmd.changeSlot.changed=Изменился на слот {0}
cmd.changeSlot.fail=Не удалось изменить слот
# Chunk
cmd.chunk.desc=
# Connect
cmd.connect.desc=подключиться к указанному серверу.
cmd.connect.unknown=Неизвестная учетная запись '{0}'.
@ -248,6 +279,19 @@ cmd.entityCmd.distance=Дальность
cmd.entityCmd.location=Местоположение
cmd.entityCmd.type=Type
# Exec If
cmd.execif.desc=
cmd.execif.executed=
cmd.execif.executed_no_output=
cmd.execif.error_occured=
cmd.execif.error=
# Exec Multi
cmd.execmulti.desc=
cmd.execmulti.executed=
cmd.execmulti.result=
cmd.execmulti.no_result=
# Exit
cmd.exit.desc=отключиться от сервера.
@ -267,12 +311,15 @@ cmd.inventory.close_fail=Не удалось закрыть опись #{0}
cmd.inventory.not_exist=Инвентаризация #{0} не существует
cmd.inventory.inventory=Инвентарь
cmd.inventory.inventories=Инвентарь
cmd.inventory.inventories_available=
cmd.inventory.hotbar=Выбранная вами горячая панель - {0}
cmd.inventory.damage=Ущерб
cmd.inventory.left=Левый
cmd.inventory.right=Правый
cmd.inventory.middle=Середина
cmd.inventory.clicking={0} щелчок по слоту {1} в окне #{2}
cmd.inventory.shiftclick=
cmd.inventory.shiftclick_fail=
cmd.inventory.no_item=Нет предмета в слоте #{0}
cmd.inventory.drop=Сбросил 1 предмет из слота #{0}
cmd.inventory.drop_stack=Выбросил всю стопку предметов из слота #{0}
@ -284,10 +331,29 @@ cmd.inventory.help.usage=Применение
cmd.inventory.help.list=Список инвентаря.
cmd.inventory.help.close=Закрыть открытый контейнер.
cmd.inventory.help.click=Нажать на элемент.
cmd.inventory.help.shiftclick=
cmd.inventory.help.drop=Убрать предмет из инвентаря.
cmd.inventory.help.creativegive=Выдать предмет в творческом режиме.
cmd.inventory.help.creativedelete=Очистить слот в творческом режиме.
cmd.inventory.help.unknown=Неизвестное действие.
cmd.inventory.help.inventories=
cmd.inventory.help.search=
cmd.inventory.help.unknown=Неизвестное действие.
cmd.inventory.found_items=
cmd.inventory.no_found_items=
# Leave bed
cmd.bed.desc=
cmd.bed.leaving=
cmd.bed.trying_to_use=
cmd.bed.in=
cmd.bed.not_in=
cmd.bed.not_a_bed=
cmd.bed.searching=
cmd.bed.bed_not_found=
cmd.bed.found_a_bed_at=
cmd.bed.cant_reach_safely=
cmd.bed.moving=
cmd.bed.failed_to_reach_in_time=
# List
cmd.list.desc=получить список игроков.
@ -301,6 +367,8 @@ cmd.look.desc=смотреть направление или координат
cmd.look.unknown=Неизвестное направление '{0}'
cmd.look.at=Посмотреть на YAW: {0} PITCH: {1}
cmd.look.block=Посмотреть на {0}
cmd.look.inspection=
cmd.look.noinspection=
# Move
cmd.move.desc= идти или начать идти.
@ -310,10 +378,24 @@ cmd.move.moving=Перемещение {0}
cmd.move.dir_fail=Невозможно двигаться в этом направлении.
cmd.move.walk=Путь к {0}
cmd.move.fail=Не удалось вычислить путь к {0}
cmd.move.suggestforce=
cmd.move.gravity.enabled=
cmd.move.gravity.disabled=
cmd.move.chunk_loading_status=
cmd.move.chunk_not_loaded=
# Reco
cmd.reco.desc=перезапустить и заново подключиться к серверу.
# Reload
cmd.reload.started=
cmd.reload.warning1=
cmd.reload.warning2=
cmd.reload.warning3=
cmd.reload.warning4=
cmd.reload.finished=
cmd.reload.desc=
# Respawn
cmd.respawn.desc=Используйте это, чтобы возродиться, если вы мертвы.
cmd.respawn.done=Вы переродились.
@ -328,6 +410,11 @@ cmd.send.desc=отправить сообщение в чат или коман
cmd.set.desc=установить пользовательскую %переменную%.
cmd.set.format=имя переменной должно быть A-Za-z0-9.
# SetRnd
cmd.setrnd.desc=
cmd.setrndnum.format=
cmd.setrndstr.format=
# Sneak
cmd.sneak.desc=Выключает подкрадывание
cmd.sneak.on=Вы сейчас крадетесь
@ -344,6 +431,7 @@ cmd.tps.current=Текущий tps
# Useblock
cmd.useblock.desc=Поставить блок или открыть сундук
cmd.useblock.use=
# Useitem
cmd.useitem.desc=Использовать (левый клик) предмет на руке
@ -353,9 +441,18 @@ cmd.useitem.use=Использовать предмет
[bot]
# ChatBots. Naming style: bot.<className>.<msg...>
# Alerts
bot.alerts.start_rain=
bot.alerts.end_rain=
bot.alerts.start_thunderstorm=
bot.alerts.end_thunderstorm=
# Anti AFK
bot.antiafk.not_using_terrain_handling=
bot.antiafk.swapping=
bot.antiafk.invalid_walk_range=
# AutoAttack
bot.autoAttack.mode=Неизвестный режим атаки: {0}. По умолчанию используется одиночный режим.
bot.autoAttack.priority=Неизвестный приоритет: {0}. По умолчанию используется приоритет расстояния.
bot.autoAttack.invalidcooldown=Значение кулдауна атаки не может быть меньше 0. По умолчанию используется auto.
# AutoCraft
@ -384,15 +481,11 @@ bot.autoCraft.aborted=Разработка прервана! Проверьте
bot.autoCraft.craft_fail=Разработка не удалась! Ожидание новых материалов
bot.autoCraft.timeout=Время выполнения действия истекло! Причина: {0}
bot.autoCraft.error.config=Ошибка при разборе конфига: {0}
bot.autoCraft.exception.empty=Пустой файл конфигурации: {0}
bot.autoCraft.exception.invalid=Неправильный файл конфигурации: {0}
bot.autoCraft.exception.item_miss=Пропущен элемент в рецепте: {0}
bot.autoCraft.exception.invalid_table=Неправильный формат расположения таблицы: {0}
bot.autoCraft.exception.item_name=Неправильное имя элемента в рецепте {0} в {1}
bot.autoCraft.exception.name_miss=Пропущено имя рецепта при разборе рецепта
bot.autoCraft.exception.slot=Неправильное поле слота в рецепте: {0}
bot.autoCraft.exception.duplicate=Дублируется указанное имя рецепта: {0}
bot.autoCraft.debug.no_config=Конфигурация не найдена. Записываем новый.
bot.autocraft.invaild_slots=
bot.autocraft.invaild_invaild_result=
# AutoDrop
bot.autoDrop.cmd=Команда автоудаления ЧатБота
@ -411,9 +504,17 @@ bot.autoDrop.no_mode=Невозможно прочитать режим паде
bot.autoDrop.no_inventory=Не удается найти инвентарь {0}!
# AutoFish
bot.autoFish.no_inv_handle=
bot.autoFish.start=
bot.autoFish.throw=Закинул удочку
bot.autoFish.caught=Поймал рыбу!
bot.autoFish.caught_at=
bot.autoFish.no_rod=Нет удочки под рукой. Может быть сломана?
bot.autoFish.despawn=
bot.autoFish.fishing_timeout=
bot.autoFish.cast_timeout=
bot.autoFish.update_lookat=
bot.autoFish.switch=
# AutoRelog
bot.autoRelog.launch=Запуск с {0} попытками повторного подключения
@ -457,7 +558,7 @@ bot.mailer.init_fail.mail_retention=Невозможно включить Mailer
bot.mailer.create.db=Создание нового файла базы данных: {0}
bot.mailer.create.ignore=Создание нового списка игнорирования: {0}
bot.mailer.load.db=Загрузка файла базы данных: {0}
bot.mailer.load.ignore=Загрузка списка игнорирования:
bot.mailer.load.ignore=Загрузка списка игнорирования:
bot.mailer.cmd=команда почтового клиента
@ -473,12 +574,43 @@ bot.mailer.cmd.ignore.removed=Удалил {0} из списка игнорир
bot.mailer.cmd.ignore.invalid=Пропущено или недопустимое имя. Использование: {0} <имя пользователя
bot.mailer.cmd.help=Смотрите использование
# Maps
bot.map.cmd.desc=
bot.map.cmd.not_found=
bot.map.cmd.invalid_id=
bot.map.received=
bot.map.no_maps=
bot.map.received_map=
bot.map.rendered=
bot.map.failed_to_render=
bot.map.list_item=
# ReplayCapture
bot.replayCapture.cmd=команда воспроизведения
bot.replayCapture.created=Файл воспроизведения создан.
bot.replayCapture.stopped=Запись остановлена.
bot.replayCapture.restart=Запись была остановлена. Перезапустите программу, чтобы начать другую запись.
# Follow player
cmd.follow.desc=
cmd.follow.usage=
cmd.follow.already_stopped=
cmd.follow.stopping=
cmd.follow.invalid_name=
cmd.follow.invalid_player=
cmd.follow.cant_reach_player=
cmd.follow.already_following=
cmd.follow.switched=
cmd.follow.started=
cmd.follow.unsafe_enabled=
cmd.follow.note=
cmd.follow.player_came_to_the_range=
cmd.follow.resuming=
cmd.follow.player_left_the_range=
cmd.follow.pausing=
cmd.follow.player_left=
cmd.follow.stopping=
# Script
bot.script.not_found=§8[MCC] [{0}] Не удается найти файл скрипта: {1}
bot.script.file_not_found=Файл не найден: '{0}'
@ -486,8 +618,6 @@ bot.script.fail=Сценарий '{0}' не удалось запустить ({
bot.script.pm.loaded=Сценарий '{0}' загружен.
# ScriptScheduler
bot.scriptScheduler.loading=Загрузка задач из '{0}'
bot.scriptScheduler.not_found=Файл не найден: '{0}'
bot.scriptScheduler.loaded_task=Загруженная задача:\n{0}
bot.scriptScheduler.no_trigger=Эта задача никогда не сработает:\n{0}
bot.scriptScheduler.no_action=Нет действия для задачи:\n{0}
@ -499,3 +629,220 @@ bot.scriptScheduler.task=triggeronfirstlogin: {0}\n triggeronlogin: {1}\n trigge
# TestBot
bot.testBot.told=Bot: {0} сказал мне : {1}
bot.testBot.said=Бот: {0} сказал: {1}
[config]
config.load=
config.load.fail=
config.write.fail=
config.backup.fail=
config.saving=
# Head
config.Head=
# Main.General
config.Main.General.account=
config.Main.General.login=
config.Main.General.server_info=
config.Main.General.method=
# Main.Advanced
config.Main.Advanced=
config.Main.Advanced.language=
config.Main.Advanced.internal_cmd_char=
config.Main.Advanced.message_cooldown=
config.Main.Advanced.bot_owners=
config.Main.Advanced.mc_version=
config.Main.Advanced.mc_forge=
config.Main.Advanced.brand_info=
config.Main.Advanced.chatbot_log_file=
config.Main.Advanced.private_msgs_cmd_name=
config.Main.Advanced.show_system_messages=
config.Main.Advanced.show_xpbar_messages=
config.Main.Advanced.show_chat_links=
config.Main.Advanced.show_inventory_layout=
config.Main.Advanced.terrain_and_movements=
config.Main.Advanced.inventory_handling=
config.Main.Advanced.entity_handling=
config.Main.Advanced.session_cache=
config.Main.Advanced.profilekey_cache=
config.Main.Advanced.resolve_srv_records=
config.Main.Advanced.account_list=
config.Main.Advanced.server_list=
config.Main.Advanced.player_head_icon=
config.Main.Advanced.exit_on_failure=
config.Main.Advanced.script_cache=
config.Main.Advanced.timestamps=
config.Main.Advanced.auto_respawn=
config.Main.Advanced.minecraft_realms=
config.Main.Advanced.move_head_while_walking=
config.Main.Advanced.timeout=
config.Main.Advanced.enable_emoji=
config.Main.Advanced.movement_speed=
config.Main.Advanced.language.invaild=
# Signature
config.Signature=
config.Signature.LoginWithSecureProfile=
config.Signature.SignChat=
config.Signature.SignMessageInCommand=
config.Signature.MarkLegallySignedMsg=
config.Signature.MarkModifiedMsg=
config.Signature.MarkIllegallySignedMsg=
config.Signature.MarkSystemMessage=
config.Signature.ShowModifiedChat=
config.Signature.ShowIllegalSignedChat=
# Logging
config.Logging=
config.Logging.DebugMessages=
config.Logging.ChatMessages=
config.Logging.InfoMessages=
config.Logging.WarningMessages=
config.Logging.ErrorMessages=
config.Logging.ChatFilter=
config.Logging.DebugFilter=
config.Logging.FilterMode=
config.Logging.LogToFile=
config.Logging.LogFile=
config.Logging.PrependTimestamp=
config.Logging.SaveColorCodes=
# AppVars
config.AppVars.Variables=
# Proxy
config.Proxy=
config.Proxy.Enabled_Login=
config.Proxy.Enabled_Ingame=
config.Proxy.Server=
config.Proxy.Proxy_Type=
config.Proxy.Username=
config.Proxy.Password=
# ChatFormat
config.ChatFormat=
config.ChatFormat.Builtins=
config.ChatFormat.UserDefined=
# MCSettings
config.MCSettings=
config.MCSettings.Enabled=
config.MCSettings.Locale=
config.MCSettings.RenderDistance=
config.MCSettings.Difficulty=
config.MCSettings.ChatMode=
config.MCSettings.ChatColors=
config.MCSettings.MainHand=
# ChatBot
config.ChatBot=
# ChatBot.Alerts
config.ChatBot.Alerts=
config.ChatBot.Alerts.Beep_Enabled=
config.ChatBot.Alerts.Trigger_By_Words=
config.ChatBot.Alerts.Trigger_By_Rain=
config.ChatBot.Alerts.Trigger_By_Thunderstorm=
config.ChatBot.Alerts.Matches=
config.ChatBot.Alerts.Excludes=
config.ChatBot.Alerts.Log_To_File=
config.ChatBot.Alerts.Log_File=
# ChatBot.AntiAFK
config.ChatBot.AntiAfk=
config.ChatBot.AntiAfk.Delay=
config.ChatBot.AntiAfk.Command=
config.ChatBot.AntiAfk.Use_Terrain_Handling=
config.ChatBot.AntiAfk.Walk_Range=
config.ChatBot.AntiAfk.Walk_Retries=
# ChatBot.AutoAttack
config.ChatBot.AutoAttack=
config.ChatBot.AutoAttack.Mode=
config.ChatBot.AutoAttack.Priority=
config.ChatBot.AutoAttack.Cooldown_Time=
config.ChatBot.AutoAttack.Interaction=
config.ChatBot.AutoAttack.Attack_Hostile=
config.ChatBot.AutoAttack.Attack_Passive=
config.ChatBot.AutoAttack.List_Mode=
config.ChatBot.AutoAttack.Entites_List=
# ChatBot.AutoCraft
config.ChatBot.AutoCraft=
config.ChatBot.AutoCraft.CraftingTable=
config.ChatBot.AutoCraft.OnFailure=
config.ChatBot.AutoCraft.Recipes=
# ChatBot.AutoDrop
config.ChatBot.AutoDrop=
config.ChatBot.AutoDrop.Mode=
# ChatBot.AutoEat
config.ChatBot.AutoEat=
# ChatBot.AutoFishing
config.ChatBot.AutoFishing=
config.ChatBot.AutoFishing.Antidespawn=
config.ChatBot.AutoFishing.Mainhand=
config.ChatBot.AutoFishing.Auto_Start=
config.ChatBot.AutoFishing.Cast_Delay=
config.ChatBot.AutoFishing.Fishing_Delay=
config.ChatBot.AutoFishing.Fishing_Timeout=
config.ChatBot.AutoFishing.Durability_Limit=
config.ChatBot.AutoFishing.Auto_Rod_Switch=
config.ChatBot.AutoFishing.Stationary_Threshold=
config.ChatBot.AutoFishing.Hook_Threshold=
config.ChatBot.AutoFishing.Log_Fish_Bobber=
config.ChatBot.AutoFishing.Enable_Move=
config.ChatBot.AutoFishing.Movements=
# ChatBot.AutoRelog
config.ChatBot.AutoRelog=
config.ChatBot.AutoRelog.Delay=
config.ChatBot.AutoRelog.Retries=
config.ChatBot.AutoRelog.Ignore_Kick_Message=
config.ChatBot.AutoRelog.Kick_Messages=
# ChatBot.AutoRespond
config.ChatBot.AutoRespond=
config.ChatBot.AutoRespond.Match_Colors=
# ChatBot.ChatLog
config.ChatBot.ChatLog=
# ChatBot.FollowPlayer
config.ChatBot.FollowPlayer=
config.ChatBot.FollowPlayer.Update_Limit=
config.ChatBot.FollowPlayer.Stop_At_Distance=
# ChatBot.HangmanGame
config.ChatBot.HangmanGame=
# ChatBot.Mailer
config.ChatBot.Mailer=
# ChatBot.Map
config.ChatBot.Map=
config.ChatBot.Map.Should_Resize=
config.ChatBot.Map.Resize_To=
config.ChatBot.Map.Auto_Render_On_Update=
config.ChatBot.Map.Delete_All_On_Unload=
config.ChatBot.Map.Notify_On_First_Update=
# ChatBot.PlayerListLogger
config.ChatBot.PlayerListLogger=
config.ChatBot.PlayerListLogger.Delay=
# ChatBot.RemoteControl
config.ChatBot.RemoteControl=
# ChatBot.ReplayCapture
config.ChatBot.ReplayCapture=
config.ChatBot.ReplayCapture.Backup_Interval=
# ChatBot.ScriptScheduler
config.ChatBot.ScriptScheduler=

View file

@ -1,5 +1,9 @@
[mcc]
# Messages from MCC itself
mcc.help_us_translate=
mcc.run_with_default_settings=
mcc.settings_generated=
mcc.has_update=
mcc.login=Đăng nhập:
mcc.login_basic_io=Hãy nhập địa chỉ email hoặc tên tài khoản của bạn:
mcc.password=Mật khẩu:
@ -8,8 +12,11 @@ mcc.password_hidden=Password : {0}
mcc.offline=§8Bạn chọn sử dụng chế độ ngoại tuyến.
mcc.session_invalid=§8Phiên không hợp lệ hoặc đã hết hạn.
mcc.session_valid=§8Phiên vẫn còn hợp lệ cho {0}.
mcc.profile_key_invalid=
mcc.profile_key_valid=
mcc.connecting=Đang kết nối tới {0}...
mcc.ip=Địa chỉ máy chủ:
mcc.fetching_key=
mcc.ip=Địa chỉ máy chủ:
mcc.use_version=§8Sử dụng Minecraft phiên bản {0} (protocol v{1})
mcc.unknown_version=§8Phiên bản không hợp lệ {0}.\nChuyển sang chế độ nhận diện tự động.
mcc.forge=Đang kiểm tra xem máy chủ có dùng Forge...
@ -20,7 +27,7 @@ mcc.not_found=§8Tìm kiếm SRV thất bại cho {0}\n{1}: {2}
mcc.retrieve=Đang nhận thông tin máy chủ...
mcc.restart=Đang khởi động lại Minecraft Console Client...
mcc.restart_delay=Đang chờ {0} giây trước khi khởi động lại...
mcc.server_version=Phiên bản máy chủ:
mcc.server_version=Phiên bản máy chủ:
mcc.disconnected=Chưa kết nối tới máy chủ nào. Dùng '{0}help' để in ra hướng dẫn.
mcc.press_exit=Hoặc nhấn Enter để đóng Minecraft Console Client
mcc.version_supported=Phiên bản hợp lệ \nĐang đăng nhập
@ -41,13 +48,16 @@ mcc.with_forge=, với Forge
mcc.handshake=§8Bắt tay thành công (ID máy chủ: {0})
mcc.realms_available=Bạn có quyền tham gia vào những máy chủ Realm này
mcc.realms_join=Dùng realm:[thứ tự] để tham gia máy chủ Realm
mcc.generator.generating=
mcc.generator.done=
[debug]
# Messages from MCC Debug Mode
debug.color_test=Color test: Màn hình của bạn sẽ hiển thị {0}
debug.session_cache_ok=§8Đã load thông tin phiên thành công
debug.session_cache_fail=§8Không có phiên nào có thể load.
debug.keys_cache_ok=
debug.keys_cache_fail=
debug.session_id=Thành công. (session ID: {0})
debug.crypto=§8Khóa mật mã và hash đã được tạo.
debug.request=§8Đang gửi yêu cầu tới {0}
@ -67,7 +77,6 @@ error.login.premium=User not premium.
error.login.network=Network error.
error.login.ssl=SSL Error.
error.login.unknown=Unknown Error.
error.login.ssl_help=§8It appears that you are using Mono to run this program.\nThe first time, you have to import HTTPS certificates using:\nmozroots --import --ask-remove
error.login.cancel=User cancelled.
error.login_failed=Failed to login to this server.
error.join=Failed to join this server.
@ -81,10 +90,7 @@ error.no_version_report=§8Server does not report its protocol version, autodete
error.connection_timeout=§8A timeout occured while attempting to connect to this IP.
error.forge=§8Forge Login Handshake did not complete successfully
error.forge_encrypt=§8Forge StartEncryption Handshake did not complete successfully
error.setting.str2int=Failed to convert '{0}' into an int. Please check your settings.
error.setting.argument_syntax={0}: Invalid syntax, expecting --argname=value or --section.argname=value
error.setting.unknown_section={0}: Unknown setting section '{1}'
error.setting.unknown_or_invalid={0}: Unknown setting or invalid value
error.http_code=§8Got error code from server: {0}
error.auth=§8Got error code from server while refreshing authentication: {0}
error.realms.ip_error=Cannot retrieve the server IP of your Realms world
@ -92,6 +98,11 @@ error.realms.access_denied=This Realms world does not exist or access was denied
error.realms.server_unavailable=Realms server may require some time to start up. Please retry again later.
error.realms.server_id=Invalid or unknown Realms server ID.
error.realms.disabled=Trying to join a Realms world but Realms support is disabled in config
error.missing.argument=
error.usage=
error.generator.invalid=
error.generator.path=
error.generator.json=
[internal command]
# MCC internal help command
@ -173,6 +184,14 @@ cache.ignore_line=§8Ignoring invalid session token line: {0}
cache.read_fail_plain=§8Failed to read session cache from disk: {0}
cache.saving=§8Saving session cache to disk
cache.save_fail=§8Failed to write session cache to disk: {0}
# Profile Key Cache
cache.loading_keys=
cache.loaded_keys=
cache.ignore_string_keys=
cache.ignore_line_keys=
cache.read_fail_plain_keys=
cache.saving_keys=
cache.save_fail_keys=
[proxy]
proxy.connected=§8Connected to proxy {0}:{1}
@ -186,6 +205,7 @@ chat.fail=§8Failed to download the file.
chat.from_dir=§8Defaulting to en_GB.lang from your Minecraft directory.
chat.loaded=§8Translations file loaded.
chat.not_found=§8Translations file not found: '{0}'\nSome messages won't be properly printed without this file.
chat.message_chain_broken=
[general]
# General message/information (i.e. Done)
@ -201,12 +221,23 @@ general.available_cmd=Available commands: {0}
# Animation
cmd.animation.desc=Swing your arm.
# Bots
cmd.bots.desc=
cmd.bots.list=
cmd.bots.notfound=
cmd.bots.noloaded=
cmd.bots.unloaded=
cmd.bots.unloaded_all=
# ChangeSlot
cmd.changeSlot.desc=Change hotbar
cmd.changeSlot.nan=Could not change slot: Not a Number
cmd.changeSlot.changed=Changed to slot {0}
cmd.changeSlot.fail=Could not change slot
# Chunk
cmd.chunk.desc=
# Connect
cmd.connect.desc=connect to the specified server.
cmd.connect.unknown=Unknown account '{0}'.
@ -248,6 +279,19 @@ cmd.entityCmd.distance=Distance
cmd.entityCmd.location=Location
cmd.entityCmd.type=Type
# Exec If
cmd.execif.desc=
cmd.execif.executed=
cmd.execif.executed_no_output=
cmd.execif.error_occured=
cmd.execif.error=
# Exec Multi
cmd.execmulti.desc=
cmd.execmulti.executed=
cmd.execmulti.result=
cmd.execmulti.no_result=
# Exit
cmd.exit.desc=disconnect from the server.
@ -267,12 +311,15 @@ cmd.inventory.close_fail=Failed to close Inventory #{0}
cmd.inventory.not_exist=Inventory #{0} do not exist
cmd.inventory.inventory=Inventory
cmd.inventory.inventories=Inventories
cmd.inventory.inventories_available=
cmd.inventory.hotbar=Your selected hotbar is {0}
cmd.inventory.damage=Damage
cmd.inventory.left=Left
cmd.inventory.right=Right
cmd.inventory.middle=Middle
cmd.inventory.clicking={0} clicking slot {1} in window #{2}
cmd.inventory.shiftclick=
cmd.inventory.shiftclick_fail=
cmd.inventory.no_item=No item in slot #{0}
cmd.inventory.drop=Dropped 1 item from slot #{0}
cmd.inventory.drop_stack=Dropped whole item stack from slot #{0}
@ -284,10 +331,29 @@ cmd.inventory.help.usage=Usage
cmd.inventory.help.list=List your inventory.
cmd.inventory.help.close=Close an opened container.
cmd.inventory.help.click=Click on an item.
cmd.inventory.help.shiftclick=
cmd.inventory.help.drop=Drop an item from inventory.
cmd.inventory.help.creativegive=Give item in creative mode.
cmd.inventory.help.creativedelete=Clear slot in creative mode.
cmd.inventory.help.unknown=Unknown action.
cmd.inventory.help.inventories=
cmd.inventory.help.search=
cmd.inventory.help.unknown=Unknown action.
cmd.inventory.found_items=
cmd.inventory.no_found_items=
# Leave bed
cmd.bed.desc=
cmd.bed.leaving=
cmd.bed.trying_to_use=
cmd.bed.in=
cmd.bed.not_in=
cmd.bed.not_a_bed=
cmd.bed.searching=
cmd.bed.bed_not_found=
cmd.bed.found_a_bed_at=
cmd.bed.cant_reach_safely=
cmd.bed.moving=
cmd.bed.failed_to_reach_in_time=
# List
cmd.list.desc=get the player list.
@ -301,6 +367,8 @@ cmd.look.desc=look at direction or coordinates.
cmd.look.unknown=Unknown direction '{0}'
cmd.look.at=Looking at YAW: {0} PITCH: {1}
cmd.look.block=Looking at {0}
cmd.look.inspection=
cmd.look.noinspection=
# Move
cmd.move.desc=walk or start walking.
@ -310,10 +378,24 @@ cmd.move.moving=Moving {0}
cmd.move.dir_fail=Cannot move in that direction.
cmd.move.walk=Walking to {0}
cmd.move.fail=Failed to compute path to {0}
cmd.move.suggestforce=
cmd.move.gravity.enabled=
cmd.move.gravity.disabled=
cmd.move.chunk_loading_status=
cmd.move.chunk_not_loaded=
# Reco
cmd.reco.desc=restart and reconnect to the server.
# Reload
cmd.reload.started=
cmd.reload.warning1=
cmd.reload.warning2=
cmd.reload.warning3=
cmd.reload.warning4=
cmd.reload.finished=
cmd.reload.desc=
# Respawn
cmd.respawn.desc=Use this to respawn if you are dead.
cmd.respawn.done=You have respawned.
@ -328,6 +410,11 @@ cmd.send.desc=send a chat message or command.
cmd.set.desc=set a custom %variable%.
cmd.set.format=variable name must be A-Za-z0-9.
# SetRnd
cmd.setrnd.desc=
cmd.setrndnum.format=
cmd.setrndstr.format=
# Sneak
cmd.sneak.desc=Toggles sneaking
cmd.sneak.on=You are sneaking now
@ -344,6 +431,7 @@ cmd.tps.current=Current tps
# Useblock
cmd.useblock.desc=Place a block or open chest
cmd.useblock.use=
# Useitem
cmd.useitem.desc=Use (left click) an item on the hand
@ -353,9 +441,18 @@ cmd.useitem.use=Used an item
[bot]
# ChatBots. Naming style: bot.<className>.<msg...>
# Alerts
bot.alerts.start_rain=
bot.alerts.end_rain=
bot.alerts.start_thunderstorm=
bot.alerts.end_thunderstorm=
# Anti AFK
bot.antiafk.not_using_terrain_handling=
bot.antiafk.swapping=
bot.antiafk.invalid_walk_range=
# AutoAttack
bot.autoAttack.mode=Unknown attack mode: {0}. Using single mode as default.
bot.autoAttack.priority=Unknown priority: {0}. Using distance priority as default.
bot.autoAttack.invalidcooldown=Attack cooldown value cannot be smaller than 0. Using auto as default
# AutoCraft
@ -384,15 +481,11 @@ bot.autoCraft.aborted=Crafting aborted! Check your available materials.
bot.autoCraft.craft_fail=Crafting failed! Waiting for more materials
bot.autoCraft.timeout=Action timeout! Reason: {0}
bot.autoCraft.error.config=Error while parsing config: {0}
bot.autoCraft.exception.empty=Empty configuration file: {0}
bot.autoCraft.exception.invalid=Invalid configuration file: {0}
bot.autoCraft.exception.item_miss=Missing item in recipe: {0}
bot.autoCraft.exception.invalid_table=Invalid tablelocation format: {0}
bot.autoCraft.exception.item_name=Invalid item name in recipe {0} at {1}
bot.autoCraft.exception.name_miss=Missing recipe name while parsing a recipe
bot.autoCraft.exception.slot=Invalid slot field in recipe: {0}
bot.autoCraft.exception.duplicate=Duplicate recipe name specified: {0}
bot.autoCraft.debug.no_config=No config found. Writing a new one.
bot.autocraft.invaild_slots=
bot.autocraft.invaild_invaild_result=
# AutoDrop
bot.autoDrop.cmd=AutoDrop ChatBot command
@ -411,9 +504,17 @@ bot.autoDrop.no_mode=Cannot read drop mode from config. Using include mode.
bot.autoDrop.no_inventory=Cannot find inventory {0}!
# AutoFish
bot.autoFish.no_inv_handle=
bot.autoFish.start=
bot.autoFish.throw=Threw a fishing rod
bot.autoFish.caught=Caught a fish!
bot.autoFish.caught_at=
bot.autoFish.no_rod=No Fishing Rod on hand. Maybe broken?
bot.autoFish.despawn=
bot.autoFish.fishing_timeout=
bot.autoFish.cast_timeout=
bot.autoFish.update_lookat=
bot.autoFish.switch=
# AutoRelog
bot.autoRelog.launch=Launching with {0} reconnection attempts
@ -457,7 +558,7 @@ bot.mailer.init_fail.mail_retention=Cannot enable Mailer: Mail Retention must be
bot.mailer.create.db=Creating new database file: {0}
bot.mailer.create.ignore=Creating new ignore list: {0}
bot.mailer.load.db=Loading database file: {0}
bot.mailer.load.ignore=Loading ignore list:
bot.mailer.load.ignore=Loading ignore list:
bot.mailer.cmd=mailer command
@ -473,12 +574,43 @@ bot.mailer.cmd.ignore.removed=Removed {0} from the ignore list!
bot.mailer.cmd.ignore.invalid=Missing or invalid name. Usage: {0} <username>
bot.mailer.cmd.help=See usage
# Maps
bot.map.cmd.desc=
bot.map.cmd.not_found=
bot.map.cmd.invalid_id=
bot.map.received=
bot.map.no_maps=
bot.map.received_map=
bot.map.rendered=
bot.map.failed_to_render=
bot.map.list_item=
# ReplayCapture
bot.replayCapture.cmd=replay command
bot.replayCapture.created=Replay file created.
bot.replayCapture.stopped=Record stopped.
bot.replayCapture.restart=Record was stopped. Restart the program to start another record.
# Follow player
cmd.follow.desc=
cmd.follow.usage=
cmd.follow.already_stopped=
cmd.follow.stopping=
cmd.follow.invalid_name=
cmd.follow.invalid_player=
cmd.follow.cant_reach_player=
cmd.follow.already_following=
cmd.follow.switched=
cmd.follow.started=
cmd.follow.unsafe_enabled=
cmd.follow.note=
cmd.follow.player_came_to_the_range=
cmd.follow.resuming=
cmd.follow.player_left_the_range=
cmd.follow.pausing=
cmd.follow.player_left=
cmd.follow.stopping=
# Script
bot.script.not_found=§8[MCC] [{0}] Cannot find script file: {1}
bot.script.file_not_found=File not found: '{0}'
@ -486,8 +618,6 @@ bot.script.fail=Script '{0}' failed to run ({1}).
bot.script.pm.loaded=Script '{0}' loaded.
# ScriptScheduler
bot.scriptScheduler.loading=Loading tasks from '{0}'
bot.scriptScheduler.not_found=File not found: '{0}'
bot.scriptScheduler.loaded_task=Loaded task:\n{0}
bot.scriptScheduler.no_trigger=This task will never trigger:\n{0}
bot.scriptScheduler.no_action=No action for task:\n{0}
@ -499,3 +629,220 @@ bot.scriptScheduler.task=triggeronfirstlogin: {0}\n triggeronlogin: {1}\n trigge
# TestBot
bot.testBot.told=Bot: {0} told me : {1}
bot.testBot.said=Bot: {0} said : {1}
[config]
config.load=
config.load.fail=
config.write.fail=
config.backup.fail=
config.saving=
# Head
config.Head=
# Main.General
config.Main.General.account=
config.Main.General.login=
config.Main.General.server_info=
config.Main.General.method=
# Main.Advanced
config.Main.Advanced=
config.Main.Advanced.language=
config.Main.Advanced.internal_cmd_char=
config.Main.Advanced.message_cooldown=
config.Main.Advanced.bot_owners=
config.Main.Advanced.mc_version=
config.Main.Advanced.mc_forge=
config.Main.Advanced.brand_info=
config.Main.Advanced.chatbot_log_file=
config.Main.Advanced.private_msgs_cmd_name=
config.Main.Advanced.show_system_messages=
config.Main.Advanced.show_xpbar_messages=
config.Main.Advanced.show_chat_links=
config.Main.Advanced.show_inventory_layout=
config.Main.Advanced.terrain_and_movements=
config.Main.Advanced.inventory_handling=
config.Main.Advanced.entity_handling=
config.Main.Advanced.session_cache=
config.Main.Advanced.profilekey_cache=
config.Main.Advanced.resolve_srv_records=
config.Main.Advanced.account_list=
config.Main.Advanced.server_list=
config.Main.Advanced.player_head_icon=
config.Main.Advanced.exit_on_failure=
config.Main.Advanced.script_cache=
config.Main.Advanced.timestamps=
config.Main.Advanced.auto_respawn=
config.Main.Advanced.minecraft_realms=
config.Main.Advanced.move_head_while_walking=
config.Main.Advanced.timeout=
config.Main.Advanced.enable_emoji=
config.Main.Advanced.movement_speed=
config.Main.Advanced.language.invaild=
# Signature
config.Signature=
config.Signature.LoginWithSecureProfile=
config.Signature.SignChat=
config.Signature.SignMessageInCommand=
config.Signature.MarkLegallySignedMsg=
config.Signature.MarkModifiedMsg=
config.Signature.MarkIllegallySignedMsg=
config.Signature.MarkSystemMessage=
config.Signature.ShowModifiedChat=
config.Signature.ShowIllegalSignedChat=
# Logging
config.Logging=
config.Logging.DebugMessages=
config.Logging.ChatMessages=
config.Logging.InfoMessages=
config.Logging.WarningMessages=
config.Logging.ErrorMessages=
config.Logging.ChatFilter=
config.Logging.DebugFilter=
config.Logging.FilterMode=
config.Logging.LogToFile=
config.Logging.LogFile=
config.Logging.PrependTimestamp=
config.Logging.SaveColorCodes=
# AppVars
config.AppVars.Variables=
# Proxy
config.Proxy=
config.Proxy.Enabled_Login=
config.Proxy.Enabled_Ingame=
config.Proxy.Server=
config.Proxy.Proxy_Type=
config.Proxy.Username=
config.Proxy.Password=
# ChatFormat
config.ChatFormat=
config.ChatFormat.Builtins=
config.ChatFormat.UserDefined=
# MCSettings
config.MCSettings=
config.MCSettings.Enabled=
config.MCSettings.Locale=
config.MCSettings.RenderDistance=
config.MCSettings.Difficulty=
config.MCSettings.ChatMode=
config.MCSettings.ChatColors=
config.MCSettings.MainHand=
# ChatBot
config.ChatBot=
# ChatBot.Alerts
config.ChatBot.Alerts=
config.ChatBot.Alerts.Beep_Enabled=
config.ChatBot.Alerts.Trigger_By_Words=
config.ChatBot.Alerts.Trigger_By_Rain=
config.ChatBot.Alerts.Trigger_By_Thunderstorm=
config.ChatBot.Alerts.Matches=
config.ChatBot.Alerts.Excludes=
config.ChatBot.Alerts.Log_To_File=
config.ChatBot.Alerts.Log_File=
# ChatBot.AntiAFK
config.ChatBot.AntiAfk=
config.ChatBot.AntiAfk.Delay=
config.ChatBot.AntiAfk.Command=
config.ChatBot.AntiAfk.Use_Terrain_Handling=
config.ChatBot.AntiAfk.Walk_Range=
config.ChatBot.AntiAfk.Walk_Retries=
# ChatBot.AutoAttack
config.ChatBot.AutoAttack=
config.ChatBot.AutoAttack.Mode=
config.ChatBot.AutoAttack.Priority=
config.ChatBot.AutoAttack.Cooldown_Time=
config.ChatBot.AutoAttack.Interaction=
config.ChatBot.AutoAttack.Attack_Hostile=
config.ChatBot.AutoAttack.Attack_Passive=
config.ChatBot.AutoAttack.List_Mode=
config.ChatBot.AutoAttack.Entites_List=
# ChatBot.AutoCraft
config.ChatBot.AutoCraft=
config.ChatBot.AutoCraft.CraftingTable=
config.ChatBot.AutoCraft.OnFailure=
config.ChatBot.AutoCraft.Recipes=
# ChatBot.AutoDrop
config.ChatBot.AutoDrop=
config.ChatBot.AutoDrop.Mode=
# ChatBot.AutoEat
config.ChatBot.AutoEat=
# ChatBot.AutoFishing
config.ChatBot.AutoFishing=
config.ChatBot.AutoFishing.Antidespawn=
config.ChatBot.AutoFishing.Mainhand=
config.ChatBot.AutoFishing.Auto_Start=
config.ChatBot.AutoFishing.Cast_Delay=
config.ChatBot.AutoFishing.Fishing_Delay=
config.ChatBot.AutoFishing.Fishing_Timeout=
config.ChatBot.AutoFishing.Durability_Limit=
config.ChatBot.AutoFishing.Auto_Rod_Switch=
config.ChatBot.AutoFishing.Stationary_Threshold=
config.ChatBot.AutoFishing.Hook_Threshold=
config.ChatBot.AutoFishing.Log_Fish_Bobber=
config.ChatBot.AutoFishing.Enable_Move=
config.ChatBot.AutoFishing.Movements=
# ChatBot.AutoRelog
config.ChatBot.AutoRelog=
config.ChatBot.AutoRelog.Delay=
config.ChatBot.AutoRelog.Retries=
config.ChatBot.AutoRelog.Ignore_Kick_Message=
config.ChatBot.AutoRelog.Kick_Messages=
# ChatBot.AutoRespond
config.ChatBot.AutoRespond=
config.ChatBot.AutoRespond.Match_Colors=
# ChatBot.ChatLog
config.ChatBot.ChatLog=
# ChatBot.FollowPlayer
config.ChatBot.FollowPlayer=
config.ChatBot.FollowPlayer.Update_Limit=
config.ChatBot.FollowPlayer.Stop_At_Distance=
# ChatBot.HangmanGame
config.ChatBot.HangmanGame=
# ChatBot.Mailer
config.ChatBot.Mailer=
# ChatBot.Map
config.ChatBot.Map=
config.ChatBot.Map.Should_Resize=
config.ChatBot.Map.Resize_To=
config.ChatBot.Map.Auto_Render_On_Update=
config.ChatBot.Map.Delete_All_On_Unload=
config.ChatBot.Map.Notify_On_First_Update=
# ChatBot.PlayerListLogger
config.ChatBot.PlayerListLogger=
config.ChatBot.PlayerListLogger.Delay=
# ChatBot.RemoteControl
config.ChatBot.RemoteControl=
# ChatBot.ReplayCapture
config.ChatBot.ReplayCapture=
config.ChatBot.ReplayCapture.Backup_Interval=
# ChatBot.ScriptScheduler
config.ChatBot.ScriptScheduler=

View file

@ -1,530 +0,0 @@
[mcc]
# Messages from MCC itself
mcc.login=登录:
mcc.login_basic_io=请输入用户名或邮箱。
mcc.password=密码:
mcc.password_basic_io=请输入{0}的密码。
mcc.password_hidden=密码:{0}
mcc.offline=§8您正在使用离线模式。
mcc.session_invalid=§8缓存无效或已过期。
mcc.session_valid=§8{0}的缓存仍然有效。
mcc.profile_key_invalid=§8缓存的聊天签名密钥需要刷新。
mcc.profile_key_valid=§8{0}的聊天签名密钥缓存仍然有效.
mcc.connecting=正在连接至{0}...
mcc.ip=服务器IP
mcc.use_version=§8正在运行Minecraft版本{0} (v{1}协议)
mcc.unknown_version=§8未知或不受支持的Minecraft版本{0}。\n正在切换至自动检测模式。
mcc.forge=检查服务器是否正在运行Forge...
mcc.forgeforce=正在强制启动Forge支持。
mcc.resolve=正在解析{0}...
mcc.found=§8已找到服务器{0}:{1},域名:{2}
mcc.not_found=§8无法执行{0}的SRV解析\n{1}{2}
mcc.retrieve=正在获取服务器信息...
mcc.restart=正在重启Minecraft Console Client...
mcc.restart_delay=等待{0}秒后重启...
mcc.server_version=服务器版本:
mcc.disconnected=未连接至任何服务器。输入 '{0}help' 获得帮助。
mcc.press_exit=或者敲击回车退出Minecraft Console Client。
mcc.version_supported=该版本受到支持\n正在登录...
mcc.single_cmd=§7已发送命令§8 {0}
mcc.joined=已成功加入服务器。\n输入 '{0}quit' 离开服务器。
mcc.reconnect=等待5秒 (剩余{0}次尝试)...
mcc.disconnect.lost=失去连接。
mcc.disconnect.server=从服务器断开:
mcc.disconnect.login=连接失败:
mcc.link=链接:{0}
mcc.player_dead_respawn=你死了1秒后自动重生。
mcc.player_dead=你死了!输入 '{0}respawn' 重生。
mcc.server_offline=§8服务器正处于离线模式。
mcc.session=检查会话...
mcc.session_fail=检查会话失败
mcc.server_protocol=§8服务器版本{0} (v{1}协议)
mcc.with_forge=, 带有Forge
mcc.handshake=§8握手成功。 (服务器ID{0})
mcc.realms_available==您可以访问以下Realms世界
mcc.realms_join=请使用realms:<序号>作为服务器IP加入Realms世界
[debug]
# Messages from MCC Debug Mode
debug.color_test=颜色测试:终端应该显示的颜色是:{0}
debug.session_cache_ok=§8已成功从磁盘中加载会话数据。
debug.session_cache_fail=§8无法从磁盘加载会话
debug.keys_cache_ok=§8已成功从磁盘中加载聊天签名密钥。
debug.keys_cache_fail=§8无法从磁盘中加载聊天签名密钥。
debug.session_id=成功!(会话ID{0})
debug.crypto=§8密钥和哈希值已生成
debug.request=§8正在请求{0}
[error]
# Error messages from MCC
error.ping=ping此IP失败。
error.unsupported=无法连接到服务器:不支持此版本!
error.determine=无法确定服务器版本。
error.forgeforce=无法为此Minecraft版本强制启动Forge支持
error.login=登录失败:
error.login.migrated=帐户已迁移,使用电子邮件作为用户名。
error.login.server=登录服务器不可用。请稍后再试。
error.login.blocked=密码错误、IP被禁用或登录次数过多。
error.login.response=服务器响应无效。
error.login.premium=不是Premium用户。
error.login.network=网络错误。
error.login.ssl=SSL错误。
error.login.unknown=未知错误。
error.login.ssl_help=§8您似乎正在使用Mono运行此程序.\n当第一次运行您必须使用以下命令导入HTTPS证书\nmozroots --import --ask-remove
error.login.cancel=用户取消。
error.login_failed=无法登录到此服务器。
error.join=加入服务器时发生错误。
error.connect=无法连接到此IP。
error.timeout=连接超时
error.unexpect_response=§8来自服务器的意外响应这是Minecraft服务器吗
error.invalid_response=§8对握手包的响应无效
error.invalid_encrypt=§8对StartEncryption数据包的响应无效
error.version_different=§8服务器报告的版本与手动设置的版本不同。登录可能无法工作。
error.no_version_report=§8服务器未报告其协议版本自动检测将不起作用。
error.connection_timeout=§8尝试连接到此IP时超时。
error.forge=§8Forge登录握手未成功完成
error.forge_encrypt=§8Forge StartEncryption握手未成功完成
error.setting.str2int=无法将'{0}'转换为一个整数。请检查设置。
error.setting.str2double=无法将'{0}'转换为一个浮点数。请检查设置。
error.setting.argument_syntax={0}:无效语法,应为 --argname=value 或 --section.argname=value
error.setting.unknown_section={0}:未知设置部分'{1}'
error.setting.unknown_or_invalid={0}:未知设置或无效值
error.http_code=§8接收到服务器错误{0}
error.auth=§8在刷新身份验证时接收到服务器错误{0}
error.realms.ip_error=无法获取您Realms世界的服务器IP
error.realms.access_denied=此Realms世界不存在或访问被拒绝
error.realms.server_unavailable=Realms服务器可能需要一些时间来启动。请稍后再试。
error.realms.server_id=Realms服务器ID无效或未知。
error.realms.disabled=正在尝试加入Realms世界但配置中禁用了Realms支持
[internal command]
# MCC internal help command
icmd.help=help <命令名称> :显示有关命令的简要帮助。
icmd.unknown=未知命令 '{0}'。请使用 'help' 命令来获取命令列表。
icmd.list=help <命令名称>。可用命令:{0}。在服务器上获取帮助,请改用 '{1}send /help'。
icmd.error=OnInternalCommand: 来自{0}的错误{1}
[exception]
# Exception messages threw by MCC
exception.user_logout=用户发起的注销应该通过调用Disconnect()来完成
exception.unknown_direction=未知方向
exception.palette.block=请为此Minecraft版本更新方块类型处理。详细请参考 Material.cs
exception.palette.entity=请为此Minecraft版本更新实体类型处理。详细请参考 EntityType.cs
exception.palette.item=请为此Minecraft版本更新物品类型处理。详细请参考 ItemType.cs
exception.palette.packet=请为此Minecraft版本更新数据包类型调色板。详细请参考 PacketTypePalette.cs
exception.packet_process=无法处理传入的{0}类型的数据包。(数据包ID{1},协议:{2},登陆阶段:{3},内部异常:{4})。
exception.version_unsupport=版本{0}的协议未被支持。
exception.chatbot.init=不应在构造函数中调用ChatBot的方法因为作为API处理程序的模块尚未初始化。请重写 Initialize() 或 AfterGameJoined() 来执行初始化任务。
exception.csrunner.invalid_head=提供的脚本没有有效的MCCScript头
[chatbot]
# ChatBot API
chatbot.reconnect=[{0}] 断开并重新连接到服务器
[filemonitor]
# FileMonitor
filemonitor.init=§8[{0}] 正在为文件{1}初始化FileSystemWatcher
filemonitor.fail=§8[{0}] 无法初始化FileSystemWatcher正在使用轮询重试
[extra]
# Inventory, Terrain & Movements, Entity related messages
# Terrain & Movements
extra.terrainandmovement_enabled=地形和移动现在已启用。
extra.terrainandmovement_disabled=§c该MC版本目前未支持处理地形和移动。
extra.terrainandmovement_required=请先在配置文件中启用地形和移动。
# Inventory
extra.inventory_enabled=物品栏处理现在已启用。
extra.inventory_disabled=§c该MC版本目前未支持处理物品栏。
extra.inventory_required=请先在配置文件中启用InventoryHandling。
extra.inventory_interact=请使用 /inventory 来与其交互。
extra.inventory_open=物品栏# {0}已开启:{1}
extra.inventory_close=物品栏# {0}已关闭。
# Entity
extra.entity_disabled=§c该MC版本当前未支持处理实体。
extra.entity_required=请先在配置文件中启用EntityHandling。
[forge]
# Messages from Forge handler
forge.version=§8Forge协议版本{0}
forge.send_mod=§8向服务器发送伪造的forge模组列表...
forge.accept=§8接受来自的服务器模组列表...
forge.registry=§8已接收的注册表包含{0}个条目
forge.registry_2=§8已接收注册表{0},包含{1}个条目
forge.accept_registry=§8接受服务器注册表...
forge.complete=Forge服务器连接完成!
forge.with_mod=§8服务器正在运行Forge有{0}个模组。
forge.no_mod=§8正在运行的服务器没有Forge模组。
forge.mod_list=§8模组列表:
# FML2
forge.fml2.mod=§8收到FM2服务器模组列表
forge.fml2.mod_send=§8发回FML2客户端的模组列表
forge.fml2.registry=§8确认FML2服务器注册表{0}
forge.fml2.config=§8确认FML2服务器配置{0}
forge.fml2.unknown=§8收到未知的FML2握手信息编号{0}
forge.fml2.unknown_channel=§8忽略未知的FML2登录消息通道{0}
[cache]
# Session Cache
cache.loading=§8加载Minecraft配置文件{0}
cache.loaded=§8已加载会话{0}:{1}
cache.converting=§8从磁盘转换会话缓存{0}
cache.read_fail=§8无法从磁盘读取序列化会话缓存{0}
cache.malformed=§8从磁盘读取序列化会话缓存时获取到格式错误的数据{0}
cache.loading_session=§8从磁盘加载会话缓存{0}
cache.ignore_string=§8忽略会话令牌字符串'{0}'{1}
cache.ignore_line=§8忽略无效的会话令牌行{0}
cache.read_fail_plain=§8无法从磁盘读取会话缓存{0}
cache.saving=§8将会话缓存保存到磁盘
cache.save_fail=§8无法将会话缓存写入磁盘{0}
# Profile Key Cache
cache.loading_keys=§8从磁盘加载聊天签名密钥缓存: {0}
cache.loaded_keys=§8已加载签名密钥下次刷新于 {0}
cache.ignore_string_keys=§8忽略聊天签名密钥字符串 '{0}'{1}
cache.ignore_line_keys=§8忽略无效的聊天签名密钥行{0}
cache.read_fail_plain_keys=§8无法从磁盘读取聊天签名密钥缓存{0}
cache.saving_keys=§8将聊天签名密钥保存到磁盘
cache.save_fail_keys=§8无法将聊天签名密钥写入磁盘{0}
[proxy]
proxy.connected=§8已连接到代理{0}:{1}
[chat]
# Chat Parser
chat.download=§8从Mojang服务器下载 '{0}.lang'...
chat.request=§8正在请求{0}...
chat.done=§8完成。文件另存为 '{0}'
chat.fail=§8下载文件失败。
chat.from_dir=§8默认为你的Minecraft目录中的en_GB.lang
chat.loaded=§8已加载翻译文件。
chat.not_found=§8找不到翻译文件'{0}'\n如果没有此文件某些信息将无法正确打印。
[general]
# General message/information (i.e. Done)
general.done=完成
general.fail=失败
general.bot_unload=将会卸载此bot。
general.available_cmd=可用命令:{0}
[cmd]
# Commands. Naming style: cmd.<className>.<msg...>
# Animation
cmd.animation.desc=挥动你的手臂。
# ChangeSlot
cmd.changeSlot.desc=变更快捷栏栏位
cmd.changeSlot.nan=无法变更栏位:不是数字
cmd.changeSlot.changed=已变更为栏位{0}
cmd.changeSlot.fail=无法变更栏位
# Connect
cmd.connect.desc=连接到指定的服务器。
cmd.connect.unknown=未知帐户 '{0}'。
cmd.connect.invalid_ip=无效的服务器IP '{0}'。
# Debug
cmd.debug.desc=切换调试消息。
cmd.debug.state_on=调试消息现在已打开
cmd.debug.state_off=调试消息现在已关闭
# Dig
cmd.dig.desc=试图破坏一个方块
cmd.dig.too_far=你离这个方块太远了。
cmd.dig.no_block=这个地方没有方块 (空气)
cmd.dig.dig=尝试挖掘位于({0}, {1}, {2})的方块({3})。
cmd.dig.fail=无法开始挖掘方块。
# Entitycmd
cmd.entityCmd.attacked=已攻击实体
cmd.entityCmd.used=已使用实体
cmd.entityCmd.not_found=找不到实体
cmd.entityCmd.entity=实体
cmd.entityCmd.entities=实体集
cmd.entityCmd.nickname=昵称
cmd.entityCmd.customname=自定义名称
cmd.entityCmd.latency=延迟
cmd.entityCmd.item=物品
cmd.entityCmd.equipment=装备
cmd.entityCmd.mainhand=主手
cmd.entityCmd.offhane=副手
cmd.entityCmd.helmet=头盔
cmd.entityCmd.chestplate=胸甲
cmd.entityCmd.leggings=护腿
cmd.entityCmd.boots=靴子
cmd.entityCmd.pose=姿势
cmd.entityCmd.health=生命值
cmd.entityCmd.distance=距离
cmd.entityCmd.location=位置
cmd.entityCmd.type=类型
# Exit
cmd.exit.desc=断开与服务器的连接。
# Health
cmd.health.desc=显示生命值和饱食度。
cmd.health.response=生命值:{0},饱食度:{1},等级:{2},总经验值:{3}
# Inventory
cmd.inventory.desc=物品栏相关命令
cmd.inventory.creative_done=向栏位#{2}请求{0} x{1}
cmd.inventory.creative_delete=请求清除栏位 #{0}
cmd.inventory.creative_fail=请求创造模式操作失败
cmd.inventory.need_creative=你必须在创造模式
cmd.inventory.container_not_found=找不到容器请使用显式ID重试
cmd.inventory.close=关闭物品栏 #{0}
cmd.inventory.close_fail=关闭物品栏失败 #{0}
cmd.inventory.not_exist=物品栏#{0}不存在
cmd.inventory.inventory=物品栏
cmd.inventory.inventories=物品栏集
cmd.inventory.hotbar=您选择的快捷栏是{0}
cmd.inventory.damage=武器伤害值
cmd.inventory.left=
cmd.inventory.right=
cmd.inventory.middle=中间
cmd.inventory.clicking={0}正在点击窗口#{2}中的栏位{1}
cmd.inventory.no_item=栏位#{0}中没有物品
cmd.inventory.drop=从栏位#{0}中丢弃了1个物品
cmd.inventory.drop_stack=从栏位#{0}中丢弃了所有堆叠的物品
# Inventory Help
cmd.inventory.help.basic=基本用法
cmd.inventory.help.available=可用操作
cmd.inventory.help.help={0}\n使用 '/inventory help <action>' 获取帮助。\n'player' 和 'container' 可以简化为 'p' 和 'c'。\n请注意'[]' 中的参数是可选的。
cmd.inventory.help.usage=用法
cmd.inventory.help.list=列出你的物品栏。
cmd.inventory.help.close=关闭打开的容器。
cmd.inventory.help.click=单击物品。
cmd.inventory.help.drop=从物品栏中丢弃物品。
cmd.inventory.help.creativegive=在创造模式中给予物品。
cmd.inventory.help.creativedelete=在创造性模式中清除栏位。
cmd.inventory.help.unknown=未知操作。
# List 列表设置
cmd.list.desc=获取玩家列表。
cmd.list.players=玩家列表:{0}
# Log
cmd.log.desc=将文本记录到控制台。
# Look
cmd.look.desc=查看方向或坐标。
cmd.look.unknown=未知方向 '{0}'。
cmd.look.at=当前视角 偏航角:{0} 俯仰角:{1}。
cmd.look.block=正看向位于 {0} 的方块。
cmd.look.inspection=与视线相交的第一个方块是 {0} ({1:0}, {2:0}, {3:0}),距离玩家 {4:0.0}({5:0.0})。
cmd.look.noinspection=在 {0} 米内没有任何方块与视线相交。
# Move
cmd.move.desc=移动或开始移动。
cmd.move.enable=在下次服务器登录、重生或更换世界时启用地形和移动。
cmd.move.disable=禁用地形和移动。
cmd.move.moving=移动{0}
cmd.move.dir_fail=不能朝此方向移动。
cmd.move.walk=移动到{0}
cmd.move.fail=无法计算到达{0}的路径。
cmd.move.suggestforce=无法计算安全到达{0}的路径. 请使用 -f 参数允许不安全移动。
cmd.move.gravity.enabled=重力已开启。
cmd.move.gravity.disabled=重力已关闭。
# Reco
cmd.reco.desc=重新启动并重新连接到服务器。
# Respawn
cmd.respawn.desc=如果你死亡了,请用这个来重生。
cmd.respawn.done=你重生了。
# Script
cmd.script.desc=运行脚本文件。
# Send
cmd.send.desc=发送聊天信息或命令。
# Set
cmd.set.desc=设置自定义 %variable%。
cmd.set.format=变量名范围必须为 A-Za-z0-9。
# SetRnd
cmd.setrnd.desc=随机为自定义 %变量名% 赋值。
cmd.setrndnum.format=setrnd 变量名 -7to17
cmd.setrndstr.format=setrnd 变量名 字符串1 "\"字符串2\" 字符串3"
# Sneak
cmd.sneak.desc=切换到潜行
cmd.sneak.on=现在你在潜行状态。
cmd.sneak.off=你不在潜行状态了。
# DropItem
cmd.dropItem.desc=丢弃玩家物品栏中的指定类型物品或打开的容器
cmd.dropItem.dropped=已从物品栏#{1}中丢弃所有{0}
cmd.dropItem.unknown_item=未知物品:{0}
# Tps
cmd.tps.desc=显示服务器当前tps (tick per second)。(可能不精确)
cmd.tps.current=当前TPS
# Useblock
cmd.useblock.desc=放置一个方块或打开箱子
# Useitem
cmd.useitem.desc=使用(左键单击)手上的物品
cmd.useitem.use=使用了一个物品。
[bot]
# ChatBots. Naming style: bot.<className>.<msg...>
# Alerts
bot.alerts.start_rain=§c天气变化开始下雨了。§r
bot.alerts.end_rain=§c天气变化雨停了。§r
bot.alerts.start_thunderstorm=§c天气变化现在是雷雨天。§r
bot.alerts.end_thunderstorm=§c天气变化现在不再是雷雨天了。§r
# AutoAttack
bot.autoAttack.mode=未知的攻击模式:{0},使用单一模式作为默认值。
bot.autoAttack.priority=未知优先模式:{0},使用距离优先作为默认值。
bot.autoAttack.invalidcooldown=攻击冷却时间值不能小于0已使用自动作为默认值
# AutoCraft
bot.autoCraft.cmd=自动制作ChatBot命令
bot.autoCraft.alias=自动制作ChatBot命令的别名
bot.autoCraft.cmd.list=已加载{0}个配方:{1}
bot.autoCraft.cmd.resetcfg=将配置重置为默认值
bot.autoCraft.recipe_not_exist=指定的配方名称不存在。请检查配置文件。
bot.autoCraft.no_recipe_name=请指定要制作的配方名称。
bot.autoCraft.stop=AutoCraft已停止
bot.autoCraft.available_cmd=可用命令:{0}。可使用 /autocraft help <命令名> 了解更多信息。您可以使用 /ac 作为命令别名。
bot.autoCraft.help.load=加载配置文件。
bot.autoCraft.help.list=列出可用配方。
bot.autoCraft.help.reload=重新加载配置文件。
bot.autoCraft.help.resetcfg=将默认示例配置写入默认位置。
bot.autoCraft.help.start=开始制作。用法:/autocraft start <配方名称>
bot.autoCraft.help.stop=停止当前正在进行的制作过程
bot.autoCraft.help.help=获取命令描述。用法: /autocraft help <命令名>
bot.autoCraft.loaded=已成功加载
bot.autoCraft.start=AutoCraft启动中{0}
bot.autoCraft.start_fail=无法启动AutoCraft。请检查用于制作{0}的可用材料
bot.autoCraft.table_not_found=找不到工作台
bot.autoCraft.close_inventory=物品栏#{0}被AutoCraft关闭
bot.autoCraft.missing_material=缺失材料:{0}
bot.autoCraft.aborted=制作被终止!请检查可用材料。
bot.autoCraft.craft_fail=制作失败!等待更多材料
bot.autoCraft.timeout=动作超时!原因:{0}
bot.autoCraft.error.config=分析配置时出错:{0}
bot.autoCraft.exception.empty=空配置文件:{0}
bot.autoCraft.exception.invalid=配置文件无效:{0}
bot.autoCraft.exception.item_miss=配方中缺少物品:{0}
bot.autoCraft.exception.invalid_table=tablelocation格式无效{0}
bot.autoCraft.exception.item_name=配方{0}中在{1}的物品名称无效
bot.autoCraft.exception.name_miss=解析配方时缺少配方名称
bot.autoCraft.exception.slot=配方中的栏位字段无效:{0}
bot.autoCraft.exception.duplicate=指定了重复的配方名称:{0}
bot.autoCraft.debug.no_config=找不到配置。请新建一个。
# AutoDrop
bot.autoDrop.cmd=AutoDrop ChatBot命令
bot.autoDrop.alias=AutoDrop ChatBot命令别名
bot.autoDrop.on=已启用AutoDrop
bot.autoDrop.off=已禁用AutoDrop
bot.autoDrop.added=已添加物品{0}
bot.autoDrop.incorrect_name=物品名称不正确:{0}。请再试一次。
bot.autoDrop.removed=已删除物品{0}
bot.autoDrop.not_in_list=物品不在列表中
bot.autoDrop.no_item=列表中没有物品
bot.autoDrop.list=列表中总计{0}个物品:\n {1}
bot.autoDrop.switched= 切换到{0}模式。
bot.autoDrop.unknown_mode=未知模式。可用的模式Include, Exclude, Everything
bot.autoDrop.no_mode=无法从配置中读取丢弃模式drop mode。使用Include模式。
bot.autoDrop.no_inventory=找不到物品栏{0}!
# AutoFish
bot.autoFish.throw=抛竿
bot.autoFish.caught=钓到鱼了!
bot.autoFish.no_rod=手上没有鱼竿,可能用坏了?
# AutoRelog
bot.autoRelog.launch=已启动,尝试了{0}次重新连接
bot.autoRelog.no_kick_msg=在没有kick消息文件的情况下初始化
bot.autoRelog.loading=从文件{0}加载消息
bot.autoRelog.loaded=已加载消息:{0}
bot.autoRelog.not_found=找不到文件或目录:{0}
bot.autoRelog.curr_dir=当前目录为:{0}
bot.autoRelog.ignore_user_logout=由用户或MCC bot启动的断开连接。忽略。
bot.autoRelog.disconnect_msg=连接断开,收到消息:{0}
bot.autoRelog.reconnect_always=忽略kick消息仍要重新连接。
bot.autoRelog.reconnect=信息包含 '{0}'。重新连接。
bot.autoRelog.reconnect_ignore=不包含任何已定义关键字的消息,忽略。
bot.autoRelog.wait=等待{0}秒后重新连接...
# AutoRespond
bot.autoRespond.loading=正在从'{0}'加载匹配项
bot.autoRespond.file_not_found=找不到文件或目录: '{0}'
bot.autoRespond.loaded_match=加载匹配项:\n{0}
bot.autoRespond.no_trigger=这个匹配永远不会触发:\n{0}
bot.autoRespond.no_action=匹配没有对应操作:\n{0}
bot.autoRespond.match_run=进行操作:{0}
bot.autoRespond.match=match: {0}\nregex: {1}\naction: {2}\nactionPrivate: {3}\nactionOther: {4}\nownersOnly: {5}\ncooldown: {6}
# ChatLog
bot.chatLog.invalid_file=路径'{0}'包含无效字符。
# Mailer
bot.mailer.init=使用设置初始化Mailer
bot.mailer.init.db= - 数据库文件:{0}
bot.mailer.init.ignore= - 忽略列表:{0}
bot.mailer.init.public= - 公开交互:{0}
bot.mailer.init.max_mails= - 每位玩家最多邮件数:{0}
bot.mailer.init.db_size= - 最大数据库大小:{0}
bot.mailer.init.mail_retention= - 邮件保留天数:{0}
bot.mailer.init_fail.db_size=无法启用Mailer最大数据库大小必须大于0。请检查设置。
bot.mailer.init_fail.max_mails=无法启用Mailer每个玩家的最大邮件数必须大于0。请检查设置。
bot.mailer.init_fail.mail_retention=无法启用Mailer邮件保留天数必须大于0。请检查设置。
bot.mailer.create.db=创建新数据库文件:{0}
bot.mailer.create.ignore=创建新忽略列表:{0}
bot.mailer.load.db=加载数据库文件:{0}
bot.mailer.load.ignore=加载忽略列表:
bot.mailer.cmd=mailer 命令
bot.mailer.saving=正在保存邮件:{0}
bot.mailer.user_ignored={0}已被忽略!
bot.mailer.process_mails=正在查找要发送的邮件 @ {0}
bot.mailer.delivered=已发送:{0}
bot.mailer.cmd.getmails=--- 数据库中的邮件 ---\n{0}
bot.mailer.cmd.getignored=--- 忽略列表 ---\n{0}
bot.mailer.cmd.ignore.added=添加{0}到忽略列表!
bot.mailer.cmd.ignore.removed={0}已从忽略列表中删除!
bot.mailer.cmd.ignore.invalid=丢失或无效的名称。用法:{0}<用户名>
bot.mailer.cmd.help=查看用法
# ReplayCapture
bot.replayCapture.cmd=replay 命令
bot.replayCapture.created=已创建重播文件。
bot.replayCapture.stopped=录制已停止。
bot.replayCapture.restart=录制已停止。请重新启动程序以进行另一段录制。
# Script
bot.script.not_found=§8[MCC] [{0}] 找不到脚本文件:{1}
bot.script.file_not_found=找不到文件:'{0}'
bot.script.fail=脚本'{0}'运行失败 ({1})。
bot.script.pm.loaded=脚本'{0}'加载。
# ScriptScheduler
bot.scriptScheduler.loading=正在从'{0}'加载任务
bot.scriptScheduler.not_found=找不到文件:'{0}'
bot.scriptScheduler.loaded_task=已加载任务:\n{0}
bot.scriptScheduler.no_trigger=这个任务永远不会触发:\n{0}
bot.scriptScheduler.no_action=任务没有对应操作:\n{0}
bot.scriptScheduler.running_time=时间 / 运行中的操作:{0}
bot.scriptScheduler.running_inverval=间隔 / 运行中的操作:{0}
bot.scriptScheduler.running_login=登录 / 运行中的操作:{0}
bot.scriptScheduler.task=triggeronfirstlogin: {0}\n triggeronlogin: {1}\n triggerontime: {2}\n triggeroninterval: {3}\n timevalue: {4}\n timeinterval: {5}\n action: {6}
# TestBot
bot.testBot.told=Bot{0}对我说:{1}
bot.testBot.said=Bot{0}说:{1}

View file

@ -0,0 +1,883 @@
[mcc]
# Messages from MCC itself
mcc.help_us_translate=帮助我们翻译MCC{0}
mcc.run_with_default_settings=\nMCC正在使用默认配置运行。
mcc.settings_generated=§c配置文件 MinecraftClient.ini 已经生成。
mcc.has_update=§e新版本的MCC已经推出{0}
mcc.login=账户名:
mcc.login_basic_io=请输入用户名或邮箱。
mcc.password=密码:
mcc.password_basic_io=请输入用户 {0} 的密码。
mcc.password_hidden=密码(不会显示){0}
mcc.offline=§8您正在使用离线模式。
mcc.session_invalid=§8会话缓存无效或已过期。
mcc.session_valid=§8{0}的会话缓存仍然有效。
mcc.profile_key_invalid=§8缓存的聊天签名密钥需要刷新。
mcc.profile_key_valid=§8{0}的聊天签名密钥缓存仍然有效.
mcc.connecting=正在连接至{0}...
mcc.fetching_key=正在从微软获取聊天签名密钥。
mcc.ip=服务器IP
mcc.use_version=§8正在运行Minecraft版本{0} (v{1}协议)
mcc.unknown_version=§8未知或不受支持的Minecraft版本{0}。\n正在切换至自动检测模式。
mcc.forge=检查服务器是否正在运行Forge...
mcc.forgeforce=正在强制启动Forge支持。
mcc.resolve=正在解析{0}...
mcc.found=§8已找到服务器{0}:{1},域名:{2}
mcc.not_found=§8无法执行{0}的SRV解析\n{1}{2}
mcc.retrieve=正在获取服务器信息...
mcc.restart=正在重启Minecraft Console Client...
mcc.restart_delay=等待 {0} 秒后重启...
mcc.server_version=服务器版本:
mcc.disconnected=未连接至任何服务器。输入 '{0}help' 获得帮助。
mcc.press_exit=或者敲击回车退出Minecraft Console Client。
mcc.version_supported=该版本受到支持\n正在登录...
mcc.single_cmd=§7已发送命令§8 {0}
mcc.joined=已成功加入服务器。\n输入 '{0}quit' 离开服务器。
mcc.reconnect=等待5秒 (剩余{0}次尝试)...
mcc.disconnect.lost=失去连接。
mcc.disconnect.server=从服务器断开连接:
mcc.disconnect.login=连接失败:
mcc.link=链接:{0}
mcc.player_dead_respawn=你死了1秒后自动重生。
mcc.player_dead=你死了!输入 '{0}respawn' 重生。
mcc.server_offline=§8服务器正处于离线模式。
mcc.session=检查会话...
mcc.session_fail=检查会话失败
mcc.server_protocol=§8服务器的Minecraft版本{0} (协议v{1})
mcc.with_forge=, 带有Forge
mcc.handshake=§8握手成功。 (服务器ID{0})
mcc.realms_available==您可以访问以下Realms世界
mcc.realms_join=请使用"realms:<序号>"作为服务器IP加入Realms世界
mcc.generator.generating=正在从 {1} 生成 {0} 信息。
mcc.generator.done=已完成从 {0} 信息生成,使用 {1}
mcc.invaild_config=解析配置文件失败,输入 "{0}new" 以生成一个新的配置。
mcc.gen_new_config=已生成新的配置文件 "{0}" 。
[debug]
# Messages from MCC Debug Mode
debug.color_test=颜色测试:终端应该显示:{0}
debug.session_cache_ok=§8已成功从磁盘中加载会话数据。
debug.session_cache_fail=§8无法从磁盘加载缓存的会话数据。
debug.keys_cache_ok=§8已成功从磁盘中加载聊天签名密钥。
debug.keys_cache_fail=§8无法从磁盘中加载聊天签名密钥。
debug.session_id=成功!(会话ID{0})
debug.crypto=§8密钥和哈希值已生成
debug.request=§8正在请求{0}
[error]
# Error messages from MCC
error.ping=ping此IP失败。
error.unsupported=无法连接到服务器:不支持此版本!
error.determine=无法确定服务器版本。
error.forgeforce=无法为此Minecraft版本强制启动Forge支持
error.login=登录失败:
error.login.migrated=帐户已迁移,请使用电子邮件作为用户名。
error.login.server=登录服务器不可用。请稍后再试。
error.login.blocked=用户名/密码错误、IP被禁用或登录次数过多。
error.login.response=服务器返回了无效的响应。
error.login.premium=不是Premium用户。
error.login.network=网络错误。
error.login.ssl=SSL错误。
error.login.unknown=未知错误。
error.login.cancel=用户取消。
error.login_failed=无法登录到此服务器。
error.join=加入服务器时发生错误。
error.connect=无法连接到此IP。
error.timeout=连接超时
error.unexpect_response=§8来自服务器的意外响应这是Minecraft服务器吗
error.invalid_response=§8对握手包的响应无效
error.invalid_encrypt=§8对StartEncryption数据包的响应无效
error.version_different=§8服务器报告的版本与手动设置的版本不同。登录可能无法工作。
error.no_version_report=§8服务器未报告其协议版本自动检测将不起作用。
error.connection_timeout=§8尝试连接到此IP时超时。
error.forge=§8Forge登录握手未成功完成
error.forge_encrypt=§8Forge StartEncryption握手未成功完成
error.setting.argument_syntax={0}:无效语法,应为 --argname=value 或 --section.argname=value
error.http_code=§8接收到服务器错误{0}
error.auth=§8在刷新身份验证时接收到服务器错误{0}
error.realms.ip_error=无法获取您Realms世界的服务器IP
error.realms.access_denied=此Realms世界不存在或访问被拒绝
error.realms.server_unavailable=Realms服务器可能需要一些时间来启动。请稍后再试。
error.realms.server_id=Realms服务器ID无效或未知。
error.realms.disabled=正在尝试加入Realms世界但配置中禁用了Realms支持
error.missing.argument=缺少参数 {0}
error.usage=使用方法:
error.generator.invalid=该生成器命令用法无效!
error.generator.path=提供的数据路径无效! (路径不存在或是输入错误)
error.generator.json=提供的路径必须指向一个.json格式的文件!
[internal command]
# MCC internal help command
icmd.help=help <命令名称> :显示有关命令的简要帮助。
icmd.unknown=未知命令 '{0}'。请使用 'help' 命令来获取命令列表。
icmd.list=help <命令名称>。可用命令:{0}。在服务器上获取帮助,请改用 '{1}send /help'。
icmd.error=OnInternalCommand: 来自{0}的错误{1}
[exception]
# Exception messages threw by MCC
exception.user_logout=用户发起的注销应该通过调用Disconnect()来完成
exception.unknown_direction=未知方向
exception.palette.block=请为此Minecraft版本更新方块类型处理。详细请参考 Material.cs
exception.palette.entity=请为此Minecraft版本更新实体类型处理。详细请参考 EntityType.cs
exception.palette.item=请为此Minecraft版本更新物品类型处理。详细请参考 ItemType.cs
exception.palette.packet=请为此Minecraft版本更新数据包类型调色板。详细请参考 PacketTypePalette.cs
exception.packet_process=无法处理传入的{0}类型的数据包。(数据包ID{1},协议:{2},登陆阶段:{3},内部异常:{4})。
exception.version_unsupport=版本{0}的协议未被支持。
exception.chatbot.init=不应在构造函数中调用ChatBot的方法因为作为API处理程序的模块尚未初始化。请重写 Initialize() 或 AfterGameJoined() 来执行初始化任务。
exception.csrunner.invalid_head=提供的脚本没有有效的MCCScript头
[chatbot]
# ChatBot API
chatbot.reconnect=[{0}] 断开并重新连接到服务器
[filemonitor]
# FileMonitor
filemonitor.init=§8[{0}] 正在为文件{1}初始化FileSystemWatcher
filemonitor.fail=§8[{0}] 无法初始化FileSystemWatcher正在使用轮询重试
[extra]
# Inventory, Terrain & Movements, Entity related messages
# Terrain & Movements
extra.terrainandmovement_enabled=地形和移动处理现在已启用。
extra.terrainandmovement_disabled=§c该游戏版本目前还不支持地形和移动处理。
extra.terrainandmovement_required=请先在配置文件中启用地形和移动处理。
# Inventory
extra.inventory_enabled=库存(物品)处理现在已启用。
extra.inventory_disabled=§c该MC版本目前未支持处理库存(物品)。
extra.inventory_required=请先在配置文件中启用"Main.Advanced.inventory_handling"。
extra.inventory_interact=请使用 /inventory 来与其交互。
extra.inventory_open=容器# {0}已开启:{1}
extra.inventory_close=容器# {0}已关闭。
# Entity
extra.entity_disabled=§c该MC版本当前还不支持处理实体。
extra.entity_required=请先在配置文件中启用"Main.Advanced.entity_handling"。
[forge]
# Messages from Forge handler
forge.version=§8Forge协议版本{0}
forge.send_mod=§8向服务器发送伪造的forge模组列表...
forge.accept=§8接受来自的服务器模组列表...
forge.registry=§8已接收的注册表包含{0}个条目
forge.registry_2=§8已接收注册表{0},包含{1}个条目
forge.accept_registry=§8接受服务器注册表...
forge.complete=Forge服务器连接完成!
forge.with_mod=§8服务器正在运行Forge有{0}个模组。
forge.no_mod=§8正在运行的服务器没有Forge模组。
forge.mod_list=§8模组列表:
# FML2
forge.fml2.mod=§8收到FM2服务器模组列表
forge.fml2.mod_send=§8发回FML2客户端的模组列表
forge.fml2.registry=§8确认FML2服务器注册表{0}
forge.fml2.config=§8确认FML2服务器配置{0}
forge.fml2.unknown=§8收到未知的FML2握手信息编号{0}
forge.fml2.unknown_channel=§8忽略未知的FML2登录消息通道{0}
[cache]
# Session Cache
cache.loading=§8加载Minecraft配置文件{0}
cache.loaded=§8已加载会话{0}:{1}
cache.converting=§8从磁盘转换会话缓存{0}
cache.read_fail=§8无法从磁盘读取序列化会话缓存{0}
cache.malformed=§8从磁盘读取序列化会话缓存时获取到格式错误的数据{0}
cache.loading_session=§8从磁盘加载会话缓存{0}
cache.ignore_string=§8忽略会话令牌字符串'{0}'{1}
cache.ignore_line=§8忽略无效的会话令牌行{0}
cache.read_fail_plain=§8无法从磁盘读取会话缓存{0}
cache.saving=§8将会话缓存保存到磁盘
cache.save_fail=§8无法将会话缓存写入磁盘{0}
# Profile Key Cache
cache.loading_keys=§8从磁盘加载聊天签名密钥缓存: {0}
cache.loaded_keys=§8已加载签名密钥下次刷新于 {0}
cache.ignore_string_keys=§8忽略聊天签名密钥字符串 '{0}'{1}
cache.ignore_line_keys=§8忽略无效的聊天签名密钥行{0}
cache.read_fail_plain_keys=§8无法从磁盘读取聊天签名密钥缓存{0}
cache.saving_keys=§8将聊天签名密钥保存到磁盘
cache.save_fail_keys=§8无法将聊天签名密钥写入磁盘{0}
[proxy]
proxy.connected=§8已连接到代理{0}:{1}
[chat]
# Chat Parser
chat.download=§8正在从Mojang服务器下载语言文件 '{0}.lang'...
chat.request=§8正在请求{0}...
chat.done=§8下载完成。文件另存为 '{0}'
chat.fail=§8下载文件失败。
chat.from_dir=§8默认为你的Minecraft目录中的en_GB.lang
chat.loaded=§8已加载翻译文件。
chat.not_found=§8找不到翻译文件'{0}'\n如果没有此文件某些信息将无法正确打印。
chat.message_chain_broken=玩家 {0} 的消息签名链已经被破坏。(签名不在可信)
[general]
# General message/information (i.e. Done)
general.done=完成
general.fail=失败
general.bot_unload=将会卸载此bot。
general.available_cmd=可用命令:{0}
[cmd]
# Commands. Naming style: cmd.<className>.<msg...>
# Animation
cmd.animation.desc=挥动你的手臂。
# Bots
cmd.bots.desc=列出全部 ChatBot ,加载或卸载一个 ChatBot。
cmd.bots.list=已加载的 ChatBot
cmd.bots.notfound=该 ChatBot 并未加载,请检查输入。
cmd.bots.noloaded=没有 ChatBot 被加载。
cmd.bots.unloaded=成功卸载 ChatBot{0}
cmd.bots.unloaded_all=成功卸载所有 ChatBot。
# ChangeSlot
cmd.changeSlot.desc=变更快捷栏栏位
cmd.changeSlot.nan=无法变更栏位:不是数字
cmd.changeSlot.changed=已变更为栏位{0}
cmd.changeSlot.fail=无法变更栏位
# Chunk
cmd.chunk.desc=显示区块加载状态。\n如果显示错乱竟在设置中更改 EnableEmoji=false 。
cmd.chunk.current=当前位置:{0},所在区块:({1}, {2})。
cmd.chunk.marked=标记的位置:
cmd.chunk.chunk_pos=区块:({0}, {1})。
cmd.chunk.outside=§x§0由于被标记的区块距离玩家太远它不会被显示在图中§r
cmd.chunk.icon=玩家:{0},标记的区块:{1},未收到:{2},加载中:{3},已加载:{4}
cmd.chunk.for_debug=§x§0此命令仅用于调试使用确保你已经了解执行该命令会造成的影响。§r
# Connect
cmd.connect.desc=连接到指定的服务器。
cmd.connect.unknown=未知帐户 '{0}'。
cmd.connect.invalid_ip=无效的服务器IP '{0}'。
# Debug
cmd.debug.desc=切换调试消息。
cmd.debug.state_on=调试消息现在已打开
cmd.debug.state_off=调试消息现在已关闭
# Dig
cmd.dig.desc=试图破坏一个方块
cmd.dig.too_far=你离这个方块太远了。
cmd.dig.no_block=这个地方没有方块 (空气)
cmd.dig.dig=尝试挖掘位于({0}, {1}, {2})的方块({3})。
cmd.dig.fail=无法开始挖掘方块。
# Entitycmd
cmd.entityCmd.attacked=已攻击实体
cmd.entityCmd.used=已使用实体
cmd.entityCmd.not_found=找不到实体
cmd.entityCmd.entity=实体
cmd.entityCmd.entities=实体集
cmd.entityCmd.nickname=昵称
cmd.entityCmd.customname=自定义名称
cmd.entityCmd.latency=延迟
cmd.entityCmd.item=物品
cmd.entityCmd.equipment=装备
cmd.entityCmd.mainhand=主手
cmd.entityCmd.offhane=副手
cmd.entityCmd.helmet=头盔
cmd.entityCmd.chestplate=胸甲
cmd.entityCmd.leggings=护腿
cmd.entityCmd.boots=靴子
cmd.entityCmd.pose=姿势
cmd.entityCmd.health=生命值
cmd.entityCmd.distance=距离
cmd.entityCmd.location=位置
cmd.entityCmd.type=类型
# Exec If
cmd.execif.desc=允许你在某个条件成立时执行一个命令。(你可以使用"MinecraftClient.ini"中的变量和使用"/set"命令定义的变量以及CSharp表达式
cmd.execif.executed=条件'{0}'满足,已执行命令'{1}',得到结果'{2}'。
cmd.execif.executed_no_output=条件'{0}'满足,已执行命令'{1}',该命令没有返回任何结果。
cmd.execif.error_occured=在执行命令 {0} 时出现错误。
cmd.execif.error=错误:{0}
# Exec Multi
cmd.execmulti.desc=依次执行多个命令。
cmd.execmulti.executed=执行了命令 '{0}'
cmd.execmulti.result=结果为 '{0}'
cmd.execmulti.no_result=没有返回结果!
# Exit
cmd.exit.desc=断开与服务器的连接。
# Health
cmd.health.desc=显示生命值和饱食度。
cmd.health.response=生命值:{0},饱食度:{1},等级:{2},总经验值:{3}
# Inventory
cmd.inventory.desc=容器相关命令
cmd.inventory.creative_done=向容器#{2}请求{0} x{1}
cmd.inventory.creative_delete=请求清除栏位 #{0}
cmd.inventory.creative_fail=请求创造模式操作失败
cmd.inventory.need_creative=你必须在创造模式
cmd.inventory.container_not_found=找不到容器请使用显式ID重试
cmd.inventory.close=关闭容器 #{0}
cmd.inventory.close_fail=关闭容器失败 #{0}
cmd.inventory.not_exist=容器#{0}不存在
cmd.inventory.inventory=容器
cmd.inventory.inventories=容器
cmd.inventory.inventories_available=可用容器
cmd.inventory.hotbar=您选择的快捷栏是{0}
cmd.inventory.damage=武器伤害值
cmd.inventory.left=
cmd.inventory.right=
cmd.inventory.middle=中间
cmd.inventory.clicking={0}正在点击容器#{2}中的栏位{1}
cmd.inventory.shiftclick=按住Shift键点击容器#{1}中的栏位{0}
cmd.inventory.shiftclick_fail=执行Shift点击失败这可能是因为该容器类型目前不被支持。
cmd.inventory.no_item=栏位#{0}中没有物品
cmd.inventory.drop=从栏位#{0}中丢弃了1个物品
cmd.inventory.drop_stack=从栏位#{0}中丢弃了所有堆叠的物品
# Inventory Help
cmd.inventory.help.basic=基本用法
cmd.inventory.help.available=可用操作
cmd.inventory.help.help={0}\n使用 '/inventory help <action>' 获取帮助。\n'player' 和 'container' 可以简化为 'p' 和 'c'。\n请注意'[]' 中的参数是可选的。
cmd.inventory.help.usage=用法
cmd.inventory.help.list=列出所有容器。
cmd.inventory.help.close=关闭打开的容器。
cmd.inventory.help.click=单击物品。
cmd.inventory.help.shiftclick=按住Shift键点击一个物品。
cmd.inventory.help.drop=从容器中丢弃物品。
cmd.inventory.help.creativegive=在创造模式中给予物品。
cmd.inventory.help.creativedelete=在创造性模式中清除栏位。
cmd.inventory.help.inventories=列出所有可用的窗口。
cmd.inventory.help.search=在打开的所有窗口中搜索物品。
cmd.inventory.help.unknown=未知操作。
cmd.inventory.found_items=找到物品
cmd.inventory.no_found_items=在任何窗口中都没有找到该物品!
# Leave bed
cmd.bed.desc=用于右键床开始睡觉或离开正在睡觉的床。
cmd.bed.leaving=已向服务器发送离开床的数据包。
cmd.bed.trying_to_use=试图在位于 (X: {0:0.0}, Y: {1:0.0}, Z: {2:0.0}) 上的床上睡觉,结果:{3}
cmd.bed.in=成功地躺在了床上!
cmd.bed.not_in=上床睡觉失败了。PS: 你必须使用床头对应的坐标)
cmd.bed.not_a_bed=位于 (X: {0:0.0}, Y: {1:0.0}, Z: {2:0.0}) 的方块不是一个床!
cmd.bed.searching=在半径为{0}的范围内寻找床...
cmd.bed.bed_not_found=没有找到床!
cmd.bed.found_a_bed_at=在 (X: {0:0.0}, Y: {1:0.0}, Z: {2:0.0}) 找到了一个床。
cmd.bed.cant_reach_safely=无法安全地到达床边!
cmd.bed.moving=正在移动到床所在的位置: (X: {0:0.0}, Y: {1:0.0}, Z: {2:0.0})
cmd.bed.failed_to_reach_in_time=无法在30秒内到达(X: {0:0.0}, Y: {1:0.0}, Z: {2:0.0}),放弃本次寻路。
# List
cmd.list.desc=获取玩家列表。
cmd.list.players=玩家列表:{0}
# Log
cmd.log.desc=将文本记录到控制台。
# Look
cmd.look.desc=查看方向或坐标。
cmd.look.unknown=未知方向 '{0}'。
cmd.look.at=当前视角 偏航角:{0} 俯仰角:{1}。
cmd.look.block=正看向位于 {0} 的方块。
cmd.look.inspection=与视线相交的第一个方块是 {0} ({1:0}, {2:0}, {3:0}),距离玩家 {4:0.0}({5:0.0})。
cmd.look.noinspection=在 {0} 米内没有任何方块与视线相交。
# Move
cmd.move.desc=移动或开始移动。
cmd.move.enable=在下次服务器登录、重生或更换世界时启用地形和移动。
cmd.move.disable=禁用地形和移动。
cmd.move.moving=移动{0}
cmd.move.dir_fail=不能朝此方向移动。
cmd.move.walk=移动到{0}
cmd.move.fail=无法计算到达{0}的路径。
cmd.move.suggestforce=无法计算安全到达{0}的路径. 请使用 -f 参数允许不安全移动。
cmd.move.gravity.enabled=重力已开启。
cmd.move.gravity.disabled=重力已关闭。
cmd.move.chunk_loading_status=区块加载进度:{0:P} - 共{2}个,加载完成了{1}个。
cmd.move.chunk_not_loaded=目标位置所在的区块还没有被加载。你可以使用"/chunk status {0:0.0} {1:0.0} {2:0.0}"来查看区块的加载状态。
# Reco
cmd.reco.desc=重新启动并重新连接到服务器。
# Reload
cmd.reload.started=重新加载设置中...
cmd.reload.warning1=这条命令不会影响在连接到服务器之前的某些设置。
cmd.reload.warning2=一些通过命令行参数传递的设置可能会被覆盖!
cmd.reload.warning3=你有可能需要重新连接(/reco)才能使某些设置生效。
cmd.reload.warning4=由于技术限制ReplayCapturer 将不会被强制重载!
cmd.reload.finished=重新加载设置完成!
cmd.reload.desc=重新加载MCC的设置。
# Respawn
cmd.respawn.desc=如果你死亡了,请用这个来重生。
cmd.respawn.done=你重生了。
# Script
cmd.script.desc=运行脚本文件。
# Send
cmd.send.desc=发送聊天信息或命令。
# Set
cmd.set.desc=设置自定义 %variable%。
cmd.set.format=变量名范围必须为 A-Za-z0-9。
# SetRnd
cmd.setrnd.desc=随机为自定义 %变量名% 赋值。
cmd.setrndnum.format=setrnd 变量名 -7to17
cmd.setrndstr.format=setrnd 变量名 字符串1 "\"字符串2\" 字符串3"
# Sneak
cmd.sneak.desc=切换到潜行
cmd.sneak.on=现在你在潜行状态。
cmd.sneak.off=你不在潜行状态了。
# DropItem
cmd.dropItem.desc=丢弃玩家容器中的指定类型物品或打开的容器
cmd.dropItem.dropped=已从容器#{1}中丢弃所有{0}
cmd.dropItem.unknown_item=未知物品:{0}
# Tps
cmd.tps.desc=显示服务器当前tps (tick per second)。(可能不精确)
cmd.tps.current=当前TPS
# Useblock
cmd.useblock.desc=放置一个方块或打开箱子
cmd.useblock.use=使用位于 ({0:0.0}, {1:0.0}, {2:0.0}) 的 {3}。
# Useitem
cmd.useitem.desc=使用(左键单击)手上的物品
cmd.useitem.use=使用了一个物品。
[bot]
# ChatBots. Naming style: bot.<className>.<msg...>
# Alerts
bot.alerts.start_rain=§c天气变化开始下雨了。§r
bot.alerts.end_rain=§c天气变化雨停了。§r
bot.alerts.start_thunderstorm=§c天气变化现在是雷雨天。§r
bot.alerts.end_thunderstorm=§c天气变化现在不再是雷雨天了。§r
# Anti AFK
bot.antiafk.not_using_terrain_handling=当前未启用地形处理,如果你想使用相关的特性,请在设置中启用它。当前将继续使用替代方法运行(定时发送命令)。
bot.antiafk.swapping=最短时间大于最长时间,已将它们交换。
bot.antiafk.invalid_walk_range=当前提供的行走范围无效它必须是一个大于0的正整数将使用默认值5!
# AutoAttack
bot.autoAttack.invalidcooldown=攻击冷却时间值不能小于0已使用自动作为默认值
# AutoCraft
bot.autoCraft.cmd=自动制作ChatBot命令
bot.autoCraft.alias=自动制作ChatBot命令的别名
bot.autoCraft.cmd.list=已加载{0}个配方:{1}
bot.autoCraft.cmd.resetcfg=将配置重置为默认值
bot.autoCraft.recipe_not_exist=指定的配方名称不存在。请检查配置文件。
bot.autoCraft.no_recipe_name=请指定要制作的配方名称。
bot.autoCraft.stop=AutoCraft已停止
bot.autoCraft.available_cmd=可用命令:{0}。可使用 /autocraft help <命令名> 了解更多信息。您可以使用 /ac 作为命令别名。
bot.autoCraft.help.load=加载配置文件。
bot.autoCraft.help.list=列出可用配方。
bot.autoCraft.help.reload=重新加载配置文件。
bot.autoCraft.help.resetcfg=将默认示例配置写入默认位置。
bot.autoCraft.help.start=开始制作。用法:/autocraft start <配方名称>
bot.autoCraft.help.stop=停止当前正在进行的制作过程
bot.autoCraft.help.help=获取命令描述。用法:/autocraft help <命令名>
bot.autoCraft.loaded=已成功加载
bot.autoCraft.start=AutoCraft启动中{0}
bot.autoCraft.start_fail=无法启动AutoCraft。请检查用于制作{0}的可用材料
bot.autoCraft.table_not_found=找不到工作台
bot.autoCraft.close_inventory=容器#{0}被AutoCraft关闭
bot.autoCraft.missing_material=缺失材料:{0}
bot.autoCraft.aborted=制作被终止!请检查可用材料。
bot.autoCraft.craft_fail=制作失败!等待更多材料
bot.autoCraft.timeout=动作超时!原因:{0}
bot.autoCraft.error.config=分析配置时出错:{0}
bot.autoCraft.exception.name_miss=解析配方时缺少配方名称
bot.autoCraft.exception.duplicate=指定了重复的配方名称:{0}
bot.autoCraft.debug.no_config=找不到配置。请新建一个。
bot.autocraft.invaild_slots=配方的物品数量不匹配,已自动调整。
bot.autocraft.invaild_invaild_result=无效的输出物品!
# AutoDig
bot.autodig.start_delay=将在 {0:0.0} 秒后开始自动挖掘。
bot.autodig.dig_timeout=挖掘方块超时,重试。
bot.autodig.not_allow=当前所看向的方块不在允许挖掘列表中。
bot.autodig.cmd=自动挖掘 ChatBot 命令
bot.autodig.available_cmd=可用命令:{0}。可使用 /digbot help <命令名> 了解更多信息。
bot.autodig.start=开始自动挖掘。
bot.autodig.stop=停止自动挖掘。
bot.autodig.help.start=开始运行自动挖掘。
bot.autodig.help.stop=停止运行自动挖掘。
bot.autodig.help.help=获取命令描述。用法:/digbot help <命令名>
# AutoDrop
bot.autoDrop.cmd=AutoDrop ChatBot命令
bot.autoDrop.alias=AutoDrop ChatBot命令别名
bot.autoDrop.on=已启用AutoDrop
bot.autoDrop.off=已禁用AutoDrop
bot.autoDrop.added=已添加物品{0}
bot.autoDrop.incorrect_name=物品名称不正确:{0}。请再试一次。
bot.autoDrop.removed=已删除物品{0}
bot.autoDrop.not_in_list=物品不在列表中
bot.autoDrop.no_item=列表中没有物品
bot.autoDrop.list=列表中总计{0}个物品:\n {1}
bot.autoDrop.switched= 切换到{0}模式。
bot.autoDrop.unknown_mode=未知模式。可用的模式Include, Exclude, Everything
bot.autoDrop.no_mode=无法从配置中读取丢弃模式drop mode。使用Include模式。
bot.autoDrop.no_inventory=找不到容器{0}!
# AutoFish
bot.autoFish.no_inv_handle=未启用库存(物品)处理。将不支持检查鱼竿耐久度都和自动切换鱼竿。
bot.autoFish.start=将在 {0:0.0} 秒后自动开始钓鱼。
bot.autoFish.throw=抛竿成功。
bot.autoFish.caught=钓到了一条鱼!(总计 {0} 条)
bot.autoFish.caught_at=在 ({0:0.0},{1:0.0},{2:0.0}) 掉到了一条鱼!(总计 {0} 条)
bot.autoFish.no_rod=没有可使用的钓鱼竿了。也许是用坏了或耐久度过低?
bot.autoFish.despawn=鱼钩消失,将会重新抛竿。
bot.autoFish.fishing_timeout=钓鱼超时,将于几秒钟后重新抛竿。
bot.autoFish.cast_timeout=抛竿超时,将在等待一段时间后重试。(超时时间延长至 {0:0.0} 秒)
bot.autoFish.update_lookat=更新当前朝向 偏航角(yaw) = {0:0.00}, 俯仰角(pitch) = {1:0.00}。
bot.autoFish.switch=切换到位于背包 {0} 位置的鱼竿,剩余耐用 {1}/64。
# AutoRelog
bot.autoRelog.launch=已启动,尝试了{0}次重新连接
bot.autoRelog.no_kick_msg=在没有kick消息文件的情况下初始化
bot.autoRelog.loading=从文件{0}加载消息
bot.autoRelog.loaded=已加载消息:{0}
bot.autoRelog.not_found=找不到文件或目录:{0}
bot.autoRelog.curr_dir=当前目录为:{0}
bot.autoRelog.ignore_user_logout=由用户或MCC bot启动的断开连接。忽略。
bot.autoRelog.disconnect_msg=连接断开,收到消息:{0}
bot.autoRelog.reconnect_always=忽略kick消息仍要重新连接。
bot.autoRelog.reconnect=信息包含 '{0}'。重新连接。
bot.autoRelog.reconnect_ignore=不包含任何已定义关键字的消息,忽略。
bot.autoRelog.wait=等待{0}秒后重新连接...
# AutoRespond
bot.autoRespond.loading=正在从'{0}'加载匹配项
bot.autoRespond.file_not_found=找不到文件或目录: '{0}'
bot.autoRespond.loaded_match=加载匹配项:\n{0}
bot.autoRespond.no_trigger=这个匹配永远不会触发:\n{0}
bot.autoRespond.no_action=匹配没有对应操作:\n{0}
bot.autoRespond.match_run=进行操作:{0}
bot.autoRespond.match=match: {0}\nregex: {1}\naction: {2}\nactionPrivate: {3}\nactionOther: {4}\nownersOnly: {5}\ncooldown: {6}
# ChatLog
bot.chatLog.invalid_file=路径'{0}'包含无效字符。
# Mailer
bot.mailer.init=使用设置初始化Mailer
bot.mailer.init.db= - 数据库文件:{0}
bot.mailer.init.ignore= - 忽略列表:{0}
bot.mailer.init.public= - 公开交互:{0}
bot.mailer.init.max_mails= - 每位玩家最多邮件数:{0}
bot.mailer.init.db_size= - 最大数据库大小:{0}
bot.mailer.init.mail_retention= - 邮件保留天数:{0}
bot.mailer.init_fail.db_size=无法启用Mailer最大数据库大小必须大于0。请检查设置。
bot.mailer.init_fail.max_mails=无法启用Mailer每个玩家的最大邮件数必须大于0。请检查设置。
bot.mailer.init_fail.mail_retention=无法启用Mailer邮件保留天数必须大于0。请检查设置。
bot.mailer.create.db=创建新数据库文件:{0}
bot.mailer.create.ignore=创建新忽略列表:{0}
bot.mailer.load.db=加载数据库文件:{0}
bot.mailer.load.ignore=加载忽略列表:
bot.mailer.cmd=mailer 命令
bot.mailer.saving=正在保存邮件:{0}
bot.mailer.user_ignored={0}已被忽略!
bot.mailer.process_mails=正在查找要发送的邮件 @ {0}
bot.mailer.delivered=已发送:{0}
bot.mailer.cmd.getmails=--- 数据库中的邮件 ---\n{0}
bot.mailer.cmd.getignored=--- 忽略列表 ---\n{0}
bot.mailer.cmd.ignore.added=添加{0}到忽略列表!
bot.mailer.cmd.ignore.removed={0}已从忽略列表中删除!
bot.mailer.cmd.ignore.invalid=丢失或无效的名称。用法:{0}<用户名>
bot.mailer.cmd.help=查看用法
# Maps
bot.map.cmd.desc=渲染物品形式的地图
bot.map.cmd.not_found=没有找到编号为 '{0}' 的地图!
bot.map.cmd.invalid_id=无效的地图编号,必须是一个数字。
bot.map.received=从服务器接收到的地图有:
bot.map.no_maps=没有收到过地图!
bot.map.received_map=收到一个编号为 {0} 的新地图。
bot.map.rendered=成功接收到地图 '{0}' ,保存为 '{1}'
bot.map.failed_to_render=无法渲染编号为 '{0}' 的地图。
bot.map.list_item=- 地图编号:{0}(最近更新于:{1}
bot.map.windows_only=保存地图到文件功能目前仅可用于Windows平台。
# ReplayCapture
bot.replayCapture.cmd=replay 命令
bot.replayCapture.created=已创建重播文件。
bot.replayCapture.stopped=录制已停止。
bot.replayCapture.restart=录制已停止。请重新启动程序以进行另一段录制。
# Follow player
cmd.follow.desc=让机器人跟随指定的玩家
cmd.follow.usage=follow <player name|stop> [-f] (使用 -f 允许机器人途径不安全的地方)
cmd.follow.already_stopped=已经停止过了
cmd.follow.stopping=已停止!
cmd.follow.invalid_name=提供的玩家名无效!
cmd.follow.invalid_player=指定的玩家没有上线或距离太远!
cmd.follow.cant_reach_player=无法寻路到该玩家,有可能他在没有加载的区块中,或是距离太远,也有可能是间隙或水体等障碍使机器人无法到达。
cmd.follow.already_following=已经在跟随 {0} 了!
cmd.follow.switched=切换为跟随 {0}
cmd.follow.started=开始跟随 {0}
cmd.follow.unsafe_enabled=启用了允许途径不安全位置(注意:机器人可能会受伤或死亡!)
cmd.follow.note=注意:此机器人的速度很慢,你需要慢慢地走,而且要保持很近的距离,这样它才能跟上,有点像拿着食物让动物跟着你。这是由于寻路算法的限制,我们正在努力改进它。
cmd.follow.player_came_to_the_range=玩家 {0} 回到了可寻路范围之内!
cmd.follow.resuming=继续跟随!
cmd.follow.player_left_the_range=玩家 {0} 离开了可寻路范围!
cmd.follow.pausing=已暂停!
cmd.follow.player_left=玩家 {0} 离开了服务器!
cmd.follow.stopping=已停止!
# Script
bot.script.not_found=§8[MCC] [{0}] 找不到脚本文件:{1}
bot.script.file_not_found=找不到文件:'{0}'
bot.script.fail=脚本'{0}'运行失败 ({1})。
bot.script.pm.loaded=脚本'{0}'加载。
# ScriptScheduler
bot.scriptScheduler.loaded_task=已加载任务:\n{0}
bot.scriptScheduler.no_trigger=这个任务永远不会触发:\n{0}
bot.scriptScheduler.no_action=任务没有对应操作:\n{0}
bot.scriptScheduler.running_time=时间 / 运行中的操作:{0}
bot.scriptScheduler.running_inverval=间隔 / 运行中的操作:{0}
bot.scriptScheduler.running_login=登录 / 运行中的操作:{0}
bot.scriptScheduler.task=triggeronfirstlogin: {0}\n triggeronlogin: {1}\n triggerontime: {2}\n triggeroninterval: {3}\n timevalue: {4}\n timeinterval: {5}\n action: {6}
# TestBot
bot.testBot.told=Bot{0}对我说:{1}
bot.testBot.said=Bot{0}说:{1}
[config]
config.load=已从 {0} 加载设置。
config.load.fail=§c加载设置时出错§r
config.write.fail=§保存备份文件({0}时出错§r
config.backup.fail=§c写入设置文件{0}时出错§r
config.saving=§a当前设置已保存至 {0}
# Head
config.Head=启动配置文件\n\n# 对 MCCMinecraft 命令行客户端不熟悉请看这个文档https://mccteam.github.io/guide/configuration.html\n\n# 想升级到较新的版本吗?请访问 https://github.com/MCCTeam/Minecraft-Console-Client/#download
# Main.General
config.Main.General.account=Login请填写邮箱或玩家名称。若要以离线模式登录请使用"-"作为密码。若留空则使用交互式登录。
config.Main.General.login=游戏服务器的地址和端口可填入域名或IP地址。可删除端口字段会自动解析SRV记录
config.Main.General.server_info=帐户类型mojang 或是 microsoft。此项设置也会影响交互式登录。
config.Main.General.method=微软账户的登录方式mcc 或是 browser手动在网页上登录
# Main.Advanced
config.Main.Advanced=在更改这里的某项设置之前,请确保你理解了该选项的影响。
config.Main.Advanced.language=请使用Minecraft的语言代码填写详见 https://github.com/MCCTeam/Minecraft-Console-Client/discussions/2239
config.Main.Advanced.internal_cmd_char=MCC内部命令的前缀可使用 "none", "slash"(/) 或 "backslash"(\)。
config.Main.Advanced.message_cooldown=控制向服务器发送消息的最小间隔时间(秒)。
config.Main.Advanced.bot_owners=设置机器人的所有者。/!\服务器管理员可以伪装成任何玩家!
config.Main.Advanced.mc_version=游戏版本,可使用 "auto"(自动) 或类似 "1.X.X" 的值。设定具体版本将跳过从服务器解析的过程。
config.Main.Advanced.mc_forge=可使用 "auto"(自动)"no"(禁用) 或是 "force"(强制启用,仅在 1.13 及更高的版本中可用)。
config.Main.Advanced.brand_info=客户端标识,可用 "mcc""vanilla"(原版客户端) 或 "none"(空标识)。这用于改变MCC向服务器发送的客户端标识内容。
config.Main.Advanced.chatbot_log_file=留空将禁用 ChatBot 写入日志文件。
config.Main.Advanced.private_msgs_cmd_name=远程控制功能将会使用它。
config.Main.Advanced.show_system_messages=显示游戏服务器的系统消息(来自管理员或命令方块等)。
config.Main.Advanced.show_xpbar_messages=显示经验条上方的消息,如果被此类消息刷屏请禁用此选项。
config.Main.Advanced.show_chat_links=解码聊天信息里的链接,并在控制台单独显示。
config.Main.Advanced.show_inventory_layout=以字符画形式显示库存布局。
config.Main.Advanced.terrain_and_movements=开启地形处理将消耗更多的内存、CPU和网络带宽但这允许你进行移动以及和方块交互。
config.Main.Advanced.inventory_handling=启用库存处理(可操作背包、箱子等容器)。
config.Main.Advanced.entity_handling=启用实体处理。
config.Main.Advanced.session_cache=如何缓存会话令牌。可使用 "none"(不缓存)"memory"(内存缓存) 或 "disk"(磁盘缓存)。
config.Main.Advanced.profilekey_cache=如何缓存聊天签名密钥。可使用 "none"(不缓存)"memory"(内存缓存) 或 "disk"(磁盘缓存)。
config.Main.Advanced.resolve_srv_records=可填写 "no""fast"(超时时间为五秒钟)或是 "yes"。加入某些服务器需要开启此项。
config.Main.Advanced.account_list=AccountList使你可以不用输入账号信息而快速在多个账号间切换\n# 可用命令示例:"/tell <mybot> reco Player2""/connect <serverip> Player1"
config.Main.Advanced.server_list=ServerList可用使用服务器别名快速连接到该服务器\n# 别名不能包含空格和小数点",而且 "localhost" 不能作为别名使用。\n# 可用命令示例:"/tell <mybot> connect Server1""/connect Server2"
config.Main.Advanced.player_head_icon=使用玩家皮肤头像作为窗口图标,这仅在部分旧版控制台中有效。
config.Main.Advanced.exit_on_failure=发生错误时是否直接退出用于在非交互式脚本中使用MCC。
config.Main.Advanced.script_cache=缓存已编译的脚本,以便在低端设备上更快的加载。
config.Main.Advanced.timestamps=在聊天信息头部添加时间戳。
config.Main.Advanced.auto_respawn=死亡时自动重生(开启前请确保你的出生点是安全的)
config.Main.Advanced.minecraft_realms=启用对加入我的世界领域(Realms)服务器的支持。
config.Main.Advanced.move_head_while_walking=在移动时转向头部。
config.Main.Advanced.timeout=与服务器的TCP连接超时时间
config.Main.Advanced.enable_emoji=如果关闭Emoji表情符号将被替换成更简单的字符用于 "/chunk status" 命令)
config.Main.Advanced.movement_speed=高于 2 的移动速度可能会被检测为作弊。
config.Main.Advanced.language.invaild=无效的语言代码!
# Signature
config.Signature=聊天签名相关设置影响1.19及以上版本)
config.Signature.LoginWithSecureProfile=仅微软账户可用。如禁用此项,将无法签名消息和进入某些的服务器。
config.Signature.SignChat=是否签名发送的聊天消息。
config.Signature.SignMessageInCommand=是否签名指令中的消息。例如"/msg"和"/me"中的消息。
config.Signature.MarkLegallySignedMsg=是否使用绿色色块标识拥有合法签名的聊天。
config.Signature.MarkModifiedMsg=是否使用黄色色块标识被服务器更改过的聊天。
config.Signature.MarkIllegallySignedMsg=是否使用红色色块标识没有合法签名的聊天。
config.Signature.MarkSystemMessage=是否使用灰色色块标识系统消息(它们总是不会被签名)。
config.Signature.ShowModifiedChat=设置为 true显示被服务器修改过的信息设置为 false显示经过签名的原始信息。
config.Signature.ShowIllegalSignedChat=是否显示没有被正确签名的聊天消息。
# Logging
config.Logging=此项设置仅会影响到控制台中的信息(日志)。
config.Logging.DebugMessages=请在提交错误报告之前先启用此项。谢谢!
config.Logging.ChatMessages=是否显示来自服务器的聊天消息。
config.Logging.InfoMessages=信息性的消息。大部分来自MCC内部
config.Logging.WarningMessages=显示警告消息。
config.Logging.ErrorMessages=显示错误消息。
config.Logging.ChatFilter=过滤聊天消息所用的正则表达式。
config.Logging.DebugFilter=过滤调试消息所用的正则表达式。
config.Logging.FilterMode=过滤方式:"disable"(禁用),"blacklist"(隐藏匹配的消息) 或 "whitelist"(仅显示匹配的消息)
config.Logging.LogToFile=是否将日志信息写入到文件。
config.Logging.LogFile=日志文件名称。
config.Logging.PrependTimestamp=写入日志文件时是否添加时间戳。
config.Logging.SaveColorCodes=是否保留消息中的颜色字符。(例如"§b"
# AppVars
config.AppVars.Variables=可以在某些字段中以"%yourvar%"的形式使用。\n# %username% 和 %serverip% 时保留的变量名。
# Proxy
config.Proxy=通过代理连接到服务器。\n# 如果Mojang/微软登录服务被防火墙阻断设置Enabled_Login=true以使用代理进行登录。\n# 如果到Minecraft游戏服务器的连接被防火墙阻止设置Enabled_Ingame=true以使用代理连接游戏服务器。\n# /!\ 在启用代理前请确保你的服务器规则允许使用代理或VPN否则你可能面临被封禁等风险
config.Proxy.Enabled_Login=是否使用代理连接Mojang或微软的登录服务器。
config.Proxy.Enabled_Ingame=是否通过代理连接Minecraft游戏服务器。
config.Proxy.Server=代理服务器必须允许HTTPS登录。
config.Proxy.Proxy_Type=支持的代理类型:"HTTP""SOCKS4""SOCKS4a""SOCKS5"。
config.Proxy.Username=只有连接到受密码保护的代理才需要。
config.Proxy.Password=只有连接到受密码保护的代理才需要。
# ChatFormat
config.ChatFormat=MCC会尽力检测聊天信息但有些服务器有不寻常的聊天格式\n# 当这种情况发生时,你需要在下面自定义匹配聊天所用的正则表达式,详见 https://mccteam.github.io/guide/configuration.html#chat-format
config.ChatFormat.Builtins=是否启用MCC内置的聊天检测规则。设置为 false 以避免与自定义格式冲突。
config.ChatFormat.UserDefined=是否启用下方的自定义正则表达式进行聊天检测。
# MCSettings
config.MCSettings=下面的设置将会被发送到游戏服务器,只影响一些服务器端的东西,比如你的皮肤。
config.MCSettings.Enabled=如果禁用,下面的设置就不会被发送到服务器上。
config.MCSettings.Locale=请使用Minecraft的语言代码填写详见[Main.Advanced.Language]
config.MCSettings.RenderDistance=渲染距离,取值范围[0 - 255]。
config.MCSettings.Difficulty=Minecraft 1.7及更早版本难度。"peaceful""easy""normal""difficult"。
config.MCSettings.ChatMode=使用 "enabled"(完全启用聊天)、"commands"(仅限命令)或 "disabled"(完全禁用聊天)。这允许你禁言自己...
config.MCSettings.ChatColors=这允许你在服务器端禁用聊天颜色。
config.MCSettings.MainHand=在1.9及更高版本中的主手设置。"left"(左手) 或 "right"(右手)。
# ChatBot
config.ChatBot================================ #\n# Minecraft Console Client Bots #\n# =============================== #
# ChatBot.Alerts
config.ChatBot.Alerts=当检测到特定聊天消息或特定事件发生时提醒你\n # 对检测特定玩家的聊天消息很有用。
config.ChatBot.Alerts.Beep_Enabled=除了高亮显示外,当检测到一个词时还会播放类似蜂鸣器的哔哔声。
config.ChatBot.Alerts.Trigger_By_Words=在收到指定的关键词后触发提醒。
config.ChatBot.Alerts.Trigger_By_Rain=在开始下雨和停止下雨时触发提醒。
config.ChatBot.Alerts.Trigger_By_Thunderstorm=在雷暴天气的开始与结束触发提醒。
config.ChatBot.Alerts.Matches=触发提醒的聊天关键词列表。
config.ChatBot.Alerts.Excludes=出现这些关键词后该条消息一定不触发提醒。
config.ChatBot.Alerts.Log_To_File=是否将提醒消息写入到日志文件。
config.ChatBot.Alerts.Log_File=日志文件的路径。
# ChatBot.AntiAFK
config.ChatBot.AntiAfk=定期发送命令,或让机器人随机走动,以避免检测到挂机后被踢出服务器\n # /!\启用前请确保你的服务器规则不禁止反AFK机制\n# /!\如果启用随机移动请将机器人围在围栏里以防走失建议尺寸5x5x5
config.ChatBot.AntiAfk.Delay=执行操作的间隔时间。(秒)
config.ChatBot.AntiAfk.Command=发送给服务器的指令。
config.ChatBot.AntiAfk.Use_Sneak=在发送命令时是否蹲下。
config.ChatBot.AntiAfk.Use_Terrain_Handling=启用地形处理,以使机器人能够四处移动。
config.ChatBot.AntiAfk.Walk_Range=机器人可以随机移动的范围(注意:范围越大,速度越慢)
config.ChatBot.AntiAfk.Walk_Retries=尝试移动失败几次后在改为发送命令模式。
# ChatBot.AutoAttack
config.ChatBot.AutoAttack=自动攻击周围的生物\n# 使用此功能之前,你需要开启实体处理。\n# /!\确保你的服务器允许使用自动攻击。\n# /!\服务器插件可能会认为此功能时作弊,并可能会封禁你的账号,所以请自己检查服务器规则是否允许。
config.ChatBot.AutoAttack.Mode="single"(单目标) 或 "multi"(多目标)。一次攻击一个生物还是范围内的所有生物。
config.ChatBot.AutoAttack.Priority="health"(生命值)或 "distance"(距离)。当使用"single"模式时,以哪一个属性确定优先级。
config.ChatBot.AutoAttack.Cooldown_Time=每次攻击间的冷却时间,设置 "Custom = false" 以让MCC自动计算攻击速度。
config.ChatBot.AutoAttack.Interaction=可选项:"Interact"(交互),"Attack"(攻击) 或 "InteractAt"(交互并攻击)
config.ChatBot.AutoAttack.Attack_Hostile=是否攻击敌对生物。
config.ChatBot.AutoAttack.Attack_Passive=是否攻击被动生物。
config.ChatBot.AutoAttack.List_Mode=将实体列表作为 "whitelist"(白名单)还是 "blacklist"(黑名单)。
config.ChatBot.AutoAttack.Entites_List=所有可用的实体类型可以在这里找到https://bit.ly/3Rg68lp
# ChatBot.AutoCraft
config.ChatBot.AutoCraft=自动使用背包中的物品进行合成。\n# 请看 https://mccteam.github.io/guide/chat-bots.html#auto-craft\n# 你需要启用库存处理来使用这个功能\n# 如果需要使用工作台,你还需要启用地形处理。
config.ChatBot.AutoCraft.CraftingTable=如果你打算使用工作台,请填写它所在的位置。(需要启用地形处理)
config.ChatBot.AutoCraft.OnFailure=合成失败时应该怎么处理,"abort"(中止)或 "wait"(等待)。
config.ChatBot.AutoCraft.Recipes=Recipes.Name给该配方起一个独一无二的名字。不能包含空白字符Recipes.Type合成类型"player"背包2x2或 "table"工作台3x3\n# Recipes.Result合成的目标物品\n# Recipes.Slots合成的物品摆放方式以从左到右、从上到下的格式填写。需留空请填写"Null"。\n# 最新的物品命名请看https://github.com/MCCTeam/Minecraft-Console-Client/blob/master/MinecraftClient/Inventory/ItemType.cs
# AutoDig
config.ChatBot.AutoDig=自动挖掘方块。\n# 你可以使用 "/digbot start" 和 "/digbot stop" 指令来控制 AutoDig 的启停。\n# 由于MCC目前还不支持精确计算方块的碰撞体积在获取看向的方块时视线上所有的方块都被看作是完整的立方体。\n# 查询方块的名字,请访问 https://github.com/MCCTeam/Minecraft-Console-Client/blob/master/MinecraftClient/Mapping/Material.cs
config.ChatBot.AutoDig.Auto_Tool_Switch=自动切换到合适的工具。
config.ChatBot.AutoDig.Durability_Limit=不会使用低于此耐久度的工具。(需要启用库存处理)
config.ChatBot.AutoDig.Drop_Low_Durability_Tools=在当前使用的工具耐久度过低后,是否丢掉它。
config.ChatBot.AutoDig.Mode="lookat""fixedpos" 或 "both"。挖掘看向的方块还是固定位置的方块,或者是两个条件都满足的方块。
config.ChatBot.AutoDig.Locations=使用 "fixedpos" 或 "both" 模式时,方块的坐标。
config.ChatBot.AutoDig.Location_Order="distance" 或 "index",当使用 "fixedpos" 模式时,按照到玩家的距离,还是列表中的顺序确定挖掘的方块。
config.ChatBot.AutoDig.Auto_Start_Delay=进入游戏后等待多少秒后开始自动挖掘,设置为-1禁用自动开始。
config.ChatBot.AutoDig.Dig_Timeout=若挖掘一个方块用时超过这个值,将会重新获取目标进行挖掘。
config.ChatBot.AutoDig.Log_Block_Dig=是否输出挖掘方块的相关信息。
config.ChatBot.AutoDig.List_Type=将方块列表作为 "whitelist"(白名单)还是 "blacklist"(黑名单)。
# ChatBot.AutoDrop
config.ChatBot.AutoDrop=自动从背包/库存中丢弃指定的物品\n# 你需要启用库存处理来使用这个功能。\n# 可用物品请看 https://github.com/MCCTeam/Minecraft-Console-Client/blob/master/MinecraftClient/Inventory/ItemType.cs
config.ChatBot.AutoDrop.Mode="include"(丢弃列表中的物品),"exclude"(丢弃列表外的所有物品) 或 "everything"(丢弃所有物品)
# ChatBot.AutoEat
config.ChatBot.AutoEat=在饱食度较低是自动在背包中寻找食物食用。\n# 你需要启用库存处理来使用这个功能。
# ChatBot.AutoFishing
config.ChatBot.AutoFishing=使用鱼竿自动钓鱼。指南https://mccteam.github.io/guide/chat-bots.html#auto-fishingn# /!\ 启用前请确保服务器允许自动钓鱼。
config.ChatBot.AutoFishing.Antidespawn=如果你之前没有启用过这个选项,请保持它为 false 。
config.ChatBot.AutoFishing.Mainhand=使用主手还是副手拿鱼竿。
config.ChatBot.AutoFishing.Auto_Start=是否在进入服务器后自动开始钓鱼,禁用此功能后,你需要使用"/usehand"手动使用鱼竿一次。
config.ChatBot.AutoFishing.Cast_Delay=钓到鱼后多久开始下一次钓鱼(抛竿)。
config.ChatBot.AutoFishing.Fishing_Delay=进入服务器后多久后开始自动钓鱼。(秒)
config.ChatBot.AutoFishing.Fishing_Timeout=多少秒后没有钓到鱼视为超时。超时后会重新抛竿。
config.ChatBot.AutoFishing.Durability_Limit=不会使用低于此耐久度的鱼竿鱼竿耐久度最高为64需要启用库存处理
config.ChatBot.AutoFishing.Auto_Rod_Switch=在当前鱼竿不可用后自动切换到背包中的其他鱼竿。(需要启用库存处理)
config.ChatBot.AutoFishing.Stationary_Threshold=鱼钩在X轴和Z轴方向上的移动小于这个值将被认为是静止的过高的阈值会在抛竿途中触发收竿。
config.ChatBot.AutoFishing.Hook_Threshold=一个“静止”的鱼钩在Y轴方向上的移动超过这个阈值将被认为钓到了鱼。
config.ChatBot.AutoFishing.Log_Fish_Bobber=用于调整以上两个阈值,启用后会在收到鱼钩实体移动数据包后打印其坐标变化。
config.ChatBot.AutoFishing.Enable_Move=这允许玩家在钓到鱼后改变其位置或朝向。(需要启用地形处理)
config.ChatBot.AutoFishing.Movements=会按照 "1->2->3->4->3->2->1->2->..." 的顺序执行。每次可用改变位置、朝向或是都改变。推荐只改变朝向。
# ChatBot.AutoRelog
config.ChatBot.AutoRelog=在被服务器断开连接时自动重连,例如服务器重启时。\n# /!\ 谨慎使用Ignore_Kick_Message=true这会在服务器管理员将你踢出时依然连回
config.ChatBot.AutoRelog.Delay=重新加入到服务器前的延迟时间。(单位:秒)
config.ChatBot.AutoRelog.Retries=重新登录服务器失败时的重试次数,使用-1表示无限重试。
config.ChatBot.AutoRelog.Ignore_Kick_Message=当设置为 true 时,将不考虑踢出的信息直接重连。
config.ChatBot.AutoRelog.Kick_Messages=如果踢出信息与这其中的任何一个字符串匹配,那么将触发自动重连。
# ChatBot.AutoRespond
config.ChatBot.AutoRespond=当聊天消息与文件中的规则匹配时,自动执行指定命令。\n# /!\ 服务器管理员可以以任意玩家的身份发送任意消息,记住这一点!\n# 此机器人如果设置的不得当可能会造成刷屏,建议设置一个冷却时间。
config.ChatBot.AutoRespond.Match_Colors=不要删除文本中的颜色代码(使用§字符的代码)。注意:启用后你的匹配模板也必须包括颜色代码。
# ChatBot.ChatLog
config.ChatBot.ChatLog=将聊天信息写入到日志文件中。
# ChatBot.FollowPlayer
config.ChatBot.FollowPlayer=让机器人跟随指定玩家\n# 注意这是一个实验性的功能,目前的寻路速度可能很慢,你可能需要时常等一会机器人来让它跟上你。\n# 你可以调整"Update_Limit"找到最适合你的速度。注意不要设置的太低这样可能导致反效果或使MCC卡顿。\n# /!\ 在使用此功能之前,请先确保服务器规则允许你这样做。
config.ChatBot.FollowPlayer.Update_Limit=机器人寻路的间隔时间(以秒为单位)
config.ChatBot.FollowPlayer.Stop_At_Distance=如果玩家在该范围内,则视为已经接近玩家了。(防止机器人将玩家推开而产生无限循环)
# ChatBot.HangmanGame
config.ChatBot.HangmanGame=一个用于演示聊天互动的小游戏。玩家可以一次一个字母地猜出神秘的单词。\n# 你需要正确地使用 ChatFormat并在 botowners 中添加自己,用/tell <bot username> start\n# /!\ 这个机器人可能会造成刷屏,如果许多玩家与它互动。
# ChatBot.Mailer
config.ChatBot.Mailer=在玩家和服务器之间中继消息,就像一个邮件插件一样。\n# 这个机器人可以在收件人离线时存储消息,并在他们加入服务器时发送消息。\n# /!\ 服务器管理员可以以任意玩家的身份发送任意消息,请记住这一点。
# ChatBot.Map
config.ChatBot.Map=允许你将地图渲染成.jpg图片该图片会被渲染到Rendered_Maps文件夹中。\n# 注意:这个功能目前只对解决使用地图的验证码有用。\n# 如果一些服务器解决验证码的时间很短请启用Auto_Render_On_Update并准备快速打开该文件。\n# 在linux上你可以使用FTP来访问生成的文件。
config.ChatBot.Map.Should_Resize=是否需要调整地图的大小?(默认大小是128x128)
config.ChatBot.Map.Resize_To=将地图调整到什么大小?(注意:大小越大,质量越低)
config.ChatBot.Map.Auto_Render_On_Update=一旦接收到新的地图或已有地图被更新,自动渲染该地图。
config.ChatBot.Map.Delete_All_On_Unload=在卸载/重新加载地图时删除所有已渲染的地图退出MCC时不会删除图像
config.ChatBot.Map.Notify_On_First_Update=当第一次从服务器上收到一张地图时,发送一个通知。
# ChatBot.PlayerListLogger
config.ChatBot.PlayerListLogger=定期记录当前的玩家列表到文件中。
config.ChatBot.PlayerListLogger.Delay=(单位:秒)
# ChatBot.RemoteControl
config.ChatBot.RemoteControl=通过游戏中的私聊向机器人发送MCC控制台命令\n# 你需要先配置好[ChatFormat]章节的设置,并在[Main.Advanced.bot_owners]中添加自己的账号。\n# /!\ 服务器管理员可以以任意玩家的身份发送任意消息,仅在信任他们时启用本功能。
# ChatBot.ReplayCapture
config.ChatBot.ReplayCapture=使用"/replay start"开始记录游戏,并在之后使用 Replay Mod (https://www.replaymod.com/) 进行重放。\n# 请注意,由于技术限制,玩家自身不会显示在重放文件中。\n# /!\ 你应该使用"/replay stop"停止记录或者使用"/quit"退出程序,否则回放文件可能会损坏。
config.ChatBot.ReplayCapture.Backup_Interval=每间隔多少秒自动保存一次回放文件,以秒为单位。使用-1禁用自动保存。
# ChatBot.ScriptScheduler
config.ChatBot.ScriptScheduler=在加入服务器时、到达特定时间时或以设定的时间间隔执行命令或脚本文件\n# 详细使用方法请查看 https://mccteam.github.io/guide/chat-bots.html#script-scheduler

View file

@ -0,0 +1,883 @@
[mcc]
# Messages from MCC itself
mcc.help_us_translate=幫助我們翻譯MCC{0}
mcc.run_with_default_settings=\nMCC正在使用預設配置執行。
mcc.settings_generated=§c配置檔案 MinecraftClient.ini 已經生成。
mcc.has_update=§e新版本的MCC已經推出{0}
mcc.login=賬戶名:
mcc.login_basic_io=請輸入使用者名稱或郵箱。
mcc.password=密碼:
mcc.password_basic_io=請輸入使用者 {0} 的密碼。
mcc.password_hidden=密碼(不會顯示){0}
mcc.offline=§8您正在使用離線模式。
mcc.session_invalid=§8會話快取無效或已過期。
mcc.session_valid=§8{0}的會話快取仍然有效。
mcc.profile_key_invalid=§8快取的聊天簽名金鑰需要重新整理。
mcc.profile_key_valid=§8{0}的聊天簽名金鑰快取仍然有效.
mcc.connecting=正在連線至{0}...
mcc.fetching_key=正在從微軟獲取聊天簽名金鑰。
mcc.ip=伺服器IP
mcc.use_version=§8正在執行Minecraft版本{0} (v{1}協議)
mcc.unknown_version=§8未知或不受支援的Minecraft版本{0}。\n正在切換至自動檢測模式。
mcc.forge=檢查伺服器是否正在執行Forge...
mcc.forgeforce=正在強制啟動Forge支援。
mcc.resolve=正在解析{0}...
mcc.found=§8已找到伺服器{0}:{1},域名:{2}
mcc.not_found=§8無法執行{0}的SRV解析\n{1}{2}
mcc.retrieve=正在獲取伺服器資訊...
mcc.restart=正在重啟Minecraft Console Client...
mcc.restart_delay=等待 {0} 秒後重啟...
mcc.server_version=伺服器版本:
mcc.disconnected=未連線至任何伺服器。輸入 '{0}help' 獲得幫助。
mcc.press_exit=或者敲擊回車退出Minecraft Console Client。
mcc.version_supported=該版本受到支援\n正在登入...
mcc.single_cmd=§7已傳送命令§8 {0}
mcc.joined=已成功加入伺服器。\n輸入 '{0}quit' 離開伺服器。
mcc.reconnect=等待5秒 (剩餘{0}次嘗試)...
mcc.disconnect.lost=失去連線。
mcc.disconnect.server=從伺服器斷開連線:
mcc.disconnect.login=連線失敗:
mcc.link=連結:{0}
mcc.player_dead_respawn=你死了1秒後自動重生。
mcc.player_dead=你死了!輸入 '{0}respawn' 重生。
mcc.server_offline=§8伺服器正處於離線模式。
mcc.session=檢查會話...
mcc.session_fail=檢查會話失敗
mcc.server_protocol=§8伺服器的Minecraft版本{0} (協議v{1})
mcc.with_forge=, 帶有Forge
mcc.handshake=§8握手成功。 (伺服器ID{0})
mcc.realms_available==您可以訪問以下Realms世界
mcc.realms_join=請使用"realms:<序號>"作為伺服器IP加入Realms世界
mcc.generator.generating=正在從 {1} 生成 {0} 資訊。
mcc.generator.done=已完成從 {0} 資訊生成,使用 {1}
mcc.invaild_config=解析配置檔案失敗,輸入 "{0}new" 以生成一個新的配置。
mcc.gen_new_config=已生成新的配置檔案 "{0}" 。
[debug]
# Messages from MCC Debug Mode
debug.color_test=顏色測試:終端應該顯示:{0}
debug.session_cache_ok=§8已成功從磁碟中載入會話資料。
debug.session_cache_fail=§8無法從磁碟載入快取的會話資料。
debug.keys_cache_ok=§8已成功從磁碟中載入聊天簽名金鑰。
debug.keys_cache_fail=§8無法從磁碟中載入聊天簽名金鑰。
debug.session_id=成功!(會話ID{0})
debug.crypto=§8金鑰和雜湊值已生成
debug.request=§8正在請求{0}
[error]
# Error messages from MCC
error.ping=ping此IP失敗。
error.unsupported=無法連線到伺服器:不支援此版本!
error.determine=無法確定伺服器版本。
error.forgeforce=無法為此Minecraft版本強制啟動Forge支援
error.login=登入失敗:
error.login.migrated=帳戶已遷移,請使用電子郵件作為使用者名稱。
error.login.server=登入伺服器不可用。請稍後再試。
error.login.blocked=使用者名稱/密碼錯誤、IP被禁用或登入次數過多。
error.login.response=伺服器返回了無效的響應。
error.login.premium=不是Premium使用者。
error.login.network=網路錯誤。
error.login.ssl=SSL錯誤。
error.login.unknown=未知錯誤。
error.login.cancel=使用者取消。
error.login_failed=無法登入到此伺服器。
error.join=加入伺服器時發生錯誤。
error.connect=無法連線到此IP。
error.timeout=連線超時
error.unexpect_response=§8來自伺服器的意外響應這是Minecraft伺服器嗎
error.invalid_response=§8對握手包的響應無效
error.invalid_encrypt=§8對StartEncryption資料包的響應無效
error.version_different=§8伺服器報告的版本與手動設定的版本不同。登入可能無法工作。
error.no_version_report=§8伺服器未報告其協議版本自動檢測將不起作用。
error.connection_timeout=§8嘗試連線到此IP時超時。
error.forge=§8Forge登入握手未成功完成
error.forge_encrypt=§8Forge StartEncryption握手未成功完成
error.setting.argument_syntax={0}:無效語法,應為 --argname=value 或 --section.argname=value
error.http_code=§8接收到伺服器錯誤{0}
error.auth=§8在重新整理身份驗證時接收到伺服器錯誤{0}
error.realms.ip_error=無法獲取您Realms世界的伺服器IP
error.realms.access_denied=此Realms世界不存在或訪問被拒絕
error.realms.server_unavailable=Realms伺服器可能需要一些時間來啟動。請稍後再試。
error.realms.server_id=Realms伺服器ID無效或未知。
error.realms.disabled=正在嘗試加入Realms世界但配置中禁用了Realms支援
error.missing.argument=缺少引數 {0}
error.usage=使用方法:
error.generator.invalid=該生成器命令用法無效!
error.generator.path=提供的資料路徑無效! (路徑不存在或是輸入錯誤)
error.generator.json=提供的路徑必須指向一個.json格式的檔案!
[internal command]
# MCC internal help command
icmd.help=help <命令名稱> :顯示有關命令的簡要幫助。
icmd.unknown=未知命令 '{0}'。請使用 'help' 命令來獲取命令列表。
icmd.list=help <命令名稱>。可用命令:{0}。在伺服器上獲取幫助,請改用 '{1}send /help'。
icmd.error=OnInternalCommand: 來自{0}的錯誤{1}
[exception]
# Exception messages threw by MCC
exception.user_logout=使用者發起的登出應該通過呼叫Disconnect()來完成
exception.unknown_direction=未知方向
exception.palette.block=請為此Minecraft版本更新方塊型別處理。詳細請參考 Material.cs
exception.palette.entity=請為此Minecraft版本更新實體型別處理。詳細請參考 EntityType.cs
exception.palette.item=請為此Minecraft版本更新物品型別處理。詳細請參考 ItemType.cs
exception.palette.packet=請為此Minecraft版本更新資料包型別調色盤。詳細請參考 PacketTypePalette.cs
exception.packet_process=無法處理傳入的{0}型別的資料包。(資料包ID{1},協議:{2},登陸階段:{3},內部異常:{4})。
exception.version_unsupport=版本{0}的協議未被支援。
exception.chatbot.init=不應在建構函式中呼叫ChatBot的方法因為作為API處理程式的模組尚未初始化。請重寫 Initialize() 或 AfterGameJoined() 來執行初始化任務。
exception.csrunner.invalid_head=提供的指令碼沒有有效的MCCScript頭
[chatbot]
# ChatBot API
chatbot.reconnect=[{0}] 斷開並重新連線到伺服器
[filemonitor]
# FileMonitor
filemonitor.init=§8[{0}] 正在為檔案{1}初始化FileSystemWatcher
filemonitor.fail=§8[{0}] 無法初始化FileSystemWatcher正在使用輪詢重試
[extra]
# Inventory, Terrain & Movements, Entity related messages
# Terrain & Movements
extra.terrainandmovement_enabled=地形和移動處理現在已啟用。
extra.terrainandmovement_disabled=§c該遊戲版本目前還不支援地形和移動處理。
extra.terrainandmovement_required=請先在配置檔案中啟用地形和移動處理。
# Inventory
extra.inventory_enabled=庫存(物品)處理現在已啟用。
extra.inventory_disabled=§c該MC版本目前未支援處理庫存(物品)。
extra.inventory_required=請先在配置檔案中啟用"Main.Advanced.inventory_handling"。
extra.inventory_interact=請使用 /inventory 來與其互動。
extra.inventory_open=容器# {0}已開啟:{1}
extra.inventory_close=容器# {0}已關閉。
# Entity
extra.entity_disabled=§c該MC版本當前還不支援處理實體。
extra.entity_required=請先在配置檔案中啟用"Main.Advanced.entity_handling"。
[forge]
# Messages from Forge handler
forge.version=§8Forge協議版本{0}
forge.send_mod=§8向伺服器傳送偽造的forge模組列表...
forge.accept=§8接受來自的伺服器模組列表...
forge.registry=§8已接收的登錄檔包含{0}個條目
forge.registry_2=§8已接收登錄檔{0},包含{1}個條目
forge.accept_registry=§8接受伺服器登錄檔...
forge.complete=Forge伺服器連線完成!
forge.with_mod=§8伺服器正在執行Forge有{0}個模組。
forge.no_mod=§8正在執行的伺服器沒有Forge模組。
forge.mod_list=§8模組列表:
# FML2
forge.fml2.mod=§8收到FM2伺服器模組列表
forge.fml2.mod_send=§8發回FML2客戶端的模組列表
forge.fml2.registry=§8確認FML2伺服器登錄檔{0}
forge.fml2.config=§8確認FML2伺服器配置{0}
forge.fml2.unknown=§8收到未知的FML2握手資訊編號{0}
forge.fml2.unknown_channel=§8忽略未知的FML2登入訊息通道{0}
[cache]
# Session Cache
cache.loading=§8載入Minecraft配置檔案{0}
cache.loaded=§8已載入會話{0}:{1}
cache.converting=§8從磁碟轉換會話快取{0}
cache.read_fail=§8無法從磁碟讀取序列化會話快取{0}
cache.malformed=§8從磁碟讀取序列化會話快取時獲取到格式錯誤的資料{0}
cache.loading_session=§8從磁碟載入會話快取{0}
cache.ignore_string=§8忽略會話令牌字串'{0}'{1}
cache.ignore_line=§8忽略無效的會話令牌行{0}
cache.read_fail_plain=§8無法從磁碟讀取會話快取{0}
cache.saving=§8將會話快取儲存到磁碟
cache.save_fail=§8無法將會話快取寫入磁碟{0}
# Profile Key Cache
cache.loading_keys=§8從磁碟載入聊天簽名金鑰快取: {0}
cache.loaded_keys=§8已載入簽名金鑰下次重新整理於 {0}
cache.ignore_string_keys=§8忽略聊天簽名金鑰字串 '{0}'{1}
cache.ignore_line_keys=§8忽略無效的聊天簽名金鑰行{0}
cache.read_fail_plain_keys=§8無法從磁碟讀取聊天簽名金鑰快取{0}
cache.saving_keys=§8將聊天簽名金鑰儲存到磁碟
cache.save_fail_keys=§8無法將聊天簽名金鑰寫入磁碟{0}
[proxy]
proxy.connected=§8已連線到代理{0}:{1}
[chat]
# Chat Parser
chat.download=§8正在從Mojang伺服器下載語言檔案 '{0}.lang'...
chat.request=§8正在請求{0}...
chat.done=§8下載完成。檔案另存為 '{0}'
chat.fail=§8下載檔案失敗。
chat.from_dir=§8預設為你的Minecraft目錄中的en_GB.lang
chat.loaded=§8已載入翻譯檔案。
chat.not_found=§8找不到翻譯檔案'{0}'\n如果沒有此檔案某些資訊將無法正確列印。
chat.message_chain_broken=玩家 {0} 的訊息簽名鏈已經被破壞。(簽名不在可信)
[general]
# General message/information (i.e. Done)
general.done=完成
general.fail=失敗
general.bot_unload=將會解除安裝此bot。
general.available_cmd=可用命令:{0}
[cmd]
# Commands. Naming style: cmd.<className>.<msg...>
# Animation
cmd.animation.desc=揮動你的手臂。
# Bots
cmd.bots.desc=列出全部 ChatBot ,載入或解除安裝一個 ChatBot。
cmd.bots.list=已載入的 ChatBot
cmd.bots.notfound=該 ChatBot 並未載入,請檢查輸入。
cmd.bots.noloaded=沒有 ChatBot 被載入。
cmd.bots.unloaded=成功解除安裝 ChatBot{0}
cmd.bots.unloaded_all=成功解除安裝所有 ChatBot。
# ChangeSlot
cmd.changeSlot.desc=變更快捷欄欄位
cmd.changeSlot.nan=無法變更欄位:不是數字
cmd.changeSlot.changed=已變更為欄位{0}
cmd.changeSlot.fail=無法變更欄位
# Chunk
cmd.chunk.desc=顯示區塊載入狀態。\n如果顯示錯亂竟在設定中更改 EnableEmoji=false 。
cmd.chunk.current=當前位置:{0},所在區塊:({1}, {2})。
cmd.chunk.marked=標記的位置:
cmd.chunk.chunk_pos=區塊:({0}, {1})。
cmd.chunk.outside=§x§0由於被標記的區塊距離玩家太遠它不會被顯示在圖中§r
cmd.chunk.icon=玩家:{0},標記的區塊:{1},未收到:{2},載入中:{3},已載入:{4}
cmd.chunk.for_debug=§x§0此命令僅用於除錯使用確保你已經瞭解執行該命令會造成的影響。§r
# Connect
cmd.connect.desc=連線到指定的伺服器。
cmd.connect.unknown=未知帳戶 '{0}'。
cmd.connect.invalid_ip=無效的伺服器IP '{0}'。
# Debug
cmd.debug.desc=切換除錯訊息。
cmd.debug.state_on=除錯訊息現在已開啟
cmd.debug.state_off=除錯訊息現在已關閉
# Dig
cmd.dig.desc=試圖破壞一個方塊
cmd.dig.too_far=你離這個方塊太遠了。
cmd.dig.no_block=這個地方沒有方塊 (空氣)
cmd.dig.dig=嘗試挖掘位於({0}, {1}, {2})的方塊({3})。
cmd.dig.fail=無法開始挖掘方塊。
# Entitycmd
cmd.entityCmd.attacked=已攻擊實體
cmd.entityCmd.used=已使用實體
cmd.entityCmd.not_found=找不到實體
cmd.entityCmd.entity=實體
cmd.entityCmd.entities=實體集
cmd.entityCmd.nickname=暱稱
cmd.entityCmd.customname=自定義名稱
cmd.entityCmd.latency=延遲
cmd.entityCmd.item=物品
cmd.entityCmd.equipment=裝備
cmd.entityCmd.mainhand=主手
cmd.entityCmd.offhane=副手
cmd.entityCmd.helmet=頭盔
cmd.entityCmd.chestplate=胸甲
cmd.entityCmd.leggings=護腿
cmd.entityCmd.boots=靴子
cmd.entityCmd.pose=姿勢
cmd.entityCmd.health=生命值
cmd.entityCmd.distance=距離
cmd.entityCmd.location=位置
cmd.entityCmd.type=型別
# Exec If
cmd.execif.desc=允許你在某個條件成立時執行一個命令。(你可以使用"MinecraftClient.ini"中的變數和使用"/set"命令定義的變數以及CSharp表示式
cmd.execif.executed=條件'{0}'滿足,已執行命令'{1}',得到結果'{2}'。
cmd.execif.executed_no_output=條件'{0}'滿足,已執行命令'{1}',該命令沒有返回任何結果。
cmd.execif.error_occured=在執行命令 {0} 時出現錯誤。
cmd.execif.error=錯誤:{0}
# Exec Multi
cmd.execmulti.desc=依次執行多個命令。
cmd.execmulti.executed=執行了命令 '{0}'
cmd.execmulti.result=結果為 '{0}'
cmd.execmulti.no_result=沒有返回結果!
# Exit
cmd.exit.desc=斷開與伺服器的連線。
# Health
cmd.health.desc=顯示生命值和飽食度。
cmd.health.response=生命值:{0},飽食度:{1},等級:{2},總經驗值:{3}
# Inventory
cmd.inventory.desc=容器相關命令
cmd.inventory.creative_done=向容器#{2}請求{0} x{1}
cmd.inventory.creative_delete=請求清除欄位 #{0}
cmd.inventory.creative_fail=請求創造模式操作失敗
cmd.inventory.need_creative=你必須在創造模式
cmd.inventory.container_not_found=找不到容器請使用顯式ID重試
cmd.inventory.close=關閉容器 #{0}
cmd.inventory.close_fail=關閉容器失敗 #{0}
cmd.inventory.not_exist=容器#{0}不存在
cmd.inventory.inventory=容器
cmd.inventory.inventories=容器
cmd.inventory.inventories_available=可用容器
cmd.inventory.hotbar=您選擇的快捷欄是{0}
cmd.inventory.damage=武器傷害值
cmd.inventory.left=
cmd.inventory.right=
cmd.inventory.middle=中間
cmd.inventory.clicking={0}正在點選容器#{2}中的欄位{1}
cmd.inventory.shiftclick=按住Shift鍵點選容器#{1}中的欄位{0}
cmd.inventory.shiftclick_fail=執行Shift點選失敗這可能是因為該容器型別目前不被支援。
cmd.inventory.no_item=欄位#{0}中沒有物品
cmd.inventory.drop=從欄位#{0}中丟棄了1個物品
cmd.inventory.drop_stack=從欄位#{0}中丟棄了所有堆疊的物品
# Inventory Help
cmd.inventory.help.basic=基本用法
cmd.inventory.help.available=可用操作
cmd.inventory.help.help={0}\n使用 '/inventory help <action>' 獲取幫助。\n'player' 和 'container' 可以簡化為 'p' 和 'c'。\n請注意'[]' 中的引數是可選的。
cmd.inventory.help.usage=用法
cmd.inventory.help.list=列出所有容器。
cmd.inventory.help.close=關閉開啟的容器。
cmd.inventory.help.click=單擊物品。
cmd.inventory.help.shiftclick=按住Shift鍵點選一個物品。
cmd.inventory.help.drop=從容器中丟棄物品。
cmd.inventory.help.creativegive=在創造模式中給予物品。
cmd.inventory.help.creativedelete=在創造性模式中清除欄位。
cmd.inventory.help.inventories=列出所有可用的視窗。
cmd.inventory.help.search=在開啟的所有視窗中搜索物品。
cmd.inventory.help.unknown=未知操作。
cmd.inventory.found_items=找到物品
cmd.inventory.no_found_items=在任何視窗中都沒有找到該物品!
# Leave bed
cmd.bed.desc=用於右鍵床開始睡覺或離開正在睡覺的床。
cmd.bed.leaving=已向伺服器傳送離開床的資料包。
cmd.bed.trying_to_use=試圖在位於 (X: {0:0.0}, Y: {1:0.0}, Z: {2:0.0}) 上的床上睡覺,結果:{3}
cmd.bed.in=成功地躺在了床上!
cmd.bed.not_in=上床睡覺失敗了。PS: 你必須使用床頭對應的座標)
cmd.bed.not_a_bed=位於 (X: {0:0.0}, Y: {1:0.0}, Z: {2:0.0}) 的方塊不是一個床!
cmd.bed.searching=在半徑為{0}的範圍內尋找床...
cmd.bed.bed_not_found=沒有找到床!
cmd.bed.found_a_bed_at=在 (X: {0:0.0}, Y: {1:0.0}, Z: {2:0.0}) 找到了一個床。
cmd.bed.cant_reach_safely=無法安全地到達床邊!
cmd.bed.moving=正在移動到床所在的位置: (X: {0:0.0}, Y: {1:0.0}, Z: {2:0.0})
cmd.bed.failed_to_reach_in_time=無法在30秒內到達(X: {0:0.0}, Y: {1:0.0}, Z: {2:0.0}),放棄本次尋路。
# List
cmd.list.desc=獲取玩家列表。
cmd.list.players=玩家列表:{0}
# Log
cmd.log.desc=將文字記錄到控制檯。
# Look
cmd.look.desc=檢視方向或座標。
cmd.look.unknown=未知方向 '{0}'。
cmd.look.at=當前視角 偏航角:{0} 俯仰角:{1}。
cmd.look.block=正看向位於 {0} 的方塊。
cmd.look.inspection=與視線相交的第一個方塊是 {0} ({1:0}, {2:0}, {3:0}),距離玩家 {4:0.0}({5:0.0})。
cmd.look.noinspection=在 {0} 米內沒有任何方塊與視線相交。
# Move
cmd.move.desc=移動或開始移動。
cmd.move.enable=在下次伺服器登入、重生或更換世界時啟用地形和移動。
cmd.move.disable=禁用地形和移動。
cmd.move.moving=移動{0}
cmd.move.dir_fail=不能朝此方向移動。
cmd.move.walk=移動到{0}
cmd.move.fail=無法計算到達{0}的路徑。
cmd.move.suggestforce=無法計算安全到達{0}的路徑. 請使用 -f 引數允許不安全移動。
cmd.move.gravity.enabled=重力已開啟。
cmd.move.gravity.disabled=重力已關閉。
cmd.move.chunk_loading_status=區塊載入進度:{0:P} - 共{2}個,載入完成了{1}個。
cmd.move.chunk_not_loaded=目標位置所在的區塊還沒有被載入。你可以使用"/chunk status {0:0.0} {1:0.0} {2:0.0}"來檢視區塊的載入狀態。
# Reco
cmd.reco.desc=重新啟動並重新連線到伺服器。
# Reload
cmd.reload.started=重新載入設定中...
cmd.reload.warning1=這條命令不會影響在連線到伺服器之前的某些設定。
cmd.reload.warning2=一些通過命令列引數傳遞的設定可能會被覆蓋!
cmd.reload.warning3=你有可能需要重新連線(/reco)才能使某些設定生效。
cmd.reload.warning4=由於技術限制ReplayCapturer 將不會被強制過載!
cmd.reload.finished=重新載入設定完成!
cmd.reload.desc=重新載入MCC的設定。
# Respawn
cmd.respawn.desc=如果你死亡了,請用這個來重生。
cmd.respawn.done=你重生了。
# Script
cmd.script.desc=執行指令碼檔案。
# Send
cmd.send.desc=傳送聊天資訊或命令。
# Set
cmd.set.desc=設定自定義 %variable%。
cmd.set.format=變數名範圍必須為 A-Za-z0-9。
# SetRnd
cmd.setrnd.desc=隨機為自定義 %變數名% 賦值。
cmd.setrndnum.format=setrnd 變數名 -7to17
cmd.setrndstr.format=setrnd 變數名 字串1 "\"字串2\" 字串3"
# Sneak
cmd.sneak.desc=切換到潛行
cmd.sneak.on=現在你在潛行狀態。
cmd.sneak.off=你不在潛行狀態了。
# DropItem
cmd.dropItem.desc=丟棄玩家容器中的指定型別物品或開啟的容器
cmd.dropItem.dropped=已從容器#{1}中丟棄所有{0}
cmd.dropItem.unknown_item=未知物品:{0}
# Tps
cmd.tps.desc=顯示伺服器當前tps (tick per second)。(可能不精確)
cmd.tps.current=當前TPS
# Useblock
cmd.useblock.desc=放置一個方塊或開啟箱子
cmd.useblock.use=使用位於 ({0:0.0}, {1:0.0}, {2:0.0}) 的 {3}。
# Useitem
cmd.useitem.desc=使用(左鍵單擊)手上的物品
cmd.useitem.use=使用了一個物品。
[bot]
# ChatBots. Naming style: bot.<className>.<msg...>
# Alerts
bot.alerts.start_rain=§c天氣變化開始下雨了。§r
bot.alerts.end_rain=§c天氣變化雨停了。§r
bot.alerts.start_thunderstorm=§c天氣變化現在是雷雨天。§r
bot.alerts.end_thunderstorm=§c天氣變化現在不再是雷雨天了。§r
# Anti AFK
bot.antiafk.not_using_terrain_handling=當前未啟用地形處理,如果你想使用相關的特性,請在設定中啟用它。當前將繼續使用替代方法執行(定時傳送命令)。
bot.antiafk.swapping=最短時間大於最長時間,已將它們交換。
bot.antiafk.invalid_walk_range=當前提供的行走範圍無效它必須是一個大於0的正整數將使用預設值5!
# AutoAttack
bot.autoAttack.invalidcooldown=攻擊冷卻時間值不能小於0已使用自動作為預設值
# AutoCraft
bot.autoCraft.cmd=自動製作ChatBot命令
bot.autoCraft.alias=自動製作ChatBot命令的別名
bot.autoCraft.cmd.list=已載入{0}個配方:{1}
bot.autoCraft.cmd.resetcfg=將配置重置為預設值
bot.autoCraft.recipe_not_exist=指定的配方名稱不存在。請檢查配置檔案。
bot.autoCraft.no_recipe_name=請指定要製作的配方名稱。
bot.autoCraft.stop=AutoCraft已停止
bot.autoCraft.available_cmd=可用命令:{0}。可使用 /autocraft help <命令名> 瞭解更多資訊。您可以使用 /ac 作為命令別名。
bot.autoCraft.help.load=載入配置檔案。
bot.autoCraft.help.list=列出可用配方。
bot.autoCraft.help.reload=重新載入配置檔案。
bot.autoCraft.help.resetcfg=將預設示例配置寫入預設位置。
bot.autoCraft.help.start=開始製作。用法:/autocraft start <配方名稱>
bot.autoCraft.help.stop=停止當前正在進行的製作過程
bot.autoCraft.help.help=獲取命令描述。用法: /autocraft help <命令名>
bot.autoCraft.loaded=已成功載入
bot.autoCraft.start=AutoCraft啟動中{0}
bot.autoCraft.start_fail=無法啟動AutoCraft。請檢查用於製作{0}的可用材料
bot.autoCraft.table_not_found=找不到工作臺
bot.autoCraft.close_inventory=容器#{0}被AutoCraft關閉
bot.autoCraft.missing_material=缺失材料:{0}
bot.autoCraft.aborted=製作被終止!請檢查可用材料。
bot.autoCraft.craft_fail=製作失敗!等待更多材料
bot.autoCraft.timeout=動作超時!原因:{0}
bot.autoCraft.error.config=分析配置時出錯:{0}
bot.autoCraft.exception.name_miss=解析配方時缺少配方名稱
bot.autoCraft.exception.duplicate=指定了重複的配方名稱:{0}
bot.autoCraft.debug.no_config=找不到配置。請新建一個。
bot.autocraft.invaild_slots=配方的物品數量不匹配,已自動調整。
bot.autocraft.invaild_invaild_result=無效的輸出物品!
# AutoDig
bot.autodig.start_delay=將在 {0:0.0} 秒後開始自動挖掘。
bot.autodig.dig_timeout=挖掘方塊超時,重試。
bot.autodig.not_allow=當前所看向的方塊不在允許挖掘列表中。
bot.autodig.cmd=自動挖掘 ChatBot 命令
bot.autodig.available_cmd=可用命令:{0}。可使用 /digbot help <命令名> 瞭解更多資訊。
bot.autodig.start=開始自動挖掘。
bot.autodig.stop=停止自動挖掘。
bot.autodig.help.start=開始執行自動挖掘。
bot.autodig.help.stop=停止執行自動挖掘。
bot.autodig.help.help=獲取命令描述。用法:/digbot help <命令名>
# AutoDrop
bot.autoDrop.cmd=AutoDrop ChatBot命令
bot.autoDrop.alias=AutoDrop ChatBot命令別名
bot.autoDrop.on=已啟用AutoDrop
bot.autoDrop.off=已禁用AutoDrop
bot.autoDrop.added=已新增物品{0}
bot.autoDrop.incorrect_name=物品名稱不正確:{0}。請再試一次。
bot.autoDrop.removed=已刪除物品{0}
bot.autoDrop.not_in_list=物品不在列表中
bot.autoDrop.no_item=列表中沒有物品
bot.autoDrop.list=列表中總計{0}個物品:\n {1}
bot.autoDrop.switched= 切換到{0}模式。
bot.autoDrop.unknown_mode=未知模式。可用的模式Include, Exclude, Everything
bot.autoDrop.no_mode=無法從配置中讀取丟棄模式drop mode。使用Include模式。
bot.autoDrop.no_inventory=找不到容器{0}!
# AutoFish
bot.autoFish.no_inv_handle=未啟用庫存(物品)處理。將不支援檢查魚竿耐久度都和自動切換魚竿。
bot.autoFish.start=將在 {0:0.0} 秒後自動開始釣魚。
bot.autoFish.throw=拋竿成功。
bot.autoFish.caught=釣到了一條魚!(總計 {0} 條)
bot.autoFish.caught_at=在 ({0:0.0},{1:0.0},{2:0.0}) 掉到了一條魚!(總計 {0} 條)
bot.autoFish.no_rod=沒有可使用的釣魚竿了。也許是用壞了或耐久度過低?
bot.autoFish.despawn=魚鉤消失,將會重新拋竿。
bot.autoFish.fishing_timeout=釣魚超時,將於幾秒鐘後重新拋竿。
bot.autoFish.cast_timeout=拋竿超時,將在等待一段時間後重試。(超時時間延長至 {0:0.0} 秒)
bot.autoFish.update_lookat=更新當前朝向 偏航角(yaw) = {0:0.00}, 俯仰角(pitch) = {1:0.00}。
bot.autoFish.switch=切換到位於揹包 {0} 位置的魚竿,剩餘耐用 {1}/64。
# AutoRelog
bot.autoRelog.launch=已啟動,嘗試了{0}次重新連線
bot.autoRelog.no_kick_msg=在沒有kick訊息檔案的情況下初始化
bot.autoRelog.loading=從檔案{0}載入訊息
bot.autoRelog.loaded=已載入訊息:{0}
bot.autoRelog.not_found=找不到檔案或目錄:{0}
bot.autoRelog.curr_dir=當前目錄為:{0}
bot.autoRelog.ignore_user_logout=由使用者或MCC bot啟動的斷開連線。忽略。
bot.autoRelog.disconnect_msg=連線斷開,收到訊息:{0}
bot.autoRelog.reconnect_always=忽略kick訊息仍要重新連線。
bot.autoRelog.reconnect=資訊包含 '{0}'。重新連線。
bot.autoRelog.reconnect_ignore=不包含任何已定義關鍵字的訊息,忽略。
bot.autoRelog.wait=等待{0}秒後重新連線...
# AutoRespond
bot.autoRespond.loading=正在從'{0}'載入匹配項
bot.autoRespond.file_not_found=找不到檔案或目錄: '{0}'
bot.autoRespond.loaded_match=載入匹配項:\n{0}
bot.autoRespond.no_trigger=這個匹配永遠不會觸發:\n{0}
bot.autoRespond.no_action=匹配沒有對應操作:\n{0}
bot.autoRespond.match_run=進行操作:{0}
bot.autoRespond.match=match: {0}\nregex: {1}\naction: {2}\nactionPrivate: {3}\nactionOther: {4}\nownersOnly: {5}\ncooldown: {6}
# ChatLog
bot.chatLog.invalid_file=路徑'{0}'包含無效字元。
# Mailer
bot.mailer.init=使用設定初始化Mailer
bot.mailer.init.db= - 資料庫檔案:{0}
bot.mailer.init.ignore= - 忽略列表:{0}
bot.mailer.init.public= - 公開互動:{0}
bot.mailer.init.max_mails= - 每位玩家最多郵件數:{0}
bot.mailer.init.db_size= - 最大資料庫大小:{0}
bot.mailer.init.mail_retention= - 郵件保留天數:{0}
bot.mailer.init_fail.db_size=無法啟用Mailer最大資料庫大小必須大於0。請檢查設定。
bot.mailer.init_fail.max_mails=無法啟用Mailer每個玩家的最大郵件數必須大於0。請檢查設定。
bot.mailer.init_fail.mail_retention=無法啟用Mailer郵件保留天數必須大於0。請檢查設定。
bot.mailer.create.db=建立新資料庫檔案:{0}
bot.mailer.create.ignore=建立新忽略列表:{0}
bot.mailer.load.db=載入資料庫檔案:{0}
bot.mailer.load.ignore=載入忽略列表:
bot.mailer.cmd=Mailer 命令
bot.mailer.saving=正在儲存郵件:{0}
bot.mailer.user_ignored={0}已被忽略!
bot.mailer.process_mails=正在查詢要傳送的郵件 @ {0}
bot.mailer.delivered=已傳送:{0}
bot.mailer.cmd.getmails=--- 資料庫中的郵件 ---\n{0}
bot.mailer.cmd.getignored=--- 忽略列表 ---\n{0}
bot.mailer.cmd.ignore.added=新增{0}到忽略列表!
bot.mailer.cmd.ignore.removed={0}已從忽略列表中刪除!
bot.mailer.cmd.ignore.invalid=丟失或無效的名稱。用法:{0}<使用者名稱>
bot.mailer.cmd.help=檢視用法
# Maps
bot.map.cmd.desc=渲染物品形式的地圖
bot.map.cmd.not_found=沒有找到編號為 '{0}' 的地圖!
bot.map.cmd.invalid_id=無效的地圖編號,必須是一個數字。
bot.map.received=從伺服器接收到的地圖有:
bot.map.no_maps=沒有收到過地圖!
bot.map.received_map=收到一個編號為 {0} 的新地圖。
bot.map.rendered=成功接收到地圖 '{0}' ,儲存為 '{1}'
bot.map.failed_to_render=無法渲染編號為 '{0}' 的地圖。
bot.map.list_item=- 地圖編號:{0}(最近更新於:{1}
bot.map.windows_only=儲存地圖到檔案功能目前僅可用於Windows平臺。
# ReplayCapture
bot.replayCapture.cmd=replay 命令
bot.replayCapture.created=已建立重播檔案。
bot.replayCapture.stopped=錄製已停止。
bot.replayCapture.restart=錄製已停止。請重新啟動程式以進行另一段錄製。
# Follow player
cmd.follow.desc=讓機器人跟隨指定的玩家
cmd.follow.usage=follow <player name|stop> [-f] (使用 -f 允許機器人途徑不安全的地方)
cmd.follow.already_stopped=已經停止過了
cmd.follow.stopping=已停止!
cmd.follow.invalid_name=提供的玩家名無效!
cmd.follow.invalid_player=指定的玩家沒有上線或距離太遠!
cmd.follow.cant_reach_player=無法尋路到該玩家,有可能他在沒有載入的區塊中,或是距離太遠,也有可能是間隙或水體等障礙使機器人無法到達。
cmd.follow.already_following=已經在跟隨 {0} 了!
cmd.follow.switched=切換為跟隨 {0}
cmd.follow.started=開始跟隨 {0}
cmd.follow.unsafe_enabled=啟用了允許途徑不安全位置(注意:機器人可能會受傷或死亡!)
cmd.follow.note=注意:此機器人的速度很慢,你需要慢慢地走,而且要保持很近的距離,這樣它才能跟上,有點像拿著食物讓動物跟著你。這是由於尋路演算法的限制,我們正在努力改進它。
cmd.follow.player_came_to_the_range=玩家 {0} 回到了可尋路範圍之內!
cmd.follow.resuming=繼續跟隨!
cmd.follow.player_left_the_range=玩家 {0} 離開了可尋路範圍!
cmd.follow.pausing=已暫停!
cmd.follow.player_left=玩家 {0} 離開了伺服器!
cmd.follow.stopping=已停止!
# Script
bot.script.not_found=§8[MCC] [{0}] 找不到指令碼檔案:{1}
bot.script.file_not_found=找不到檔案:'{0}'
bot.script.fail=指令碼'{0}'執行失敗 ({1})。
bot.script.pm.loaded=指令碼'{0}'載入。
# ScriptScheduler
bot.scriptScheduler.loaded_task=已載入任務:\n{0}
bot.scriptScheduler.no_trigger=這個任務永遠不會觸發:\n{0}
bot.scriptScheduler.no_action=任務沒有對應操作:\n{0}
bot.scriptScheduler.running_time=時間 / 執行中的操作:{0}
bot.scriptScheduler.running_inverval=間隔 / 執行中的操作:{0}
bot.scriptScheduler.running_login=登入 / 執行中的操作:{0}
bot.scriptScheduler.task=triggeronfirstlogin: {0}\n triggeronlogin: {1}\n triggerontime: {2}\n triggeroninterval: {3}\n timevalue: {4}\n timeinterval: {5}\n action: {6}
# TestBot
bot.testBot.told=Bot{0}對我說:{1}
bot.testBot.said=Bot{0}說:{1}
[config]
config.load=已從 {0} 載入設定。
config.load.fail=§c載入設定時出錯§r
config.write.fail=§儲存備份檔案({0}時出錯§r
config.backup.fail=§c寫入設定檔案{0}時出錯§r
config.saving=§a當前設定已儲存至 {0}
# Head
config.Head=啟動配置檔案\n\n# 對 MCCMinecraft 命令列客戶端不熟悉請看這個文件https://mccteam.github.io/guide/configuration.html\n\n# 想升級到較新的版本嗎?請訪問 https://github.com/MCCTeam/Minecraft-Console-Client/#download
# Main.General
config.Main.General.account=Login請填寫郵箱或玩家名稱。若要以離線模式登入請使用"-"作為密碼。若留空則使用互動式登入。
config.Main.General.login=遊戲伺服器的地址和埠可填入域名或IP地址。可刪除埠欄位會自動解析SRV記錄
config.Main.General.server_info=帳戶型別mojang 或是 microsoft。此項設定也會影響互動式登入。
config.Main.General.method=微軟賬戶的登入方式mcc 或是 browser手動在網頁上登入
# Main.Advanced
config.Main.Advanced=在更改這裏的某項設定之前,請確保你理解了該選項的影響。
config.Main.Advanced.language=請使用Minecraft的語言程式碼填寫詳見 https://github.com/MCCTeam/Minecraft-Console-Client/discussions/2239
config.Main.Advanced.internal_cmd_char=MCC內部命令的字首可使用 "none", "slash"(/) 或 "backslash"(\)。
config.Main.Advanced.message_cooldown=控制向伺服器傳送訊息的最小間隔時間(秒)。
config.Main.Advanced.bot_owners=設定機器人的所有者。/!\伺服器管理員可以偽裝成任何玩家!
config.Main.Advanced.mc_version=遊戲版本,可使用 "auto"(自動) 或類似 "1.X.X" 的值。設定具體版本將跳過從伺服器解析的過程。
config.Main.Advanced.mc_forge=可使用 "auto"(自動)"no"(禁用) 或是 "force"(強制啟用,僅在 1.13 及更高的版本中可用)。
config.Main.Advanced.brand_info=客戶端標識,可用 "mcc""vanilla"(原版客戶端) 或 "none"(空標識)。這用於改變MCC向伺服器傳送的客戶端標識內容。
config.Main.Advanced.chatbot_log_file=留空將禁用 ChatBot 寫入日誌檔案。
config.Main.Advanced.private_msgs_cmd_name=遠端控制功能將會使用它。
config.Main.Advanced.show_system_messages=顯示遊戲伺服器的系統訊息(來自管理員或命令方塊等)。
config.Main.Advanced.show_xpbar_messages=顯示經驗條上方的訊息,如果被此類訊息刷屏請禁用此選項。
config.Main.Advanced.show_chat_links=解碼聊天資訊裡的連結,並在控制檯單獨顯示。
config.Main.Advanced.show_inventory_layout=以字元畫形式顯示庫存佈局。
config.Main.Advanced.terrain_and_movements=開啟地形處理將消耗更多的記憶體、CPU和網路頻寬但這允許你進行移動以及和方塊互動。
config.Main.Advanced.inventory_handling=啟用庫存處理(可操作揹包、箱子等容器)。
config.Main.Advanced.entity_handling=啟用實體處理。
config.Main.Advanced.session_cache=如何快取會話令牌。可使用 "none"(不快取)"memory"(記憶體快取) 或 "disk"(磁碟快取)。
config.Main.Advanced.profilekey_cache=如何快取聊天簽名金鑰。可使用 "none"(不快取)"memory"(記憶體快取) 或 "disk"(磁碟快取)。
config.Main.Advanced.resolve_srv_records=可填寫 "no""fast"(超時時間為五秒鐘)或是 "yes"。加入某些伺服器需要開啟此項。
config.Main.Advanced.account_list=AccountList使你可以不用輸入賬號資訊而快速在多個賬號間切換\n# 可用命令示例:"/tell <mybot> reco Player2""/connect <serverip> Player1"
config.Main.Advanced.server_list=ServerList可用使用伺服器別名快速連線到該伺服器\n# 別名不能包含空格和小數點",而且 "localhost" 不能作為別名使用。\n# 可用命令示例:"/tell <mybot> connect Server1""/connect Server2"
config.Main.Advanced.player_head_icon=使用玩家面板頭像作為視窗圖示,這僅在部分舊版控制檯中有效。
config.Main.Advanced.exit_on_failure=發生錯誤時是否直接退出用於在非互動式指令碼中使用MCC。
config.Main.Advanced.script_cache=快取已編譯的指令碼,以便在低端裝置上更快的載入。
config.Main.Advanced.timestamps=在聊天資訊頭部新增時間戳。
config.Main.Advanced.auto_respawn=死亡時自動重生(開啟前請確保你的出生點是安全的)
config.Main.Advanced.minecraft_realms=啟用對加入我的世界領域(Realms)伺服器的支援。
config.Main.Advanced.move_head_while_walking=在移動時轉向頭部。
config.Main.Advanced.timeout=與伺服器的TCP連線超時時間
config.Main.Advanced.enable_emoji=如果關閉Emoji表情符號將被替換成更簡單的字元用於 "/chunk status" 命令)
config.Main.Advanced.movement_speed=高於 2 的移動速度可能會被檢測為作弊。
config.Main.Advanced.language.invaild=無效的語言程式碼!
# Signature
config.Signature=聊天簽名相關設定影響1.19及以上版本)
config.Signature.LoginWithSecureProfile=僅微軟賬戶可用。如禁用此項,將無法簽名訊息和進入某些的伺服器。
config.Signature.SignChat=是否簽名傳送的聊天訊息。
config.Signature.SignMessageInCommand=是否簽名指令中的訊息。例如"/msg"和"/me"中的訊息。
config.Signature.MarkLegallySignedMsg=是否使用綠色色塊標識擁有合法簽名的聊天。
config.Signature.MarkModifiedMsg=是否使用黃色色塊標識被伺服器更改過的聊天。
config.Signature.MarkIllegallySignedMsg=是否使用紅色色塊標識沒有合法簽名的聊天。
config.Signature.MarkSystemMessage=是否使用灰色色塊標識系統訊息(它們總是不會被簽名)。
config.Signature.ShowModifiedChat=設定為 true顯示被伺服器修改過的資訊設定為 false顯示經過簽名的原始資訊。
config.Signature.ShowIllegalSignedChat=是否顯示沒有被正確簽名的聊天訊息。
# Logging
config.Logging=此項設定僅會影響到控制檯中的資訊(日誌)。
config.Logging.DebugMessages=請在提交錯誤報告之前先啟用此項。謝謝!
config.Logging.ChatMessages=是否顯示來自伺服器的聊天訊息。
config.Logging.InfoMessages=資訊性的訊息。大部分來自MCC內部
config.Logging.WarningMessages=顯示警告訊息。
config.Logging.ErrorMessages=顯示錯誤訊息。
config.Logging.ChatFilter=過濾聊天訊息所用的正規表示式。
config.Logging.DebugFilter=過濾除錯訊息所用的正規表示式。
config.Logging.FilterMode=過濾方式:"disable"(禁用),"blacklist"(隱藏匹配的訊息) 或 "whitelist"(僅顯示匹配的訊息)
config.Logging.LogToFile=是否將日誌資訊寫入到檔案。
config.Logging.LogFile=日誌檔名稱。
config.Logging.PrependTimestamp=寫入日誌檔案時是否新增時間戳。
config.Logging.SaveColorCodes=是否保留訊息中的顏色字元。(例如"§b"
# AppVars
config.AppVars.Variables=可以在某些欄位中以"%yourvar%"的形式使用。\n# %username% 和 %serverip% 時保留的變數名。
# Proxy
config.Proxy=通過代理連線到伺服器。\n# 如果Mojang/微軟登入服務被防火牆阻斷設定Enabled_Login=true以使用代理進行登入。\n# 如果到Minecraft遊戲伺服器的連線被防火牆阻止設定Enabled_Ingame=true以使用代理連線遊戲伺服器。\n# /!\ 在啟用代理前請確保你的伺服器規則允許使用代理或VPN否則你可能面臨被封禁等風險
config.Proxy.Enabled_Login=是否使用代理連線Mojang或微軟的登入伺服器。
config.Proxy.Enabled_Ingame=是否通過代理連線Minecraft遊戲伺服器。
config.Proxy.Server=代理伺服器必須允許HTTPS登入。
config.Proxy.Proxy_Type=支援的代理型別:"HTTP""SOCKS4""SOCKS4a""SOCKS5"。
config.Proxy.Username=只有連線到受密碼保護的代理才需要。
config.Proxy.Password=只有連線到受密碼保護的代理才需要。
# ChatFormat
config.ChatFormat=MCC會盡力檢測聊天資訊但有些伺服器有不尋常的聊天格式\n# 當這種情況發生時,你需要在下面自定義匹配聊天所用的正規表示式,詳見 https://mccteam.github.io/guide/configuration.html#chat-format
config.ChatFormat.Builtins=是否啟用MCC內建的聊天檢測規則。設定為 false 以避免與自定義格式衝突。
config.ChatFormat.UserDefined=是否啟用下方的自定義正規表示式進行聊天檢測。
# MCSettings
config.MCSettings=下面的設定將會被髮送到遊戲伺服器,隻影響一些伺服器端的東西,比如你的面板。
config.MCSettings.Enabled=如果禁用,下面的設定就不會被髮送到伺服器上。
config.MCSettings.Locale=請使用Minecraft的語言程式碼填寫詳見[Main.Advanced.Language]
config.MCSettings.RenderDistance=渲染距離,取值範圍[0 - 255]。
config.MCSettings.Difficulty=Minecraft 1.7及更早版本難度。"peaceful""easy""normal""difficult"。
config.MCSettings.ChatMode=使用 "enabled"(完全啟用聊天)、"commands"(僅限命令)或 "disabled"(完全禁用聊天)。這允許你禁言自己...
config.MCSettings.ChatColors=這允許你在伺服器端禁用聊天顏色。
config.MCSettings.MainHand=在1.9及更高版本中的主手設定。"left"(左手) 或 "right"(右手)。
# ChatBot
config.ChatBot================================ #\n# Minecraft Console Client Bots #\n# =============================== #
# ChatBot.Alerts
config.ChatBot.Alerts=當檢測到特定聊天訊息或特定事件發生時提醒你\n # 對檢測特定玩家的聊天訊息很有用。
config.ChatBot.Alerts.Beep_Enabled=除了高亮顯示外,當檢測到一個詞時還會播放類似蜂鳴器的嗶嗶聲。
config.ChatBot.Alerts.Trigger_By_Words=在收到指定的關鍵詞後觸發提醒。
config.ChatBot.Alerts.Trigger_By_Rain=在開始下雨和停止下雨時觸發提醒。
config.ChatBot.Alerts.Trigger_By_Thunderstorm=在雷暴天氣的開始與結束觸發提醒。
config.ChatBot.Alerts.Matches=觸發提醒的聊天關鍵詞列表。
config.ChatBot.Alerts.Excludes=出現這些關鍵詞後該條訊息一定不觸發提醒。
config.ChatBot.Alerts.Log_To_File=是否將提醒訊息寫入到日誌檔案。
config.ChatBot.Alerts.Log_File=日誌檔案的路徑。
# ChatBot.AntiAFK
config.ChatBot.AntiAfk=定期傳送命令,或讓機器人隨機走動,以避免檢測到掛機後被踢出伺服器\n # /!\啟用前請確保你的伺服器規則不禁止反AFK機制\n# /!\如果啟用隨機移動請將機器人圍在圍欄裡以防走失建議尺寸5x5x5
config.ChatBot.AntiAfk.Delay=執行操作的間隔時間。(秒)
config.ChatBot.AntiAfk.Command=傳送給伺服器的指令。
config.ChatBot.AntiAfk.Use_Sneak=在傳送指令時是否蹲下。
config.ChatBot.AntiAfk.Use_Terrain_Handling=啟用地形處理,以使機器人能夠四處移動。
config.ChatBot.AntiAfk.Walk_Range=機器人可以隨機移動的範圍(注意:範圍越大,速度越慢)
config.ChatBot.AntiAfk.Walk_Retries=嘗試移動失敗幾次後在改為傳送命令模式。
# ChatBot.AutoAttack
config.ChatBot.AutoAttack=自動攻擊周圍的生物\n# 使用此功能之前,你需要開啟實體處理。\n# /!\確保你的伺服器允許使用自動攻擊。\n# /!\伺服器外掛可能會認為此功能時作弊,並可能會封禁你的賬號,所以請自己檢查伺服器規則是否允許。
config.ChatBot.AutoAttack.Mode="single"(單目標) 或 "multi"(多目標)。一次攻擊一個生物還是範圍內的所有生物。
config.ChatBot.AutoAttack.Priority="health"(生命值)或 "distance"(距離)。當使用"single"模式時,以哪一個屬性確定優先順序。
config.ChatBot.AutoAttack.Cooldown_Time=每次攻擊間的冷卻時間,設定 "Custom = false" 以讓MCC自動計算攻擊速度。
config.ChatBot.AutoAttack.Interaction=可選項:"Interact"(互動),"Attack"(攻擊) 或 "InteractAt"(互動並攻擊)
config.ChatBot.AutoAttack.Attack_Hostile=是否攻擊敵對生物。
config.ChatBot.AutoAttack.Attack_Passive=是否攻擊被動生物。
config.ChatBot.AutoAttack.List_Mode=將實體列表作為 "whitelist"(白名單)還是 "blacklist"(黑名單)。
config.ChatBot.AutoAttack.Entites_List=所有可用的實體型別可以在這裏找到https://bit.ly/3Rg68lp
# ChatBot.AutoCraft
config.ChatBot.AutoCraft=自動使用揹包中的物品進行合成。\n# 請看 https://mccteam.github.io/guide/chat-bots.html#auto-craft\n# 你需要啟用庫存處理來使用這個功能\n# 如果需要使用工作臺,你還需要啟用地形處理。
config.ChatBot.AutoCraft.CraftingTable=如果你打算使用工作臺,請填寫它所在的位置。(需要啟用地形處理)
config.ChatBot.AutoCraft.OnFailure=合成失敗時應該怎麼處理,"abort"(中止)或 "wait"(等待)。
config.ChatBot.AutoCraft.Recipes=Recipes.Name給該配方起一個獨一無二的名字。不能包含空白字元Recipes.Type合成型別"player"揹包2x2或 "table"工作臺3x3\n# Recipes.Result合成的目標物品\n# Recipes.Slots合成的物品擺放方式以從左到右、從上到下的格式填寫。需留空請填寫"Null"。\n# 最新的物品命名請看https://github.com/MCCTeam/Minecraft-Console-Client/blob/master/MinecraftClient/Inventory/ItemType.cs
# AutoDig
config.ChatBot.AutoDig=自動挖掘方塊。\n# 你可以使用 "/digbot start" 和 "/digbot stop" 指令來控制 AutoDig 的啟停。\n# 由於MCC目前還不支援精確計算方塊的碰撞體積在獲取看向的方塊時視線上所有的方塊都被看作是完整的立方體。\n# 查詢方塊的名字,請訪問 https://github.com/MCCTeam/Minecraft-Console-Client/blob/master/MinecraftClient/Mapping/Material.cs
config.ChatBot.AutoDig.Auto_Tool_Switch=自動切換到合適的工具。
config.ChatBot.AutoDig.Durability_Limit=不會使用低於此耐久度的工具。(需要啟用庫存處理)
config.ChatBot.AutoDig.Drop_Low_Durability_Tools=在當前使用的工具耐久度過低後,是否丟掉它。
config.ChatBot.AutoDig.Mode="lookat""fixedpos" 或 "both"。挖掘看向的方塊還是固定位置的方塊,或者是兩個條件都滿足的方塊。
config.ChatBot.AutoDig.Locations=使用 "fixedpos" 或 "both" 模式時,方塊的座標。
config.ChatBot.AutoDig.Location_Order="distance" 或 "index",當使用 "fixedpos" 模式時,按照到玩家的距離,還是列表中的順序確定挖掘的方塊。
config.ChatBot.AutoDig.Auto_Start_Delay=進入遊戲後等待多少秒後開始自動挖掘,設定為-1禁用自動開始。
config.ChatBot.AutoDig.Dig_Timeout=若挖掘一個方塊用時超過這個值,將會重新獲取目標進行挖掘。
config.ChatBot.AutoDig.Log_Block_Dig=是否輸出挖掘方塊的相關資訊。
config.ChatBot.AutoDig.List_Type=將方塊列表作為 "whitelist"(白名單)還是 "blacklist"(黑名單)。
# ChatBot.AutoDrop
config.ChatBot.AutoDrop=自動從揹包/庫存中丟棄指定的物品\n# 你需要啟用庫存處理來使用這個功能。\n# 可用物品請看 https://github.com/MCCTeam/Minecraft-Console-Client/blob/master/MinecraftClient/Inventory/ItemType.cs
config.ChatBot.AutoDrop.Mode="include"(丟棄列表中的物品),"exclude"(丟棄列表外的所有物品) 或 "everything"(丟棄所有物品)
# ChatBot.AutoEat
config.ChatBot.AutoEat=在飽食度較低是自動在揹包中尋找食物食用。\n# 你需要啟用庫存處理來使用這個功能。
# ChatBot.AutoFishing
config.ChatBot.AutoFishing=使用魚竿自動釣魚。指南https://mccteam.github.io/guide/chat-bots.html#auto-fishingn# /!\ 啟用前請確保伺服器允許自動釣魚。
config.ChatBot.AutoFishing.Antidespawn=如果你之前沒有啟用過這個選項,請保持它為 false 。
config.ChatBot.AutoFishing.Mainhand=使用主手還是副手拿魚竿。
config.ChatBot.AutoFishing.Auto_Start=是否在進入伺服器後自動開始釣魚,禁用此功能後,你需要使用"/usehand"手動使用魚竿一次。
config.ChatBot.AutoFishing.Cast_Delay=釣到魚後多久開始下一次釣魚(拋竿)。
config.ChatBot.AutoFishing.Fishing_Delay=進入伺服器後多久後開始自動釣魚。(秒)
config.ChatBot.AutoFishing.Fishing_Timeout=多少秒後沒有釣到魚視為超時。超時後會重新拋竿。
config.ChatBot.AutoFishing.Durability_Limit=不會使用低於此耐久度的魚竿魚竿耐久度最高為64需要啟用庫存處理
config.ChatBot.AutoFishing.Auto_Rod_Switch=在當前魚竿不可用後自動切換到揹包中的其他魚竿。(需要啟用庫存處理)
config.ChatBot.AutoFishing.Stationary_Threshold=魚鉤在X軸和Z軸方向上的移動小於這個值將被認為是靜止的過高的閾值會在拋竿途中觸發收竿。
config.ChatBot.AutoFishing.Hook_Threshold=一個「靜止」的魚鉤在Y軸方向上的移動超過這個閾值將被認為釣到了魚。
config.ChatBot.AutoFishing.Log_Fish_Bobber=用於調整以上兩個閾值,啟用後會在收到魚鉤實體移動資料包後列印其座標變化。
config.ChatBot.AutoFishing.Enable_Move=這允許玩家在釣到魚後改變其位置或朝向。(需要啟用地形處理)
config.ChatBot.AutoFishing.Movements=會按照 "1->2->3->4->3->2->1->2->..." 的順序執行。每次可用改變位置、朝向或是都改變。推薦只改變朝向。
# ChatBot.AutoRelog
config.ChatBot.AutoRelog=在被伺服器斷開連線時自動重連,例如伺服器重啟時。\n# /!\ 謹慎使用Ignore_Kick_Message=true這會在伺服器管理員將你踢出時依然連回
config.ChatBot.AutoRelog.Delay=重新加入到伺服器前的延遲時間。(單位:秒)
config.ChatBot.AutoRelog.Retries=重新登入伺服器失敗時的重試次數,使用-1表示無限重試。
config.ChatBot.AutoRelog.Ignore_Kick_Message=當設定為 true 時,將不考慮踢出的資訊直接重連。
config.ChatBot.AutoRelog.Kick_Messages=如果踢出資訊與這其中的任何一個字串匹配,那麼將觸發自動重連。
# ChatBot.AutoRespond
config.ChatBot.AutoRespond=當聊天訊息與檔案中的規則匹配時,自動執行指定命令。\n# /!\ 伺服器管理員可以以任意玩家的身份傳送任意訊息,記住這一點!\n# 此機器人如果設定的不得當可能會造成刷屏,建議設定一個冷卻時間。
config.ChatBot.AutoRespond.Match_Colors=不要刪除文字中的顏色程式碼(使用§字元的程式碼)。注意:啟用後你的匹配模板也必須包括顏色程式碼。
# ChatBot.ChatLog
config.ChatBot.ChatLog=將聊天資訊寫入到日誌檔案中。
# ChatBot.FollowPlayer
config.ChatBot.FollowPlayer=讓機器人跟隨指定玩家\n# 注意這是一個實驗性的功能,目前的尋路速度可能很慢,你可能需要時常等一會機器人來讓它跟上你。\n# 你可以調整"Update_Limit"找到最適合你的速度。注意不要設定的太低這樣可能導致反效果或使MCC卡頓。\n# /!\ 在使用此功能之前,請先確保伺服器規則允許你這樣做。
config.ChatBot.FollowPlayer.Update_Limit=機器人尋路的間隔時間(以秒為單位)
config.ChatBot.FollowPlayer.Stop_At_Distance=如果玩家在該範圍內,則視為已經接近玩家了。(防止機器人將玩家推開而產生無限迴圈)
# ChatBot.HangmanGame
config.ChatBot.HangmanGame=一個用於演示聊天互動的小遊戲。玩家可以一次一個字母地猜出神祕的單詞。\n# 你需要正確地使用 ChatFormat並在 botowners 中新增自己,用/tell <bot username> start\n# /!\ 這個機器人可能會造成刷屏,如果許多玩家與它互動。
# ChatBot.Mailer
config.ChatBot.Mailer=在玩家和伺服器之間中繼訊息,就像一個郵件外掛一樣。\n# 這個機器人可以在收件人離線時儲存訊息,並在他們加入伺服器時傳送訊息。\n# /!\ 伺服器管理員可以以任意玩家的身份傳送任意訊息,請記住這一點。
# ChatBot.Map
config.ChatBot.Map=允許你將地圖渲染成.jpg圖片該圖片會被渲染到Rendered_Maps資料夾中。\n# 注意:這個功能目前只對解決使用地圖的驗證碼有用。\n# 如果一些伺服器解決驗證碼的時間很短請啟用Auto_Render_On_Update並準備快速開啟該檔案。\n# 在linux上你可以使用FTP來訪問生成的檔案。
config.ChatBot.Map.Should_Resize=是否需要調整地圖的大小?(預設大小是128x128)
config.ChatBot.Map.Resize_To=將地圖調整到什麼大小?(注意:大小越大,質量越低)
config.ChatBot.Map.Auto_Render_On_Update=一旦接收到新的地圖或已有地圖被更新,自動渲染該地圖。
config.ChatBot.Map.Delete_All_On_Unload=在解除安裝/重新載入地圖時刪除所有已渲染的地圖退出MCC時不會刪除影象
config.ChatBot.Map.Notify_On_First_Update=當第一次從伺服器上收到一張地圖時,傳送一個通知。
# ChatBot.PlayerListLogger
config.ChatBot.PlayerListLogger=定期記錄當前的玩家列表到檔案中。
config.ChatBot.PlayerListLogger.Delay=(單位:秒)
# ChatBot.RemoteControl
config.ChatBot.RemoteControl=通過遊戲中的私聊向機器人傳送MCC控制檯命令\n# 你需要先配置好[ChatFormat]章節的設定,並在[Main.Advanced.bot_owners]中新增自己的賬號。\n# /!\ 伺服器管理員可以以任意玩家的身份傳送任意訊息,僅在信任他們時啟用本功能。
# ChatBot.ReplayCapture
config.ChatBot.ReplayCapture=使用"/replay start"開始記錄遊戲,並在之後使用 Replay Mod (https://www.replaymod.com/) 進行重放。\n# 請注意,由於技術限制,玩家自身不會顯示在重放檔案中。\n# /!\ 你應該使用"/replay stop"停止記錄或者使用"/quit"退出程式,否則回放檔案可能會損壞。
config.ChatBot.ReplayCapture.Backup_Interval=每間隔多少秒自動儲存一次回放檔案,以秒為單位。使用-1禁用自動儲存。
# ChatBot.ScriptScheduler
config.ChatBot.ScriptScheduler=在加入伺服器時、到達特定時間時或以設定的時間間隔執行命令或指令碼檔案\n# 詳細使用方法請檢視 https://mccteam.github.io/guide/chat-bots.html#script-scheduler

View file

@ -5,6 +5,7 @@ using System.IO;
using System.Linq;
using System.Text;
using DynamicRun.Builder;
using static MinecraftClient.Settings;
namespace MinecraftClient
{
@ -43,7 +44,7 @@ namespace MinecraftClient
lock (CompileCache)
{
///Process and compile script only if not already compiled
if (!Settings.CacheScripts || !CompileCache.ContainsKey(scriptHash))
if (!Config.Main.Advanced.CacheScript || !CompileCache.ContainsKey(scriptHash))
{
//Process different sections of the script file
bool scriptMain = true;
@ -111,10 +112,10 @@ namespace MinecraftClient
//Retrieve compiled assembly
assembly = result.Assembly;
if (Settings.CacheScripts)
if (Config.Main.Advanced.CacheScript)
CompileCache[scriptHash] = assembly!;
}
else if (Settings.CacheScripts)
else if (Config.Main.Advanced.CacheScript)
assembly = CompileCache[scriptHash];
}
@ -293,7 +294,7 @@ namespace MinecraftClient
if (localVars != null && localVars.ContainsKey(varName))
return localVars[varName];
else
return Settings.GetVar(varName);
return Settings.Config.AppVar.GetVar(varName);
}
/// <summary>
@ -305,7 +306,7 @@ namespace MinecraftClient
{
if (localVars != null && localVars.ContainsKey(varName))
localVars.Remove(varName);
return Settings.SetVar(varName, varValue);
return Settings.Config.AppVar.SetVar(varName, varValue);
}
/// <summary>
@ -347,7 +348,7 @@ namespace MinecraftClient
/// <returns>True if the account was found and loaded</returns>
public bool SetAccount(string accountAlias, bool andReconnect = false)
{
bool result = Settings.SetAccount(accountAlias);
bool result = Settings.Config.Main.Advanced.SetAccount(accountAlias);
if (result && andReconnect)
ReconnectToTheServer();
return result;
@ -360,7 +361,7 @@ namespace MinecraftClient
/// <returns>True if the server IP was valid and loaded, false otherwise</returns>
public bool SetServer(string server, bool andReconnect = false)
{
bool result = Settings.SetServerIP(server);
bool result = Settings.Config.Main.SetServerIP(new MainConfigHealper.MainConfig.ServerInfoConfig(server), true);
if (result && andReconnect)
ReconnectToTheServer();
return result;

View file

@ -6,6 +6,7 @@ using System.Text;
using System.Text.RegularExpressions;
using MinecraftClient.Inventory;
using MinecraftClient.Mapping;
using static MinecraftClient.Settings;
namespace MinecraftClient
{
@ -425,6 +426,14 @@ namespace MinecraftClient
/// <param name="level"></param>
public virtual void OnThunderLevelChange(float level) { }
/// <summary>
/// Called when a block is changed.
/// </summary>
/// <param name="location">The location of the block.</param>
/// <param name="block">The block</param>
public virtual void OnBlockChange(Location location, Block block) { }
/* =================================================================== */
/* ToolBox - Methods below might be useful while creating your bot. */
/* You should not need to interact with other classes of the program. */
@ -521,9 +530,9 @@ namespace MinecraftClient
text = GetVerbatim(text);
//User-defined regex for private chat messages
if (Settings.ChatFormat_Private != null)
if (Config.ChatFormat.UserDefined && !string.IsNullOrWhiteSpace(Config.ChatFormat.Private))
{
Match regexMatch = Settings.ChatFormat_Private.Match(text);
Match regexMatch = new Regex(Config.ChatFormat.Private).Match(text);
if (regexMatch.Success && regexMatch.Groups.Count >= 3)
{
sender = regexMatch.Groups[1].Value;
@ -533,7 +542,7 @@ namespace MinecraftClient
}
//Built-in detection routine for private messages
if (Settings.ChatFormat_Builtins)
if (Config.ChatFormat.Builtins)
{
string[] tmp = text.Split(' ');
try
@ -632,9 +641,9 @@ namespace MinecraftClient
text = GetVerbatim(text);
//User-defined regex for public chat messages
if (Settings.ChatFormat_Public != null)
if (Config.ChatFormat.UserDefined && !string.IsNullOrWhiteSpace(Config.ChatFormat.Public))
{
Match regexMatch = Settings.ChatFormat_Public.Match(text);
Match regexMatch = new Regex(Config.ChatFormat.Public).Match(text);
if (regexMatch.Success && regexMatch.Groups.Count >= 3)
{
sender = regexMatch.Groups[1].Value;
@ -644,7 +653,7 @@ namespace MinecraftClient
}
//Built-in detection routine for public messages
if (Settings.ChatFormat_Builtins)
if (Config.ChatFormat.Builtins)
{
string[] tmp = text.Split(' ');
@ -735,9 +744,9 @@ namespace MinecraftClient
text = GetVerbatim(text);
//User-defined regex for teleport requests
if (Settings.ChatFormat_TeleportRequest != null)
if (Config.ChatFormat.UserDefined && !string.IsNullOrWhiteSpace(Config.ChatFormat.TeleportRequest))
{
Match regexMatch = Settings.ChatFormat_TeleportRequest.Match(text);
Match regexMatch = new Regex(Config.ChatFormat.TeleportRequest).Match(text);
if (regexMatch.Success && regexMatch.Groups.Count >= 2)
{
sender = regexMatch.Groups[1].Value;
@ -746,7 +755,7 @@ namespace MinecraftClient
}
//Built-in detection routine for teleport requests
if (Settings.ChatFormat_Builtins)
if (Config.ChatFormat.Builtins)
{
string[] tmp = text.Split(' ');
@ -786,7 +795,26 @@ namespace MinecraftClient
ConsoleIO.WriteLogLine(String.Format("[{0}] {1}", GetType().Name, text));
else
Handler.Log.Info(String.Format("[{0}] {1}", GetType().Name, text));
string logfile = Settings.ExpandVars(Settings.chatbotLogFile);
string logfile = Settings.Config.AppVar.ExpandVars(Config.Main.Advanced.ChatbotLogFile);
if (!String.IsNullOrEmpty(logfile))
{
if (!File.Exists(logfile))
{
try { Directory.CreateDirectory(Path.GetDirectoryName(logfile)!); }
catch { return; /* Invalid path or access denied */ }
try { File.WriteAllText(logfile, ""); }
catch { return; /* Invalid file name or access denied */ }
}
File.AppendAllLines(logfile, new string[] { GetTimestamp() + ' ' + text });
}
}
protected static void LogToConsole(string botName, object? text)
{
ConsoleIO.WriteLogLine(String.Format("[{0}] {1}", botName, text));
string logfile = Settings.Config.AppVar.ExpandVars(Config.Main.Advanced.ChatbotLogFile);
if (!String.IsNullOrEmpty(logfile))
{
@ -808,7 +836,7 @@ namespace MinecraftClient
/// <param name="text">Debug log text to write</param>
protected void LogDebugToConsole(object text)
{
if (Settings.DebugMessages)
if (Settings.Config.Logging.DebugMessages)
LogToConsole(text);
}
@ -840,7 +868,7 @@ namespace MinecraftClient
/// <param name="delaySeconds">Optional delay, in seconds, before restarting</param>
protected void ReconnectToTheServer(int ExtraAttempts = 3, int delaySeconds = 0)
{
if (Settings.DebugMessages)
if (Settings.Config.Logging.DebugMessages)
ConsoleIO.WriteLogLine(Translations.Get("chatbot.reconnect", GetType().Name));
McClient.ReconnectionAttemptsLeft = ExtraAttempts;
Program.Restart(delaySeconds);
@ -873,7 +901,7 @@ namespace MinecraftClient
/// <param name="message">Message</param>
protected void SendPrivateMessage(string player, string message)
{
SendText(String.Format("/{0} {1} {2}", Settings.PrivateMsgsCmdName, player, message));
SendText(String.Format("/{0} {1} {2}", Config.Main.Advanced.PrivateMsgsCmdName, player, message));
}
/// <summary>

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
@ -15,9 +14,8 @@ namespace MinecraftClient
/// </remarks>
public static class Translations
{
private static readonly Dictionary<string, string> translations;
private static Dictionary<string, string> translations;
private static readonly string translationFilePath = "lang" + Path.DirectorySeparatorChar + "mcc";
private static readonly string defaultTranslation = "en.ini";
private static readonly Regex translationKeyRegex = new(@"\(\[(.*?)\]\)", RegexOptions.Compiled); // Extract string inside ([ ])
/// <summary>
@ -52,6 +50,21 @@ namespace MinecraftClient
return msgName;
}
/// <summary>
/// Return a tranlation for the requested text. Support string formatting. If not found, return the original text
/// </summary>
/// <param name="msgName">text identifier</param>
/// <param name="args"></param>
/// <returns>Translated text or original text if not found</returns>
/// <remarks>Useful when not sure msgName is a translation mapping key or a normal text</remarks>
public static string? GetOrNull(string msgName, params object?[] args)
{
if (translations.ContainsKey(msgName))
return Get(msgName, args);
else
return null;
}
/// <summary>
/// Replace the translation key inside a sentence to translated text. Wrap the key in ([translation.key])
/// </summary>
@ -81,71 +94,541 @@ namespace MinecraftClient
/// </summary>
static Translations()
{
translations = new Dictionary<string, string>();
LoadDefaultTranslationsFile();
string[] engLang = DefaultConfigResource.Translation_en.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None); // use embedded translations
translations = ParseTranslationContent(engLang);
}
public static Tuple<string, string[]> GetTranslationPriority()
{
string gameLanguage = "en_gb";
List<string> name = new();
string systemLanguage = string.IsNullOrWhiteSpace(Program.ActualCulture.Name)
? Program.ActualCulture.Parent.Name
: Program.ActualCulture.Name;
switch (systemLanguage)
{
case "af":
case "af-ZA":
gameLanguage = "af_za";
break;
case "ar":
case "ar-AE":
case "ar-BH":
case "ar-DZ":
case "ar-EG":
case "ar-IQ":
case "ar-JO":
case "ar-KW":
case "ar-LB":
case "ar-LY":
case "ar-MA":
case "ar-OM":
case "ar-QA":
case "ar-SA":
case "ar-SY":
case "ar-TN":
case "ar-YE":
gameLanguage = "ar_sa";
break;
case "az":
case "az-Cyrl-AZ":
case "az-Latn-AZ":
gameLanguage = "az_az";
break;
case "be":
case "be-BY":
gameLanguage = "be_by";
break;
case "bg":
case "bg-BG":
gameLanguage = "bg_bg";
break;
case "bs-Latn-BA":
gameLanguage = "bs_ba";
break;
case "ca":
case "ca-ES":
gameLanguage = "ca_es";
break;
case "cs":
case "cs-CZ":
gameLanguage = "cs_cz";
break;
case "cy-GB":
gameLanguage = "cy_gb";
break;
case "da":
case "da-DK":
gameLanguage = "da_dk";
break;
case "de":
case "de-DE":
case "de-LI":
case "de-LU":
gameLanguage = "de_de";
name.Add("de");
break;
case "de-AT":
gameLanguage = "de_at";
name.Add("de");
break;
case "de-CH":
gameLanguage = "de_ch";
name.Add("de");
break;
case "dv":
case "dv-MV":
break;
case "el":
case "el-GR":
gameLanguage = "el_gr";
break;
case "en":
case "en-029":
case "en-BZ":
case "en-IE":
case "en-JM":
case "en-PH":
case "en-TT":
case "en-ZA":
case "en-ZW":
case "en-GB":
gameLanguage = "en_gb";
break;
case "en-AU":
gameLanguage = "en_au";
break;
case "en-CA":
gameLanguage = "en_ca";
break;
case "en-US":
gameLanguage = "en_us";
break;
case "en-NZ":
gameLanguage = "en_nz";
break;
case "es":
case "es-BO":
case "es-CO":
case "es-CR":
case "es-DO":
case "es-ES":
case "es-GT":
case "es-HN":
case "es-NI":
case "es-PA":
case "es-PE":
case "es-PR":
case "es-PY":
case "es-SV":
gameLanguage = "es_es";
break;
case "es-AR":
gameLanguage = "es_ar";
break;
case "es-CL":
gameLanguage = "es_cl";
break;
case "es-EC":
gameLanguage = "es_ec";
break;
case "es-MX":
gameLanguage = "es_mx";
break;
case "es-UY":
gameLanguage = "es_uy";
break;
case "es-VE":
gameLanguage = "es_ve";
break;
case "et":
case "et-EE":
gameLanguage = "et_ee";
break;
case "eu":
case "eu-ES":
gameLanguage = "eu_es";
break;
case "fa":
case "fa-IR":
gameLanguage = "fa_ir";
break;
case "fi":
case "fi-FI":
gameLanguage = "fi_fi";
break;
case "fo":
case "fo-FO":
gameLanguage = "fo_fo";
break;
case "fr":
case "fr-BE":
case "fr-FR":
case "fr-CH":
case "fr-LU":
case "fr-MC":
gameLanguage = "fr_fr";
name.Add("fr");
break;
case "fr-CA":
gameLanguage = "fr_ca";
name.Add("fr");
break;
case "gl":
case "gl-ES":
gameLanguage = "gl_es";
break;
case "gu":
case "gu-IN":
break;
case "he":
case "he-IL":
gameLanguage = "he_il";
break;
case "hi":
case "hi-IN":
gameLanguage = "hi_in";
break;
case "hr":
case "hr-BA":
case "hr-HR":
gameLanguage = "hr_hr";
break;
case "hu":
case "hu-HU":
gameLanguage = "hu_hu";
break;
case "hy":
case "hy-AM":
gameLanguage = "hy_am";
break;
case "id":
case "id-ID":
gameLanguage = "id_id";
break;
case "is":
case "is-IS":
gameLanguage = "is_is";
break;
case "it":
case "it-CH":
case "it-IT":
gameLanguage = "it_it";
break;
case "ja":
case "ja-JP":
gameLanguage = "ja_jp";
break;
case "ka":
case "ka-GE":
gameLanguage = "ka_ge";
break;
case "kk":
case "kk-KZ":
gameLanguage = "kk_kz";
break;
case "kn":
case "kn-IN":
gameLanguage = "kn_in";
break;
case "kok":
case "kok-IN":
break;
case "ko":
case "ko-KR":
gameLanguage = "ko_kr";
break;
case "ky":
case "ky-KG":
break;
case "lt":
case "lt-LT":
gameLanguage = "lt_lt";
break;
case "lv":
case "lv-LV":
gameLanguage = "lv_lv";
break;
case "mi-NZ":
break;
case "mk":
case "mk-MK":
gameLanguage = "mk_mk";
break;
case "mn":
case "mn-MN":
gameLanguage = "mn_mn";
break;
case "mr":
case "mr-IN":
break;
case "ms":
case "ms-BN":
case "ms-MY":
gameLanguage = "ms_my";
break;
case "mt-MT":
gameLanguage = "mt_mt";
break;
case "nb-NO":
break;
case "nl":
case "nl-NL":
gameLanguage = "nl_nl";
break;
case "nl-BE":
gameLanguage = "nl_be";
break;
case "nn-NO":
gameLanguage = "nn_no";
break;
case "no":
gameLanguage = "no_no";
break;
case "ns-ZA":
break;
case "pa":
case "pa-IN":
break;
case "pl":
case "pl-PL":
gameLanguage = "pl_pl";
break;
case "pt":
case "pt-PT":
gameLanguage = "pt_pt";
break;
case "pt-BR":
gameLanguage = "pt_br";
break;
case "quz-BO":
break;
case "quz-EC":
break;
case "quz-PE":
break;
case "ro":
case "ro-RO":
gameLanguage = "ro_ro";
break;
case "ru":
case "ru-RU":
gameLanguage = "ru_ru";
name.Add("ru");
break;
case "sa":
case "sa-IN":
break;
case "se-FI":
case "se-NO":
case "se-SE":
gameLanguage = "se_no";
break;
case "sk":
case "sk-SK":
gameLanguage = "sk_sk";
break;
case "sl":
case "sl-SI":
gameLanguage = "sl_si";
break;
case "sma-NO":
break;
case "sma-SE":
break;
case "smj-NO":
break;
case "smj-SE":
break;
case "smn-FI":
break;
case "sms-FI":
break;
case "sq":
case "sq-AL":
gameLanguage = "sq_al";
break;
case "sr":
case "sr-Cyrl-BA":
case "sr-Cyrl-CS":
case "sr-Latn-BA":
case "sr-Latn-CS":
gameLanguage = "sr_sp";
break;
case "sv":
case "sv-FI":
case "sv-SE":
gameLanguage = "sv_se";
break;
case "sw":
case "sw-KE":
break;
case "syr":
case "syr-SY":
break;
case "ta":
case "ta-IN":
gameLanguage = "ta_in";
break;
case "te":
case "te-IN":
break;
case "th":
case "th-TH":
gameLanguage = "th_th";
break;
case "tn-ZA":
break;
case "tr":
case "tr-TR":
gameLanguage = "tr_tr";
break;
case "tt":
case "tt-RU":
gameLanguage = "tt_ru";
break;
case "uk":
case "uk-UA":
gameLanguage = "uk_ua";
break;
case "ur":
case "ur-PK":
break;
case "uz":
case "uz-Cyrl-UZ":
case "uz-Latn-UZ":
break;
case "vi":
case "vi-VN":
gameLanguage = "vi_vn";
name.Add("vi");
break;
case "xh-ZA":
break;
case "zh-Hans": /* CurrentCulture.Parent.Name */
case "zh":
case "zh-CN":
case "zh-CHS":
case "zh-SG":
gameLanguage = "zh_cn";
name.Add("zh_Hans");
name.Add("zh_Hant");
break;
case "zh-Hant": /* CurrentCulture.Parent.Name */
case "zh-HK":
case "zh-CHT":
case "zh-MO":
gameLanguage = "zh_hk";
name.Add("zh_Hant");
name.Add("zh_Hans");
break;
case "zh-TW":
gameLanguage = "zh_tw";
name.Add("zh_Hant");
name.Add("zh_Hans");
break;
case "zu-ZA":
break;
}
name.Add("en");
return new(gameLanguage, name.ToArray());
}
public static string[] GetTranslationPriority(string gameLanguage)
{
List<string> name = new();
switch (gameLanguage)
{
case "de_at":
case "de_ch":
case "de_de":
name.Add("de");
break;
case "en_au":
case "en_ca":
case "en_gb":
case "en_nz":
case "en_pt":
case "en_ud":
case "en_us":
break;
case "fr_ca":
case "fr_fr":
name.Add("fr");
break;
case "ru_ru":
name.Add("ru");
break;
case "vi_vn":
name.Add("vi");
break;
case "zh_cn":
name.Add("zh_Hans");
name.Add("zh_Hant");
break;
case "zh_hk":
case "zh_tw":
name.Add("zh_Hant");
name.Add("zh_Hans");
break;
}
name.Add("en");
return name.ToArray();
}
/// <summary>
/// Load default translation file (English)
/// Load translation files
/// </summary>
/// <remarks>
/// This will be loaded during program start up.
/// </remarks>
private static void LoadDefaultTranslationsFile()
public static void LoadTranslationFile(string[] languageList)
{
string[] engLang = DefaultConfigResource.TranslationEnglish.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None); // use embedded translations
ParseTranslationContent(engLang);
}
translations = new();
/// <summary>
/// Load translation file depends on system language or by giving a file path. Default to English if translation file does not exist
/// </summary>
public static void LoadExternalTranslationFile(string language)
{
/*
* External translation files
* These files are loaded from the installation directory as:
* Lang/abc.ini, e.g. Lang/eng.ini which is the default language file
* Useful for adding new translations of fixing typos without recompiling
*/
// Try to convert Minecraft language file name to two letters language name
if (language == "zh_cn")
language = "zh-CHS";
else if (language == "zh_tw")
language = "zh-CHT";
else
language = language.Split('_')[0];
string systemLanguage = string.IsNullOrEmpty(CultureInfo.CurrentCulture.Parent.Name) // Parent.Name might be empty
? CultureInfo.CurrentCulture.Name
: CultureInfo.CurrentCulture.Parent.Name;
string baseDir = AppDomain.CurrentDomain.BaseDirectory;
string langDir = baseDir + ((baseDir.EndsWith(Path.DirectorySeparatorChar) ? String.Empty : Path.DirectorySeparatorChar) +
translationFilePath + Path.DirectorySeparatorChar);
string langFileSystemLanguage = langDir + systemLanguage + ".ini";
string langFileConfigLanguage = langDir + language + ".ini";
if (File.Exists(langFileConfigLanguage))
{// Language set in ini config
ParseTranslationContent(File.ReadAllLines(langFileConfigLanguage));
return;
}
else
foreach (string lang in languageList)
{
if (Settings.DebugMessages)
ConsoleIO.WriteLogLine("[Translations] No translation file found for " + language + ". (Looked '" + langFileConfigLanguage + "'");
}
bool fileLoaded = false;
string langFileName = string.Format("{0}{1}.ini", langDir, lang);
if (File.Exists(langFileSystemLanguage))
{// Fallback to system language
ParseTranslationContent(File.ReadAllLines(langFileSystemLanguage));
return;
}
else
{
if (Settings.DebugMessages)
ConsoleIO.WriteLogLine("[Translations] No translation file found for system language (" + systemLanguage + "). (Looked '" + langFileSystemLanguage + "'");
if (File.Exists(langFileName)) // Language set in ini config
{
fileLoaded = true;
Dictionary<string, string> trans = ParseTranslationContent(File.ReadAllLines(langFileName));
foreach ((string key, string value) in trans)
if (!string.IsNullOrWhiteSpace(value) && !translations.ContainsKey(key))
translations.Add(key, value);
}
string? resourseLangFile = DefaultConfigResource.ResourceManager.GetString("Translation_" + lang);
if (resourseLangFile != null)
{
fileLoaded = true;
Dictionary<string, string> trans = ParseTranslationContent(resourseLangFile.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None));
foreach ((string key, string value) in trans)
if (!string.IsNullOrWhiteSpace(value) && !translations.ContainsKey(key))
translations.Add(key, value);
}
if (!fileLoaded)
{
if (Settings.Config.Logging.DebugMessages)
ConsoleIO.WriteLogLine("[Translations] No translation file found for " + lang + ". (Looked '" + langFileName + "'");
}
}
}
@ -153,39 +636,77 @@ namespace MinecraftClient
/// Parse the given array to translation map
/// </summary>
/// <param name="content">Content of the translation file (in ini format)</param>
private static void ParseTranslationContent(string[] content)
private static Dictionary<string, string> ParseTranslationContent(string[] content)
{
Dictionary<string, string> translations = new();
foreach (string lineRaw in content)
{
string line = lineRaw.Trim();
if (line.Length <= 0)
if (line.Length < 3)
continue;
if (line.StartsWith("#")) // ignore comment line started with #
continue;
if (line[0] == '[' && line[^1] == ']') // ignore section
if (!char.IsLetterOrDigit(line[0])) // ignore comment line started with #
continue;
string translationName = line.Split('=')[0];
if (line.Length > (translationName.Length + 1))
{
string translationValue = line[(translationName.Length + 1)..].Replace("\\n", "\n");
translations[translationName] = translationValue;
}
int index = line.IndexOf('=');
if (index != -1 && line.Length > (index + 1))
translations[line[..index]] = line[(index + 1)..].Replace("\\n", "\n");
}
return translations;
}
/// <summary>
/// Write the default translation file (English) to the disk.
/// </summary>
private static void WriteDefaultTranslation()
public static void TrimAllTranslations()
{
string defaultPath = AppDomain.CurrentDomain.BaseDirectory + Path.DirectorySeparatorChar + translationFilePath + Path.DirectorySeparatorChar + defaultTranslation;
string[] transEn = DefaultConfigResource.ResourceManager.GetString("Translation_en")!
.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None);
if (!Directory.Exists(translationFilePath))
foreach (string lang in new string[] { "de", "fr", "ru", "vi", "zh_Hans", "zh_Hant" })
{
Directory.CreateDirectory(translationFilePath);
Dictionary<string, string> trans = ParseTranslationContent(
DefaultConfigResource.ResourceManager.GetString("Translation_" + lang)!
.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None)
);
string fileName = AppDomain.CurrentDomain.BaseDirectory + Path.DirectorySeparatorChar + translationFilePath + Path.DirectorySeparatorChar + lang + ".ini";
if (File.Exists(fileName))
{
string backupFilePath = Path.ChangeExtension(fileName, ".backup.ini");
try { File.Copy(fileName, backupFilePath, true); }
catch (Exception ex)
{
ConsoleIO.WriteLineFormatted(Translations.TryGet("config.backup.fail", backupFilePath));
ConsoleIO.WriteLine(ex.Message);
return;
}
}
using FileStream file = File.OpenWrite(fileName);
int total = 0, translated = 0;
for (int i = 0; i < transEn.Length; ++i)
{
string line = transEn[i].Trim();
int index = transEn[i].IndexOf('=');
if (line.Length < 3 || !char.IsLetterOrDigit(line[0]) || index == -1 || line.Length <= (index + 1))
{
file.Write(Encoding.UTF8.GetBytes(line));
}
else
{
string key = line[..index];
file.Write(Encoding.UTF8.GetBytes(key));
file.Write(Encoding.UTF8.GetBytes("="));
if (trans.TryGetValue(key, out string? value))
{
file.Write(Encoding.UTF8.GetBytes(value.Replace("\n", "\\n")));
++total;
++translated;
}
else
{
++total;
}
}
file.Write(Encoding.UTF8.GetBytes(Environment.NewLine));
}
ConsoleIO.WriteLine(string.Format("Language {0}: Translated {1} of {2}, {3:0.00}%", lang, translated, total, 100.0 * (double)translated / total));
}
File.WriteAllText(defaultPath, DefaultConfigResource.TranslationEnglish, Encoding.UTF8);
}
#region Console writing method wrapper

View file

@ -3,6 +3,7 @@ using System.Drawing;
using System.IO;
using System.Net.Http;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Threading;
using System.Threading.Tasks;
@ -42,56 +43,55 @@ namespace MinecraftClient.WinAPI
/// <summary>
/// Asynchronously download the player's skin and set the head as console icon
/// </summary>
[SupportedOSPlatform("windows")]
public static void SetPlayerIconAsync(string playerName)
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
Thread t = new(new ThreadStart(delegate
{
Thread t = new(new ThreadStart(delegate
HttpClient httpClient = new();
try
{
HttpClient httpClient = new();
Task<Stream> httpWebRequest = httpClient.GetStreamAsync("https://minotar.net/helm/" + playerName + "/100.png");
httpWebRequest.Wait();
Stream imageStream = httpWebRequest.Result;
try
{
Task<Stream> httpWebRequest = httpClient.GetStreamAsync("https://minotar.net/helm/" + playerName + "/100.png");
httpWebRequest.Wait();
Stream imageStream = httpWebRequest.Result;
try
{
Bitmap skin = new(Image.FromStream(imageStream)); //Read skin from network
SetWindowIcon(Icon.FromHandle(skin.GetHicon())); // Windows 10+ (New console)
SetConsoleIcon(skin.GetHicon()); // Windows 8 and lower (Older console)
}
catch (ArgumentException)
{
/* Invalid image in HTTP response */
}
imageStream.Dispose();
httpWebRequest.Dispose();
Bitmap skin = new(Image.FromStream(imageStream)); //Read skin from network
SetWindowIcon(Icon.FromHandle(skin.GetHicon())); // Windows 10+ (New console)
SetConsoleIcon(skin.GetHicon()); // Windows 8 and lower (Older console)
}
catch (AggregateException ae)
catch (ArgumentException)
{
foreach (var ex in ae.InnerExceptions)
{
if (ex is HttpRequestException) //Skin not found? Reset to default icon
RevertToMCCIcon();
else
throw ex;
}
}
catch (HttpRequestException) //Skin not found? Reset to default icon
{
RevertToMCCIcon();
}
finally
{
httpClient.Dispose();
/* Invalid image in HTTP response */
}
imageStream.Dispose();
httpWebRequest.Dispose();
}
))
catch (AggregateException ae)
{
Name = "Player skin icon setter"
};
t.Start();
bool needRevert = false;
foreach (var ex in ae.InnerExceptions)
{
if (ex is HttpRequestException || ex is TaskCanceledException) //Skin not found? Reset to default icon
needRevert = true;
}
if (needRevert)
RevertToMCCIcon();
}
catch (HttpRequestException) //Skin not found? Reset to default icon
{
RevertToMCCIcon();
}
finally
{
httpClient.Dispose();
}
}
))
{
Name = "Player skin icon setter"
};
t.Start();
}
/// <summary>

View file

@ -79,9 +79,10 @@ namespace MinecraftClient.WinAPI
}
[DllImport("Kernel32")]
private static extern bool SetConsoleCtrlHandler(ConsoleCtrlHandler handler, bool add);
private delegate bool ConsoleCtrlHandler(CtrlType sig);
private static readonly ConsoleCtrlHandler? _handler;
private static extern bool SetConsoleCtrlHandler(EventHandler handler, bool add);
private delegate bool EventHandler(CtrlType sig);
static EventHandler? _handler;
enum CtrlType
{

View file

@ -1,102 +0,0 @@
using System.Globalization;
using System.Runtime.InteropServices;
using Microsoft.Win32;
namespace MinecraftClient.WinAPI
{
/// <summary>
/// Retrieve information about the current Windows version
/// </summary>
/// <remarks>
/// Environment.OSVersion does not work with Windows 10.
/// It returns 6.2 which is Windows 8
/// </remarks>
/// <seealso>
/// https://stackoverflow.com/a/37755503
/// </seealso>
class WindowsVersion
{
/// <summary>
/// Returns the Windows major version number for this computer.
/// </summary>
public static uint WinMajorVersion
{
get
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
// The 'CurrentMajorVersionNumber' string value in the CurrentVersion key is new for Windows 10,
// and will most likely (hopefully) be there for some time before MS decides to change this - again...
if (TryGetRegistryKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion", "CurrentMajorVersionNumber", out dynamic? major))
return (uint)major;
// When the 'CurrentMajorVersionNumber' value is not present we fallback to reading the previous key used for this: 'CurrentVersion'
if (!TryGetRegistryKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion", "CurrentVersion", out dynamic? version))
return 0;
var versionParts = ((string)version!).Split('.');
if (versionParts.Length != 2) return 0;
return uint.TryParse(versionParts[0], NumberStyles.Any, CultureInfo.CurrentCulture, out uint majorAsUInt) ? majorAsUInt : 0;
}
return 0;
}
}
/// <summary>
/// Returns the Windows minor version number for this computer.
/// </summary>
public static uint WinMinorVersion
{
get
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
// The 'CurrentMinorVersionNumber' string value in the CurrentVersion key is new for Windows 10,
// and will most likely (hopefully) be there for some time before MS decides to change this - again...
if (TryGetRegistryKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion", "CurrentMinorVersionNumber", out dynamic? minor))
return (uint)minor;
// When the 'CurrentMinorVersionNumber' value is not present we fallback to reading the previous key used for this: 'CurrentVersion'
if (!TryGetRegistryKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion", "CurrentVersion", out dynamic? version))
return 0;
var versionParts = ((string)version!).Split('.');
if (versionParts.Length != 2) return 0;
return uint.TryParse(versionParts[1], NumberStyles.Any, CultureInfo.CurrentCulture, out uint minorAsUInt) ? minorAsUInt : 0;
}
return 0;
}
}
/// <summary>
/// Try retrieving a registry key
/// </summary>
/// <param name="path">key path</param>
/// <param name="key">Key</param>
/// <param name="value">Value (output)</param>
/// <returns>TRUE if successfully retrieved</returns>
private static bool TryGetRegistryKey(string path, string key, out dynamic? value)
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
value = null;
try
{
var rk = Registry.LocalMachine.OpenSubKey(path);
if (rk == null) return false;
value = rk.GetValue(key);
return value != null;
}
catch
{
return false;
}
}
value = null;
return false;
}
}
}

View file

@ -1,8 +0,0 @@
myserver.com
Yourname>:
Player Yourname
Yourname joined
Yourname left
[Lockette] (Admin)
Yourname:
Yourname is

View file

@ -1,37 +0,0 @@
Yourname
whispers
-> me
admin
.com
.net
.fr
.us
.uk
!!!!
????
aaaa
zzzz
eeee
rrrr
tttt
yyyy
uuuu
iiii
oooo
pppp
qqqq
ssss
dddd
ffff
gggg
hhhh
jjjj
kkkk
llll
mmmm
wwww
xxxx
cccc
vvvv
bbbb
nnnn

View file

@ -1,4 +0,0 @@
Connection has been lost
Server is restarting
Server is full
Too Many people

View file

@ -1,14 +0,0 @@
# Minecraft Console Client
# Account list file
# Put account data as comma separated values
# Values are: Alias,Login,Password
# It allows a fast account switching
# without directly using the credentials
# Usage examples:
# /tell <mybot> reco Player2
# /connect <serverip> Player1
Player1,playerone@email.com,thepassword
Player2,TestBot,-

View file

@ -1,18 +0,0 @@
# Minecraft Console Client
# Server list file
# Put server data as comma separated values
# Values are: Alias,ServerIP:Port
# Aliases cannot contains dots or spaces
# The name "localhost" cannot be used as an alias
# It allows an easier and faster server switching
# with short aliases instead of full server IP
# It also adds a bit of privacy for remote control
# Usage examples:
# /tell <mybot> connect Server1
# /connect Server2
Server1,localhost
Server2,mc.awesomeserver.com:25567
Server3,192.168.1.27:1348 # Example of LAN server

View file

@ -1,52 +0,0 @@
# Minecraft Console Client
# ScriptScheduler Tasks
# Example config file
# Structure of a task: [Task] Followed by triggers and other settings.
# The example below contains all the possible fields for a task
# Time is HH:mm format, several different hours can be provided
# Action command can be "script" or any other internal command
[Task]
triggerOnFirstLogin=false
triggerOnLogin=false
triggerOnTime=true
triggerOnInterval=false
timeValue=19:30
timeValue=08:10
timeInterval=0
action=script event.txt
# Another minimal example: some properties may be omitted
# This is highly recommended for improving task readability
[Task]
triggerOnFirstLogin=true
action=script startup.txt
# Intervals can be random
# To define a random interval between 2 numbers, use <numer>-<number>, example: 1-100
[Task]
triggerOnInterval=true
timeInterval=1-15
action=send I am triggered!
# Of course, the tasks file can contain as much tasks as you want.
# Another example triggered on logging in and every night at midnight:
[Task]
triggerOnLogin=true
triggerOnTime=true
timeValue=00:00
action=log It's midnight!
# Example of task occuring every 30 seconds
# Could be used for jumping as antiAFK method
[Task]
triggerOnInterval=true
timeInterval=30
action=move up
# Enjoy!
# - ORelio

View file

@ -45,11 +45,15 @@
## 翻译 Minecraft 控制台客户端 (MCC) 🌍
如果你想将 Minecraft 控制台客户端 (MCC) 翻译成其他语言,请从 [lang 文件夹](https://github.com/MCCTeam/Minecraft-Console-Client/tree/master/MinecraftClient/Resources/lang)下载翻译文件或直接 fork 仓库。一旦你完成了翻译工作,请提交一个 Pull Request。如果你不熟悉 Git 的话,你也可以通过 [Issue](https://github.com/MCCTeam/Minecraft-Console-Client/issues) 将文件发送给我们
请查看:[如何为MCC添加或更新翻译](https://mccteam.github.io/guide/contibuting.html#translations)
要使用翻译后的语言文件,请将其放在 `lang/mcc/` 文件夹下,并在 `.ini` 配置文件中设置语言。如果该目录不存在,你可以创建它。
对于翻译文件的名称,请参阅[此评论](https://github.com/MCCTeam/Minecraft-Console-Client/pull/1282#issuecomment-711150715)。
MCC 现在支持这些语言(按字母顺序排列):
* `de.ini` : Deutsch - German
* `en.ini` : English - English
* `fr.ini` : Français (France) - French
* `ru.ini` : Русский (Russkiy) - Russian
* `vi.ini` : Tiếng Việt (Việt Nam) - Vietnamese
* `zh-Hans.ini` : 简体中文(中国大陆) - Chinese Simplified (China; Mandarin)
## 从源码构建 🏗️

View file

@ -6,6 +6,8 @@
[Documentation](https://mccteam.github.io/) | [Download](#download) | [Installation](https://mccteam.github.io/guide/installation.html) | [Configuration](https://mccteam.github.io/guide/configuration.html) | [Usage](https://mccteam.github.io/guide/usage.html)
[English](https://github.com/MCCTeam/Minecraft-Console-Client/blob/master/README.md) | [Nederlands](https://github.com/MCCTeam/Minecraft-Console-Client/blob/master/README-nl.md) | [Српски](https://github.com/MCCTeam/Minecraft-Console-Client/blob/master/README-sr.md) | [Türkçe](https://github.com/MCCTeam/Minecraft-Console-Client/blob/master/README-tr.md) | [Tiếng Việt](https://github.com/MCCTeam/Minecraft-Console-Client/blob/master/README-vi-vn.md) | [简体中文](https://github.com/MCCTeam/Minecraft-Console-Client/blob/master/README-zh-Hans.md)
[![GitHub Actions build status](https://github.com/MCCTeam/Minecraft-Console-Client/actions/workflows/build-and-release.yml/badge.svg)](https://github.com/MCCTeam/Minecraft-Console-Client/releases/latest) <a href="https://discord.gg/sfBv4TtpC9"><img src="https://img.shields.io/discord/1018553894831403028?color=5865F2&logo=discord&logoColor=white" alt="Discord server" /></a>
</div>
@ -45,11 +47,16 @@ If you'd like to contribute to Minecraft Console Client, great, just fork the re
## Translating Minecraft Console Client 🌍
If you would like to translate Minecraft Console Client to a different language, please download the translation file from [the lang folder](https://github.com/MCCTeam/Minecraft-Console-Client/tree/master/MinecraftClient/Resources/lang) or just fork the repository. Once you finished the translation work, submit a pull request or send us the file through an [Issue](https://github.com/MCCTeam/Minecraft-Console-Client/issues) in case you are not familiar with Git.
Check out: [How to update or add translations for MCC](https://mccteam.github.io/guide/contibuting.html#translations).
To use the translated language file, place it under `lang/mcc/` folder and set your language in `.ini` config. You may create the directory if it does not exist.
For the names of the translation file, please see [this comment](https://github.com/MCCTeam/Minecraft-Console-Client/pull/1282#issuecomment-711150715).
MCC now supports the following languages (Alphabetical order) :
* `de.ini` (57.12% translated) : Deutsch - German
* `en.ini` : English - English
* `fr.ini` (57.12% translated) : Français (France) - French
* `ru.ini` (56.18% translated) : Русский (Russkiy) - Russian
* `vi.ini` (56.18% translated) : Tiếng Việt (Việt Nam) - Vietnamese
* `zh-Hans.ini` (100.00% translated) : 简体中文 - Chinese Simplified
* `zh-Hant.ini` (100.00% translated) : 繁體中文 - Chinese Traditional
## Building from the source 🏗️