using Oxide.Core;
using Oxide.Core.Configuration;
using Oxide.Game.Rust.Libraries;
using System.Collections.Generic;
using UnityEngine;
using Newtonsoft.Json;
namespace Oxide.Plugins
{
///
/// Blueprint Only Plugin
/// Compatible with both Oxide and Carbon
///
/// Features:
/// - Blueprint learning notifications (Multi-language support)
/// - Research table usage restrictions
/// - Workbench tech tree unlock restrictions
///
/// Permissions:
/// - blueprintonly.notify.bypass: Bypass notifications
/// - blueprintonly.research.use: Allow research table usage
/// - blueprintonly.workbench.use: Allow workbench tech tree usage
///
[Info("Blueprint Only", "MiaygawaYuu", "0.6.0")]
[Description("Blueprint Only Plugin - Compatible with Oxide and Carbon")]
public class BlueprintOnly : RustPlugin
{
#region Fields
private readonly Dictionary> _translations = new Dictionary>();
private bool _translationsLoaded = false;
#endregion
protected override void LoadDefaultMessages()
{
lang.RegisterMessages(new Dictionary
{
["BP Notify"] = "{0} learned {1}.",
["Workbench Block Notify"] = "The tech tree cannot be opened at the workbench.",
["ResearchTable Block Notify"] = "Research tables are not available."
}, this);
lang.RegisterMessages(new Dictionary
{
["BP Notify"] = "{0} さんが {1} をおぼえました。",
["Workbench Block Notify"] = "ワークベンチでのテックツリーのカイホウはできません。",
["ResearchTable Block Notify"] = "リサーチテーブルはつかえません。"
}, this, "ja");
}
private void Init()
{
// Register permissions
permission.RegisterPermission("blueprintonly.notify.bypass", this);
permission.RegisterPermission("blueprintonly.research.use", this);
permission.RegisterPermission("blueprintonly.workbench.use", this);
}
private void OnServerInitialized()
{
LoadTranslations();
}
#region Translation System
///
/// Load translation data from Rust asset bundles
///
private void LoadTranslations()
{
try
{
AssetBundleBackend assets = (AssetBundleBackend)FileSystem.Backend;
Dictionary files = assets.files;
foreach (var kvp in files)
{
string path = kvp.Key;
AssetBundle bundle = kvp.Value;
if (!path.EndsWith(".json") || !path.StartsWith("assets/localization/"))
continue;
TextAsset textAsset = bundle.LoadAsset(path) as TextAsset;
if (textAsset == null)
continue;
int lastIndex = path.LastIndexOf('/');
int secondLastIndex = path.LastIndexOf('/', lastIndex - 1) + 1;
string language = path.Substring(secondLastIndex, lastIndex - secondLastIndex);
if (language.Equals("editor", System.StringComparison.OrdinalIgnoreCase))
continue;
if (!_translations.ContainsKey(language))
{
_translations[language] = new Dictionary();
}
Dictionary tokens = JsonConvert.DeserializeObject>(textAsset.text);
if (tokens != null)
{
foreach (var token in tokens)
{
_translations[language][token.Key] = token.Value;
}
}
}
_translationsLoaded = true;
Puts($"Translation system initialized: {_translations.Count} languages loaded");
}
catch (System.Exception ex)
{
PrintError($"Failed to load translations: {ex.Message}");
_translationsLoaded = false;
}
}
///
/// Get player's language setting
///
private string GetPlayerLanguage(BasePlayer player)
{
return player?.net?.connection?.info?.GetString("global.language", "en") ?? "en";
}
///
/// Get translation for specified language and token
///
private string GetTranslation(string language, string token)
{
if (!_translationsLoaded || string.IsNullOrEmpty(token))
return null;
if (_translations.TryGetValue(language, out Dictionary tokens))
{
if (tokens.TryGetValue(token, out string translation))
{
return translation;
}
}
return null;
}
///
/// Get translated item name
///
private string GetItemTranslation(BasePlayer player, Item item)
{
if (item?.blueprintTargetDef?.displayName == null)
return "Unknown Item";
string language = GetPlayerLanguage(player);
string token = item.blueprintTargetDef.displayName.token;
// Get translation in player's language
string translation = GetTranslation(language, token);
// Fallback to English name if translation not found
return translation ?? item.blueprintTargetDef.displayName.english;
}
#endregion
// Hook: Block research table usage
object CanResearchItem(BasePlayer player, Item targetItem)
{
if (!permission.UserHasPermission(player.UserIDString, "blueprintonly.research.use"))
{
string _message = lang.GetMessage("ResearchTable Block Notify", this, player.UserIDString);
PrintToChat(player,_message);
return false;
}else{
return null;
}
}
// Hook: Block workbench tech tree unlocking
object CanUnlockTechTreeNode(BasePlayer player, TechTreeData.NodeInstance node, TechTreeData techTree)
{
if (!permission.UserHasPermission(player.UserIDString, "blueprintonly.workbench.use"))
{
string _message = lang.GetMessage("Workbench Block Notify", this, player.UserIDString);
PrintToChat(player,_message);
return false;
}else{
return null;
}
}
// Hook: Blueprint learning notification
object OnItemAction(Item item, string action, BasePlayer player)
{
if (action == "study")
{
if (!player.PersistantPlayerInfo.unlockedItems.Contains(item.blueprintTargetDef.itemid))
{
if (!permission.UserHasPermission(player.UserIDString, "blueprintonly.notify.bypass"))
{
// Send translated message to each online player
foreach (BasePlayer onlinePlayer in BasePlayer.activePlayerList)
{
string _message = lang.GetMessage("BP Notify", this, onlinePlayer.UserIDString);
string itemName = GetItemTranslation(onlinePlayer, item);
string message = string.Format(_message, player.displayName, itemName);
PrintToChat(onlinePlayer, message);
}
}
}
}
return null;
}
}
}