【m】框架优化
This commit is contained in:
278
Assets/00.StaryEvo/Editor/Tools/CustomEditorPrefs.cs
Normal file
278
Assets/00.StaryEvo/Editor/Tools/CustomEditorPrefs.cs
Normal file
@@ -0,0 +1,278 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Stary.Evo.Editor
|
||||
{
|
||||
/// <summary>
|
||||
/// 自定义EditorPrefs实现,数据存储在项目根目录的EditorPrefs.ini文件中
|
||||
/// </summary>
|
||||
public static class CustomEditorPrefs
|
||||
{
|
||||
private const string FileName = "EditorPrefs.ini";
|
||||
private static string FilePath => Path.Combine(Application.dataPath, "..", FileName);
|
||||
|
||||
// 缓存的数据
|
||||
private static Dictionary<string, object> _dataCache;
|
||||
private static bool _isDataLoaded;
|
||||
|
||||
/// <summary>
|
||||
/// 设置字符串值
|
||||
/// </summary>
|
||||
/// <param name="key">键</param>
|
||||
/// <param name="value">值</param>
|
||||
public static void SetString(string key, string value)
|
||||
{
|
||||
LoadData();
|
||||
_dataCache[key] = value;
|
||||
SaveData();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取字符串值
|
||||
/// </summary>
|
||||
/// <param name="key">键</param>
|
||||
/// <param name="defaultValue">默认值</param>
|
||||
/// <returns>值</returns>
|
||||
public static string GetString(string key, string defaultValue = "")
|
||||
{
|
||||
LoadData();
|
||||
return _dataCache.TryGetValue(key, out var value) ? (string)value : defaultValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置整数值
|
||||
/// </summary>
|
||||
/// <param name="key">键</param>
|
||||
/// <param name="value">值</param>
|
||||
public static void SetInt(string key, int value)
|
||||
{
|
||||
LoadData();
|
||||
_dataCache[key] = value;
|
||||
SaveData();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取整数值
|
||||
/// </summary>
|
||||
/// <param name="key">键</param>
|
||||
/// <param name="defaultValue">默认值</param>
|
||||
/// <returns>值</returns>
|
||||
public static int GetInt(string key, int defaultValue = 0)
|
||||
{
|
||||
LoadData();
|
||||
return _dataCache.TryGetValue(key, out var value) ? (int)value : defaultValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置浮点数值
|
||||
/// </summary>
|
||||
/// <param name="key">键</param>
|
||||
/// <param name="value">值</param>
|
||||
public static void SetFloat(string key, float value)
|
||||
{
|
||||
LoadData();
|
||||
_dataCache[key] = value;
|
||||
SaveData();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取浮点数值
|
||||
/// </summary>
|
||||
/// <param name="key">键</param>
|
||||
/// <param name="defaultValue">默认值</param>
|
||||
/// <returns>值</returns>
|
||||
public static float GetFloat(string key, float defaultValue = 0.0f)
|
||||
{
|
||||
LoadData();
|
||||
return _dataCache.TryGetValue(key, out var value) ? (float)value : defaultValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置布尔值
|
||||
/// </summary>
|
||||
/// <param name="key">键</param>
|
||||
/// <param name="value">值</param>
|
||||
public static void SetBool(string key, bool value)
|
||||
{
|
||||
LoadData();
|
||||
_dataCache[key] = value;
|
||||
SaveData();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取布尔值
|
||||
/// </summary>
|
||||
/// <param name="key">键</param>
|
||||
/// <param name="defaultValue">默认值</param>
|
||||
/// <returns>值</returns>
|
||||
public static bool GetBool(string key, bool defaultValue = false)
|
||||
{
|
||||
LoadData();
|
||||
return _dataCache.TryGetValue(key, out var value) ? (bool)value : defaultValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检查是否存在指定的键
|
||||
/// </summary>
|
||||
/// <param name="key">键</param>
|
||||
/// <returns>是否存在</returns>
|
||||
public static bool HasKey(string key)
|
||||
{
|
||||
LoadData();
|
||||
return _dataCache.ContainsKey(key);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除指定的键
|
||||
/// </summary>
|
||||
/// <param name="key">键</param>
|
||||
public static void DeleteKey(string key)
|
||||
{
|
||||
LoadData();
|
||||
if (_dataCache.Remove(key))
|
||||
{
|
||||
SaveData();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清除所有数据
|
||||
/// </summary>
|
||||
public static void DeleteAll()
|
||||
{
|
||||
_dataCache.Clear();
|
||||
SaveData();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有键
|
||||
/// </summary>
|
||||
/// <returns>键列表</returns>
|
||||
public static string[] GetAllKeys()
|
||||
{
|
||||
LoadData();
|
||||
return _dataCache.Keys.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有键值对
|
||||
/// </summary>
|
||||
/// <returns>键值对字典</returns>
|
||||
public static Dictionary<string, object> GetAll()
|
||||
{
|
||||
LoadData();
|
||||
return new Dictionary<string, object>(_dataCache);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从文件加载数据
|
||||
/// </summary>
|
||||
private static void LoadData()
|
||||
{
|
||||
if (_isDataLoaded && _dataCache != null)
|
||||
return;
|
||||
|
||||
_dataCache = new Dictionary<string, object>();
|
||||
|
||||
if (!File.Exists(FilePath))
|
||||
{
|
||||
_isDataLoaded = true;
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var lines = File.ReadAllLines(FilePath);
|
||||
foreach (var line in lines)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(line) || line.StartsWith("#"))
|
||||
continue;
|
||||
|
||||
var parts = line.Split(new[] { '=' }, 2);
|
||||
if (parts.Length != 2)
|
||||
continue;
|
||||
|
||||
var key = parts[0].Trim();
|
||||
var valueStr = parts[1].Trim();
|
||||
|
||||
// 尝试解析不同类型的值
|
||||
if (bool.TryParse(valueStr, out var boolValue))
|
||||
{
|
||||
_dataCache[key] = boolValue;
|
||||
}
|
||||
else if (int.TryParse(valueStr, out var intValue))
|
||||
{
|
||||
_dataCache[key] = intValue;
|
||||
}
|
||||
else if (float.TryParse(valueStr, out var floatValue))
|
||||
{
|
||||
_dataCache[key] = floatValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 字符串类型
|
||||
_dataCache[key] = valueStr;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError($"加载CustomEditorPrefs数据失败: {e.Message}");
|
||||
_dataCache = new Dictionary<string, object>();
|
||||
}
|
||||
|
||||
_isDataLoaded = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 保存数据到文件
|
||||
/// </summary>
|
||||
private static void SaveData()
|
||||
{
|
||||
if (_dataCache == null)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
var lines = new List<string>
|
||||
{
|
||||
"# Custom Editor Prefs Data",
|
||||
$"# Last Modified: {DateTime.Now}",
|
||||
""
|
||||
};
|
||||
|
||||
foreach (var kvp in _dataCache)
|
||||
{
|
||||
var valueStr = kvp.Value.ToString();
|
||||
lines.Add($"{kvp.Key}={valueStr}");
|
||||
}
|
||||
|
||||
// 确保目录存在
|
||||
var directory = Path.GetDirectoryName(FilePath);
|
||||
if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
|
||||
{
|
||||
Directory.CreateDirectory(directory);
|
||||
}
|
||||
|
||||
File.WriteAllLines(FilePath, lines);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError($"保存CustomEditorPrefs数据失败: {e.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 手动刷新数据(重新从文件加载)
|
||||
/// </summary>
|
||||
public static void Refresh()
|
||||
{
|
||||
_isDataLoaded = false;
|
||||
LoadData();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 794f2171aa6c41a3a0845f2dd0b9ef91
|
||||
timeCreated: 1767769690
|
||||
367
Assets/00.StaryEvo/Editor/Tools/PlayerPrefsWindow.cs
Normal file
367
Assets/00.StaryEvo/Editor/Tools/PlayerPrefsWindow.cs
Normal file
@@ -0,0 +1,367 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Stary.Evo.Editor
|
||||
{
|
||||
/// <summary>
|
||||
/// PlayerPrefs和CustomEditorPrefs的管理窗口
|
||||
/// </summary>
|
||||
public class PlayerPrefsWindow : EditorWindow
|
||||
{
|
||||
private Vector2 _scrollPosition;
|
||||
private string _searchFilter = "";
|
||||
private Dictionary<string, object> _dataCache;
|
||||
private bool _isAutoSave = true;
|
||||
private string _lastSaveTime = "";
|
||||
|
||||
// 添加新键值对的相关字段
|
||||
private string _newKey = "";
|
||||
private string _newStringValue = "";
|
||||
private int _newIntValue = 0;
|
||||
private float _newFloatValue = 0f;
|
||||
private bool _newBoolValue = false;
|
||||
|
||||
private enum ValueType
|
||||
{
|
||||
String,
|
||||
Int,
|
||||
Float,
|
||||
Bool
|
||||
}
|
||||
|
||||
private ValueType _selectedValueType = ValueType.String;
|
||||
|
||||
// 数据存储类型
|
||||
private enum PrefsType
|
||||
{
|
||||
CustomEditorPrefs,
|
||||
CustomPlayerPrefs
|
||||
}
|
||||
|
||||
private PrefsType _selectedPrefsType = PrefsType.CustomEditorPrefs;
|
||||
|
||||
[MenuItem("Evo/Utility/PlayerPrefs")]
|
||||
public static void ShowWindow()
|
||||
{
|
||||
var window = GetWindow<PlayerPrefsWindow>("PlayerPrefs Manager");
|
||||
window.minSize = new Vector2(700, 500);
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
RefreshData();
|
||||
}
|
||||
|
||||
private void OnGUI()
|
||||
{
|
||||
// 顶部工具栏
|
||||
GUILayout.BeginHorizontal(EditorStyles.toolbar);
|
||||
|
||||
// 数据类型选择 - 保存当前值以便检查是否有变化
|
||||
var oldPrefsType = _selectedPrefsType;
|
||||
_selectedPrefsType =
|
||||
(PrefsType)EditorGUILayout.EnumPopup(_selectedPrefsType, EditorStyles.toolbarPopup,
|
||||
GUILayout.Width(150));
|
||||
|
||||
// 当_selectedPrefsType被修改时,刷新数据
|
||||
if (_selectedPrefsType != oldPrefsType)
|
||||
{
|
||||
RefreshData();
|
||||
}
|
||||
|
||||
// 搜索框
|
||||
_searchFilter = EditorGUILayout.TextField(_searchFilter, EditorStyles.toolbarSearchField);
|
||||
|
||||
// 自动保存选项
|
||||
_isAutoSave = GUILayout.Toggle(_isAutoSave, "自动保存", EditorStyles.toolbarButton);
|
||||
|
||||
// 刷新按钮
|
||||
if (GUILayout.Button("刷新", EditorStyles.toolbarButton))
|
||||
{
|
||||
RefreshData();
|
||||
}
|
||||
|
||||
if (!_isAutoSave)
|
||||
{
|
||||
// 手动保存按钮
|
||||
if (GUILayout.Button("保存", EditorStyles.toolbarButton))
|
||||
{
|
||||
SaveDataManually();
|
||||
}
|
||||
}
|
||||
|
||||
// 清除所有按钮
|
||||
if (GUILayout.Button("清除所有", EditorStyles.toolbarButton, GUILayout.Width(80)))
|
||||
{
|
||||
if (EditorUtility.DisplayDialog("确认清除", $"确定要清除所有{_selectedPrefsType}数据吗?", "清除", "取消"))
|
||||
{
|
||||
if (_selectedPrefsType == PrefsType.CustomEditorPrefs)
|
||||
CustomEditorPrefs.DeleteAll();
|
||||
else
|
||||
CustomPlayerPrefs.DeleteAll();
|
||||
|
||||
RefreshData();
|
||||
_lastSaveTime = $"最后保存: {DateTime.Now.ToString("HH:mm:ss")}";
|
||||
}
|
||||
}
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
// 保存状态提示
|
||||
if (!string.IsNullOrEmpty(_lastSaveTime))
|
||||
{
|
||||
GUILayout.Label(_lastSaveTime, EditorStyles.miniLabel);
|
||||
}
|
||||
|
||||
// 添加新键值对区域
|
||||
GUILayout.BeginVertical(EditorStyles.helpBox);
|
||||
|
||||
GUILayout.BeginHorizontal();
|
||||
_selectedValueType = (ValueType)EditorGUILayout.EnumPopup(_selectedValueType);
|
||||
GUILayout.Space(20);
|
||||
_newKey = EditorGUILayout.TextField("键:", _newKey);
|
||||
GUILayout.Space(20);
|
||||
// 根据选择的类型显示不同的输入框
|
||||
switch (_selectedValueType)
|
||||
{
|
||||
case ValueType.String:
|
||||
_newStringValue = EditorGUILayout.TextField("值:", _newStringValue);
|
||||
break;
|
||||
case ValueType.Int:
|
||||
_newIntValue = EditorGUILayout.IntField("值:", _newIntValue);
|
||||
break;
|
||||
case ValueType.Float:
|
||||
_newFloatValue = EditorGUILayout.FloatField("值:", _newFloatValue);
|
||||
break;
|
||||
case ValueType.Bool:
|
||||
_newBoolValue = EditorGUILayout.Toggle("值:", _newBoolValue);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (GUILayout.Button("添加", GUILayout.Width(80)))
|
||||
{
|
||||
AddNewKeyValuePair();
|
||||
}
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
GUILayout.EndVertical();
|
||||
|
||||
// 内容区域
|
||||
_scrollPosition = GUILayout.BeginScrollView(_scrollPosition);
|
||||
|
||||
// 绘制数据
|
||||
DrawData();
|
||||
|
||||
GUILayout.EndScrollView();
|
||||
}
|
||||
|
||||
private void RefreshData()
|
||||
{
|
||||
if (_selectedPrefsType == PrefsType.CustomEditorPrefs)
|
||||
_dataCache = CustomEditorPrefs.GetAll();
|
||||
else
|
||||
_dataCache = CustomPlayerPrefs.GetAll();
|
||||
|
||||
Repaint();
|
||||
}
|
||||
|
||||
private void DrawData()
|
||||
{
|
||||
var filteredData = string.IsNullOrEmpty(_searchFilter)
|
||||
? _dataCache
|
||||
: _dataCache.Where(kvp => kvp.Key.Contains(_searchFilter, StringComparison.OrdinalIgnoreCase))
|
||||
.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
|
||||
|
||||
foreach (var kvp in filteredData)
|
||||
{
|
||||
GUILayout.BeginHorizontal("box");
|
||||
|
||||
// 键名
|
||||
GUILayout.Label(kvp.Key, GUILayout.Width(200));
|
||||
|
||||
// 值类型和编辑
|
||||
var key = kvp.Key;
|
||||
var value = kvp.Value;
|
||||
|
||||
if (value is string stringValue)
|
||||
{
|
||||
GUILayout.Label("String", GUILayout.Width(80));
|
||||
var newValue = EditorGUILayout.TextField(stringValue);
|
||||
if (newValue != stringValue)
|
||||
{
|
||||
if (_selectedPrefsType == PrefsType.CustomEditorPrefs)
|
||||
CustomEditorPrefs.SetString(key, newValue);
|
||||
else
|
||||
CustomPlayerPrefs.SetString(key, newValue);
|
||||
|
||||
if (_isAutoSave)
|
||||
{
|
||||
_lastSaveTime = $"最后保存: {DateTime.Now.ToString("HH:mm:ss")}";
|
||||
}
|
||||
|
||||
RefreshData();
|
||||
}
|
||||
}
|
||||
else if (value is float floatValue)
|
||||
{
|
||||
GUILayout.Label("Float", GUILayout.Width(80));
|
||||
var newValue = EditorGUILayout.FloatField(floatValue);
|
||||
if (newValue != floatValue)
|
||||
{
|
||||
if (_selectedPrefsType == PrefsType.CustomEditorPrefs)
|
||||
CustomEditorPrefs.SetFloat(key, newValue);
|
||||
else
|
||||
CustomPlayerPrefs.SetFloat(key, newValue);
|
||||
|
||||
if (_isAutoSave)
|
||||
{
|
||||
_lastSaveTime = $"最后保存: {DateTime.Now.ToString("HH:mm:ss")}";
|
||||
}
|
||||
|
||||
RefreshData();
|
||||
}
|
||||
}
|
||||
else if (value is int intValue)
|
||||
{
|
||||
GUILayout.Label("Int", GUILayout.Width(80));
|
||||
var newValue = EditorGUILayout.IntField(intValue);
|
||||
if (newValue != intValue)
|
||||
{
|
||||
if (_selectedPrefsType == PrefsType.CustomEditorPrefs)
|
||||
CustomEditorPrefs.SetInt(key, newValue);
|
||||
else
|
||||
CustomPlayerPrefs.SetInt(key, newValue);
|
||||
|
||||
if (_isAutoSave)
|
||||
{
|
||||
_lastSaveTime = $"最后保存: {DateTime.Now.ToString("HH:mm:ss")}";
|
||||
}
|
||||
|
||||
RefreshData();
|
||||
}
|
||||
}
|
||||
else if (value is bool boolValue)
|
||||
{
|
||||
GUILayout.Label("Bool", GUILayout.Width(80));
|
||||
var newValue = EditorGUILayout.Toggle(boolValue);
|
||||
if (newValue != boolValue)
|
||||
{
|
||||
if (_selectedPrefsType == PrefsType.CustomEditorPrefs)
|
||||
CustomEditorPrefs.SetBool(key, newValue);
|
||||
else
|
||||
CustomPlayerPrefs.SetBool(key, newValue);
|
||||
|
||||
if (_isAutoSave)
|
||||
{
|
||||
_lastSaveTime = $"最后保存: {DateTime.Now.ToString("HH:mm:ss")}";
|
||||
}
|
||||
|
||||
RefreshData();
|
||||
}
|
||||
}
|
||||
|
||||
// 删除按钮
|
||||
if (GUILayout.Button("删除", GUILayout.Width(60)))
|
||||
{
|
||||
if (EditorUtility.DisplayDialog("确认删除", $"确定要删除键 '{key}' 吗?", "删除", "取消"))
|
||||
{
|
||||
if (_selectedPrefsType == PrefsType.CustomEditorPrefs)
|
||||
CustomEditorPrefs.DeleteKey(key);
|
||||
else
|
||||
CustomPlayerPrefs.DeleteKey(key);
|
||||
|
||||
if (_isAutoSave)
|
||||
{
|
||||
_lastSaveTime = $"最后保存: {DateTime.Now.ToString("HH:mm:ss")}";
|
||||
}
|
||||
|
||||
RefreshData();
|
||||
}
|
||||
}
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
if (filteredData.Count == 0)
|
||||
{
|
||||
GUILayout.Label("没有找到数据", EditorStyles.centeredGreyMiniLabel);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 手动保存数据
|
||||
/// </summary>
|
||||
private void SaveDataManually()
|
||||
{
|
||||
// 这两个类在每个Set方法中已经自动保存,这里只需要更新状态提示
|
||||
_lastSaveTime = $"最后保存: {DateTime.Now.ToString("HH:mm:ss")}";
|
||||
EditorUtility.DisplayDialog("保存成功", $"{_selectedPrefsType}数据已保存", "确定");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加新键值对
|
||||
/// </summary>
|
||||
private void AddNewKeyValuePair()
|
||||
{
|
||||
if (string.IsNullOrEmpty(_newKey))
|
||||
{
|
||||
EditorUtility.DisplayDialog("错误", "键名不能为空", "确定");
|
||||
return;
|
||||
}
|
||||
|
||||
if (_dataCache.ContainsKey(_newKey))
|
||||
{
|
||||
EditorUtility.DisplayDialog("错误", $"键 '{_newKey}' 已存在", "确定");
|
||||
return;
|
||||
}
|
||||
|
||||
// 根据选择的类型添加新键值对
|
||||
switch (_selectedValueType)
|
||||
{
|
||||
case ValueType.String:
|
||||
if (_selectedPrefsType == PrefsType.CustomEditorPrefs)
|
||||
CustomEditorPrefs.SetString(_newKey, _newStringValue);
|
||||
else
|
||||
CustomPlayerPrefs.SetString(_newKey, _newStringValue);
|
||||
break;
|
||||
case ValueType.Int:
|
||||
if (_selectedPrefsType == PrefsType.CustomEditorPrefs)
|
||||
CustomEditorPrefs.SetInt(_newKey, _newIntValue);
|
||||
else
|
||||
CustomPlayerPrefs.SetInt(_newKey, _newIntValue);
|
||||
break;
|
||||
case ValueType.Float:
|
||||
if (_selectedPrefsType == PrefsType.CustomEditorPrefs)
|
||||
CustomEditorPrefs.SetFloat(_newKey, _newFloatValue);
|
||||
else
|
||||
CustomPlayerPrefs.SetFloat(_newKey, _newFloatValue);
|
||||
break;
|
||||
case ValueType.Bool:
|
||||
if (_selectedPrefsType == PrefsType.CustomEditorPrefs)
|
||||
CustomEditorPrefs.SetBool(_newKey, _newBoolValue);
|
||||
else
|
||||
CustomPlayerPrefs.SetBool(_newKey, _newBoolValue);
|
||||
break;
|
||||
}
|
||||
|
||||
if (_isAutoSave)
|
||||
{
|
||||
_lastSaveTime = $"最后保存: {DateTime.Now.ToString("HH:mm:ss")}";
|
||||
}
|
||||
|
||||
// 清空输入框
|
||||
_newKey = "";
|
||||
_newStringValue = "";
|
||||
_newIntValue = 0;
|
||||
_newFloatValue = 0f;
|
||||
_newBoolValue = false;
|
||||
|
||||
RefreshData();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 32bc456fb1324efcb559a6f809fc2fcb
|
||||
timeCreated: 1767767824
|
||||
Reference in New Issue
Block a user