Иконка ресурса

FREE DeathFeedFree : 1.0.0 1.0.0

Нет прав для скачивания
C#:
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Oxide.Core.Libraries;
namespace Oxide.Plugins {
    [Info("Death Feed Free", "Goo_", "1.0.0")]
    [Description("Free AI death commentary using Hugging Face Inference Providers")]
    public class DeathFeedFree : RustPlugin {
        private const string Version = "1.0.0";
        private const string ApiUrl = "https://router.huggingface.co/v1/chat/completions";
        private static readonly Regex RichTextRegex = new Regex(@"<[^>]+>", RegexOptions.Compiled);
        private static readonly Regex WhitespaceRegex = new Regex(@"\s+", RegexOptions.Compiled);
        private Configuration _config;
        private Dictionary<string, string> _headers;
        private float _lastRequestTime;
#region Configuration
        private class Configuration {
            [JsonProperty("Config Version")]
            public string ConfigVersion {
                get;
                set;
            }
            = "";
            [JsonProperty("Enabled")]
            public bool Enabled {
                get;
                set;
            }
            = true;
            [JsonProperty("API Token (Hugging Face)")]
            public string ApiToken {
                get;
                set;
            }
            = "";
            [JsonProperty("Model")]
            public string Model {
                get;
                set;
            }
            = "meta-llama/Llama-3.3-70B-Instruct";
            [JsonProperty("Provider (auto/fastest/cheapest/groq/together/cerebras)")]
            public string Provider {
                get;
                set;
            }
            = "auto";
            [JsonProperty("System Prompt")]
            public string SystemPrompt {
                get;
                set;
            }
            = "You are a witty sports commentator providing brief, entertaining commentary on deaths in a Rust game server. Keep responses to 1-2 sentences, be funny but not offensive. No slurs or excessive profanity.";
            [JsonProperty("Max Tokens")]
            public int MaxTokens {
                get;
                set;
            }
            = 64;
            [JsonProperty("Temperature")]
            public float Temperature {
                get;
                set;
            }
            = 0.8f;
            [JsonProperty("Cooldown Seconds")]
            public float CooldownSeconds {
                get;
                set;
            }
            = 5f;
            [JsonProperty("Response Prefix")]
            public string ResponsePrefix {
                get;
                set;
            }
            = "[Commentary]";
            [JsonProperty("Response Color")]
            public string ResponseColor {
                get;
                set;
            }
            = "#FFD700";
            [JsonProperty("Use BetterChat Integration")]
            public bool UseBetterChat {
                get;
                set;
            }
            = true;
            [JsonProperty("Bot Name")]
            public string BotName {
                get;
                set;
            }
            = "Death Feed";
            [JsonProperty("Bot Steam ID (0 = server)")]
            public ulong BotSteamId {
                get;
                set;
            }
            = 0;
            [JsonProperty("Chat Channel (0 = Global, 1 = Team)")]
            public int ChatChannel {
                get;
                set;
            }
            = 0;
            [JsonProperty("Play Sound")]
            public bool PlaySound {
                get;
                set;
            }
            = false;
            [JsonProperty("Sound Prefab")]
            public string SoundPrefab {
                get;
                set;
            }
            = "assets/prefabs/misc/easter/painted eggs/effects/egg_upgrade.prefab";
            [JsonProperty("Debug Mode")]
            public bool DebugMode {
                get;
                set;
            }
            = false;
        }
        protected override void LoadDefaultConfig() {
            _config = new Configuration {
                ConfigVersion = Version
            }
            ;
        }
        protected override void LoadConfig() {
            base.LoadConfig();
            try {
                _config = Config.ReadObject<Configuration>() ?? new Configuration();
                ValidateAndMigrate();
                SaveConfig();
            }
            catch {
                LoadDefaultConfig();
            }
            RebuildHeaders();
        }
        protected override void SaveConfig() => Config.WriteObject(_config);
        private void ValidateAndMigrate() {
            _config.CooldownSeconds = Math.Max(0f, _config.CooldownSeconds);
            _config.MaxTokens = Math.Max(1, Math.Min(256, _config.MaxTokens));
            _config.Temperature = Math.Max(0f, Math.Min(2f, _config.Temperature));
            _config.ChatChannel = Math.Max(0, Math.Min(1, _config.ChatChannel));
            if (string.IsNullOrEmpty(_config.Model)) _config.Model = "meta-llama/Llama-3.3-70B-Instruct";
            if (string.IsNullOrEmpty(_config.Provider)) _config.Provider = "auto";
            if (_config.ConfigVersion != Version) {
                var old = string.IsNullOrEmpty(_config.ConfigVersion) ? "0.0.0" : _config.ConfigVersion;
                _config.ConfigVersion = Version;
                Puts($"Config migrated: {old} -> {Version}");
            }
        }
        private void RebuildHeaders() {
            _headers = new Dictionary<string, string> {
                ["Authorization"]
                = $"Bearer {_config.ApiToken}", ["Content-Type"] = "application/json"
            }
            ;
        }
#endregion
#region Hooks
        private void Init() {
            if (!_config.Enabled) {
                Puts("Plugin disabled in config.");
                return;
            }
            if (string.IsNullOrEmpty(_config.ApiToken)) PrintWarning("No API token configured. Get one from https://hf.co/settings/tokens");
        }
        private void OnServerInitialized() {
            if (!_config.Enabled) return;
            if (plugins.Find("DeathNotes") == null) {
                PrintError("══════ MISSING DEPENDENCY ══════");
                PrintError("DeathNotes plugin is REQUIRED but not installed.");
                PrintError("Download: https://umod.org/plugins/death-notes");
                PrintError("This plugin will NOT function without DeathNotes.");
            }
            else {
                Puts("Ready. DeathNotes detected.");
            }
        }
        private object OnDeathNotice(Dictionary<string, object> data, string message) {
            if (!_config.Enabled || string.IsNullOrEmpty(_config.ApiToken) || string.IsNullOrEmpty(message)) return null;
            var now = UnityEngine.Time.realtimeSinceStartup;
            if (_config.CooldownSeconds > 0 && now - _lastRequestTime < _config.CooldownSeconds) return null;
            var text = StripTags(message);
            if (string.IsNullOrEmpty(text)) return null;
            if (_config.DebugMode) Puts($"[Debug] Death: {text}");
            SendRequest(text);
            return null;
        }
#endregion
#region API
        private void SendRequest(string deathMessage) {
            var model = BuildModelString();
            var payload = JsonConvert.SerializeObject(new {
                model, messages = new[] {
                    new {
                        role = "system", content = _config.SystemPrompt
                    }
                    , new {
                        role = "user", content = deathMessage
                    }
                }
                , max_tokens = _config.MaxTokens, temperature = _config.Temperature
            }
            );
            if (_config.DebugMode) Puts($"[Debug] Request: {model}");
            webrequest.Enqueue(ApiUrl, payload, OnResponse, this, RequestMethod.POST, _headers);
        }
        private string BuildModelString() {
            var provider = _config.Provider?.ToLowerInvariant()?.Trim();
            if (string.IsNullOrEmpty(provider) || provider == "auto") return _config.Model;
            return $"{_config.Model}:{provider}";
        }
        private void OnResponse(int code, string response) {
            if (_config.DebugMode) Puts($"[Debug] Response: {code}");
            if (code != 200) {
                if (code == 401) PrintError("Auth failed. Check API token.");
                else if (_config.DebugMode) Puts($"[Debug] Error {code}: {response}");
                return;
            }
            try {
                var json = JObject.Parse(response);
                var content = json["choices"]?[0]?["message"]?["content"]?.ToString()?.Trim();
                if (string.IsNullOrEmpty(content)) return;
                _lastRequestTime = UnityEngine.Time.realtimeSinceStartup;
                if (_config.DebugMode) Puts($"[Debug] Commentary: {content}");
                Broadcast(content);
                if (_config.PlaySound && !string.IsNullOrEmpty(_config.SoundPrefab)) PlaySound();
            }
            catch (Exception ex) {
                PrintError($"Parse error: {ex.Message}");
            }
        }
#endregion
#region Output
        private void Broadcast(string commentary) {
            var color = string.IsNullOrEmpty(_config.ResponseColor) ? "#FFD700" : _config.ResponseColor;
            var prefix = string.IsNullOrEmpty(_config.ResponsePrefix) ? "" : $"{_config.ResponsePrefix} ";
            var formatted = $"<color={color}>{prefix}{commentary}</color>";
            if (_config.UseBetterChat) {
                var msg = string.IsNullOrEmpty(_config.BotName) ? formatted : $"<color={color}>{_config.BotName}</color>: {formatted}";
                var connections = Facepunch.Pool.GetList<Network.Connection>();
                try {
                    foreach (var p in BasePlayer.activePlayerList) if (p?.net?.connection != null) connections.Add(p.net.connection);
                    if (connections.Count > 0) ConsoleNetwork.SendClientCommand(connections, "chat.add", _config.ChatChannel, _config.BotSteamId.ToString(), msg);
                }
                finally {
                    Facepunch.Pool.FreeList(ref connections);
                }
                Puts($"[Chat] {_config.BotName ?? "DeathFeed"}: {StripTags(commentary)}");
            }
            else {
                foreach (var p in BasePlayer.activePlayerList) p?.ChatMessage(formatted);
            }
        }
        private void PlaySound() {
            foreach (var p in BasePlayer.activePlayerList) if (p != null) Effect.server.Run(_config.SoundPrefab, p.transform.position, UnityEngine.Vector3.zero, null, false);
        }
#endregion
#region Helpers
        private string StripTags(string text) {
            if (string.IsNullOrEmpty(text)) return text;
            return WhitespaceRegex.Replace(RichTextRegex.Replace(text, ""), " ").Trim();
        }
#endregion
#region Commands
        [ConsoleCommand("deathfeed.test")]
        private void CmdTest(ConsoleSystem.Arg arg) {
            if (!arg.IsAdmin) return;
            if (string.IsNullOrEmpty(_config.ApiToken)) {
                arg.ReplyWith("No API token configured.");
                return;
            }
            arg.ReplyWith("Testing API...");
            SendRequest("TestPlayer was killed by AnotherPlayer with AK47 from 150m");
        }
        [ConsoleCommand("deathfeed.status")]
        private void CmdStatus(ConsoleSystem.Arg arg) {
            if (!arg.IsAdmin) return;
            arg.ReplyWith($@"=== Death Feed Free v{Version} ===
            Config: {_config.ConfigVersion}
            Enabled: {_config.Enabled}
            Token: {(string.IsNullOrEmpty(_config.ApiToken) ? "NOT SET" : "Set")}
            Model: {_config.Model}
            Provider: {_config.Provider}
            Cooldown: {_config.CooldownSeconds}s
            BetterChat: {_config.UseBetterChat}
            DeathNotes: {(plugins.Find("DeathNotes") != null ? "Loaded" : "NOT FOUND")}");
        }
#endregion
    }
}

Автор
15FPS
Скачиваний
0
Просмотры
1
Первый выпуск
Обновление
Оценка
0.00 звёзд 0 оценок
Сверху