using Newtonsoft.Json; using System; using System.Collections.Generic; using Oxide.Core.Plugins; using UnityEngine; /* * MajestatBuild 1.0.0 * ==================== * Moduł dla MajestatCore 3.0.0 — zlicza postawione konstrukcje. * * WYMAGA: MajestatCore 3.0.0+ * * Rejestruje zakładkę "BUILD" w UI MajestatCore przez API_RegisterTab. * * Śledzone statystyki: * Build.Total — wszystkie postawione obiekty łącznie * Build.Walls — ściany, drzwi, okna, ramy * Build.Floors — podłogi, schody, skośne podłogi * Build.Turrets — wieżyczki automatyczne (autoturret) * Build.Traps — pułapki (beartrap, landmine, shotguntrap, flameturret) * Build.Doors — drzwi * Build.Electrical — elementy elektryczne (solary, baterie, switche) * Build.Pipes — rury wodne i przemysłowe */ namespace Oxide.Plugins { [Info("MajestatTopBuild", "Wo0t", "1.0.1")] [Description("Build module for MajestatTopCore — tracks placed structures.")] class MajestatTopBuild : RustPlugin { [PluginReference] Plugin MajestatTopCore; private bool _registered = false; // Poziom logowania pobierany z Core (0=all 1=system 2=alert 3=none) private int _logLevel = 1; private void MLog(int level, string msg) { int effective = MajestatTopCore != null ? (int)(MajestatTopCore.Call("API_GetLogLevel") ?? 1) : _logLevel; if (level < effective) return; // Podczas AutoReload wycisz komunikaty systemowe (1) — Core drukuje summary if (level == 1 && MajestatTopCore != null) { var ar = MajestatTopCore.Call("API_IsAutoReloading"); if (ar is bool b && b) return; } if (level >= 2) PrintWarning(msg); else Puts(msg); } // ── Update checker ──────────────────────────────────────────── private const string PluginVersion = "1.0.1"; private const string PluginUpdateUrl = "http://download.koldrix.com/rust/plugins/MajestatTopBuild/version.json"; // ═════════════════════════════════════════════════════════════ // INIT // ═════════════════════════════════════════════════════════════ void OnServerInitialized() { if (MajestatTopCore == null) { PrintWarning("[MajestatTopBuild] MajestatTopCore nie jest załadowany! Moduł nieaktywny."); return; } if (!CheckMinVersion(MajestatTopCore.Version, 3, 0, 0)) { PrintError($"[MajestatTopBuild] Wymaga MajestatTopCore 3.0.0+. Zainstalowana: {MajestatTopCore.Version}. Moduł nieaktywny."); return; } RegisterTab(); } private static bool CheckMinVersion(Oxide.Core.VersionNumber v, int major, int minor, int patch) => v.Major > major || (v.Major == major && (v.Minor > minor || (v.Minor == minor && v.Patch >= patch))); void OnPluginLoaded(Plugin plugin) { if (plugin?.Name == "MajestatTopCore" && !_registered) { if (!CheckMinVersion(plugin.Version, 3, 0, 0)) { PrintError($"[MajestatTopBuild] Wymaga MajestatTopCore 3.0.0+. Zainstalowana: {plugin.Version}."); return; } RegisterTab(); } } void OnPluginUnloaded(Plugin plugin) { if (plugin?.Name == "MajestatTopCore") _registered = false; } void Unload() { if (MajestatTopCore != null && _registered) MajestatTopCore.Call("API_UnregisterTab", "build"); } // ═════════════════════════════════════════════════════════════ // REJESTRACJA ZAKŁADKI // ═════════════════════════════════════════════════════════════ private void RegisterTab() { if (MajestatTopCore == null) return; var columns = new List> { new Dictionary { ["key"] = "Build.Total", ["header"] = "TOTAL" }, new Dictionary { ["key"] = "Build.Walls", ["header"] = "ŚCIANY" }, new Dictionary { ["key"] = "Build.Floors", ["header"] = "PODŁOGI" }, new Dictionary { ["key"] = "Build.Doors", ["header"] = "DRZWI" }, new Dictionary { ["key"] = "Build.Turrets", ["header"] = "WIEŻYCZKI"}, new Dictionary { ["key"] = "Build.Traps", ["header"] = "PUŁAPKI" }, new Dictionary { ["key"] = "Build.Electrical", ["header"] = "ELEKTR." }, new Dictionary { ["key"] = "Build.Pipes", ["header"] = "RURY" }, }; var tabDef = new Dictionary { ["id"] = "build", ["label"] = "BUILD", ["sort"] = "Build.Total", ["fame_sort"] = "Build.Total", ["order"] = 20, // TOP PvP=0, Gather=10, Build=20 ["columns"] = columns }; bool ok = (bool)(MajestatTopCore.Call("API_RegisterTab", tabDef) ?? false); if (!ok) { PrintError("Rejestracja zakładki nie powiodła się."); return; } // Zarejestruj źródła XP — Core doda je do cfg jeśli nie istnieją. // Admin ustawia wartości XP w konfiguracji MajestatCore. MajestatTopCore.Call("API_RegisterXpSource", "Build.Walls", 0.0); MajestatTopCore.Call("API_RegisterXpSource", "Build.Floors", 0.0); MajestatTopCore.Call("API_RegisterXpSource", "Build.Doors", 0.0); MajestatTopCore.Call("API_RegisterXpSource", "Build.Turrets", 0.0); MajestatTopCore.Call("API_RegisterXpSource", "Build.Traps", 0.0); MajestatTopCore.Call("API_RegisterXpSource", "Build.Electrical", 0.0); MajestatTopCore.Call("API_RegisterXpSource", "Build.Pipes", 0.0); _registered = true; MajestatTopCore.Call("API_RegisterModule", new Dictionary { ["name"] = "MajestatTopBuild", ["version"] = PluginVersion, ["author"] = "Wo0t", ["description"] = "Build stats module" }); // startup log handled by Core } // ═════════════════════════════════════════════════════════════ // HOOK — POSTAWIENIE OBIEKTU // ═════════════════════════════════════════════════════════════ void OnEntityBuilt(Planner planner, GameObject go) { if (planner == null || go == null || MajestatTopCore == null) return; var player = planner.GetOwnerPlayer(); if (player == null) return; var entity = go.GetComponent(); if (entity == null) return; string prefab = entity.ShortPrefabName?.ToLower() ?? ""; string statKey = ResolveKey(prefab); if (statKey == null) return; // Dodaj do konkretnej kategorii (z XP jeśli skonfigurowane) MajestatTopCore.Call("API_AddStat", player.UserIDString, statKey, 1.0, true, true); // Dodaj do sumy (bez XP — żeby nie liczyć podwójnie) MajestatTopCore.Call("API_AddStat", player.UserIDString, "Build.Total", 1.0, true, false); MLog(0, $"BUILD: {player.displayName} postawił {prefab} → {statKey}"); } // ═════════════════════════════════════════════════════════════ // MAPOWANIE PREFAB → STATYSTYKA // ═════════════════════════════════════════════════════════════ private string ResolveKey(string prefab) { if (prefab == null) return null; // Ściany (wall, doorway, window, embrasure, wall.frame) if (prefab.Contains("wall") && !prefab.Contains("turret") && !prefab.Contains("fireplace")) return "Build.Walls"; // Podłogi i schody (floor, roof, stairs) if (prefab.Contains("floor") || prefab.Contains("roof") || prefab.Contains("stairs") || prefab.Contains("ramp")) return "Build.Floors"; // Drzwi (door, hatch, shutter) if (prefab.Contains("door") || prefab.Contains("hatch") || prefab.Contains("shutter")) return "Build.Doors"; // Wieżyczki automatyczne if (prefab.Contains("autoturret") || prefab.Contains("sam.site")) return "Build.Turrets"; // Pułapki (beartrap, landmine, shotguntrap, flameturret, guntrap) if (prefab.Contains("beartrap") || prefab.Contains("landmine") || prefab.Contains("shotguntrap") || prefab.Contains("flameturret") || prefab.Contains("guntrap") || prefab.Contains("spikes")) return "Build.Traps"; // Elektryka (solarpanel, battery, switch, generator, splitter, // combiner, blocker, xor, timer, counter, pressurepad, // sirenlight, strobelight, smartalarm, rf.broadcaster) if (prefab.Contains("electric") || prefab.Contains("solar") || prefab.Contains("battery") || prefab.Contains("switch") || prefab.Contains("generator") || prefab.Contains("splitter") || prefab.Contains("combiner") || prefab.Contains("blocker") || prefab.Contains("timer") || prefab.Contains("counter") || prefab.Contains("pressurepad") || prefab.Contains("sirenlight") || prefab.Contains("strobelight") || prefab.Contains("smartalarm") || prefab.Contains("rf.broadcaster") || prefab.Contains("rf.receiver") || prefab.Contains("igniter") || prefab.Contains("doorcontroller")) return "Build.Electrical"; // Rury i przemysł (water.pump, fluid.combiner, fluid.splitter, // industrial.conveyor, industrial.crafter) if (prefab.Contains("water.pump") || prefab.Contains("fluid") || prefab.Contains("industrial") || prefab.Contains("pipe") || prefab.Contains("sprinkler") || prefab.Contains("water.catcher")) return "Build.Pipes"; return null; } // ═════════════════════════════════════════════════════════════ // UPDATE CHECKER — synchronizowany przez MajestatTopCore // Core wywołuje hook OnMajestatUpdateCheck na wszystkich modułach // ═════════════════════════════════════════════════════════════ void OnMajestatUpdateCheck() { webrequest.Enqueue(PluginUpdateUrl, null, OnUpdateResponse, this); } private void OnUpdateResponse(int code, string response) { string pluginName = "MajestatTopBuild"; if (code == 0 || code >= 400 || string.IsNullOrEmpty(response)) { MLog(2, $"[Update] Nie można sprawdzić aktualizacji — serwer niedostępny (HTTP {code})."); MajestatTopCore?.Call("API_ReportUpdateResult", pluginName, null, null); return; } try { var data = Newtonsoft.Json.JsonConvert.DeserializeObject>(response); string latest = data != null && data.ContainsKey("version") ? data["version"].Trim() : null; if (latest != null && IsNewerVersion(latest, PluginVersion)) { string url = data.ContainsKey("url") ? data["url"] : PluginUpdateUrl; PrintWarning($"[Update] Dostępna nowsza wersja ({latest}) - Twoja wersja ({PluginVersion})"); MajestatTopCore?.Call("API_ReportUpdateResult", pluginName, latest, url); } else { MLog(1, $"[Update] Wersja aktualna ({PluginVersion}) — brak aktualizacji."); MajestatTopCore?.Call("API_ReportUpdateResult", pluginName, null, null); } } catch (Exception ex) { MLog(2, $"[Update] Błąd: {ex.Message}"); MajestatTopCore?.Call("API_ReportUpdateResult", pluginName, null, null); } } private bool IsNewerVersion(string latest, string current) { try { var l = System.Array.ConvertAll(latest.Split('.'), int.Parse); var c = System.Array.ConvertAll(current.Split('.'), int.Parse); int len = System.Math.Max(l.Length, c.Length); for (int i = 0; i < len; i++) { int lv = i < l.Length ? l[i] : 0; int cv = i < c.Length ? c[i] : 0; if (lv > cv) return true; if (lv < cv) return false; } return false; } catch { return false; } } } }