Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of PartyPlus English v1.0.0
PartyPlusEnglish.dll
Decompiled 4 days agousing System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using HarmonyLib; [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: AssemblyVersion("0.0.0.0")] namespace PartyPlusEnglish; [BepInPlugin("ridvan.partyplus.english", "PartyPlus English", "1.0.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { public const string Guid = "ridvan.partyplus.english"; public const string Version = "1.0.0"; private const string PartyPlusGuid = "com.yourname.partyplus"; private const string ModHubGuid = "kaefchik.modhub"; private static int _replaced; private void Awake() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown Harmony val = new Harmony("ridvan.partyplus.english"); HarmonyMethod val2 = new HarmonyMethod(typeof(Plugin).GetMethod("Transpiler", BindingFlags.Static | BindingFlags.NonPublic)); int num = 0; string[] array = new string[2] { "com.yourname.partyplus", "kaefchik.modhub" }; foreach (string text in array) { if (!Chainloader.PluginInfos.TryGetValue(text, out var value) || value.Instance == null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Plugin not found: " + text)); continue; } Assembly assembly = ((object)value.Instance).GetType().Assembly; foreach (MethodBase item in TargetMethods(assembly)) { try { MethodBase methodBase = item; HarmonyMethod val3 = val2; val.Patch(methodBase, (HarmonyMethod)null, (HarmonyMethod)null, val3, (HarmonyMethod)null, (HarmonyMethod)null); num++; } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)string.Concat("Could not patch ", item.DeclaringType, ".", item.Name, ": ", ex.Message)); } } TranslateConfigDescriptions(value.Instance.Config); } TranslateHubEntries(); ((BaseUnityPlugin)this).Logger.LogInfo((object)("PartyPlus English 1.0.0: patched " + num + " methods, " + _replaced + " strings.")); } private static IEnumerable<MethodBase> TargetMethods(Assembly asm) { Type[] types; try { types = asm.GetTypes(); } catch (ReflectionTypeLoadException ex) { types = ex.Types.Where((Type t) => t != null).ToArray(); } Type[] array = types; foreach (Type type in array) { if (type.IsGenericTypeDefinition) { continue; } bool isPlugin = typeof(BaseUnityPlugin).IsAssignableFrom(type); IEnumerable<MethodBase> methods = type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).Cast<MethodBase>().Concat(type.GetConstructors(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).Cast<MethodBase>()); foreach (MethodBase m in methods) { if (!m.IsAbstract && !m.ContainsGenericParameters && (!isPlugin || !(m.Name == "Awake")) && m.GetMethodBody() != null && ContainsTranslatable(m)) { yield return m; } } } } private static bool ContainsTranslatable(MethodBase m) { try { string text = default(string); foreach (CodeInstruction originalInstruction in PatchProcessor.GetOriginalInstructions(m, (ILGenerator)null)) { if (originalInstruction.opcode == OpCodes.Ldstr) { object obj = originalInstruction.operand as string; if (obj != null) { text = (string)obj; obj = text; } if (obj != null && Tr.Map.ContainsKey(text)) { return true; } } } } catch { } return false; } private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { List<CodeInstruction> list = new List<CodeInstruction>(instructions); foreach (CodeInstruction item in list) { string text = item.operand as string; if (item.opcode == OpCodes.Ldstr && text != null && Tr.Map.TryGetValue(text, out var value)) { item.operand = value; _replaced++; } } return list; } private void TranslateConfigDescriptions(ConfigFile cfg) { FieldInfo field = typeof(ConfigDescription).GetField("<Description>k__BackingField", BindingFlags.Instance | BindingFlags.NonPublic); if (field == null) { return; } bool flag = false; foreach (ConfigDefinition item in cfg.Keys.ToList()) { ConfigDescription description = cfg[item].Description; if (description != null && description.Description != null && Tr.Map.TryGetValue(description.Description, out var value)) { field.SetValue(description, value); flag = true; } } if (!flag) { return; } try { cfg.Save(); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Config save failed: " + ex.Message)); } } private void TranslateHubEntries() { try { if (!(Type.GetType("ModHub.ModHubAPI, ModHub")?.GetField("_entries", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(null) is IEnumerable enumerable)) { return; } string text = default(string); foreach (object item in enumerable) { string[] array = new string[2] { "Title", "Description" }; foreach (string name in array) { FieldInfo field = item.GetType().GetField(name); if (field != null) { object obj = field.GetValue(item) as string; if (obj != null) { text = (string)obj; obj = text; } if (obj != null && Tr.Map.TryGetValue(text, out var value)) { field.SetValue(item, value); } } } } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Hub entry translation failed: " + ex.Message)); } } } internal static class Tr { internal static readonly Dictionary<string, string> Map = new Dictionary<string, string> { { "{0} приглашает тебя в пати\n[{1}] принять [{2}] отклонить", "{0} invites you to the party\n[{1}] accept [{2}] decline" }, { "Слишком далеко для пинга (макс. {0:0} м)", "Too far to ping (max {0:0} m)" }, { "Сюда", "Here" }, { "Враг: ", "Enemy: " }, { "[PartyPlus] Загружено пати: {0}", "[PartyPlus] Parties loaded: {0}" }, { "[PartyPlus] Не удалось загрузить пати: ", "[PartyPlus] Failed to load parties: " }, { "[PartyPlus] Не удалось сохранить пати: ", "[PartyPlus] Failed to save parties: " }, { "Игрок «", "Player \"" }, { "» не в сети", "\" is offline" }, { " уже в пати", " is already in a party" }, { "Пати заполнено", "Party is full" }, { "Приглашение отправлено: ", "Invite sent: " }, { "Нет активных приглашений", "No active invites" }, { "Приглашение истекло", "Invite expired" }, { "перешёл в другое пати", "joined another party" }, { "Пати уже заполнено", "Party is already full" }, { " вступил в пати", " joined the party" }, { " отклонил приглашение", " declined the invite" }, { "вышел из пати", "left the party" }, { "Ты не в пати", "You are not in a party" }, { ". Пати распущено", ". Party disbanded" }, { "{0:0} м", "{0:0} m" }, { "Панель пати — тащи мышью", "Party panel — drag with mouse" }, { "не в сети", "offline" }, { ">мёртв</color>", ">dead</color>" }, { "</color> приглашает тебя в пати", "</color> invites you to the party" }, { "[{0}] принять [{1}] отклонить [{2}] меню", "[{0}] accept [{1}] decline [{2}] menu" }, { "[{0}] / Esc — закрыть · колесо мыши — прокрутка", "[{0}] / Esc — close · mouse wheel — scroll" }, { "Приглашение от <color=#", "Invite from <color=#" }, { "Принять", "Accept" }, { "Отклонить", "Decline" }, { "Твоё пати", "Your party" }, { "Ты не в пати. Пригласи кого-нибудь ниже.", "You are not in a party. Invite someone below." }, { ">(ты)</color>", ">(you)</color>" }, { ">не в сети</color>", ">offline</color>" }, { "Покинуть пати", "Leave party" }, { "Игроки на сервере", "Players on server" }, { "Пригласить", "Invite" }, { "Больше никого нет", "No one else here" }, { "Интерфейс", "Interface" }, { "Закрепить панель пати на месте", "Lock party panel in place" }, { ">Перетащи панель мышью, потом поставь галочку обратно.</color>", ">Drag the panel with the mouse, then tick the box again.</color>" }, { "Размер пинга", "Ping size" }, { "Прозрачность пинга", "Ping opacity" }, { "Сбросить позицию панели", "Reset panel position" }, { "Цвет полосы HP", "HP bar color" }, { "При малом здоровье", "Low health" }, { "Порог малого HP", "Low HP threshold" }, { "Обводка тиммейтов сквозь стены", "Teammate outline through walls" }, { "Выключена админом сервера", "Disabled by server admin" }, { "Включить обводку", "Enable outline" }, { "Яркость", "Brightness" }, { "Дальность", "Range" }, { "Сервер", "Server" }, { ">Менять может только админ сервера.</color>", ">Only the server admin can change these.</color>" }, { "Ты админ — изменения разойдутся всем игрокам, когда закроешь меню.", "You are admin — changes are sent to all players when you close the menu." }, { "Размер пати", "Party size" }, { "Время приглашения", "Invite time" }, { "Частота обновления", "Update rate" }, { "Пинги включены", "Pings enabled" }, { "Длительность пинга", "Ping duration" }, { "Дальность пинга", "Ping range" }, { "Ники над тиммейтами", "Names above teammates" }, { "Дальность ников", "Name range" }, { "Разрешить обводку тиммейтов", "Allow teammate outline" }, { "Отправить на сервер", "Send to server" }, { "Отправить на сервер *", "Send to server *" }, { "выкл", "off" }, { "без огр.", "unlimited" }, { "{0:0} с", "{0:0} s" }, { "{0:0.0} с", "{0:0.0} s" }, { "Сколько игроков может быть в одном пати.", "How many players can be in one party." }, { "Как часто (в секундах) сервер рассылает позиции и HP тиммейтов.", "How often (in seconds) the server sends teammate positions and HP." }, { "Через сколько секунд приглашение в пати сгорает.", "After how many seconds a party invite expires." }, { "Разрешить пинги для пати.", "Allow pings for the party." }, { "Сколько секунд пинг висит в мире.", "How many seconds a ping stays in the world." }, { "Максимальная дальность луча пинга в метрах.", "Maximum ping ray distance in meters." }, { "Показывать ник, HP и дистанцию над тиммейтами (видно сквозь стены).", "Show name, HP and distance above teammates (visible through walls)." }, { "С какой максимальной дистанции видно ник тиммейта. 0 = без ограничений.", "Maximum distance at which a teammate's name is visible. 0 = unlimited." }, { "Разрешить игрокам подсвечивать тиммейтов сквозь стены. Если выключено — обводки не будет ни у кого.", "Allow players to highlight teammates through walls. If off, nobody gets an outline." }, { "Поставить пинг туда, куда смотришь (по умолчанию колёсико мыши).", "Place a ping where you are looking (default: mouse wheel click)." }, { "Быстро принять приглашение в пати.", "Quickly accept a party invite." }, { "Быстро отклонить приглашение в пати.", "Quickly decline a party invite." }, { "Панель с никами и HP тиммейтов.", "Panel with teammate names and HP." }, { "true = панель пати закреплена на месте. false = свободное перемещение: открой меню пати (или инвентарь) и перетащи панель мышью. Позиция сохраняется сама.", "true = party panel is locked in place. false = free movement: open the party menu (or inventory) and drag the panel with the mouse. Position is saved automatically." }, { "Отступ панели пати слева (пиксели).", "Party panel offset from the left (pixels)." }, { "Отступ панели пати сверху (пиксели).", "Party panel offset from the top (pixels)." }, { "Размер метки пинга на экране (1 = обычный, 0.5 = в два раза меньше).", "Ping marker size on screen (1 = normal, 0.5 = half size)." }, { "Непрозрачность метки пинга (1 = полностью видна, 0.2 = почти прозрачная).", "Ping marker opacity (1 = fully visible, 0.2 = almost transparent)." }, { "Цвет полосы здоровья тиммейтов (HEX, например B8E0F2FF). Меняется и в меню пати.", "Teammate health bar color (HEX, e.g. B8E0F2FF). Can also be changed in the party menu." }, { "Цвет полосы, когда у тиммейта мало здоровья.", "Bar color when a teammate has low health." }, { "При какой доле HP полоса меняет цвет (0.3 = 30%). 0 = никогда.", "HP fraction at which the bar changes color (0.3 = 30%). 0 = never." }, { "Убирает ванильную полосу HP над игроками из твоего пати — вместо неё рисуется полоса PartyPlus (ник, HP, дистанция). У мобов и чужих игроков всё как было.", "Hides the vanilla HP bar above your party members and draws the PartyPlus bar instead (name, HP, distance). Mobs and other players are unchanged." }, { "Размер цифры расстояния до тиммейта и до пинга.", "Size of the distance number for teammates and pings." }, { "Подсвечивать силуэт тиммейта, когда он за стеной, деревом или горой.", "Highlight a teammate's silhouette when they are behind a wall, tree or mountain." }, { "Цвет силуэта тиммейта сквозь стены (HEX). Меняется и в меню пати.", "Teammate silhouette color through walls (HEX). Can also be changed in the party menu." }, { "Насколько яркий силуэт (1 = сплошной, 0.2 = еле видно).", "How bright the silhouette is (1 = solid, 0.2 = barely visible)." }, { "До какого расстояния (м) подсвечивать тиммейтов. 0 = без ограничений.", "Up to what distance (m) teammates are highlighted. 0 = unlimited." }, { "Использовать шрифт Valheim. Если вместо русских букв квадратики — выключи. Применяется после перезапуска.", "Use the Valheim font. If letters show up as squares, turn this off. Applies after restart." }, { "Масштаб всего интерфейса мода.", "Scale of the whole mod interface." }, { "Пати, приглашения, HUD и пинги", "Party, invites, HUD and pings" }, { "PartyPlus 1.8.0 загружен", "PartyPlus 1.8.0 loaded" }, { "[PartyPlus] Шейдер Hidden/Internal-Colored не найден — обводка тиммейтов отключена", "[PartyPlus] Shader Hidden/Internal-Colored not found — teammate outline disabled" }, { "[PartyPlus] EnemyHud.UpdateHuds не найден — стандартная полоса над тиммейтами не будет скрываться", "[PartyPlus] EnemyHud.UpdateHuds not found — the vanilla bar above teammates will not be hidden" }, { "{0} / Esc — закрыть", "{0} / Esc — close" }, { "Все плитки скрыты — включи их в настройках", "All tiles are hidden — enable them in settings" }, { "Пока ни один мод не подключён к хабу", "No mods are connected to the hub yet" }, { "Основное", "General" }, { "Клавиша хаба", "Hub key" }, { "Нажми клавишу...", "Press a key..." }, { "Надпись окна", "Window caption" }, { "Плиток в ряду", "Tiles per row" }, { "Рядов без прокрутки", "Rows without scrolling" }, { "Масштаб меню", "Menu scale" }, { "Плитки в хабе", "Tiles in hub" }, { "Пока ни один мод не подключён", "No mods connected yet" }, { "Сбросить всё", "Reset all" }, { "Изменения сохраняются сразу. Esc — назад", "Changes are saved immediately. Esc — back" }, { "Нажми новую клавишу (можно с Ctrl/Shift/Alt). Esc — отмена", "Press a new key (Ctrl/Shift/Alt allowed). Esc — cancel" }, { "Клавиша, открывающая общее меню модов", "Key that opens the shared mod menu" }, { "Надпись внизу окна хаба", "Caption at the bottom of the hub window" }, { "Сколько рядов видно без прокрутки", "How many rows are visible without scrolling" }, { "Масштаб всех меню, использующих ModHub", "Scale of all menus that use ModHub" }, { "id плиток через запятую, которые скрыты в хабе (удобнее менять в самом хабе через шестерёнку)", "Comma-separated tile ids hidden in the hub (easier to change in the hub itself via the gear)" } }; }