Decompiled source of GlitnirRanking v0.7.56

GlitnirRanking.dll

Decompiled 13 hours ago
using System;
using System.Buffers;
using System.Buffers.Binary;
using System.Buffers.Text;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Diagnostics.Tracing;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Linq.Expressions;
using System.Net;
using System.Numerics;
using System.Numerics.Hashing;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Versioning;
using System.Security;
using System.Security.AccessControl;
using System.Security.Cryptography;
using System.Security.Principal;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using FxResources.System.Buffers;
using FxResources.System.Memory;
using HarmonyLib;
using JetBrains.Annotations;
using LiteDB;
using LiteDB.Engine;
using LiteDB.Utils;
using LiteDB.Utils.Extensions;
using Microsoft.CodeAnalysis;
using ServerSync;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

[assembly: Guid("72b7e2b4-c4d2-4b2f-91db-99d0311d97bc")]
[assembly: ComVisible(false)]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCopyright("Copyright ©  2026")]
[assembly: AssemblyProduct("GlitnirRanking")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyTitle("GlitnirRanking")]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: CompilationRelaxations(8)]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace Glitnir.Ranking
{
	internal static class GlitnirRankingServerSync
	{
		internal static readonly ConfigSync ConfigSync = new ConfigSync("com.glitnir.ranking")
		{
			DisplayName = "Glitnir Ranking",
			CurrentVersion = "0.7.55",
			MinimumRequiredVersion = "0.7.55"
		};

		internal static ConfigEntry<T> BindConfig<T>(this ConfigFile config, string group, string name, T value, string description, bool synced = true)
		{
			ConfigEntry<T> val = config.Bind<T>(group, name, value, description);
			if (synced)
			{
				ConfigSync.AddConfigEntry<T>(val);
			}
			return val;
		}
	}
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInPlugin("com.glitnir.ranking", "Glitnir Ranking", "0.7.55")]
	public class GlitnirRankingPlugin : BaseUnityPlugin
	{
		private enum DebugCategory
		{
			General,
			Hit,
			Kill,
			Skill,
			PendingKill,
			Snapshot,
			Points
		}

		private sealed class SnapshotTopEntryData
		{
			public int Position;

			public string PlayerName = "";

			public int Points;

			public bool IsLocalPlayer;

			public int TotalKillsPontuadas;

			public int TotalBossesPontuadas;

			public int TotalSkillLevelUpsPontuados;

			public int TotalFishingPontuadas;

			public int TotalCraftPontuadas;

			public int TotalFarmJackpotsPontuados;

			public int TotalUniqueCraftJackpotsPontuados;

			public int TotalDeaths;

			public int KillPointsTotal;

			public int BossPointsTotal;

			public int SkillPointsTotal;

			public int FishingPointsTotal;

			public int CraftPointsTotal;

			public int FarmJackpotPointsTotal;

			public int UniqueCraftJackpotPointsTotal;

			public int DeathPenaltyPointsTotal;

			public int TotalPointsExchanges;

			public int PointsExchangePenaltyTotal;

			public int PointsExchangeCoinsTotal;

			public int ExplorationMapJackpotPointsTotal;

			public string LastReason = "";

			public string LastUpdateUtc = "";
		}

		private sealed class SnapshotPlayerData
		{
			public bool HasData;

			public int Position;

			public string PlayerName = "";

			public int Points;

			public int TotalKillsPontuadas;

			public int TotalBossesPontuadas;

			public int TotalSkillLevelUpsPontuados;

			public int KillPointsTotal;

			public int BossPointsTotal;

			public int SkillPointsTotal;

			public int TotalFishingPontuadas;

			public int TotalCraftPontuadas;

			public int TotalFarmJackpotsPontuados;

			public int TotalUniqueCraftJackpotsPontuados;

			public int TotalDeaths;

			public int FishingPointsTotal;

			public int CraftPointsTotal;

			public int FarmJackpotPointsTotal;

			public int UniqueCraftJackpotPointsTotal;

			public int DeathPenaltyPointsTotal;

			public int TotalPointsExchanges;

			public int PointsExchangePenaltyTotal;

			public int PointsExchangeCoinsTotal;

			public int ExplorationMapJackpotPointsTotal;

			public string LastReason = "";

			public string LastUpdateUtc = "";

			public bool RankingEnabled;

			public bool EnableKillPoints;

			public bool EnableBossPoints;

			public bool EnableSkillPoints;

			public bool EnableMarketplaceQuestPoints;

			public int TopCount;

			public bool RewardClaimsEnabled;

			public bool RewardCanClaim;

			public bool RewardAlreadyClaimed;

			public int RewardRank;

			public int RewardMinPoints;

			public string RewardLabel = "";

			public string RewardPrefabName = "";

			public int RewardAmount;

			public string RewardBlockReason = "";

			public string RewardClaimCycleId = "";

			public string HudKillRules = "";

			public string HudBossRules = "";

			public string HudSkillJackpotRules = "";

			public string HudMarketplaceQuestRules = "";

			public string HudFishingRules = "";

			public string HudCraftRules = "";

			public string HudFarmJackpotRules = "";

			public string HudUniqueCraftJackpotRules = "";

			public string HudDeathPenaltyRules = "";

			public bool EnableDeathPenalty;

			public bool DeathPenaltyUseMultiplier;

			public int DeathPenaltyPerDeath;

			public string HudExplorationMapJackpotRules = "";

			public Dictionary<string, int> ProgressCounters = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);

			public Dictionary<string, float> FloatProgressCounters = new Dictionary<string, float>(StringComparer.OrdinalIgnoreCase);
		}

		private sealed class PendingKillCheck
		{
			public string PrefabName = "";

			public float FirstSeenTime;

			public float LastHitTime;
		}

		private sealed class RankRewardInfo
		{
			public int Rank;

			public int MinPoints;

			public string Label = "";

			public string PrefabName = "";

			public int Amount;
		}

		private sealed class RuleGuideGroup
		{
			public readonly string Name;

			public readonly List<string> Rows = new List<string>();

			public RuleGuideGroup(string name)
			{
				Name = (string.IsNullOrWhiteSpace(name) ? "Outros" : name);
			}
		}

		private class SkillGuideGroup
		{
			public string Name;

			public List<SkillGuideMilestone> Milestones;

			public SkillGuideGroup(string name)
			{
				Name = (string.IsNullOrWhiteSpace(name) ? "Habilidade" : name);
				Milestones = new List<SkillGuideMilestone>();
			}
		}

		private class SkillGuideMilestone
		{
			public string Level;

			public string Points;

			public SkillGuideMilestone(string level, string points)
			{
				Level = (string.IsNullOrWhiteSpace(level) ? "?" : level);
				Points = (string.IsNullOrWhiteSpace(points) ? "0" : points);
			}
		}

		public const string ModGuid = "com.glitnir.ranking";

		public const string ModName = "Glitnir Ranking";

		public const string ModVersion = "0.7.55";

		internal static GlitnirRankingPlugin Instance;

		internal static ManualLogSource Log;

		private const string RpcRequestSnapshot = "glitnir.ranking.requestsnapshot";

		private const string RpcReceiveSnapshot = "glitnir.ranking.receivesnapshot";

		private const string RpcReportHit = "glitnir.ranking.reporthit";

		private const string RpcReportKill = "glitnir.ranking.reportkill";

		private const string RpcReportSkillGain = "glitnir.ranking.reportskillgain";

		private const string RpcRequestRewardClaim = "glitnir.ranking.requestrewardclaim";

		private const string RpcGrantRewardItem = "glitnir.ranking.grantrewarditem";

		private const string RpcFinalizeRewardClaim = "glitnir.ranking.finalizerewardclaim";

		private const string RpcRewardClaimFeedback = "glitnir.ranking.rewardclaimfeedback";

		private const string RpcRequestPointsExchange = "glitnir.ranking.requestpointsexchange";

		private const string RpcGrantExchangeCoins = "glitnir.ranking.grantexchangecoins";

		private const string RpcFinalizePointsExchange = "glitnir.ranking.finalizepointsexchange";

		private const string RpcPointsExchangeFeedback = "glitnir.ranking.pointsexchangefeedback";

		private const string RpcReportMarketplaceQuestComplete = "glitnir.ranking.marketquestcomplete";

		private const string RpcReportFishCaught = "glitnir.ranking.reportfishcaught";

		private const string RpcReportCraftedItem = "glitnir.ranking.reportcrafteditem";

		private const string RpcReportFarmHarvest = "glitnir.ranking.reportfarmharvest";

		private const string RpcReportPlayerDeath = "glitnir.ranking.reportplayerdeath";

		private const string RpcReportExplorationMap = "glitnir.ranking.reportexplorationmap";

		private const float DamageCreditLifetimeSeconds = 180f;

		private const float ProcessedKillLifetimeSeconds = 180f;

		private const float LocalRecentHitLifetimeSeconds = 15f;

		private const float ServerPendingKillDelaySeconds = 0.25f;

		private const float ServerPendingKillTimeoutSeconds = 12f;

		private const float ServerPendingKillCheckInterval = 0.25f;

		private const int MaxHudChars = 3000;

		private const int MaxPlayerNameLength = 32;

		private const int MaxReasonLength = 64;

		private const float ClientRefreshInterval = 1f;

		private readonly Dictionary<string, string> _hudPrefabDisplayNameCache = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);

		private readonly Dictionary<string, GameObject> _hudPrefabObjectCache = new Dictionary<string, GameObject>(StringComparer.OrdinalIgnoreCase);

		private int _hudObjectDbItemCountCached = -1;

		private int _hudZNetScenePrefabCountCached = -1;

		private Type _hudLocalizationType;

		private FieldInfo _hudLocalizationInstanceField;

		private MethodInfo _hudLocalizationLocalizeMethod;

		private bool _hudLocalizationReflectionReady;

		private Harmony _harmony;

		private bool _rpcsRegistered = false;

		private string _rulesFilePath;

		private string _uiFolderPath;

		private string _uiFilePath;

		private string _databaseFilePath;

		private string _legacyDatabaseFilePath;

		private ConfigFile _rulesConfig;

		private FileSystemWatcher _rulesConfigWatcher;

		private bool _rulesConfigReloadQueued;

		private float _rulesConfigReloadAt;

		private float _rulesConfigApplyAt;

		private const float RulesConfigApplyInterval = 1f;

		private ConfigEntry<bool> _cfgRankingEnabled;

		private ConfigEntry<bool> _cfgEnableKillPoints;

		private ConfigEntry<bool> _cfgEnableBossPoints;

		private ConfigEntry<int> _cfgDefaultKillPoints;

		private ConfigEntry<int> _cfgTopCount;

		private ConfigEntry<bool> _cfgAllowRepeatedBossPoints;

		private ConfigEntry<bool> _cfgDebugLogging;

		private ConfigEntry<bool> _cfgLogHitReports;

		private ConfigEntry<bool> _cfgLogKillReports;

		private ConfigEntry<bool> _cfgLogSkillReports;

		private ConfigEntry<bool> _cfgLogPendingKillReports;

		private ConfigEntry<bool> _cfgLogSnapshotRequests;

		private ConfigEntry<bool> _cfgLogPointsChanges;

		private ConfigEntry<bool> _cfgEnableSkillPoints;

		private ConfigEntry<bool> _cfgIgnoreTamedKills;

		private ConfigEntry<bool> _cfgEnableMarketplaceQuestPoints;

		private ConfigEntry<bool> _cfgEnableFishingPoints;

		private ConfigEntry<bool> _cfgEnableDeathPenalty;

		private ConfigEntry<bool> _cfgEnableExplorationJackpots;

		private ConfigEntry<string> _cfgExplorationMapJackpotRules;

		private ConfigEntry<string> _cfgDeathPenaltyRules;

		private ConfigEntry<bool> _cfgDeathPenaltyUseMultiplier;

		private ConfigEntry<int> _cfgDeathPenaltyPerDeath;

		private readonly Dictionary<string, ConfigEntry<string>> _cfgCombatBiomeRuleEntries = new Dictionary<string, ConfigEntry<string>>(StringComparer.OrdinalIgnoreCase);

		private ConfigEntry<string> _cfgProductionCategoryRules;

		private ConfigEntry<string> _cfgMarketplaceQuestPointMap;

		private ConfigEntry<string> _cfgFarmJackpotRules;

		private ConfigEntry<string> _cfgUniqueCraftJackpotRules;

		private ConfigEntry<bool> _cfgRewardClaimsEnabled;

		private ConfigEntry<string> _cfgRewardClaimCycleId;

		private ConfigEntry<int> _cfgRewardTop1MinPoints;

		private ConfigEntry<string> _cfgRewardTop1Label;

		private ConfigEntry<string> _cfgRewardTop1Prefab;

		private ConfigEntry<int> _cfgRewardTop1Amount;

		private ConfigEntry<int> _cfgRewardTop2MinPoints;

		private ConfigEntry<string> _cfgRewardTop2Label;

		private ConfigEntry<string> _cfgRewardTop2Prefab;

		private ConfigEntry<int> _cfgRewardTop2Amount;

		private ConfigEntry<int> _cfgRewardTop3MinPoints;

		private ConfigEntry<string> _cfgRewardTop3Label;

		private ConfigEntry<string> _cfgRewardTop3Prefab;

		private ConfigEntry<int> _cfgRewardTop3Amount;

		private ConfigEntry<bool> _cfgPointsExchangeEnabled;

		private ConfigEntry<string> _cfgPointsExchangePrefab;

		private ConfigEntry<int> _cfgPointsExchangeCoinsPerPoint;

		private ConfigEntry<int> _cfgPointsExchangeMinPoints;

		private ConfigEntry<int> _cfgPointsExchangeMaxPointsPerRequest;

		private ConfigEntry<bool> _cfgDiscordTop3WebhookEnabled;

		private ConfigEntry<string> _cfgDiscordTop3WebhookUrl;

		private ConfigEntry<bool> _cfgIgnoreAdminsInRanking;

		private ConfigEntry<string> _cfgIgnoredAdminNames;

		private readonly Dictionary<string, ConfigEntry<int>> _cfgKillPointEntries = new Dictionary<string, ConfigEntry<int>>(StringComparer.OrdinalIgnoreCase);

		private readonly Dictionary<string, ConfigEntry<int>> _cfgBossPointEntries = new Dictionary<string, ConfigEntry<int>>(StringComparer.OrdinalIgnoreCase);

		private readonly Dictionary<string, ConfigEntry<int>> _cfgFishingPointEntries = new Dictionary<string, ConfigEntry<int>>(StringComparer.OrdinalIgnoreCase);

		private readonly Dictionary<string, ConfigEntry<int>> _cfgCraftPointEntries = new Dictionary<string, ConfigEntry<int>>(StringComparer.OrdinalIgnoreCase);

		private readonly Dictionary<string, ConfigEntry<string>> _cfgFarmJackpotEntries = new Dictionary<string, ConfigEntry<string>>(StringComparer.OrdinalIgnoreCase);

		private readonly Dictionary<string, ConfigEntry<string>> _cfgUniqueCraftJackpotEntries = new Dictionary<string, ConfigEntry<string>>(StringComparer.OrdinalIgnoreCase);

		private readonly Dictionary<string, ConfigEntry<string>> _cfgSkillMilestoneJackpotPointEntries = new Dictionary<string, ConfigEntry<string>>(StringComparer.OrdinalIgnoreCase);

		private RankingDatabase _database = new RankingDatabase();

		private RankingRules _rules = new RankingRules();

		private readonly Dictionary<int, MarketplaceQuestPointRule> _marketplaceQuestPointsByUid = new Dictionary<int, MarketplaceQuestPointRule>();

		private readonly Dictionary<string, Dictionary<string, float>> _damageCredits = new Dictionary<string, Dictionary<string, float>>(StringComparer.Ordinal);

		private readonly Dictionary<string, float> _processedKills = new Dictionary<string, float>(StringComparer.Ordinal);

		private readonly Dictionary<string, float> _ignoredTamedKills = new Dictionary<string, float>(StringComparer.Ordinal);

		private readonly Dictionary<string, float> _localRecentHits = new Dictionary<string, float>(StringComparer.Ordinal);

		private readonly Dictionary<string, PendingKillCheck> _pendingKillChecks = new Dictionary<string, PendingKillCheck>(StringComparer.Ordinal);

		private float _serverPendingKillCheckAt;

		private bool _hudVisible;

		private float _hudOpenTime;

		private Rect _windowRect = new Rect(660f, 56f, 548f, 804f);

		private Rect _iconRect = new Rect(24f, 180f, 56f, 56f);

		private GameObject _rankingInputBlockerObject;

		private Canvas _rankingInputBlockerCanvas;

		private RectTransform _rankingInputBlockerRect;

		private Vector2 _rankingScrollPosition = Vector2.zero;

		private Vector2 _playerInfoScrollPosition = Vector2.zero;

		private Vector2 _rulesInfoScrollPosition = Vector2.zero;

		private Vector2 _actionsScrollPosition = Vector2.zero;

		private readonly HashSet<string> _expandedActionPlayers = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

		private int _hudTabIndex = 0;

		private float _hudTabSwitchTime = 0f;

		private readonly HashSet<string> _expandedRuleCategories = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

		private readonly HashSet<string> _expandedGuideSkillRows = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

		private readonly HashSet<string> _expandedRuleSubCategories = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

		private bool _ruleCategoriesInitialized;

		private readonly HashSet<string> _expandedPerformanceCategories = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

		private bool _performanceCategoriesInitialized;

		private float _clientRefreshTimer;

		private float _explorationReportTimer;

		private float _lastReportedMapExplorePercent = -1f;

		private long _lastKnownServerPeerUid;

		private bool _requestedInitialServerSnapshot;

		private string _cachedTopText = "Carregando ranking...";

		private string _cachedPlayerText = "Aguardando dados do servidor...";

		private string _statusText = "Sincronizando...";

		private float _statusUntil = 0f;

		private bool _rewardClaimRequestPending;

		private string _rewardClaimPendingCycleId = "";

		private int _rewardClaimPendingRank = 0;

		private readonly HashSet<string> _pendingRewardClaims = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

		private readonly HashSet<string> _pendingPointsExchanges = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

		private bool _pointsExchangeRequestPending;

		private string _pointsExchangeAmountInput = "";

		private bool _iconDragging;

		private Vector2 _iconDragOffset = Vector2.zero;

		private Vector2 _iconMouseDownPosition = Vector2.zero;

		private bool _iconMovedDuringDrag;

		private readonly List<SnapshotTopEntryData> _cachedTopEntries = new List<SnapshotTopEntryData>();

		private SnapshotPlayerData _cachedPlayerData = new SnapshotPlayerData();

		private GUIStyle _windowStyle;

		private GUIStyle _headerStyle;

		private GUIStyle _sectionTitleStyle;

		private GUIStyle _rankingTextStyle;

		private GUIStyle _playerTextStyle;

		private GUIStyle _footerStyle;

		private GUIStyle _statusStyle;

		private GUIStyle _iconButtonStyle;

		private GUIStyle _panelHeadingStyle;

		private GUIStyle _cardLabelStyle;

		private GUIStyle _cardValueStyle;

		private GUIStyle _bodyRowStyle;

		private GUIStyle _bodyValueStyle;

		private GUIStyle _mutedBodyStyle;

		private GUIStyle _rankIndexStyle;

		private GUIStyle _rankNameStyle;

		private GUIStyle _rankPointsStyle;

		private GUIStyle _youTagStyle;

		private GUIStyle _emptyStateStyle;

		private GUIStyle _configStyle;

		private bool _stylesReady;

		private string _uiTitleFontNames = "Cinzel Decorative|Cinzel|Trajan Pro|Palatino Linotype|Georgia|Times New Roman";

		private string _uiBodyFontNames = "Cormorant Garamond|Cormorant SC|Palatino Linotype|Georgia|Garamond|Arial";

		private string _uiAccentFontNames = "Cinzel|Palatino Linotype|Georgia|Arial";

		private bool _uiUseSystemFonts = false;

		private KeyCode _uiToggleKey = (KeyCode)121;

		private float _uiIconZoom = 0.96f;

		private Font _uiTitleFont;

		private Font _uiBodyFont;

		private Font _uiAccentFont;

		private Texture2D _uiTransparentTexture;

		private Texture2D _uiWhiteTexture;

		private Texture2D _uiPanelTexture;

		private Texture2D _uiBackgroundTexture;

		private Texture2D _uiRankingIconTexture;

		private Texture2D _uiTitleRankingTexture;

		private Texture2D _uiTitleTopTexture;

		private Texture2D _uiTitleGuideTexture;

		private Texture2D _uiTitlePlayerTexture;

		private Texture2D _uiTitleActionsTexture;

		private readonly Dictionary<string, Texture2D> _uiRuleCategoryIcons = new Dictionary<string, Texture2D>(StringComparer.OrdinalIgnoreCase);

		private const float RuleCategoryIconSize = 24f;

		private Texture2D _uiRank1IconTexture;

		private Texture2D _uiRank2IconTexture;

		private Texture2D _uiRank3IconTexture;

		private bool _uiTexturesLoaded;

		private readonly HashSet<string> _missingUiTextureWarnings = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

		private const string DefaultKillPointRules = "Boar:1";

		private const string DefaultCombatCategoryRules = "Prados:Boar:1,Deer:1,Neck:1;Floresta Negra:Greydwarf:1,Greydwarf_Elite:2,Greydwarf_Shaman:2,Troll:5;Pântano:Draugr:2,Draugr_Elite:3,Blob:2,Abomination:8;Montanha:Wolf:2,Hatchling:2,StoneGolem:8;Planícies:Goblin:3,GoblinBrute:5,Lox:6,Deathsquito:3;Oceano:Serpent:6;Mistlands:Seeker:4,SeekerBrute:8,Gjall:10;Ashlands:Charred_Melee:4,Charred_Archer:4,Volture:4;Especiais:Haldor:0";

		private const string DefaultProductionCategoryRules = "Armas:SwordIron=800;Armaduras:HelmetBronze=800;Comidas:DeerStew=25";

		private static readonly Dictionary<string, string> ManualPortuguesePrefabNames = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
		{
			{ "deerstew", "Ensopado de cervo" },
			{ "honeysglazedchicken", "Frango glaceado com mel" },
			{ "mushroomjotun", "Cogumelo Jotun" },
			{ "helmetbronze", "Elmo de bronze" },
			{ "helmetcarapace", "Elmo de carapaça" },
			{ "helmetdrake", "Elmo de draco" },
			{ "helmetdverger", "Tiara Dvergr" },
			{ "helmetfenris", "Capuz de Fenris" },
			{ "helmetiron", "Elmo de ferro" },
			{ "helmetleather", "Elmo de couro" },
			{ "helmetmage", "Capuz de mago" },
			{ "helmetpadded", "Elmo acolchoado" },
			{ "helmetroot", "Máscara de raiz" },
			{ "helmettrollleather", "Capuz de couro de troll" },
			{ "helmetflametal", "Elmo de flametal" },
			{ "armorbronzechest", "Peitoral de bronze" },
			{ "armorbronzelegs", "Perneiras de bronze" },
			{ "armorcarapacechest", "Peitoral de carapaça" },
			{ "armorcarapacelegs", "Perneiras de carapaça" },
			{ "armorfenringchest", "Peitoral de Fenris" },
			{ "armorfenringlegs", "Perneiras de Fenris" },
			{ "armorironchest", "Peitoral de ferro" },
			{ "armorironlegs", "Perneiras de ferro" },
			{ "armorleatherchest", "Túnica de couro" },
			{ "armorleatherlegs", "Calças de couro" },
			{ "armormagechest", "Manto de mago" },
			{ "armormagelegs", "Calças de mago" },
			{ "armorpaddedcuirass", "Couraça acolchoada" },
			{ "armorpaddedgreaves", "Grevas acolchoadas" },
			{ "armorragschest", "Túnica de trapos" },
			{ "armorragslegs", "Calças de trapos" },
			{ "armorrootchest", "Armadura de raiz" },
			{ "armorrootlegs", "Perneiras de raiz" },
			{ "armortrollleatherchest", "Túnica de couro de troll" },
			{ "armortrollleatherlegs", "Calças de couro de troll" },
			{ "knifeblackmetal", "Faca de metal negro" },
			{ "knifecopper", "Faca de cobre" },
			{ "knifeflint", "Faca de sílex" },
			{ "knifesilver", "Faca de prata" },
			{ "swordiron", "Espada de ferro" },
			{ "swordsilver", "Espada de prata" },
			{ "swordblackmetal", "Espada de metal negro" },
			{ "swordbronze", "Espada de bronze" },
			{ "swordmistwalker", "Mistwalker" },
			{ "swordflametal", "Espada de flametal" },
			{ "axeiron", "Machado de ferro" },
			{ "axebronze", "Machado de bronze" },
			{ "axeblackmetal", "Machado de metal negro" },
			{ "maceiron", "Maça de ferro" },
			{ "macebronze", "Maça de bronze" },
			{ "macesilver", "Frostner" },
			{ "sledgeiron", "Marreta de ferro" },
			{ "sledge_demolisher", "Demolidor" },
			{ "bow", "Arco bruto" },
			{ "bowfinewood", "Arco de madeira fina" },
			{ "bowhuntsman", "Arco do caçador" },
			{ "bowdraugrfang", "Presa de Draugr" },
			{ "bowspine", "Estilhaçador de espinha" },
			{ "crossbowarbalest", "Arbalest" },
			{ "crossbowripper", "Ripper" },
			{ "shieldwood", "Escudo de madeira" },
			{ "shieldbronze buckler", "Broquel de bronze" },
			{ "shieldironbuckler", "Broquel de ferro" },
			{ "shieldblackmetal", "Escudo de metal negro" },
			{ "shieldcarapace", "Escudo de carapaça" },
			{ "shieldflametal", "Escudo de flametal" },
			{ "atgierbronze", "Atgeir de bronze" },
			{ "atgieriron", "Atgeir de ferro" },
			{ "atgierblackmetal", "Atgeir de metal negro" },
			{ "spearflint", "Lança de sílex" },
			{ "spearbronze", "Lança de bronze" },
			{ "spearwolffang", "Lança de presas" },
			{ "carrot", "Cenoura" },
			{ "turnip", "Nabo" },
			{ "onion", "Cebola" },
			{ "barley", "Cevada" },
			{ "flax", "Linho" },
			{ "sap", "Seiva" },
			{ "jotunpuffs", "Cogumelo Jotun" },
			{ "magecap", "Chapéu de Mago" },
			{ "vineberry", "Baga de Videira" }
		};

		private static readonly Dictionary<string, string> BossDisplayNamesPtBr = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
		{
			{ "Eikthyr", "Eikthyr" },
			{ "gd_king", "O Ancião" },
			{ "Bonemass", "Massa Óssea" },
			{ "Dragon", "Moder" },
			{ "GoblinKing", "Yagluth" },
			{ "SeekerQueen", "Rainha Seeker" },
			{ "Fader", "Fader" },
			{ "Charred_Melee_Dyrnwyn", "Guerreiro Carbonizado Dyrnwyn" },
			{ "Fenring_Cultist_Hildir", "Cultista Fenring da Hildir" },
			{ "GoblinBruteBros", "Irmãos Berserker Fuling" },
			{ "GoblinBrute_Hildir", "Berserker Fuling da Hildir" },
			{ "GoblinShaman_Hildir", "Xamã Fuling da Hildir" },
			{ "Skeleton_Hildir", "Esqueleto da Hildir" }
		};

		private static readonly Dictionary<string, string> BossPortugueseToPrefab = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
		{
			{ "Eikthyr", "Eikthyr" },
			{ "O Ancião", "gd_king" },
			{ "Ancião", "gd_king" },
			{ "O Anciao", "gd_king" },
			{ "Anciao", "gd_king" },
			{ "Massa Óssea", "Bonemass" },
			{ "Massa Ossea", "Bonemass" },
			{ "Bonemass", "Bonemass" },
			{ "Moder", "Dragon" },
			{ "Yagluth", "GoblinKing" },
			{ "Rainha Seeker", "SeekerQueen" },
			{ "Rainha dos Seeker", "SeekerQueen" },
			{ "Seeker Queen", "SeekerQueen" },
			{ "Fader", "Fader" },
			{ "Guerreiro Carbonizado Dyrnwyn", "Charred_Melee_Dyrnwyn" },
			{ "Dyrnwyn", "Charred_Melee_Dyrnwyn" },
			{ "Cultista Fenring da Hildir", "Fenring_Cultist_Hildir" },
			{ "Irmãos Berserker Fuling", "GoblinBruteBros" },
			{ "Irmaos Berserker Fuling", "GoblinBruteBros" },
			{ "Berserker Fuling da Hildir", "GoblinBrute_Hildir" },
			{ "Xamã Fuling da Hildir", "GoblinShaman_Hildir" },
			{ "Xama Fuling da Hildir", "GoblinShaman_Hildir" },
			{ "Esqueleto da Hildir", "Skeleton_Hildir" }
		};

		private static readonly Dictionary<string, string> FishDisplayNamesPtBr = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
		{
			{ "Fish1", "Perca" },
			{ "Fish2", "Lúcio" },
			{ "Fish3", "Fish3" },
			{ "Fish4_cave", "Tetra" },
			{ "Fish5", "Peixe Troll" },
			{ "Fish6", "Arenque gigante" },
			{ "Fish7", "Garoupa" },
			{ "Fish8", "Garoupa estrelada" },
			{ "Fish9", "Peixe-pescador" },
			{ "Fish10", "Salmão do norte" },
			{ "Fish11", "Peixe magma" },
			{ "Fish12", "Baiacu" }
		};

		private static readonly Dictionary<string, string> FishPortugueseToPrefab = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
		{
			{ "Perca", "Fish1" },
			{ "Lúcio", "Fish2" },
			{ "Lucio", "Fish2" },
			{ "Fish3", "Fish3" },
			{ "Tetra", "Fish4_cave" },
			{ "Peixe Troll", "Fish5" },
			{ "Arenque gigante", "Fish6" },
			{ "Garoupa", "Fish7" },
			{ "Garoupa estrelada", "Fish8" },
			{ "Peixe-pescador", "Fish9" },
			{ "Peixe pescador", "Fish9" },
			{ "Salmão do norte", "Fish10" },
			{ "Salmao do norte", "Fish10" },
			{ "Peixe magma", "Fish11" },
			{ "Baiacu", "Fish12" }
		};

		private static readonly Dictionary<string, string> HudFriendlyNames = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
		{
			{ "Boar", "Javali" },
			{ "Neck", "Nixe" },
			{ "Greyling", "Greydwarf Jovem" },
			{ "Greydwarf", "Greydwarf" },
			{ "Greydwarf_Elite", "Greydwarf Elite" },
			{ "Greydwarf_Shaman", "Xamã Greydwarf" },
			{ "Troll", "Troll" },
			{ "Skeleton", "Esqueleto" },
			{ "Skeleton_Poison", "Esqueleto Venenoso" },
			{ "Draugr", "Draugr" },
			{ "Draugr_Elite", "Draugr Elite" },
			{ "Blob", "Gosma" },
			{ "BlobElite", "Gosma Elite" },
			{ "Leech", "Sanguessuga" },
			{ "Surtling", "Surtling" },
			{ "Abomination", "Abominação" },
			{ "Wolf", "Lobo" },
			{ "Hatchling", "Draco" },
			{ "Fenring", "Fenring" },
			{ "StoneGolem", "Golem de Pedra" },
			{ "Goblin", "Fuling" },
			{ "GoblinArcher", "Fuling Arqueiro" },
			{ "GoblinBrute", "Fuling Berserker" },
			{ "GoblinShaman", "Xamã Fuling" },
			{ "Lox", "Lox" },
			{ "Deathsquito", "Mosquito da Morte" },
			{ "Serpent", "Serpente Marinha" },
			{ "Bat", "Morcego" },
			{ "Ulv", "Ulv" },
			{ "Hare", "Lebre" },
			{ "Tick", "Carrapato" },
			{ "Seeker", "Seeker" },
			{ "SeekerBrute", "Seeker Brutamontes" },
			{ "Gjall", "Gjall" },
			{ "Dverger", "Dvergr" },
			{ "Charred_Melee", "Carbonizado Guerreiro" },
			{ "Charred_Archer", "Carbonizado Arqueiro" },
			{ "Charred_Mage", "Carbonizado Mago" },
			{ "Morgen", "Morgen" },
			{ "Asksvin", "Asksvin" },
			{ "Volture", "Abutre das Cinzas" },
			{ "Eikthyr", "Eikthyr" },
			{ "gd_king", "O Ancião" },
			{ "Bonemass", "Massa Óssea" },
			{ "Dragon", "Moder" },
			{ "GoblinKing", "Yagluth" },
			{ "SeekerQueen", "Rainha Seeker" },
			{ "Fader", "Fader" },
			{ "Fish1", "Perca" },
			{ "Fish2", "Lúcio" },
			{ "Fish3", "Fish3" },
			{ "Fish4_cave", "Tetra" },
			{ "Fish5", "Peixe Troll" },
			{ "Fish6", "Arenque gigante" },
			{ "Fish7", "Garoupa" },
			{ "Fish8", "Garoupa estrelada" },
			{ "Fish9", "Peixe-pescador" },
			{ "Fish10", "Salmão do norte" },
			{ "Fish11", "Peixe magma" },
			{ "Fish12", "Baiacu" },
			{ "Carrot", "Cenoura" },
			{ "Turnip", "Nabo" },
			{ "Onion", "Cebola" },
			{ "Barley", "Cevada" },
			{ "Flax", "Linho" },
			{ "Sap", "Seiva" },
			{ "JotunPuffs", "Cogumelo Jotun" },
			{ "Magecap", "Chapéu de Mago" },
			{ "Vineberry", "Baga de Videira" },
			{ "Fiddleheadfern", "Samambaia" },
			{ "Run", "Corrida" },
			{ "Jump", "Salto" },
			{ "Swords", "Espadas" },
			{ "Knives", "Facas" },
			{ "Clubs", "Porretes" },
			{ "Polearms", "Armas de Haste" },
			{ "Spears", "Lanças" },
			{ "Blocking", "Bloqueio" },
			{ "Axes", "Machados" },
			{ "Bows", "Arcos" },
			{ "Crossbows", "Bestas" },
			{ "ElementalMagic", "Magia Elemental" },
			{ "BloodMagic", "Magia de Sangue" },
			{ "Fishing", "Pesca" },
			{ "Cooking", "Culinária" },
			{ "Deer", "Cervo" },
			{ "EvilHeart_Forest", "Coração Maligno da Floresta" },
			{ "Ghost", "Fantasma" },
			{ "Wraith", "Aparição" },
			{ "Fenring_Cultist", "Cultista Fenring" },
			{ "SeekerBrood", "Cria de Seeker" },
			{ "DvergerMage", "Mago Dvergr" },
			{ "DvergerMageFire", "Mago Dvergr de Fogo" },
			{ "DvergerMageIce", "Mago Dvergr de Gelo" },
			{ "DvergerMageSupport", "Mago Dvergr de Suporte" },
			{ "DvergerRogue", "Ladino Dvergr" },
			{ "Charred_Twitcher", "Carbonizado Retorcido" },
			{ "Charred_Melee_Dyrnwyn", "Guerreiro Carbonizado Dyrnwyn" },
			{ "GoblinBruteBros", "Irmãos Berserker Fuling" },
			{ "GoblinBrute_Hildir", "Berserker Fuling da Hildir" },
			{ "GoblinShaman_Hildir", "Xamã Fuling da Hildir" },
			{ "Fenring_Cultist_Hildir", "Cultista Fenring da Hildir" },
			{ "Skeleton_Hildir", "Esqueleto da Hildir" },
			{ "ExploreBlackForest", "Explorador da Floresta Negra" },
			{ "ExploreSwamp", "Explorador do Pântano" },
			{ "ExploreMountain", "Explorador das Montanhas" },
			{ "ExplorePlains", "Explorador das Planícies" },
			{ "ExploreMistlands", "Explorador das Terras Nebulosas" },
			{ "ExploreAshlands", "Explorador das Terras das Cinzas" },
			{ "Kill100Enemies", "Exterminador" },
			{ "CraftMaster", "Mestre Artesão" },
			{ "Mapa 5%", "Mapa 5%" }
		};

		private const float ActionPlayerCollapsedHeight = 58f;

		private const float ActionPlayerExpandedHeight = 650f;

		private const string HudColorPoints = "#00FF7F";

		private const string HudColorDanger = "#FF5555";

		private const string HudColorProgress = "#4FC3F7";

		private const string HudColorHighlight = "#FFD700";

		private const string HudColorMuted = "#D7DCE5";

		private const string HudColorName = "#FFFFFF";

		private const string HudColorSeparator = "#8F6E38";

		private void EnsureRulesFileExists()
		{
			try
			{
				if (!File.Exists(_rulesFilePath))
				{
					File.WriteAllText(_rulesFilePath, BuildDefaultRulesFileContents(), Encoding.UTF8);
				}
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("Erro ao criar arquivo de regras: " + ex));
			}
		}

		private string BuildDefaultRulesFileContents()
		{
			StringBuilder stringBuilder = new StringBuilder(16384);
			stringBuilder.AppendLine("# =======================================================================");
			stringBuilder.AppendLine("# GLITNIR RANKING - CONFIGURACAO DE PONTUACAO");
			stringBuilder.AppendLine("# =======================================================================");
			stringBuilder.AppendLine("# Este arquivo controla as regras do ranking do servidor Glitnir.");
			stringBuilder.AppendLine("# Prefab = nome interno do item/criatura/colheita no Valheim.");
			stringBuilder.AppendLine("# Pontos = valor entregue ao jogador quando a regra for validada.");
			stringBuilder.AppendLine("#");
			stringBuilder.AppendLine("# Organizacao principal:");
			stringBuilder.AppendLine("# - KillPoints: pontos por criatura normal. Peixes NAO ficam aqui.");
			stringBuilder.AppendLine("# - FishingPoints: somente pontos por peixe realmente pescado.");
			stringBuilder.AppendLine("# - BossPoints: pontos por bosses e minibosses.");
			stringBuilder.AppendLine("# - CraftPoints.Rules: pontos por craft, em uma linha limpa separada por ponto e virgula.");
			stringBuilder.AppendLine("# - FarmJackpots.Rules: jackpots de colheita, em uma linha limpa separada por ponto e virgula.");
			stringBuilder.AppendLine("# - UniqueCraftJackpots.Rules: jackpots unicos por craft, em uma linha limpa separada por ponto e virgula.");
			stringBuilder.AppendLine("#");
			stringBuilder.AppendLine("# Nao use virgulas nas listas de producao/jackpot. Use ;");
			stringBuilder.AppendLine("# Exemplos:");
			stringBuilder.AppendLine("#   CraftPoints.Rules=MeadHealthMinor:20;ArrowNeedle:2");
			stringBuilder.AppendLine("#   FarmJackpots.Rules=Carrot:200:1000");
			stringBuilder.AppendLine("#   UniqueCraftJackpots.Rules=IronSword:1:800");
			stringBuilder.AppendLine("# =======================================================================");
			stringBuilder.AppendLine();
			stringBuilder.AppendLine("RankingEnabled=true");
			stringBuilder.AppendLine("EnableKillPoints=true");
			stringBuilder.AppendLine("EnableBossPoints=true");
			stringBuilder.AppendLine("DefaultKillPoints=1");
			stringBuilder.AppendLine("TopCount=10");
			stringBuilder.AppendLine("AllowRepeatedBossPoints=false");
			stringBuilder.AppendLine();
			stringBuilder.AppendLine("# Logging");
			stringBuilder.AppendLine("DebugLogging=false");
			stringBuilder.AppendLine("LogHitReports=false");
			stringBuilder.AppendLine("LogKillReports=false");
			stringBuilder.AppendLine("LogSkillReports=false");
			stringBuilder.AppendLine("LogPendingKillReports=false");
			stringBuilder.AppendLine("LogSnapshotRequests=false");
			stringBuilder.AppendLine("LogPointsChanges=false");
			stringBuilder.AppendLine();
			stringBuilder.AppendLine("# Skill milestone jackpot points");
			stringBuilder.AppendLine("EnableSkillPoints=true");
			stringBuilder.AppendLine("IgnoreTamedKills=true");
			stringBuilder.AppendLine("EnableMarketplaceQuestPoints=true");
			stringBuilder.AppendLine("EnableFishingPoints=true");
			stringBuilder.AppendLine("EnableDeathPenalty=true");
			stringBuilder.AppendLine();
			stringBuilder.AppendLine("# Marketplace quest points");
			stringBuilder.AppendLine("[MarketplaceQuestPoints]");
			stringBuilder.AppendLine("QuestPointMap=ccq_b21:450,ccq_b22:150");
			stringBuilder.AppendLine();
			stringBuilder.AppendLine("# Penalidade por morte");
			stringBuilder.AppendLine("[DeathPenalty]");
			stringBuilder.AppendLine("# UseMultiplierMode=false usa a tabela Rules abaixo.");
			stringBuilder.AppendLine("# UseMultiplierMode=true ignora Rules e usa PenaltyPerDeath por morte.");
			stringBuilder.AppendLine("# Exemplo multiplicador: PenaltyPerDeath=100 e 15 mortes = -1500.");
			stringBuilder.AppendLine("UseMultiplierMode=false");
			stringBuilder.AppendLine("PenaltyPerDeath=100");
			stringBuilder.AppendLine("# Formato do modo tabela: quantidadeDeMortes:pontosPerdidos,quantidadeDeMortes:pontosPerdidos");
			stringBuilder.AppendLine("# Exemplo: 1:0,2:100,5:300,10:800");
			stringBuilder.AppendLine("Rules=1:0,2:100,5:300,10:800");
			stringBuilder.AppendLine();
			stringBuilder.AppendLine("# Reward claims");
			stringBuilder.AppendLine("RewardClaimsEnabled=true");
			stringBuilder.AppendLine("RewardClaimCycleId=temporada_001");
			stringBuilder.AppendLine("RewardTop1MinPoints=300");
			stringBuilder.AppendLine("RewardTop1Label=Recompensa do 1 lugar");
			stringBuilder.AppendLine("RewardTop1Prefab=Coins");
			stringBuilder.AppendLine("RewardTop1Amount=500");
			stringBuilder.AppendLine("RewardTop2MinPoints=200");
			stringBuilder.AppendLine("RewardTop2Label=Recompensa do 2 lugar");
			stringBuilder.AppendLine("RewardTop2Prefab=AmberPearl");
			stringBuilder.AppendLine("RewardTop2Amount=10");
			stringBuilder.AppendLine("RewardTop3MinPoints=100");
			stringBuilder.AppendLine("RewardTop3Label=Recompensa do 3 lugar");
			stringBuilder.AppendLine("RewardTop3Prefab=Ruby");
			stringBuilder.AppendLine("RewardTop3Amount=5");
			stringBuilder.AppendLine();
			AppendBossPoints(stringBuilder);
			AppendKillPoints(stringBuilder);
			AppendFishingPoints(stringBuilder);
			AppendSkillMilestoneJackpotPoints(stringBuilder);
			AppendProductionRankingRules(stringBuilder);
			return stringBuilder.ToString();
		}

		private void AppendBossPoints(StringBuilder sb)
		{
			sb.AppendLine("# =========================");
			sb.AppendLine("# BOSS POINTS");
			sb.AppendLine("# =========================");
			sb.AppendLine("# Cada boss/miniboss fica em uma chave própria.");
			sb.AppendLine("BossPoints.Bonemass=2200");
			sb.AppendLine("BossPoints.Charred_Melee_Dyrnwyn=40");
			sb.AppendLine("BossPoints.Dragon=3000");
			sb.AppendLine("BossPoints.Eikthyr=1200");
			sb.AppendLine("BossPoints.Fader=10000");
			sb.AppendLine("BossPoints.Fenring_Cultist_Hildir=30");
			sb.AppendLine("BossPoints.gd_king=4200");
			sb.AppendLine("BossPoints.GoblinBruteBros=35");
			sb.AppendLine("BossPoints.GoblinBrute_Hildir=18");
			sb.AppendLine("BossPoints.GoblinKing=6000");
			sb.AppendLine("BossPoints.GoblinShaman_Hildir=18");
			sb.AppendLine("BossPoints.SeekerQueen=8600");
			sb.AppendLine("BossPoints.Skeleton_Hildir=25");
			sb.AppendLine();
		}

		private void AppendPoint(StringBuilder sb, string section, string key, int points)
		{
			sb.AppendLine(section + "." + key + "=" + points);
		}

		private void AppendKillPoint(StringBuilder sb, string prefabName, int points, string comment = null)
		{
		}

		private void AppendKillPoints(StringBuilder sb)
		{
			sb.AppendLine("# =========================");
			sb.AppendLine("# KILL POINTS / COMBATE");
			sb.AppendLine("# =========================");
			sb.AppendLine("# Pontos por criaturas normais. Peixes nao devem ficar aqui; use [FishingPoints].");
			sb.AppendLine("# Formato gerado pelo BepInEx: [KillPoints] Prefab = pontos.");
			sb.AppendLine("# Mantido no modo performance: o mod NAO envia RPC por hit; pontua apenas kill confirmada.");
			sb.AppendLine("KillPoints.Boar=1");
			sb.AppendLine("KillPoints.Neck=1");
			sb.AppendLine("KillPoints.Greyling=1");
			sb.AppendLine("KillPoints.Greydwarf=1");
			sb.AppendLine("KillPoints.Greydwarf_Elite=2");
			sb.AppendLine("KillPoints.Greydwarf_Shaman=2");
			sb.AppendLine("KillPoints.Skeleton=1");
			sb.AppendLine("KillPoints.Troll=5");
			sb.AppendLine("KillPoints.Draugr=2");
			sb.AppendLine("KillPoints.Draugr_Elite=3");
			sb.AppendLine("KillPoints.Blob=2");
			sb.AppendLine("KillPoints.Wolf=2");
			sb.AppendLine("KillPoints.Hatchling=2");
			sb.AppendLine("KillPoints.StoneGolem=8");
			sb.AppendLine("KillPoints.Deathsquito=3");
			sb.AppendLine("KillPoints.Goblin=3");
			sb.AppendLine("KillPoints.GoblinBrute=5");
			sb.AppendLine("KillPoints.GoblinShaman=4");
			sb.AppendLine("KillPoints.Lox=6");
			sb.AppendLine("KillPoints.Serpent=6");
			sb.AppendLine("KillPoints.Seeker=4");
			sb.AppendLine("KillPoints.SeekerBrute=8");
			sb.AppendLine("KillPoints.Gjall=10");
			sb.AppendLine("KillPoints.Charred_Melee=4");
			sb.AppendLine("KillPoints.Charred_Archer=4");
			sb.AppendLine("KillPoints.Morgen=12");
			sb.AppendLine();
		}

		private void AppendFishingPoints(StringBuilder sb)
		{
			sb.AppendLine("# =========================");
			sb.AppendLine("# FISHING POINTS");
			sb.AppendLine("# =========================");
			sb.AppendLine("# As chaves podem ficar em português; o código converte para o prefab real internamente.");
			sb.AppendLine("# Mapeamento: Perca=Fish1, Lúcio=Fish2, Fish3=Fish3, Tetra=Fish4_cave, Peixe Troll=Fish5, Arenque gigante=Fish6, Garoupa=Fish7, Garoupa estrelada=Fish8, Peixe-pescador=Fish9, Salmão do norte=Fish10, Peixe magma=Fish11, Baiacu=Fish12");
			AppendFishingPoint(sb, "Perca", 1);
			AppendFishingPoint(sb, "Lúcio", 1);
			AppendFishingPoint(sb, "Fish3", 2);
			AppendFishingPoint(sb, "Tetra", 3);
			AppendFishingPoint(sb, "Peixe Troll", 2);
			AppendFishingPoint(sb, "Arenque gigante", 3);
			AppendFishingPoint(sb, "Garoupa", 3000);
			AppendFishingPoint(sb, "Garoupa estrelada", 4);
			AppendFishingPoint(sb, "Peixe-pescador", 4);
			AppendFishingPoint(sb, "Salmão do norte", 5);
			AppendFishingPoint(sb, "Peixe magma", 5);
			AppendFishingPoint(sb, "Baiacu", 6);
			sb.AppendLine();
		}

		private void AppendFishingPoint(StringBuilder sb, string prefabName, int points)
		{
			sb.AppendLine("FishingPoints." + prefabName + "=" + points);
		}

		private void AppendSkillPoint(StringBuilder sb, string skillKey, int points, string comment = null)
		{
			if (!string.IsNullOrWhiteSpace(comment))
			{
				sb.AppendLine(comment);
			}
			sb.AppendLine("SkillPoints." + skillKey + "=" + points);
		}

		private void AppendSkillMilestoneJackpotPoints(StringBuilder sb)
		{
			sb.AppendLine("# =========================");
			sb.AppendLine("# SKILL MILESTONE JACKPOT POINTS");
			sb.AppendLine("# =========================");
			sb.AppendLine("# Pontos únicos por marco de skill. Formato: SkillMilestoneJackpotPoints.Skill=20:pontos,40:pontos,60:pontos,80:pontos,100:pontos");
			sb.AppendLine("# Exemplo: Bows 20/40/60/80/100. Cada marco pontua uma única vez por jogador/ciclo.");
			AppendSkillMilestoneJackpotPoint(sb, "BloodMagic", "20:1500,40:3000,60:5000,80:7500,100:12000");
			AppendSkillMilestoneJackpotPoint(sb, "ElementalMagic", "20:1000,40:2000,60:3500,80:5500,100:8000");
			AppendSkillMilestoneJackpotPoint(sb, "Bows", "20:500,40:1000,60:2000,80:3000,100:4000");
			AppendSkillMilestoneJackpotPoint(sb, "Crossbows", "20:500,40:1000,60:2000,80:3000,100:4000");
			AppendSkillMilestoneJackpotPoint(sb, "Swords", "20:500,40:1000,60:2000,80:3000,100:4000");
			AppendSkillMilestoneJackpotPoint(sb, "Axes", "20:500,40:1000,60:2000,80:3000,100:4000");
			AppendSkillMilestoneJackpotPoint(sb, "Clubs", "20:500,40:1000,60:2000,80:3000,100:4000");
			AppendSkillMilestoneJackpotPoint(sb, "Spears", "20:500,40:1000,60:2000,80:3000,100:4000");
			AppendSkillMilestoneJackpotPoint(sb, "Polearms", "20:500,40:1000,60:2000,80:3000,100:4000");
			AppendSkillMilestoneJackpotPoint(sb, "Knives", "20:500,40:1000,60:2000,80:3000,100:4000");
			AppendSkillMilestoneJackpotPoint(sb, "Blocking", "20:400,40:800,60:1500,80:2500,100:3500");
			AppendSkillMilestoneJackpotPoint(sb, "Run", "20:300,40:700,60:1200,80:2000,100:3000");
			AppendSkillMilestoneJackpotPoint(sb, "Jump", "20:300,40:700,60:1200,80:2000,100:3000");
			AppendSkillMilestoneJackpotPoint(sb, "WoodCutting", "20:300,40:700,60:1200,80:1800,100:2500");
			AppendSkillMilestoneJackpotPoint(sb, "Pickaxes", "20:300,40:700,60:1200,80:1800,100:2500");
			AppendSkillMilestoneJackpotPoint(sb, "Farming", "20:0,40:0,60:0,80:0,100:0");
			sb.AppendLine();
		}

		private void AppendSkillMilestoneJackpotPoint(StringBuilder sb, string skillKey, string milestones)
		{
			sb.AppendLine("SkillMilestoneJackpotPoints." + skillKey + "=" + milestones);
		}

		private void AppendProductionRankingRules(StringBuilder sb)
		{
			sb.AppendLine("# =======================================================================");
			sb.AppendLine("# PRODUCAO E JACKPOTS - GLITNIR RANKING");
			sb.AppendLine("# =======================================================================");
			sb.AppendLine("# Estes blocos usam UMA entrada por sistema para manter o arquivo limpo.");
			sb.AppendLine("# Nao use virgulas. Separe cada regra com ponto e virgula (;).");
			sb.AppendLine("# Formatos:");
			sb.AppendLine("#   CraftPoints.Rules = Prefab:pontos;OutroPrefab:pontos");
			sb.AppendLine("#   FarmJackpots.Rules = Prefab:quantidade:pontos;OutroPrefab:quantidade:pontos");
			sb.AppendLine("#   UniqueCraftJackpots.Rules = Prefab:quantidade:pontos;OutroPrefab:quantidade:pontos");
			sb.AppendLine("# Exemplos reais:");
			sb.AppendLine("#   MeadHealthMinor:20");
			sb.AppendLine("#   Carrot:200:1000");
			sb.AppendLine("#   IronSword:1:800");
			sb.AppendLine("# =======================================================================");
			sb.AppendLine();
			sb.AppendLine("# =========================");
			sb.AppendLine("# CRAFT POINTS");
			sb.AppendLine("# =========================");
			sb.AppendLine("# Pontos por craft de qualquer prefab configurado.");
			sb.AppendLine("# Exemplo de item: MeadHealthMinor:20");
			sb.AppendLine("CraftPoints.Rules=MeadHealthMinor:20");
			sb.AppendLine();
			sb.AppendLine("# =========================");
			sb.AppendLine("# FARM JACKPOTS");
			sb.AppendLine("# =========================");
			sb.AppendLine("# Jackpot por colheita. Premia uma vez por jogador/ciclo quando bater a quantidade.");
			sb.AppendLine("# Exemplo de item: Carrot:200:1000");
			sb.AppendLine("FarmJackpots.Rules=Carrot:200:1000");
			sb.AppendLine();
			sb.AppendLine("# =========================");
			sb.AppendLine("# UNIQUE CRAFT JACKPOTS");
			sb.AppendLine("# =========================");
			sb.AppendLine("# Jackpot unico por craft. Ideal para armas, armaduras e marcos especiais.");
			sb.AppendLine("# Exemplo de item: IronSword:1:800");
			sb.AppendLine("UniqueCraftJackpots.Rules=IronSword:1:800");
			sb.AppendLine();
		}

		private void AppendStringPoint(StringBuilder sb, string section, string key, string value)
		{
			sb.AppendLine(section + "." + key + "=" + value);
		}

		private void LoadRules()
		{
			_rules = new RankingRules();
			try
			{
				if (!File.Exists(_rulesFilePath))
				{
					return;
				}
				string[] array = File.ReadAllLines(_rulesFilePath, Encoding.UTF8);
				foreach (string text in array)
				{
					string text2 = text.Trim();
					if (string.IsNullOrWhiteSpace(text2) || text2.StartsWith("#") || text2.StartsWith(";") || text2.StartsWith("//"))
					{
						continue;
					}
					int num = text2.IndexOf('=');
					if (num <= 0)
					{
						continue;
					}
					string text3 = text2.Substring(0, num).Trim();
					string text4 = text2.Substring(num + 1).Trim();
					if (text3.Equals("RankingEnabled", StringComparison.OrdinalIgnoreCase))
					{
						_rules.RankingEnabled = ParseBool(text4, _rules.RankingEnabled);
					}
					else if (text3.Equals("EnableKillPoints", StringComparison.OrdinalIgnoreCase))
					{
						_rules.EnableKillPoints = ParseBool(text4, _rules.EnableKillPoints);
					}
					else if (text3.Equals("EnableBossPoints", StringComparison.OrdinalIgnoreCase))
					{
						_rules.EnableBossPoints = ParseBool(text4, _rules.EnableBossPoints);
					}
					else if (text3.Equals("DefaultKillPoints", StringComparison.OrdinalIgnoreCase))
					{
						_rules.DefaultKillPoints = ParseInt(text4, _rules.DefaultKillPoints);
					}
					else if (text3.Equals("TopCount", StringComparison.OrdinalIgnoreCase))
					{
						_rules.TopCount = Mathf.Clamp(ParseInt(text4, _rules.TopCount), 1, 50);
					}
					else if (text3.Equals("AllowRepeatedBossPoints", StringComparison.OrdinalIgnoreCase))
					{
						_rules.AllowRepeatedBossPoints = ParseBool(text4, _rules.AllowRepeatedBossPoints);
					}
					else if (text3.Equals("DebugLogging", StringComparison.OrdinalIgnoreCase))
					{
						_rules.DebugLogging = ParseBool(text4, _rules.DebugLogging);
					}
					else if (text3.Equals("LogHitReports", StringComparison.OrdinalIgnoreCase))
					{
						_rules.LogHitReports = ParseBool(text4, _rules.LogHitReports);
					}
					else if (text3.Equals("LogKillReports", StringComparison.OrdinalIgnoreCase))
					{
						_rules.LogKillReports = ParseBool(text4, _rules.LogKillReports);
					}
					else if (text3.Equals("LogPendingKillReports", StringComparison.OrdinalIgnoreCase))
					{
						_rules.LogPendingKillReports = ParseBool(text4, _rules.LogPendingKillReports);
					}
					else if (text3.Equals("LogSnapshotRequests", StringComparison.OrdinalIgnoreCase))
					{
						_rules.LogSnapshotRequests = ParseBool(text4, _rules.LogSnapshotRequests);
					}
					else if (text3.Equals("LogPointsChanges", StringComparison.OrdinalIgnoreCase))
					{
						_rules.LogPointsChanges = ParseBool(text4, _rules.LogPointsChanges);
					}
					else if (text3.Equals("EnableSkillPoints", StringComparison.OrdinalIgnoreCase))
					{
						_rules.EnableSkillPoints = ParseBool(text4, _rules.EnableSkillPoints);
					}
					else if (text3.Equals("LogSkillReports", StringComparison.OrdinalIgnoreCase))
					{
						_rules.LogSkillReports = ParseBool(text4, _rules.LogSkillReports);
					}
					else if (text3.Equals("EnableFishingPoints", StringComparison.OrdinalIgnoreCase))
					{
						_rules.EnableFishingPoints = ParseBool(text4, _rules.EnableFishingPoints);
					}
					else if (text3.Equals("EnableDeathPenalty", StringComparison.OrdinalIgnoreCase))
					{
						_rules.EnableDeathPenalty = ParseBool(text4, _rules.EnableDeathPenalty);
					}
					else if (text3.Equals("DeathPenalty.UseMultiplierMode", StringComparison.OrdinalIgnoreCase) || text3.Equals("DeathPenaltyUseMultiplier", StringComparison.OrdinalIgnoreCase) || text3.Equals("UseMultiplierMode", StringComparison.OrdinalIgnoreCase))
					{
						_rules.DeathPenaltyUseMultiplier = ParseBool(text4, _rules.DeathPenaltyUseMultiplier);
					}
					else if (text3.Equals("DeathPenalty.PenaltyPerDeath", StringComparison.OrdinalIgnoreCase) || text3.Equals("DeathPenaltyPerDeath", StringComparison.OrdinalIgnoreCase) || text3.Equals("PenaltyPerDeath", StringComparison.OrdinalIgnoreCase))
					{
						_rules.DeathPenaltyPerDeath = Mathf.Max(0, ParseInt(text4, _rules.DeathPenaltyPerDeath));
					}
					else if (text3.Equals("DeathPenalty.Rules", StringComparison.OrdinalIgnoreCase) || text3.Equals("DeathPenaltyRules", StringComparison.OrdinalIgnoreCase) || text3.Equals("Rules", StringComparison.OrdinalIgnoreCase))
					{
						_rules.DeathPenaltyRules = ParseDeathPenaltyRules(text4);
					}
					else if (text3.Equals("RewardClaimsEnabled", StringComparison.OrdinalIgnoreCase))
					{
						_rules.RewardClaimsEnabled = ParseBool(text4, _rules.RewardClaimsEnabled);
					}
					else if (text3.Equals("RewardClaimCycleId", StringComparison.OrdinalIgnoreCase))
					{
						_rules.RewardClaimCycleId = SafeLimit(text4, 64);
					}
					else if (text3.Equals("RewardTop1MinPoints", StringComparison.OrdinalIgnoreCase))
					{
						_rules.RewardTop1MinPoints = Mathf.Max(0, ParseInt(text4, _rules.RewardTop1MinPoints));
					}
					else if (text3.Equals("RewardTop1Label", StringComparison.OrdinalIgnoreCase))
					{
						_rules.RewardTop1Label = SafeLimit(text4, 96);
					}
					else if (text3.Equals("RewardTop1Prefab", StringComparison.OrdinalIgnoreCase))
					{
						_rules.RewardTop1Prefab = SafeLimit(text4, 96);
					}
					else if (text3.Equals("RewardTop1Amount", StringComparison.OrdinalIgnoreCase))
					{
						_rules.RewardTop1Amount = Mathf.Max(0, ParseInt(text4, _rules.RewardTop1Amount));
					}
					else if (text3.Equals("RewardTop2MinPoints", StringComparison.OrdinalIgnoreCase))
					{
						_rules.RewardTop2MinPoints = Mathf.Max(0, ParseInt(text4, _rules.RewardTop2MinPoints));
					}
					else if (text3.Equals("RewardTop2Label", StringComparison.OrdinalIgnoreCase))
					{
						_rules.RewardTop2Label = SafeLimit(text4, 96);
					}
					else if (text3.Equals("RewardTop2Prefab", StringComparison.OrdinalIgnoreCase))
					{
						_rules.RewardTop2Prefab = SafeLimit(text4, 96);
					}
					else if (text3.Equals("RewardTop2Amount", StringComparison.OrdinalIgnoreCase))
					{
						_rules.RewardTop2Amount = Mathf.Max(0, ParseInt(text4, _rules.RewardTop2Amount));
					}
					else if (text3.Equals("RewardTop3MinPoints", StringComparison.OrdinalIgnoreCase))
					{
						_rules.RewardTop3MinPoints = Mathf.Max(0, ParseInt(text4, _rules.RewardTop3MinPoints));
					}
					else if (text3.Equals("RewardTop3Label", StringComparison.OrdinalIgnoreCase))
					{
						_rules.RewardTop3Label = SafeLimit(text4, 96);
					}
					else if (text3.Equals("RewardTop3Prefab", StringComparison.OrdinalIgnoreCase))
					{
						_rules.RewardTop3Prefab = SafeLimit(text4, 96);
					}
					else if (text3.Equals("RewardTop3Amount", StringComparison.OrdinalIgnoreCase))
					{
						_rules.RewardTop3Amount = Mathf.Max(0, ParseInt(text4, _rules.RewardTop3Amount));
					}
					else if (text3.StartsWith("KillPoints.", StringComparison.OrdinalIgnoreCase))
					{
						string text5 = SafeKey(text3.Substring("KillPoints.".Length));
						if (!IsFishPrefab(text5))
						{
							_rules.KillPoints[text5] = ParseInt(text4, 0);
						}
					}
					else if (text3.StartsWith("BossPoints.", StringComparison.OrdinalIgnoreCase))
					{
						_rules.BossPoints[NormalizeBossPrefabName(text3.Substring("BossPoints.".Length))] = ParseInt(text4, 0);
					}
					else if (text3.StartsWith("FishingPoints.", StringComparison.OrdinalIgnoreCase))
					{
						string text6 = NormalizeFishPrefabName(text3.Substring("FishingPoints.".Length));
						if (IsFishPrefab(text6))
						{
							_rules.FishingPoints[text6] = ParseInt(text4, 0);
						}
					}
				}
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("Erro ao carregar regras do ranking: " + ex));
			}
		}

		private bool ParseBool(string raw, bool fallback)
		{
			bool result;
			return bool.TryParse(raw, out result) ? result : fallback;
		}

		private int ParseInt(string raw, int fallback)
		{
			int result;
			return int.TryParse(raw, out result) ? result : fallback;
		}

		private void InitializeSyncedRulesConfig()
		{
			try
			{
				string filePath = Path.Combine(Paths.ConfigPath, "glitnir.ranking.rules.cfg");
				Dictionary<string, string> dictionary = LoadLegacyRulesOverrides(filePath);
				MergeSectionOverrides(dictionary, LoadSectionRulesOverrides(filePath));
				_rulesConfig = ((BaseUnityPlugin)this).Config;
				BindSyncedRulesConfigEntries(dictionary);
				ApplyRulesFromSyncedConfig();
				_rulesConfig.Save();
				CleanupFishKillPointConfigEntries();
				RewriteRulesConfigHeaderAndGroupedSections();
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("Erro ao inicializar config sincronizada do ranking: " + ex));
				EnsureRulesFileExists();
				LoadRules();
			}
		}

		private void SetupRulesConfigWatcher()
		{
			try
			{
				if (!string.IsNullOrWhiteSpace(_rulesFilePath))
				{
					string directoryName = Path.GetDirectoryName(_rulesFilePath);
					string fileName = Path.GetFileName(_rulesFilePath);
					if (!string.IsNullOrWhiteSpace(directoryName) && !string.IsNullOrWhiteSpace(fileName))
					{
						_rulesConfigWatcher = new FileSystemWatcher(directoryName, fileName);
						_rulesConfigWatcher.NotifyFilter = NotifyFilters.FileName | NotifyFilters.Size | NotifyFilters.LastWrite | NotifyFilters.CreationTime;
						_rulesConfigWatcher.Changed += OnRulesConfigFileChanged;
						_rulesConfigWatcher.Created += OnRulesConfigFileChanged;
						_rulesConfigWatcher.Renamed += OnRulesConfigFileChanged;
						_rulesConfigWatcher.EnableRaisingEvents = true;
					}
				}
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Não foi possível iniciar watcher da config do ranking: " + ex.Message));
			}
		}

		private void OnRulesConfigFileChanged(object sender, FileSystemEventArgs args)
		{
			_rulesConfigReloadQueued = true;
			_rulesConfigReloadAt = Time.realtimeSinceStartup + 0.5f;
		}

		private void ProcessRulesConfigReloadIfNeeded()
		{
			if (!_rulesConfigReloadQueued || Time.realtimeSinceStartup < _rulesConfigReloadAt)
			{
				return;
			}
			_rulesConfigReloadQueued = false;
			try
			{
				ConfigFile rulesConfig = _rulesConfig;
				if (rulesConfig != null)
				{
					rulesConfig.Reload();
				}
				BindSyncedRulesConfigEntries(null);
				ApplyRulesFromSyncedConfig();
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("Erro ao recarregar config do ranking: " + ex));
			}
		}

		private void RefreshRulesFromSyncedConfigIfNeeded()
		{
			if (!(Time.realtimeSinceStartup < _rulesConfigApplyAt))
			{
				_rulesConfigApplyAt = Time.realtimeSinceStartup + 1f;
				ApplyRulesFromSyncedConfig();
			}
		}

		private Dictionary<string, string> LoadLegacyRulesOverrides(string filePath)
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
			try
			{
				if (string.IsNullOrWhiteSpace(filePath) || !File.Exists(filePath))
				{
					return dictionary;
				}
				bool flag = false;
				string[] array = File.ReadAllLines(filePath, Encoding.UTF8);
				foreach (string text in array)
				{
					string text2 = text.Trim();
					if (text2.StartsWith("[") && text2.EndsWith("]"))
					{
						flag = true;
						break;
					}
				}
				if (flag)
				{
					return dictionary;
				}
				string[] array2 = File.ReadAllLines(filePath, Encoding.UTF8);
				foreach (string text3 in array2)
				{
					string text4 = text3.Trim();
					if (string.IsNullOrWhiteSpace(text4) || text4.StartsWith("#") || text4.StartsWith(";") || text4.StartsWith("//"))
					{
						continue;
					}
					int num = text4.IndexOf('=');
					if (num > 0)
					{
						string text5 = text4.Substring(0, num).Trim();
						string value = text4.Substring(num + 1).Trim();
						if (!string.IsNullOrWhiteSpace(text5))
						{
							dictionary[text5] = value;
						}
					}
				}
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Falha ao ler overrides legados da config do ranking: " + ex.Message));
			}
			return dictionary;
		}

		private void MergeSectionOverrides(Dictionary<string, string> target, Dictionary<string, string> source)
		{
			if (target == null || source == null)
			{
				return;
			}
			foreach (KeyValuePair<string, string> item in source)
			{
				if (!string.IsNullOrWhiteSpace(item.Key))
				{
					target[item.Key] = item.Value;
				}
			}
		}

		private Dictionary<string, string> LoadSectionRulesOverrides(string filePath)
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
			try
			{
				if (string.IsNullOrWhiteSpace(filePath) || !File.Exists(filePath))
				{
					return dictionary;
				}
				string text = string.Empty;
				HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "BossPoints", "FishingPoints", "KillPoints", "CraftPoints", "FarmJackpots", "UniqueCraftJackpots", "SkillMilestoneJackpotPoints", "DeathPenalty", "ExplorationMapJackpots" };
				string[] array = File.ReadAllLines(filePath, Encoding.UTF8);
				foreach (string text2 in array)
				{
					string text3 = ((text2 != null) ? text2.Trim() : string.Empty);
					if (string.IsNullOrWhiteSpace(text3) || text3.StartsWith("#") || text3.StartsWith(";") || text3.StartsWith("//"))
					{
						continue;
					}
					if (text3.StartsWith("[") && text3.EndsWith("]"))
					{
						text = SafeKey(text3.Substring(1, text3.Length - 2));
						continue;
					}
					int num = text3.IndexOf('=');
					if (num <= 0)
					{
						continue;
					}
					string text4 = text3.Substring(0, num).Trim();
					string value = text3.Substring(num + 1).Trim();
					if (string.IsNullOrWhiteSpace(text4))
					{
						continue;
					}
					string text5 = text4;
					if (!text4.Contains(".") && !string.IsNullOrWhiteSpace(text))
					{
						text5 = text + "." + text4;
					}
					int num2 = text5.IndexOf('.');
					if (num2 > 0)
					{
						string text6 = text5.Substring(0, num2).Trim();
						string text7 = SafeKey(text5.Substring(num2 + 1));
						if (hashSet.Contains(text6) && !string.IsNullOrWhiteSpace(text7) && (!text6.Equals("KillPoints", StringComparison.OrdinalIgnoreCase) || !IsFishPrefab(text7)))
						{
							dictionary[text6 + "." + text7] = value;
						}
					}
				}
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Falha ao ler entradas dinâmicas da config do ranking: " + ex.Message));
			}
			return dictionary;
		}

		private bool IsLegacyRulesFileFormat(string filePath)
		{
			try
			{
				if (string.IsNullOrWhiteSpace(filePath) || !File.Exists(filePath))
				{
					return false;
				}
				string[] array = File.ReadAllLines(filePath, Encoding.UTF8);
				foreach (string text in array)
				{
					string text2 = text.Trim();
					if (!string.IsNullOrWhiteSpace(text2) && !text2.StartsWith("#") && !text2.StartsWith(";") && !text2.StartsWith("//"))
					{
						return !text2.StartsWith("[") || !text2.EndsWith("]");
					}
				}
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Falha ao detectar formato legado da config do ranking: " + ex.Message));
			}
			return false;
		}

		private void BindSyncedRulesConfigEntries(Dictionary<string, string> legacyOverrides)
		{
			if (_rulesConfig != null)
			{
				legacyOverrides = legacyOverrides ?? new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
				RankingRules rankingRules = new RankingRules();
				_cfgRankingEnabled = _rulesConfig.BindConfig("General", "RankingEnabled", ReadLegacyBool(legacyOverrides, "RankingEnabled", rankingRules.RankingEnabled), "Ativa o sistema de ranking.");
				_cfgEnableKillPoints = _rulesConfig.BindConfig("General", "EnableKillPoints", ReadLegacyBool(legacyOverrides, "EnableKillPoints", rankingRules.EnableKillPoints), "Ativa a pontuação por criaturas normais.");
				_cfgEnableBossPoints = _rulesConfig.BindConfig("General", "EnableBossPoints", ReadLegacyBool(legacyOverrides, "EnableBossPoints", rankingRules.EnableBossPoints), "Ativa a pontuação por bosses e minibosses.");
				_cfgDefaultKillPoints = _rulesConfig.BindConfig("General", "DefaultKillPoints", ReadLegacyInt(legacyOverrides, "DefaultKillPoints", rankingRules.DefaultKillPoints), "Pontos padrão para kills sem regra específica.");
				_cfgTopCount = _rulesConfig.BindConfig("General", "TopCount", ReadLegacyInt(legacyOverrides, "TopCount", rankingRules.TopCount), "Quantidade de jogadores exibidos no topo do ranking.");
				_cfgAllowRepeatedBossPoints = _rulesConfig.BindConfig("General", "AllowRepeatedBossPoints", ReadLegacyBool(legacyOverrides, "AllowRepeatedBossPoints", rankingRules.AllowRepeatedBossPoints), "Permite pontuar boss repetido.");
				_cfgEnableSkillPoints = _rulesConfig.BindConfig("General", "EnableSkillPoints", ReadLegacyBool(legacyOverrides, "EnableSkillPoints", rankingRules.EnableSkillPoints), "Ativa jackpots por marcos de skill.");
				_cfgIgnoreTamedKills = _rulesConfig.BindConfig("General", "IgnoreTamedKills", ReadLegacyBool(legacyOverrides, "IgnoreTamedKills", rankingRules.IgnoreTamedKills), "Ignora pontos por matar criaturas domadas.");
				_cfgEnableMarketplaceQuestPoints = _rulesConfig.BindConfig("General", "EnableMarketplaceQuestPoints", ReadLegacyBool(legacyOverrides, "EnableMarketplaceQuestPoints", rankingRules.EnableMarketplaceQuestPoints), "Ativa pontuação por conclusão de quests do Marketplace.");
				_cfgEnableFishingPoints = _rulesConfig.BindConfig("General", "EnableFishingPoints", ReadLegacyBool(legacyOverrides, "EnableFishingPoints", rankingRules.EnableFishingPoints), "Ativa pontuação própria por pesca.");
				_cfgEnableDeathPenalty = _rulesConfig.BindConfig("General", "EnableDeathPenalty", ReadLegacyBool(legacyOverrides, "EnableDeathPenalty", rankingRules.EnableDeathPenalty), "Ativa penalidade por morte no ranking.");
				_cfgDebugLogging = _rulesConfig.BindConfig("Logging", "DebugLogging", ReadLegacyBool(legacyOverrides, "DebugLogging", rankingRules.DebugLogging), "Ativa logs de depuração.");
				_cfgLogHitReports = _rulesConfig.BindConfig("Logging", "LogHitReports", ReadLegacyBool(legacyOverrides, "LogHitReports", rankingRules.LogHitReports), "Ativa logs de hit reports.");
				_cfgLogKillReports = _rulesConfig.BindConfig("Logging", "LogKillReports", ReadLegacyBool(legacyOverrides, "LogKillReports", rankingRules.LogKillReports), "Ativa logs de kill reports.");
				_cfgLogSkillReports = _rulesConfig.BindConfig("Logging", "LogSkillReports", ReadLegacyBool(legacyOverrides, "LogSkillReports", rankingRules.LogSkillReports), "Ativa logs de skill reports.");
				_cfgLogPendingKillReports = _rulesConfig.BindConfig("Logging", "LogPendingKillReports", ReadLegacyBool(legacyOverrides, "LogPendingKillReports", rankingRules.LogPendingKillReports), "Ativa logs das checagens pendentes de kill.");
				_cfgLogSnapshotRequests = _rulesConfig.BindConfig("Logging", "LogSnapshotRequests", ReadLegacyBool(legacyOverrides, "LogSnapshotRequests", rankingRules.LogSnapshotRequests), "Ativa logs de snapshots do ranking.");
				_cfgLogPointsChanges = _rulesConfig.BindConfig("Logging", "LogPointsChanges", ReadLegacyBool(legacyOverrides, "LogPointsChanges", rankingRules.LogPointsChanges), "Ativa logs de alterações de pontos.");
				_cfgRewardClaimsEnabled = _rulesConfig.BindConfig("Rewards", "RewardClaimsEnabled", ReadLegacyBool(legacyOverrides, "RewardClaimsEnabled", rankingRules.RewardClaimsEnabled), "Ativa o resgate de recompensas no HUD.");
				_cfgRewardClaimCycleId = _rulesConfig.BindConfig("Rewards", "RewardClaimCycleId", ReadLegacyString(legacyOverrides, "RewardClaimCycleId", rankingRules.RewardClaimCycleId), "Identificador do ciclo atual de recompensas.");
				_cfgRewardTop1MinPoints = _rulesConfig.BindConfig("Rewards", "RewardTop1MinPoints", ReadLegacyInt(legacyOverrides, "RewardTop1MinPoints", rankingRules.RewardTop1MinPoints), "Pontos mínimos para o Top 1 resgatar.");
				_cfgRewardTop1Label = _rulesConfig.BindConfig("Rewards", "RewardTop1Label", ReadLegacyString(legacyOverrides, "RewardTop1Label", rankingRules.RewardTop1Label), "Texto exibido para a recompensa do Top 1.");
				_cfgRewardTop1Prefab = _rulesConfig.BindConfig("Rewards", "RewardTop1Prefab", ReadLegacyString(legacyOverrides, "RewardTop1Prefab", rankingRules.RewardTop1Prefab), "Prefab do item entregue ao Top 1.");
				_cfgRewardTop1Amount = _rulesConfig.BindConfig("Rewards", "RewardTop1Amount", ReadLegacyInt(legacyOverrides, "RewardTop1Amount", rankingRules.RewardTop1Amount), "Quantidade do item entregue ao Top 1.");
				_cfgRewardTop2MinPoints = _rulesConfig.BindConfig("Rewards", "RewardTop2MinPoints", ReadLegacyInt(legacyOverrides, "RewardTop2MinPoints", rankingRules.RewardTop2MinPoints), "Pontos mínimos para o Top 2 resgatar.");
				_cfgRewardTop2Label = _rulesConfig.BindConfig("Rewards", "RewardTop2Label", ReadLegacyString(legacyOverrides, "RewardTop2Label", rankingRules.RewardTop2Label), "Texto exibido para a recompensa do Top 2.");
				_cfgRewardTop2Prefab = _rulesConfig.BindConfig("Rewards", "RewardTop2Prefab", ReadLegacyString(legacyOverrides, "RewardTop2Prefab", rankingRules.RewardTop2Prefab), "Prefab do item entregue ao Top 2.");
				_cfgRewardTop2Amount = _rulesConfig.BindConfig("Rewards", "RewardTop2Amount", ReadLegacyInt(legacyOverrides, "RewardTop2Amount", rankingRules.RewardTop2Amount), "Quantidade do item entregue ao Top 2.");
				_cfgRewardTop3MinPoints = _rulesConfig.BindConfig("Rewards", "RewardTop3MinPoints", ReadLegacyInt(legacyOverrides, "RewardTop3MinPoints", rankingRules.RewardTop3MinPoints), "Pontos mínimos para o Top 3 resgatar.");
				_cfgRewardTop3Label = _rulesConfig.BindConfig("Rewards", "RewardTop3Label", ReadLegacyString(legacyOverrides, "RewardTop3Label", rankingRules.RewardTop3Label), "Texto exibido para a recompensa do Top 3.");
				_cfgRewardTop3Prefab = _rulesConfig.BindConfig("Rewards", "RewardTop3Prefab", ReadLegacyString(legacyOverrides, "RewardTop3Prefab", rankingRules.RewardTop3Prefab), "Prefab do item entregue ao Top 3.");
				_cfgRewardTop3Amount = _rulesConfig.BindConfig("Rewards", "RewardTop3Amount", ReadLegacyInt(legacyOverrides, "RewardTop3Amount", rankingRules.RewardTop3Amount), "Quantidade do item entregue ao Top 3.");
				_cfgPointsExchangeEnabled = _rulesConfig.BindConfig("PointsExchange", "Enabled", ReadLegacyBool(legacyOverrides, "PointsExchangeEnabled", rankingRules.PointsExchangeEnabled), "Ativa o botão de câmbio de pontos por moedas no HUD.");
				_cfgPointsExchangePrefab = _rulesConfig.BindConfig("PointsExchange", "Prefab", ReadLegacyString(legacyOverrides, "PointsExchangePrefab", rankingRules.PointsExchangePrefab), "Prefab entregue no câmbio de pontos. Exemplo: Coins.");
				_cfgPointsExchangeCoinsPerPoint = _rulesConfig.BindConfig("PointsExchange", "CoinsPerPoint", ReadLegacyInt(legacyOverrides, "PointsExchangeCoinsPerPoint", rankingRules.PointsExchangeCoinsPerPoint), "Quantidade de moedas entregues por cada ponto trocado.");
				_cfgPointsExchangeMinPoints = _rulesConfig.BindConfig("PointsExchange", "MinPoints", ReadLegacyInt(legacyOverrides, "PointsExchangeMinPoints", rankingRules.PointsExchangeMinPoints), "Valor legado. O câmbio não exige requisito mínimo; basta o jogador ter pontos disponíveis.");
				_cfgPointsExchangeMaxPointsPerRequest = _rulesConfig.BindConfig("PointsExchange", "MaxPointsPerRequest", ReadLegacyInt(legacyOverrides, "PointsExchangeMaxPointsPerRequest", rankingRules.PointsExchangeMaxPointsPerRequest), "Máximo de pontos convertidos por clique. Use 0 para trocar todos.");
				_cfgMarketplaceQuestPointMap = _rulesConfig.BindConfig("MarketplaceQuestPoints", "QuestPointMap", BuildMarketplaceQuestPointMapDefault(legacyOverrides), "Formato: questId:pontos separados por vírgula. Ex: ccq_b21:450,ccq_b22:150");
				_cfgDeathPenaltyRules = _rulesConfig.BindConfig("DeathPenalty", "Rules", ReadLegacyString(legacyOverrides, "DeathPenalty.Rules", ReadLegacyString(legacyOverrides, "DeathPenaltyRules", "1:0,2:100,5:300,10:800")), "Penalidade por morte em marcos. Formato: mortes:pontosPerdidos,mortes:pontosPerdidos. Exemplo: 1:0,2:100,5:300,10:800");
				_cfgDeathPenaltyUseMultiplier = _rulesConfig.BindConfig("DeathPenalty", "UseMultiplierMode", ReadLegacyBool(legacyOverrides, "DeathPenalty.UseMultiplierMode", ReadLegacyBool(legacyOverrides, "DeathPenaltyUseMultiplier", fallback: false)), "Se true, ignora a tabela Rules e aplica PenaltyPerDeath a cada morte. Exemplo: 15 mortes x 100 = -1500.");
				_cfgDeathPenaltyPerDeath = _rulesConfig.BindConfig("DeathPenalty", "PenaltyPerDeath", Mathf.Max(0, ReadLegacyInt(legacyOverrides, "DeathPenalty.PenaltyPerDeath", ReadLegacyInt(legacyOverrides, "DeathPenaltyPerDeath", 100))), "Valor perdido por cada morte quando UseMultiplierMode=true.");
				_cfgEnableExplorationJackpots = _rulesConfig.BindConfig("ExplorationMapJackpots", "Enabled", ReadLegacyBool(legacyOverrides, "ExplorationMapJackpots.Enabled", fallback: true), "Ativa jackpots por porcentagem de mapa revelado.");
				_cfgExplorationMapJackpotRules = _rulesConfig.BindConfig("ExplorationMapJackpots", "Rules", ReadLegacyString(legacyOverrides, "ExplorationMapJackpots.Rules", ReadLegacyString(legacyOverrides, "ExplorationMapJackpotRules", "5:25;10:50;25:150;50:400;75:800;100:1500")), "Jackpots por porcentagem do mapa revelado. Formato: porcentagem:pontos;porcentagem:pontos. Exemplo: 5:25;10:50;25:150");
				BindCombatBiomeRuleEntries(legacyOverrides);
				_cfgProductionCategoryRules = _rulesConfig.BindConfig("HudCategories", "Production", ReadLegacyString(legacyOverrides, "HudCategories.Production", "Armas:SwordIron=800;Armaduras:HelmetBronze=800;Comidas:DeerStew=25"), "Producao/Conquistas por categoria COM pontos. O nome da categoria do config vira a aba do HUD. Formato obrigatorio: Categoria:Prefab=pontos,Prefab=pontos;Outra:Prefab=pontos. Exemplo: Armas:SwordIron=800;Armaduras:HelmetBronze=800;Comidas:DeerStew=25. Tambem organiza FarmJackpots e UniqueCraftJackpots.");
				BindPointSectionEntries("BossPoints", "Pontos por bosses e minibosses.", legacyOverrides, _cfgBossPointEntries);
				BindPointSectionEntries("FishingPoints", "Pontos por peixe pescado.", legacyOverrides, _cfgFishingPointEntries);
				BindStringPointSectionEntries("SkillMilestoneJackpotPoints", "Pontos únicos por marco de skill. Formato: 20:500,40:1000,60:2000,80:3000,100:4000.", legacyOverrides, _cfgSkillMilestoneJackpotPointEntries);
				_cfgFarmJackpotRules = _rulesConfig.BindConfig("FarmJackpots", "Rules", ReadGroupedRulesDefault(legacyOverrides, "FarmJackpots", "Carrot:200:1000;Turnip:200:1200;Onion:200:1500;Barley:500:2000;Flax:500:2000"), "Jackpots de colheita. Edite somente esta linha. Formato: Prefab:quantidade:pontos;Prefab:quantidade:pontos. Exemplo: Carrot:200:1000;Barley:500:2000.");
				_cfgUniqueCraftJackpotRules = _rulesConfig.BindConfig("UniqueCraftJackpots", "Rules", ReadGroupedRulesDefault(legacyOverrides, "UniqueCraftJackpots", "SwordIron:1:800;SwordSilver:1:1500;SwordBlackmetal:1:2500;ArmorWolfChest:1:2000;ArmorCarapaceChest:1:3500"), "Jackpot único por craft. Edite somente esta linha. Formato: Prefab:quantidade:pontos;Prefab:quantidade:pontos. Exemplo: SwordIron:1:800;ArmorWolfChest:1:2000.");
			}
		}

		private void BindCombatBiomeRuleEntries(Dictionary<string, string> legacyOverrides)
		{
			if (_cfgCombatBiomeRuleEntries != null)
			{
				_cfgCombatBiomeRuleEntries.Clear();
				Dictionary<string, string> defaults = ParseCombatBiomeDefaults("Prados:Boar:1,Deer:1,Neck:1;Floresta Negra:Greydwarf:1,Greydwarf_Elite:2,Greydwarf_Shaman:2,Troll:5;Pântano:Draugr:2,Draugr_Elite:3,Blob:2,Abomination:8;Montanha:Wolf:2,Hatchling:2,StoneGolem:8;Planícies:Goblin:3,GoblinBrute:5,Lox:6,Deathsquito:3;Oceano:Serpent:6;Mistlands:Seeker:4,SeekerBrute:8,Gjall:10;Ashlands:Charred_Melee:4,Charred_Archer:4,Volture:4;Especiais:Haldor:0");
				BindSingleCombatBiome("Prados", defaults, legacyOverrides);
				BindSingleCombatBiome("Floresta Negra", defaults, legacyOverrides);
				BindSingleCombatBiome("Pântano", defaults, legacyOverrides);
				BindSingleCombatBiome("Montanha", defaults, legacyOverrides);
				BindSingleCombatBiome("Planícies", defaults, legacyOverrides);
				BindSingleCombatBiome("Oceano", defaults, legacyOverrides);
				BindSingleCombatBiome("Mistlands", defaults, legacyOverrides);
				BindSingleCombatBiome("Ashlands", defaults, legacyOverrides);
				BindSingleCombatBiome("Especiais", defaults, legacyOverrides);
			}
		}

		private void BindSingleCombatBiome(string category, Dictionary<string, string> defaults, Dictionary<string, string> legacyOverrides)
		{
			if (defaults == null || !defaults.TryGetValue(category, out var value))
			{
				value = string.Empty;
			}
			string value2 = ReadLegacyString(legacyOverrides, "Combat." + category, value);
			_cfgCombatBiomeRuleEntries[category] = _rulesConfig.BindConfig("Combat", category, value2, "Mobs e pontos para esta aba do HUD. Formato: Prefab;Pontos,OutroPrefab;Pontos. Exemplo: Boar;2,Deer;3. Aceita qualquer prefab, inclusive de mods. O nome desta chave vira a categoria no HUD.");
		}

		private Dictionary<string, string> ParseCombatBiomeDefaults(string raw)
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
			if (string.IsNullOrWhiteSpace(raw))
			{
				return dictionary;
			}
			string[] array = raw.Split(new char[3] { ';', '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
			string[] array2 = array;
			foreach (string text in array2)
			{
				string text2 = ((text != null) ? text.Trim() : string.Empty);
				if (string.IsNullOrWhiteSpace(text2))
				{
					continue;
				}
				int num = text2.IndexOf(':');
				if (num <= 0 || num >= text2.Length - 1)
				{
					continue;
				}
				string text3 = NormalizeHudCategoryName(text2.Substring(0, num).Trim());
				string text4 = text2.Substring(num + 1).Trim();
				if (string.IsNullOrWhiteSpace(text3) || string.IsNullOrWhiteSpace(text4))
				{
					continue;
				}
				List<string> list = new List<string>();
				string[] array3 = text4.Split(new char[2] { ',', '|' }, StringSplitOptions.RemoveEmptyEntries);
				string[] array4 = array3;
				foreach (string itemRaw in array4)
				{
					if (TryParseCombatBiomeItem(itemRaw, out var prefab, out var points))
					{
						list.Add(prefab + ";" + Mathf.Max(0, points));
					}
				}
				dictionary[text3] = string.Join(",", list.ToArray());
			}
			return dictionary;
		}

		private string BuildCombatCategoryRulesFromBiomeEntries()
		{
			if (_cfgCombatBiomeRuleEntries == null || _cfgCombatBiomeRuleEntries.Count == 0)
			{
				return string.Empty;
			}
			StringBuilder stringBuilder = new StringBuilder();
			foreach (KeyValuePair<string, ConfigEntry<string>> cfgCombatBiomeRuleEntry in _cfgCombatBiomeRuleEntries)
			{
				if (cfgCombatBiomeRuleEntry.Value == null)
				{
					continue;
				}
				string value = NormalizeHudCategoryName(cfgCombatBiomeRuleEntry.Key);
				if (string.IsNullOrWhiteSpace(value))
				{
					continue;
				}
				string value2 = ConvertCombatBiomeItemsToHudCategoryItems(cfgCombatBiomeRuleEntry.Value.Value);
				if (!string.IsNullOrWhiteSpace(value2))
				{
					if (stringBuilder.Length > 0)
					{
						stringBuilder.Append(';');
					}
					stringBuilder.Append(value);
					stringBuilder.Append(':');
					stringBuilder.Append(value2);
				}
			}
			return stringBuilder.ToString();
		}

		private string ConvertCombatBiomeItemsToHudCategoryItems(string raw)
		{
			if (string.IsNullOrWhiteSpace(raw))
			{
				return string.Empty;
			}
			List<string> list = new List<string>();
			string[] array = raw.Split(new char[4] { ',', '|', '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
			string[] array2 = array;
			foreach (string itemRaw in array2)
			{
				if (TryParseCombatBiomeItem(itemRaw, out var prefab, out var points))
				{
					list.Add(prefab + ":" + Mathf.Max(0, points));
				}
			}
			return string.Join(",", list.ToArray());
		}

		private bool TryParseCombatBiomeItem(string itemRaw, out string prefab, out int points)
		{
			prefab = string.Empty;
			points = 0;
			if (string.IsNullOrWhiteSpace(itemRaw))
			{
				return false;
			}
			string text = itemRaw.Trim();
			int num = text.LastIndexOf(';');
			if (num <= 0)
			{
				num = text.LastIndexOf('=');
			}
			if (num <= 0)
			{
				num = text.LastIndexOf(':');
			}
			if (num <= 0 || num >= text.Length - 1)
			{
				return false;
			}
			string value = text.Substring(0, num).Trim();
			string s = text.Substring(num + 1).Trim();
			if (!int.TryParse(s, out var result))
			{
				return false;
			}
			prefab = SafeKey(value);
			points = Mathf.Max(0, result);
			return !string.IsNullOrWhiteSpace(prefab);
		}

		private void RewriteRulesConfigHeaderAndGroupedSections()
		{
			try
			{
				if (string.IsNullOrWhiteSpace(_rulesFilePath) || !File.Exists(_rulesFilePath))
				{
					return;
				}
				string[] array = File.ReadAllLines(_rulesFilePath, Encoding.UTF8);
				List<string> list = new List<string>(array.Length + 40);
				string a = string.Empty;
				bool flag = false;
				HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "KillPoints", "CraftPoints", "FarmJackpots", "UniqueCraftJackpots", "DeathPenalty", "ExplorationMapJackpots" };
				list.Add("## Glitnir Ranking - Regras de pontuação");
				list.Add("##");
				list.Add("## Edite este arquivo no servidor. As regras marcadas como synced são enviadas aos clientes.");
				list.Add("##");
				list.Add("## Combate fica em [Combat], uma chave por bioma/categoria, exatamente igual ao HUD.");
				list.Add("##   [Combat]");
				list.Add("##   Prados = Boar;2,Deer;3");
				list.Add("##   Floresta Negra = Troll;20,Greydwarf;1");
				list.Add("##   Pântano = Draugr;2,Blob;2");
				list.Add("##   [UniqueCraftJackpots]     Rules = Prefab:quantidade:pontos;Prefab:quantidade:pontos");
				list.Add("##   [DeathPenalty]            Rules = mortes:pontosPerdidos,mortes:pontosPerdidos");
				list.Add("##   [ExplorationMapJackpots]  Rules = porcentagem:pontos;porcentagem:pontos");
				list.Add("##");
				list.Add("## Exemplos de prefabs reais comuns:");
				list.Add("##   Carrot:200:1000");
				list.Add("##   SwordIron:1:800");
				list.Add("##   ArmorWolfChest:1:2000");
				list.Add("##   1:0,2:100,5:300,10:800");
				list.Add("##");
				list.Add("## Importante: se um item não pontuar, ative DebugLogging/LogPointsChanges e veja no log");
				list.Add("## o prefab detectado pelo ranking no momento do kill, craft ou colheita.");
				list.Add("");
				bool flag2 = false;
				bool flag3 = false;
				bool flag4 = false;
				bool flag5 = false;
				string[] array2 = array;
				foreach (string text in array2)
				{
					string text2 = ((text != null) ? text.Trim() : string.Empty);
					if (text2.StartsWith("## Glitnir Ranking - Regras de pontuação", StringComparison.OrdinalIgnoreCase) || (string.Equals(a, "HudCategories", StringComparison.OrdinalIgnoreCase) && text2.StartsWith("Combat", StringComparison.OrdinalIgnoreCase) && text2.IndexOf('=') > 0))
					{
						continue;
					}
					if (text2.StartsWith("[") && text2.EndsWith("]"))
					{
						string text3 = text2.Substring(1, text2.Length - 2).Trim();
						flag = hashSet.Contains(text3);
						a = text3;
						if (flag)
						{
							if (text3.Equals("FarmJackpots", StringComparison.OrdinalIgnoreCase) && !flag2)
							{
								AppendGroupedFarmSection(list);
								flag2 = true;
							}
							else if (text3.Equals("UniqueCraftJackpots", StringComparison.OrdinalIgnoreCase) && !flag3)
							{
								AppendGroupedUniqueCraftSection(list);
								flag3 = true;
							}
							else if (text3.Equals("DeathPenalty", StringComparison.OrdinalIgnoreCase) && !flag4)
							{
								AppendGroupedDeathPenaltySection(list);
								flag4 = true;
							}
							else if (text3.Equals("ExplorationMapJackpots", StringComparison.OrdinalIgnoreCase) && !flag5)
							{
								AppendGroupedExplorationMapSection(list);
								flag5 = true;
							}
						}
						else
						{
							list.Add(text);
						}
					}
					else if (!flag)
					{
						list.Add(text);
					}
				}
				if (!flag2)
				{
					AppendGroupedFarmSection(list);
				}
				if (!flag3)
				{
					AppendGroupedUniqueCraftSection(list);
				}
				if (!flag4)
				{
					AppendGroupedDeathPenaltySection(list);
				}
				if (!flag5)
				{
					AppendGroupedExplorationMapSection(list);
				}
				File.WriteAllLines(_rulesFilePath, list.ToArray(), Encoding.UTF8);
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("[Ranking] Falha ao organizar config do ranking: " + ex.Message));
			}
		}

		private void AppendGroupedFarmSection(List<string> lines)
		{
			lines.Add("");
			lines.Add("[FarmJackpots]");
			lines.Add("");
			lines.Add("## Jackpot de colheita por prefab configurado.");
			lines.Add("## Formato: Prefab:quantidade:pontos;Prefab:quantidade:pontos");
			lines.Add("## Exemplo: Carrot:200:1000;Barley:500:2000");
			lines.Add("Rules = " + ((_cfgFarmJackpotRules != null) ? SanitizeDelimitedJackpotRules(_cfgFarmJackpotRules.Value) : "Carrot:200:1000;Barley:500:2000"));
		}

		private void AppendGroupedUniqueCraftSection(List<string> lines)
		{
			lines.Add("");
			lines.Add("[UniqueCraftJackpots]");
			lines.Add("");
			lines.Add("## Jackpot único por craft de qualquer prefab configurado.");
			lines.Add("## Formato: Prefab:quantidade:pontos;Prefab:quantidade:pontos");
			lines.Add("## Exemplo: SwordIron:1:800;ArmorWolfChest:1:2000");
			lines.Add("Rules = " + ((_cfgUniqueCraftJackpotRules != null) ? SanitizeDelimitedJackpotRules(_cfgUniqueCraftJackpotRules.Value) : "SwordIron:1:800;ArmorWolfChest:1:2000"));
		}

		private void AppendGroupedDeathPenaltySection(List<string> lines)
		{
			lines.Add("");
			lines.Add("[DeathPenalty]");
			lines.Add("");
			lines.Add("## Penalidade por morte.");
			lines.Add("## UseMultiplierMode=false usa a tabela Rules abaixo.");
			lines.Add("## UseMultiplierMode=true ignora Rules e aplica PenaltyPerDeath para cada morte.");
			lines.Add("## Exemplo multiplicador: PenaltyPerDeath=100 e 15 mortes = -1500 pontos.");
			lines.Add("UseMultiplierMode = " + ((_cfgDeathPenaltyUseMultiplier != null) ? _cfgDeathPenaltyUseMultiplier.Value.ToString() : "false"));
			lines.Add("PenaltyPerDeath = " + ((_cfgDeathPenaltyPerDeath != null) ? Mathf.Max(0, _cfgDeathPenaltyPerDeath.Value).ToString() : "100"));
			lines.Add("");
			lines.Add("## Formato do modo tabela: mortes:pontosPerdidos,mortes:pontosPerdidos");
			lines.Add("## Exemplo: 1:0,2:100,5:300,10:800");
			lines.Add("Rules = " + ((_cfgDeathPenaltyRules != null) ? SanitizeDeathPenaltyRules(_cfgDeathPenaltyRules.Value) : "1:0,2:100,5:300,10:800"));
		}

		private void AppendGroupedExplorationMapSection(List<string> lines)
		{
			lines.Add("");
			lines.Add("[ExplorationMapJackpots]");
			lines.Add("");
			lines.Add("## Jackpot por porcentagem de mapa revelado.");
			lines.Add("## Formato: porcentagem:pontos;porcentagem:pontos");
			lines.Add("## Exemplo: 5:25;10:50;25:150;50:400;75:800;100:1500");
			lines.Add("Enabled = " + ((_cfgEnableExplorationJackpots != null) ? _cfgEnableExplorationJackpots.Value.ToString() : "true"));
			lines.Add("Rules = " + ((_cfgExplorationMapJackpotRules != null) ? _cfgExplorationMapJackpotRules.Value : "5:25;10:50;25:150;50:400;75:800;100:1500"));
		}

		private void CleanupFishKillPointConfigEntries()
		{
			try
			{
				if (string.IsNullOrWhiteSpace(_rulesFilePath) || !File.Exists(_rulesFilePath))
				{
					return;
				}
				string[] array = File.ReadAllLines(_rulesFilePath, Encoding.UTF8);
				List<string> list = new List<string>(array.Length);
				bool flag = false;
				bool flag2 = false;
				string[] array2 = array;
				foreach (string text in array2)
				{
					string text2 = ((text != null) ? text.Trim() : string.Empty);
					if (text2.StartsWith("[") && text2.EndsWith("]"))
					{
						flag = text2.Equals("[KillPoints]", StringComparison.OrdinalIgnoreCase);
					}
					int num = text2.IndexOf('=');
					if (num > 0)
					{
						string text3 = text2.Substring(0, num).Trim();
						string text4 = text3;
						if (text3.StartsWith("KillPoints.", StringComparison.OrdinalIgnoreCase))
						{
							text4 = text3.Substring("KillPoints.".Length).Trim();
						}
						else if (!flag)
						{
							text4 = null;
						}
						if (!string.IsNullOrWhiteSpace(text4) && IsFishPrefab(text4))
						{
							flag2 = true;
							continue;
						}
					}
					list.Add(text);
				}
				if (flag2)
				{
					File.WriteAllLines(_rulesFilePath, list.ToArray(), Encoding.UTF8);
				}
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("[Ranking] Falha ao limpar prefabs de peixe do config: " + ex.Message));
			}
		}

		private void CleanupGroupedProductionConfigEntries()
		{
			try
			{
				if (string.IsNullOrWhiteSpace(_rulesFilePath) || !File.Exists(_rulesFilePath))
				{
					return;
				}
				string[] array = File.ReadAllLines(_rulesFilePath, Encoding.UTF8);
				List<string> list = new List<string>(array.Length);
				string text = string.Empty;
				bool flag = false;
				HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "KillPoints", "CraftPoints", "FarmJackpots", "UniqueCraftJackpots", "DeathPenalty", "ExplorationMapJackpots" };
				string[] array2 = array;
				foreach (string text2 in array2)
				{
					string text3 = ((text2 != null) ? text2.Trim() : string.Empty);
					if (text3.StartsWith("[") && text3.EndsWith("]"))
					{
						text = text3.Substring(1, text3.Length - 2).Trim();
						list.Add(text2);
						continue;
					}
					int num = text3.IndexOf('=');
					if (num > 0 && hashSet.Contains(text))
					{
						string text4 = text3.Substring(0, num).Trim();
						bool flag2 = text4.Equals("Rules", StringComparison.OrdinalIgnoreCase);
						if (text.Equals("DeathPenalty", StringComparison.OrdinalIgnoreCase))
						{
							flag2 = flag2 || text4.Equals("UseMultiplierMode", StringComparison.OrdinalIgnoreCase) || text4.Equals("PenaltyPerDeath", StringComparison.OrdinalIgnoreCase);
						}
						else if (text.Equals("ExplorationMapJackpots", StringComparison.OrdinalIgnoreCase))
						{
							flag2 = flag2 || text4.Equals("Enabled", StringComparison.OrdinalIgnoreCase);
						}
						if (!flag2)
						{
							flag = true;
							continue;
						}
					}
					list.Add(text2);
				}
				if (flag)
				{
					File.WriteAllLines(_rulesFilePath, list.ToArray(), Encoding.UTF8);
				}
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("[Ranking] Falha ao reorganizar config de produção: " + ex.Message));
			}
		}

		private string BuildMarketplaceQuestPointMapDefault(Dictionary<string, string> legacyOverrides)
		{
			string text = ReadLegacyString(legacyOverrides, "MarketplaceQuestPoints.QuestPointMap", null);
			if (!string.IsNullOrWhiteSpace(text))
			{
				return SanitizeMarketplaceQuestPointMap(text);
			}
			text = ReadLegacyString(legacyOverrides, "QuestPointMap", null);
			if (!string.IsNullOrWhiteSpace(text))
			{
				return SanitizeMarketplaceQuestPointMap(text);
			}
			Dictionary<string, int> mergedDefaultPointEntries = GetMergedDefaultPointEntries("MarketplaceQuestPoints", legacyOverrides);
			if (mergedDefaultPointEntries.Count <= 0)
			{
				return "ccq_b21:450,ccq_b22:150";
			}
			return string.Join(",", from p in mergedDefaultPointEntries.OrderBy<KeyValuePair<string, int>, string>((KeyValuePair<string, int> p) => p.Key, StringComparer.OrdinalIgnoreCase)
				select SafeMarketplaceQuestKey(p.Key) + ":" + Mathf.Max(0, p.Value));
		}

		private Dictionary<string, int> ParseMarketplaceQuestPointMap(string raw)
		{
			Dictionary<string, int> dictionary = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
			if (string.IsNullOrWhiteSpace(raw))
			{
				return dictionary;
			}
			string[] array = raw.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries);
			string[] array2 = array;
			foreach (string text in array2)
			{
				string text2 = ((text != null) ? text.Trim() : string.Empty);
				if (string.IsNullOrWhiteSpace(text2))
				{
					continue;
				}
				string[] array3 = text2.Split(new char[1] { ':' }, 2, StringSplitOptions.None);
				if (array3.Length == 2)
				{
					string text3 = SafeMarketplaceQuestKey(array3[0]);
					if (!string.IsNullOrWhiteSpace(text3) && int.TryParse(array3[1].Trim(), out var result))
					{
						dictionary[text3] = result;
					}
				}
			}
			return dictionary;
		}

		private string SanitizeMarketplaceQuestPointMap(string raw)
		{
			Dictionary<string, int> dictionary = ParseMarketplaceQuestPointMap(raw);
			if (dictionary.Count <= 0)
			{
				return string.Empty;
			}
			return string.Join(",", from p in dictionary.OrderBy<KeyValuePair<string, int>, string>((KeyValuePair<string, int> p) => p.Key, StringComparer.OrdinalIgnoreCase)
				select p.Key + ":" + Mathf.Max(0, p.Value));
		}

		private Dictionary<int, int> ParseSkillMilestoneMap(string raw)
		{
			Dictionary<int, int> dictionary = new Dictionary<int, int>();
			if (string.IsNullOrWhiteSpace(raw))
			{
				return dictionary;
			}
			string[] array = raw.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries);
			string[] array2 = array;
			foreach (string text in array2)
			{
				string text2 = ((text != null) ? text.Trim() : string.Empty);
				if (!string.IsNullOrWhiteSpace(text2))
				{
					string[] array3 = text2.Split(new char[1] { ':' }, 2, StringSplitOptions.None);
					if (array3.Length == 2 && int.TryParse(array3[0].Trim(), out var result) && int.TryParse(array3[1].Trim(), out var result2))
					{
						result = Mathf.Clamp(result, 1, 100);
						dictionary[result] = Mathf.Max(0, result2);
					}
				}
			}
			return dictionary;
		}

		private string SanitizeSkillMilestoneMap(string raw)
		{
			Dictionary<int, int> dictionary = ParseSkillMilestoneMap(raw);
			if (dictionary.Count <= 0)
			{
				return string.Empty;
			}
			return string.Join(",", from p in dictionary
				orderby p.Key
				select p.Key + ":" + Mathf.Max(0, p.Value));
		}

		private JackpotRule ParseJackpotRule(string raw)
		{
			JackpotRule jackpotRule = new JackpotRule();
			if (string.IsNullOrWhiteSpace(raw))
			{
				return jackpotRule;
			}
			string[] array = raw.Split(new char[1] { ':' }, 2, StringSplitOptions.None);
			if (array.Length != 2)
			{
				return jackpotRule;
			}
			if (!int.TryParse(array[0].Trim(), out var result))
			{
				return jackpotRule;
			}
			if (!int.TryParse(array[1].Trim(), out var result2))
			{
				return jackpotRule;
			}
			jackpotRule.RequiredAmount = Mathf.Max(1, result);
			jackpotRule.Points = Mathf.Max(0, result2);
			return jackpotRule;
		}

		private string SanitizeJackpotRule(string raw)
		{
			JackpotRule jackpotRule = ParseJackpotRule(raw);
			if (jackpotRule == null || jackpotRule.RequiredAmount <= 0)
			{
				return "1:0";
			}
			return jackpotRule.RequiredAmount + ":" + Mathf.Max(0, jackpotRule.Points);
		}

		private string StripHudCategoryPointPart(string itemRaw)
		{
			if (string.IsNullOrWhiteSpace(itemRaw))
			{
				return "";
			}
			string text = itemRaw.Trim();
			int num = text.IndexOf('=');
			if (num > 0)
			{
				text = text.Substring(0, num).Trim();
			}
			int num2 = text.LastIndexOf(':');
			if (num2 > 0 && num2 < text.Length - 1)
			{
				string s = text.Substring(num2 + 1).Trim();
				if (int.TryParse(s, out var _))
				{
					text = text.Substring(0, num2).Trim();
				}
			}
			return SafeKey(text);
		}

		private bool TryParseHudCategoryPointItem(string itemRaw, out string prefab, out int points)
		{
			prefab = "";
			points = 0;
			if (string.IsNullOrWhiteSpace(itemRaw))
			{
				return false;
			}
			string text = itemRaw.Trim();
			int num = text.LastIndexOf('=');
			if (num <= 0)
			{
				num = text.LastIndexOf(':');
			}
			if (num <= 0 || num >= text.Length - 1)
			{
				return false;
			}
			string value = text.Substring(0, num).Trim();
			string s = text.Substring(num + 1).Trim();
			if (!int.TryParse(s, out var result))
			{
				return false;
			}
			prefab = SafeKey(value);
			points = Mathf.Max(0, result);
			return !string.IsNullOrWhiteSpace(prefab);
		}

		private Dictionary<string, string> ParseHudCategoryRules(string raw)
		{
			ParseHudCategorizedPointRules(raw, out var categories);
			return categories;
		}

		private static string NormalizeHudCategoryName(string category)
		{
			if (string.IsNullOrWhiteSpace(category))
			{
				return category;
			}
			string text = category.Trim();
			if (text.Equals("Arcos e Munições", StringComparison.OrdinalIgnoreCase) || text.Equals("Arcos e Municoes", StringComparison.OrdinalIgnoreCase) || text.Equals("Armas, Armaduras e Munições", StringComparison.OrdinalIgnoreCase) || text.Equals("Armas, Armaduras e Municoes", StringComparison.OrdinalIgnoreCase))
			{
				return "Armas";
			}
			if (text.Equals("Comidas e Consumíveis", StringComparison.OrdinalIgnoreCase) || text.Equals("Comidas e Consumiveis", StringComparison.OrdinalIgnoreCase) || text.Equals("Comidas e bebidas", StringComparison.OrdinalIgnoreCase))
			{
				return "Comidas";
			}
			return text;
		}

		private Dictionary<string, int> ParseHudCategorizedPointRules(string raw, out Dictionary<string, string> categories)
		{
			categories = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
			Dictionary<string, int> dictionary = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
			if (string.IsNullOrWhiteSpace(raw))
			{
				return dictionary;
			}
			string[] array = raw.Split(new char[3] { ';', '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
			string[] array2 = array;
			foreach (string text in array2)
			{
				string text2 = ((text != null) ? text.Trim() : "");
				if (string.IsNullOrWhiteSpace(text2))
				{
					continue;
				}
				int num = text2.IndexOf(':');
				if (num <= 0 || num >= text2.Length - 1)
				{
					continue;
				}
				string value = NormalizeHudCategoryName(text2.Substring(0, num).Trim());
				if (string.IsNullOrWhiteSpace(value))
				{
					continue;
				}
				string text3 = text2.Substring(num + 1);
				string[] array3 = text3.Split(new char[2] { ',', '|' }, StringSplitOptions.RemoveEmptyEntries);
				string[] array4 = array3;
				foreach (string itemRaw in array4)
				{
					string text4 = StripHudCategoryPointPart(itemRaw);
					if (!string.IsNullOrWhiteSpace(text4))
					{
						categories[text4] = value;
						if (TryParseHudCategoryPointItem(itemRaw, out var prefab, out var points))
						{
							dictionary[prefab] = points;
						}
					}
				}
			}
			return dictionary;
		}

		private Dictionary<string, int> ParseDelimitedPointRules(string raw)
		{
			Dictionary<string, int> dictionary = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
			if (string.IsNullOrWhiteSpace(raw))
			{
				return dictionary;
			}
			string[] array = raw.Split(new char[4] { ';', ',', '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
			string[] array2 = array;
			foreach (string text in array2)
			{
				string text2 = ((text != null) ? text.Trim() : string.Empty);
				if (string.IsNullOrWhiteSpace(text2))
				{
					continue;
				}
				string[] array3 = text2.Split(new char[1] { ':' }, 2, StringSplitOptions.None);
				if (array3.Length == 2)
				{
					string text3 = SafeKey(array3[0]);
					if (!string.IsNullOrWhiteSpace(text3) && int.TryParse(array3[1].Trim(), out var result))
					{
						dictionary[text3] = Mathf.Max(0, result);
					}
				}
			}
			return dictionary;
		}

		private Dictionary<string, JackpotRule> ParseDelimitedJackpotRules(string raw)
		{
			Dictionary<string, JackpotRule> dictionary = new Dictionary<string, JackpotRule>(StringComparer.OrdinalIgnoreCase);
			if (string.IsNullOrWhiteSpace(raw))
			{
				return dictionary;
			}
			string[] array = raw.Split(new char[4] { ';', ',', '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
			string[] array2 = array;
			foreach (string text in array2)
			{
				string text2 = ((text != null) ? text.Trim() : string.Empty);
				if (string.IsNullOrWhiteSpace(text2))
				{
					continue;
				}
				string[] array3 = text2.Split(new char[1] { ':' }, 3, StringSplitOptions.None);
				if (array3.Length == 3)
				{
					string text3 = SafeKey(array3[0]);
					if (!string.IsNullOrWhiteSpace(text3) && int.TryParse(array3[1].Trim(), out var result) && int.TryParse(array3[2].Trim(), out var result2))
					{
						dictionary[text3] = new JackpotRule
						{
							RequiredAmount = Mathf.Max(1, result),
							Points = Mathf.Max(0, result2)
						};
					}
				}
			}
			return dictionary;
		}

		private Dictionary<int, int> ParseDeathPenaltyRules(string raw)
		{
			Dictionary<int, int> dictionary = new Dictionary<int, int>();
			if (string.IsNullOrWhiteSpace(raw))
			{
				return dictionary;
			}
			string[] array = raw.Split(new char[4] { ',', ';', '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
			string[] array2 = array;
			foreach (string text in array2)
			{
				string text2 = ((text != null) ? text.Trim() : string.Empty);
				if (!string.IsNullOrWhiteSpace(text2))
				{
					string[] array3 = text2.Split(new char[1] { ':' }, 2, StringSplitOptions.None);
					if (array3.Length == 2 && int.TryParse(array3[0].Trim(), out var result) && int.TryParse(array3[1].Trim(), out var result2))
					{
						result = Mathf.Max(1, result);
						result2 = (dictionary[result] = Mathf.Max(0, result2));
					}
				}
			}
			return dictionary;
		}

		private string SanitizeDeathPenaltyRules(string raw)
		{
			Dictionary<int, int> dictionary = ParseDeathPenaltyRules(raw);
			if (dictionary.Count <= 0)
			{
				return string.Empty;
			}
			return string.Join(",", from p in dictionary
				orderby p.Key
				select Mathf.Max(1, p.Key) + ":" + Mathf.Max(0, p.Value));
		}

		private string SanitizeDelimitedPointRules(string raw)
		{
			return SanitizeDelimitedPointRules(raw, ";");
		}

		private string SanitizeDelimitedPointRules(string raw, string delimiter)
		{
			Dictionary<string, int> dictionary = ParseDelimitedPointRules(raw);
			if (dictionary.Count <= 0)
			{
				return string.Empty;
			}
			if (string.IsNullOrEmpty(delimiter))
			{
				delimiter = ";";
			}
			return string.Join(delimiter, from p in dictionary.OrderBy<KeyValuePair<string, int>, string>((KeyValuePair<string, int> p) => p.Key, StringComparer.OrdinalIgnoreCase)
				where !IsFishPrefab(p.Key)
				select p.Key + ":" + Mathf.Max(0, p.Value));
		}

		private string SanitizeDelimitedJackpotRules(string raw)
		{
			Dictionary<string, JackpotRule> dictionary = ParseDelimitedJackpotRules(raw);
			if (dictionary.Count <= 0)
			{
				return string.Empty;
			}
			return string.Join(";", from p in dictionary.OrderBy<KeyValuePair<string, JackpotRule>, string>((KeyValuePair<string, JackpotRule> p) => p.Key, StringComparer.OrdinalIgnoreCase)
				select p.Key + ":" + Mathf.Max(1, p.Value.RequiredAmount) + ":" + Mathf.Max(0, p.Value.Points));
		}

		private string ReadGroupedRul