C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
using System.Collections.Generic;
using UnityEngine;
using System.Linq;
using System.Reflection;
using System;
using System.Collections;
using Oxide.Core;
using Oxide.Game.Rust.Cui;
namespace Oxide.Plugins {
[Info("VisualDebug", "Jake_Rich", "1.0.0")]
[Description("Figure out where memory leaks probally are")]
public class VisualDebug : RustPlugin {
public static Oxide.Core.Plugins.Plugin targetPlugin {
get;
set;
}
public MemoryTableUIManager UI {
get;
set;
}
public static VisualDebug _plugin {
get;
set;
}
void Loaded() {
_plugin = this;
UI = new MemoryTableUIManager();
}
void Unload() {
UI.Destroy();
}
public void SelectPlugin(Oxide.Core.Plugins.Plugin plugin) {
targetPlugin = plugin;
Puts($"Now debugging: {plugin.Name}");
}
/*
[ConsoleCommand("dbg")]
void SelectPluginCommandConsole(ConsoleSystem.Arg arg)
{
if (!(arg.IsAdmin || arg.IsServerside))
{
Puts("This command is for admins only!");
return;
}
if (!arg.HasArgs(1))
{
Puts($"Wrong number of args! Format is \"{arg.cmd.Name} pluginName\"");
return;
}
foreach (var _plugin in Interface.Oxide.RootPluginManager.GetPlugins())
{
if (_plugin.Name.ToLower().Contains(arg.Args[0].ToLower()))
{
SelectPlugin(_plugin);
return;
}
}
Puts($"No plugin found containing {arg.Args[0]}!");
}
[ConsoleCommand("dump")]
void TestReflectionSizeOfConsole(ConsoleSystem.Arg arg)
{
if (!(arg.IsAdmin || arg.IsServerside))
{
Puts("This command is for admins only!");
return;
}
if (!arg.HasArgs(1))
{
Puts($"Wrong number of args! Format is \"{arg.cmd.Name} (int)depth\"");
return;
}
int layers = 1;
if (!int.TryParse(arg.Args[0], out layers))
{
Puts($"{arg.Args[0]} is not a number!");
return;
}
var obj = new ObjectMemoryInfo(targetPlugin, layers);
Oxide.Core.Interface.Oxide.DataFileSystem.WriteObject($"MemDump-{targetPlugin.Name}", obj);
Puts("Dumped Memory!");
}
*/
[ChatCommand("visualdbg")]
void VisualDebugging(BasePlayer player) {
if (!player.IsAdmin) {
PrintToChat(player, "This command is for admins only.");
return;
}
if (UI._player == null) {
UI.ShowPlayer(player);
}
else {
UI.HidePlayer(player);
}
}
[ChatCommand("dbg")]
void VisualDebuggingLookingAt(BasePlayer player) {
if (!player.IsAdmin) {
PrintToChat(player, "This command is for admins only.");
return;
}
BaseEntity ent;
if (!GetEntityLookingAt(player, out ent)) {
PrintToChat(player, "You aren't looking at an entity!");
return;
}
if (UI._player == null) {
UI.ShowPlayer(player, ent);
}
else {
UI.HidePlayer(player);
}
}
public bool GetEntityLookingAt(BasePlayer player, out BaseEntity entity) {
entity = null;
RaycastHit raycastHit;
Ray ray = player.eyes.BodyRay();
if (!Physics.Raycast(ray, out raycastHit, 4f, LayerMask.GetMask("Reserved1"))) {
return false;
}
else {
entity = raycastHit.GetEntity();
if (entity != null) {
return true;
}
}
return false;
}
public static bool IsValueType(object obj) {
if (obj == null) {
return true;
}
return (obj is ValueType || obj is string) && !obj.GetType().IsGenericType;
}
public class ObjectMemoryInfo {
public string name {
get;
set;
}
public int memoryUsed {
get;
set;
}
public int elements {
get;
set;
}
public object _target {
get;
set;
}
private int currentLayer {
get;
set;
}
= 0;
public ObjectMemoryInfo _parent {
get;
set;
}
private bool _autoExpand {
get;
set;
}
public List<ObjectMemoryInfo> children {
get;
set;
}
= new List<ObjectMemoryInfo>();
public List<MethodInfo> methods {
get;
set;
}
= new List<MethodInfo>();
public ObjectMemoryInfo(object targetObject, int layers, string variableName = "", ObjectMemoryInfo parent = null, bool autoExpand = false) {
_autoExpand = autoExpand;
_parent = parent;
name = variableName;
name = name.Replace("<", "");
name = name.Replace(">", "");
name = name.Replace("k__BackingField", "");
currentLayer = layers - 1;
_target = targetObject;
SetupObject();
if (autoExpand) {
Expand();
}
}
public void Expand() {
CalculateSubObjects();
}
public void SetupObject() {
#region Elements
if (_target is IEnumerable) {
elements = GetCount();
}
if (_target is IEnumerable<object>) {
elements = (_target as IEnumerable<object>).Count();
}
#endregion
#region Memory Usage
var Type = _target?.GetType();
if (Type == null) {
return;
}
if (Type == typeof(int)) {
memoryUsed = 4;
}
else if (Type == typeof(string)) {
memoryUsed = (_target as string).Length;
}
else if (Type == typeof(BaseNetworkable)) {
memoryUsed = 8;
}
else if (_target is IDictionary) {
memoryUsed = elements * 16;
}
else if (_target is IList) {
memoryUsed = elements * 8;
}
else if (Type == typeof(int)) {
memoryUsed = 4;
}
foreach (var child in children) {
memoryUsed += child.memoryUsed;
}
#endregion
#region Methods
foreach (var method in Type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) {
if (method?.GetParameters().Length != 0) {
continue;
}
methods.Add(method);
}
#endregion
}
private int GetCount() {
int? c = (_target as IEnumerable).Cast<object>()?.Count();
if (c != null) {
return (int)c;
}
return 0;
}
public string GetInfo() {
return (_target is IEnumerable) ? $"Count : {elements}" : GetMemoryUsage();
}
public string GetVisualText() {
if (_target == null) {
return $"{name} = <color=#3B8AD6FF>NULL</color>";
}
string elementText = ((_target is IEnumerable && !(_target is string)) ? $" Count : {elements}" : "");
string valueText = (IsValueType(_target) ? $" = <color=#3B8AD6FF>{_target.ToString()}</color>" : "");
return $"<color=#4EC8B0FF>{GetTypeName(_target.GetType())}</color> {name}{elementText}{valueText}";
}
public static string GetMethodText(MethodInfo info) {
return $"{(info.IsPublic ? "<color=#3B8AD6FF>public " : "<color=#3B8AD6FF>private ")}{(info.IsVirtual ? "virtual</color> " : "</color>")}{$"<color=#4EC8B0FF> {
GetTypeName(info.ReturnType)
}
</color> "}{info.Name}()";
}
private static string GetTypeName(Type type) {
if (type == null) {
return "";
}
string generic = type.IsGenericType ? $"<{string.Join(", ",type.GetGenericArguments().Select(x=>GetTypeName(x)).ToArray())}>" : "";
string name = type.Name;
if (name.Contains("`")) {
name = name.Remove(name.IndexOf('`', 2));
}
return $"{name}{generic}";
}
private string GetMemoryUsage() {
if (memoryUsed > 1000000000) {
return $"{Math.Round((double)memoryUsed / 1000000000, 2)}GB";
}
if (memoryUsed > 1000000) {
return $"{Math.Round((double)memoryUsed / 1000000, 2)}MB";
}
if (memoryUsed > 1000) {
return $"{Math.Round((double)memoryUsed / 1000, 2)}KB";
}
return $"{memoryUsed}B";
}
public void CalculateSubObjects() {
children.Clear();
try {
if (currentLayer < 0) {
return;
}
if (_target == null) {
return;
}
var Type = _target.GetType();
if (Type == null) {
return;
}
if (_target is string) //No need to expand these
{
return;
}
if (_target is IEnumerable) {
int index = 0;
var objects = (_target as IEnumerable).Cast<object>();
if (objects == null) {
return;
}
foreach (var item in objects) {
children.Add(new ObjectMemoryInfo(item, currentLayer, index.ToString(), this, _autoExpand));
index++;
}
}
else {
foreach (var field in Type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static)) {
object target = field.GetValue(_target);
if (!CheckParents()) {
continue;
}
children.Add(new ObjectMemoryInfo(target, currentLayer, field.Name, this));
}
}
}
catch (Exception ex) {
_plugin.Puts(ex.ToString());
}
}
public bool CheckParents() {
ObjectMemoryInfo parent = _parent;
while (parent != null) {
if (parent._target == _target) {
return false;
}
parent = parent._parent;
}
return true;
}
public List<string> GetOutput(int layer = 0, bool justLists = false) {
List<string> returnValue = new List<string>();
string padding = new string('\t', layer);
if (_target != null) {
if (_target is IEnumerable || !justLists || children.Count != 0) {
returnValue.Add(padding + $"{_target.GetType().Name} {name} {GetMemoryUsage()}");
}
}
if (children.Count > 0) {
returnValue.Add(padding + "{");
foreach (var child in children) {
returnValue.AddRange(child.GetOutput(layer + 1, justLists));
}
returnValue.Add(padding + "}");
}
return returnValue;
}
public string PrintOutput(bool justLists = false) {
return string.Join(Environment.NewLine, GetOutput(0, justLists).ToArray());
}
}
#region Jake's UI Framework - Old
private Dictionary<string, UIButton> UIButtonCallBacks {
get;
set;
}
= new Dictionary<string, UIButton>();
void OnButtonClick(ConsoleSystem.Arg arg) {
UIButton button;
if (UIButtonCallBacks.TryGetValue(arg.cmd.Name, out button)) {
button.OnClicked(arg);
return;
}
Puts("Unknown button command: {0}", arg.cmd.Name);
}
public class UIElement {
public CuiElement Element {
get;
protected set;
}
public CuiRectTransformComponent transform {
get;
protected set;
}
public HashSet<BasePlayer> players {
get;
set;
}
= new HashSet<BasePlayer>();
public Vector2 position {
get;
set;
}
= new Vector2();
public Vector2 size {
get;
set;
}
= new Vector2();
private VisualDebug _plugin;
protected UIElement(UIContainer container) {
transform = new CuiRectTransformComponent();
Element = new CuiElement {
Name = CuiHelper.GetGuid(), Parent = "Hud", Components = {
transform
}
}
;
container.Elements.Add(this);
}
public void SetParent(UIElement element) {
Element.Parent = element.Element.Name;
}
public void Refresh(BasePlayer player) {
Hide(player);
Show(player);
}
private bool AddPlayer(BasePlayer player) {
if (!players.Contains(player)) {
players.Add(player);
return true;
}
return false;
}
private bool RemovePlayer(BasePlayer player) {
return players.Remove(player);
}
public virtual void Show(BasePlayer player) {
if (AddPlayer(player)) {
SafeAddUi(player, Element);
}
}
public void Show(List<BasePlayer> players) {
foreach (BasePlayer player in players) {
Show(player);
}
}
public void Show(HashSet<BasePlayer> players) {
foreach (BasePlayer player in players) {
Show(player);
}
}
public virtual void Hide(BasePlayer player) {
if (RemovePlayer(player)) {
SafeDestroyUi(player, Element);
}
}
public void HideAll() {
foreach (BasePlayer player in players.ToList()) {
Hide(player);
}
}
public void RefreshAll() {
foreach (BasePlayer player in players.ToList()) {
Refresh(player);
}
}
private void SafeAddUi(BasePlayer player, CuiElement element) {
try {
//_plugin.Puts($"Adding {element.Name} to {player.userID}");
List<CuiElement> elements = new List<CuiElement>();
elements.Add(element);
CuiHelper.AddUi(player, elements);
}
catch (Exception ex) {
}
}
private void SafeDestroyUi(BasePlayer player, CuiElement element) {
try {
//_plugin.Puts($"Deleting {element.Name} to {player.userID}");
CuiHelper.DestroyUi(player, element.Name);
}
catch (Exception ex) {
}
}
public void SetSize(float x, float y) {
size = new Vector2(x, y);
UpdatePlacement();
}
public void SetPosition(float x, float y) {
position = new Vector2(x, y);
UpdatePlacement();
}
public void UpdatePlacement() {
transform.AnchorMin = $"{position.x} {position.y}";
transform.AnchorMax = $"{position.x + size.x} {position.y + size.y}";
//_plugin.Puts($"POSITION [{transform.AnchorMin},{transform.AnchorMax}]");
RefreshAll();
}
public void SetPositionAndSize(CuiRectTransformComponent trans) {
transform.AnchorMin = trans.AnchorMin;
transform.AnchorMax = trans.AnchorMax;
//_plugin.Puts($"POSITION [{transform.AnchorMin},{transform.AnchorMax}]");
RefreshAll();
}
}
public class UIButton : UIElement {
public CuiButtonComponent buttonComponent {
get;
private set;
}
public CuiTextComponent textComponent {
get;
private set;
}
private UILabel label {
get;
set;
}
private int _fontSize;
public Action<ConsoleSystem.Arg> onClicked;
public UIButton(UIContainer container, string buttonText = "", string buttonColor = "0 0 0 0.85", string textColor = "1 1 1 1", int fontSize = 15) : base(container) {
_fontSize = fontSize;
var button = new CuiButton();
buttonComponent = button.Button;
textComponent = button.Text;
buttonComponent.Command = CuiHelper.GetGuid();
buttonComponent.Color = buttonColor;
textComponent.Text = buttonText;
textComponent.FontSize = _fontSize;
textComponent.Align = TextAnchor.MiddleCenter;
Element.Components.Insert(0, buttonComponent);
_plugin.cmd.AddConsoleCommand(buttonComponent.Command, _plugin, "OnButtonClick");
_plugin.UIButtonCallBacks[buttonComponent.Command] = this;
label = new UILabel(container, buttonText, parent : Element.Name, fontSize : _fontSize);
label.SetPosition(0, 0);
label.SetSize(1f, 1f);
label.text.Align = TextAnchor.MiddleCenter;
label.text.Color = textColor;
textComponent = label.text;
}
public virtual void OnClicked(ConsoleSystem.Arg args) {
onClicked.Invoke(args);
}
public void AddChatCommand(string fullCommand) {
if (fullCommand == null) {
return;
}
/*
List<string> split = fullCommand.Split(' ').ToList();
string command = split[0];
split.RemoveAt(0); //Split = command args now*/
onClicked += (arg) => {
_plugin.rust.RunClientCommand(arg.Player(), $"chat.say \"/{fullCommand}\"");
//plugin.Puts($"Calling chat command {command} {string.Join(" ",split.ToArray())}");
//Need to call chat command somehow here
}
;
}
public void AddCallback(Action<BasePlayer> callback) {
if (callback == null) {
return;
}
onClicked += (args) => {
callback(args.Player());
}
;
}
public override void Hide(BasePlayer player) {
base.Hide(player);
//No way to remove console commands
}
}
public class UILabel : UIElement {
public CuiTextComponent text {
get;
private set;
}
public UILabel(UIContainer container, string labelText, int fontSize = 12, string fontColor = "1 1 1 1", TextAnchor alignment = TextAnchor.MiddleCenter, string parent = "") : base(container) {
text = new CuiTextComponent();
text.Text = labelText;
text.Color = fontColor;
text.Align = alignment;
text.FontSize = fontSize;
if (!string.IsNullOrEmpty(parent)) {
Element.Parent = parent;
}
Element.Components.Insert(0, text);
}
}
public class UIPanel : UIElement {
private CuiImageComponent panel;
private CuiNeedsCursorComponent needsCursor {
get;
set;
}
private bool requiresFocus {
get;
set;
}
public bool CursorEnabled {
get {
return requiresFocus;
}
set {
if (value) {
needsCursor = new CuiNeedsCursorComponent();
Element.Components.Add(needsCursor);
}
else {
Element.Components.Remove(needsCursor);
}
requiresFocus = value;
}
}
public UIPanel(UIContainer container, Vector2 position, float width, float height, string color = "0 0 0.85", string pngImage = "") : base(container) {
panel = new CuiImageComponent {
Color = color
}
;
this.SetPosition(position.x, position.y);
this.SetSize(width, height);
Element.Components.Insert(0, panel);
}
}
public class UIButtonContainer : UIContainer {
private IEnumerable<UIButtonConfiguration> _buttonConfiguration;
private Vector2 _position;
private float _width;
private float _height;
private string _title;
private string _panelColor;
private bool _stackedButtons;
private float _paddingPercentage;
private int _titleSize;
private int _buttonFontSize;
const float TITLE_PERCENTAGE = 0.20f;
private float _paddingAmount;
private bool _hasTitle;
public UIButtonContainer(IEnumerable<UIButtonConfiguration> buttonConfiguration, string panelBgColor, Vector2 position, float width, float height, float paddingPercentage = 0.05f, string title = "", int titleSize = 30, int buttonFontSize = 15, bool stackedButtons = true) {
_buttonConfiguration = buttonConfiguration;
_position = position;
_width = width;
_height = height;
_title = title;
_titleSize = titleSize;
_panelColor = panelBgColor;
_stackedButtons = stackedButtons;
_paddingPercentage = paddingPercentage;
_buttonFontSize = buttonFontSize;
Init();
}
private void Init() {
var panel = new UIPanel(this, new Vector2(_position.x, _position.y), _width, _height, _panelColor);
_paddingAmount = (_stackedButtons ? _height : _width) * _paddingPercentage / _buttonConfiguration.Count();
var firstButtonPosition = new Vector2(_position.x + _paddingAmount, _position.y + _paddingAmount);
var titleHeight = TITLE_PERCENTAGE * _height;
if (!string.IsNullOrEmpty(_title)) {
_hasTitle = true;
var titlePanel = new UIPanel(this, new Vector2(_position.x, _position.y + _height - titleHeight), _width, titleHeight);
var titleLabel = new UILabel(this, _title, fontSize : _titleSize, parent : titlePanel.Element.Name);
}
var buttonHeight = (_height - (_paddingAmount * 2) - (_hasTitle ? titleHeight : 0) - (_paddingAmount * (_buttonConfiguration.Count() - 1))) / (_stackedButtons ? _buttonConfiguration.Count() : 1);
var buttonWidth = _stackedButtons ? (_width - (_paddingAmount * 2)) : ((_width - (_paddingAmount * 2) - (_paddingAmount * (_buttonConfiguration.Count() - 1))) / _buttonConfiguration.Count());
_plugin.Puts($"ButtonHeight {buttonHeight} ButtonWidth {buttonWidth}");
for (var buttonId = 0; buttonId < _buttonConfiguration.Count();
buttonId++) {
var buttonConfig = _buttonConfiguration.ElementAt(buttonId);
var button = new UIButton(this, buttonText : buttonConfig.ButtonName, buttonColor : buttonConfig.ButtonColor, fontSize : _buttonFontSize);
if (!_stackedButtons) {
button.SetPosition(firstButtonPosition.x + ((buttonWidth + _paddingAmount) * buttonId + _paddingAmount), firstButtonPosition.y + (_paddingAmount) * 2);
}
else {
button.SetPosition(firstButtonPosition.x, firstButtonPosition.y + ((buttonHeight + _paddingAmount) * buttonId + _paddingAmount));
}
button.SetSize(buttonWidth - (_stackedButtons ? 0 : _paddingAmount * 2), buttonHeight - (_stackedButtons ? _paddingAmount * 2 : 0));
button.AddCallback(buttonConfig.callback);
button.AddChatCommand(buttonConfig.ButtonCommand);
}
}
}
public class UIButtonConfiguration {
public string ButtonName {
get;
set;
}
public string ButtonCommand {
get;
set;
}
public string ButtonColor {
get;
set;
}
public Action<BasePlayer> callback {
get;
set;
}
}
public class UIImage : UIPanel {
public CuiImageComponent Image {
get;
private set;
}
public UIImage(UIContainer container, Vector2 position, float width, float height) : base(container, position, width, height) {
Image = new CuiImageComponent();
Element.Components.Insert(0, Image);
}
}
public class UIRawImage : UIElement {
public CuiRawImageComponent Image {
get;
private set;
}
public UIRawImage(UIContainer container, Vector2 position, float width, float height, string png) : base(container) {
var panel = new UIPanel(container, position, width, height);
Element.Parent = panel.Element.Name;
Image = new CuiRawImageComponent() {
Png = png, Sprite = "assets/content/textures/generic/fulltransparent.tga"
}
;
Element.Components.Insert(0, Image);
}
}
public class UIContainer {
public List<UIContainer> ChildContainers {
get;
private set;
}
= new List<UIContainer>();
public List<UIElement> Elements {
get;
private set;
}
= new List<UIElement>();
private HashSet<BasePlayer> _players {
get;
set;
}
= new HashSet<BasePlayer>();
public UIContainer() {
}
private void AddPlayer(BasePlayer player) {
if (!_players.Contains(player)) _players.Add(player);
}
public void Show(BasePlayer player) {
AddPlayer(player);
foreach (UIElement element in Elements) {
element.Show(player);
}
foreach (UIContainer container in ChildContainers) {
container.Show(player);
}
}
public void RemoveElements<T>(IEnumerable<T> elementsToRemove) where T : UIElement {
foreach (var element in elementsToRemove) {
if (Elements.Contains(element)) {
element.HideAll();
Elements.Remove(element);
}
}
}
public void Hide(BasePlayer player) {
foreach (UIElement element in Elements) {
element.Hide(player);
}
foreach (UIContainer container in ChildContainers) {
container.Hide(player);
}
}
public void HideAll() {
foreach (BasePlayer player in _players) {
Hide(player);
}
}
public void AddElement(UIElement element) {
Elements.Add(element);
}
public void AddChildContainer(UIContainer container) {
ChildContainers.Add(container);
}
}
#endregion
public const int objectsPerScreen = 30;
public class MemoryObjectInfoUI : UIContainer {
public UIButton expand {
get;
set;
}
private UIPanel background {
get;
set;
}
private UILabel label {
get;
set;
}
public ObjectMemoryInfo memoryObject {
get;
set;
}
public MemoryObjectInfoUI(ObjectMemoryInfo obj, Vector2 pos, MemoryTableUIManager manager, bool parent = true) {
memoryObject = obj;
background = new UIPanel(this, pos, 1f - pos.x - 0.05f, (0.90f / objectsPerScreen));
AddElement(background);
label = new UILabel(this, obj.GetVisualText(), alignment : TextAnchor.MiddleLeft);
label.SetSize(1f, 1f);
label.SetPosition(0.0f, 0f);
label.SetParent(background);
AddElement(label);
if (!IsValueType(memoryObject._target)) {
expand = new UIButton(this, buttonColor : parent ? "1 0 0 1" : "0 1 0 1", fontSize : 10, textColor : "1 1 1 1");
expand.AddCallback((arg) => {
if (parent) {
manager.Shrink(this);
}
else {
manager.Expand(this);
}
}
);
expand.SetSize(0.005f, 0.45f);
expand.SetPosition(0.0f, 0.5f - expand.size.y / 2);
expand.SetParent(background);
//expand.textComponent.Text = parent ? "-" : "+";
AddElement(expand);
label.SetPosition(label.position.x + expand.size.x + 0.005f, label.position.y);
}
Show(manager._player);
}
public MemoryObjectInfoUI(MethodInfo method, Vector2 pos, MemoryTableUIManager manager, ObjectMemoryInfo obj) {
background = new UIPanel(this, pos, 1f - pos.x - 0.05f, (0.90f / objectsPerScreen));
AddElement(background);
label = new UILabel(this, ObjectMemoryInfo.GetMethodText(method), alignment : TextAnchor.MiddleLeft);
label.SetSize(1f, 1f);
label.SetPosition(0.0f, 0f);
label.SetParent(background);
AddElement(label);
expand = new UIButton(this, buttonColor : "0 0 1 1", fontSize : 10, textColor : "1 1 1 1");
expand.AddCallback((arg) => {
if (method.ReturnType != null) {
if (method.ReturnType.IsValueType || method.ReturnType == typeof(string)) {
_plugin.PrintToChat(manager._player, method.Invoke(obj._target, null)?.ToString());
}
else //When clicking on a function that returns a object to explore
{
var objectReturn = method.Invoke(obj._target, null);
if (objectReturn != null) //Explore blue function
{
var rootObject = new ObjectMemoryInfo(objectReturn, int.MaxValue, objectReturn.GetType().Name, obj);
manager.ShowObject(rootObject);
}
}
}
else {
_plugin.PrintToChat($"Executed {ObjectMemoryInfo.GetMethodText(method)}");
}
}
);
expand.SetSize(0.005f, 0.45f);
expand.SetPosition(0.0f, 0.5f - expand.size.y / 2);
expand.SetParent(background);
AddElement(expand);
label.SetPosition(label.position.x + expand.size.x + 0.005f, label.position.y);
Show(manager._player);
}
}
public class MemoryTableUIManager : UIContainer {
public ObjectMemoryInfo rootObject {
get;
set;
}
public MemoryObjectInfoUI currentObject {
get;
set;
}
public List<MemoryObjectInfoUI> shownObjects {
get;
set;
}
= new List<MemoryObjectInfoUI>();
private UIButton nextPage {
get;
set;
}
private UIButton prevPage {
get;
set;
}
public BasePlayer _player {
get;
set;
}
private int currentIndex {
get;
set;
}
public MemoryTableUIManager() {
nextPage = new UIButton(this, "Next");
nextPage.SetPosition(0.51f, 0f);
nextPage.SetSize(0.09f, 0.03f);
nextPage.AddCallback((player) => {
NextPage();
}
);
//AddElement(nextPage);
prevPage = new UIButton(this, "Prev");
prevPage.SetPosition(0.4f, 0f);
prevPage.SetSize(0.09f, 0.03f);
prevPage.AddCallback((player) => {
PrevPage();
}
);
//AddElement(prevPage);
}
public void Destroy() {
foreach(var item in shownObjects) {
item.HideAll();
}
currentObject.HideAll();
nextPage?.HideAll();
prevPage?.HideAll();
HideAll();
}
public void ShowPlayer(BasePlayer player, object obj = null) {
_player = player;
obj = obj ?? Oxide.Core.Interface.Oxide.RootPluginManager.GetPlugins();
rootObject = new ObjectMemoryInfo(obj, int.MaxValue, "Plugins");
ShowObject(rootObject);
}
public void HidePlayer(BasePlayer player) {
_player = null;
Destroy();
}
public void LinqQuery(BasePlayer player, string cmd) {
string[] commands = cmd.Split('.');
}
public void Expand(MemoryObjectInfoUI obj) {
if (obj.memoryObject != null) {
ShowObject(obj.memoryObject);
}
}
public void Shrink(MemoryObjectInfoUI obj) {
if (currentObject.memoryObject == rootObject) {
return;
}
if (obj.memoryObject._parent != null) {
ShowObject(obj.memoryObject._parent);
}
}
public void NextPage() {
currentIndex += objectsPerScreen;
ShowObject(currentObject.memoryObject, true);
}
public void PrevPage() {
currentIndex = Mathf.Clamp(currentIndex -= objectsPerScreen, 0, currentIndex);
ShowObject(currentObject.memoryObject, true);
}
private void HideCurrent() {
currentObject?.HideAll();
foreach (var item in shownObjects) {
item.HideAll();
}
}
public void ShowObject(ObjectMemoryInfo obj, bool changePage = false) {
HideCurrent();
if (!changePage) {
currentIndex = 0;
}
int i = 0;
currentObject = new MemoryObjectInfoUI(obj, new Vector2(0.25f, 0.95f), this);
obj.Expand();
if (obj.children.Count == 0) {
_plugin.Puts("No children!");
_plugin.Puts(IsValueType(obj._target).ToString());
return;
}
bool nextPageNeeded = false;
Vector2 pos = new Vector2(0.25f, 0.90f);
foreach (var item in obj.children) {
//_plugin.Puts($"i: {i}, currentIndex: {currentIndex}");
if (i < currentIndex) {
i++;
continue;
}
if (i >= currentIndex + objectsPerScreen && (obj.children.Count != objectsPerScreen)) {
nextPageNeeded = true;
break;
}
shownObjects.Add(new MemoryObjectInfoUI(item, pos, this, false));
pos.y -= (0.90f / objectsPerScreen);
i++;
}
foreach(var method in obj.methods) {
if (i < currentIndex) {
i++;
continue;
}
if (i >= currentIndex + objectsPerScreen) {
nextPageNeeded = true;
break;
}
shownObjects.Add(new MemoryObjectInfoUI(method, pos, this, obj));
pos.y -= (0.90f / objectsPerScreen);
i++;
}
nextPage.HideAll();
if (nextPageNeeded) {
nextPage.Show(_player);
}
prevPage.HideAll();
if (currentIndex > 0) {
prevPage.Show(_player);
}
}
}
}
}