【m】框架大更新
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Collections;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityEngine.U2D;
|
||||
using UnityEngine.TestTools;
|
||||
using NUnit.Framework;
|
||||
using YooAsset;
|
||||
|
||||
public class TestDestroyPackage
|
||||
{
|
||||
public IEnumerator RuntimeTester(bool destroyRawPackage)
|
||||
{
|
||||
// 销毁旧资源包 ASSET_BUNDLE
|
||||
{
|
||||
var package = YooAssets.GetPackage(TestDefine.AssetBundlePackageName);
|
||||
var destroyOp = package.DestroyAsync();
|
||||
yield return destroyOp;
|
||||
if (destroyOp.Status != EOperationStatus.Succeed)
|
||||
Debug.LogError(destroyOp.Error);
|
||||
Assert.AreEqual(EOperationStatus.Succeed, destroyOp.Status);
|
||||
|
||||
bool result = YooAssets.RemovePackage(TestDefine.AssetBundlePackageName);
|
||||
Assert.IsTrue(result);
|
||||
}
|
||||
|
||||
// 销毁旧资源包 RAW_BUNDLE
|
||||
if (destroyRawPackage)
|
||||
{
|
||||
var package = YooAssets.GetPackage(TestDefine.RawBundlePackageName);
|
||||
var destroyOp = package.DestroyAsync();
|
||||
yield return destroyOp;
|
||||
if (destroyOp.Status != EOperationStatus.Succeed)
|
||||
Debug.LogError(destroyOp.Error);
|
||||
Assert.AreEqual(EOperationStatus.Succeed, destroyOp.Status);
|
||||
|
||||
bool result = YooAssets.RemovePackage(TestDefine.RawBundlePackageName);
|
||||
Assert.IsTrue(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2772d71ea8e24f844b0ad661a3c85ee6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Collections;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityEngine.U2D;
|
||||
using UnityEngine.TestTools;
|
||||
using NUnit.Framework;
|
||||
using YooAsset;
|
||||
|
||||
public class TestLoadAllAssets
|
||||
{
|
||||
public IEnumerator RuntimeTester()
|
||||
{
|
||||
ResourcePackage package = YooAssets.GetPackage(TestDefine.AssetBundlePackageName);
|
||||
Assert.IsNotNull(package);
|
||||
|
||||
// 异步加载所有资源
|
||||
{
|
||||
var allAssetsHandle = package.LoadAllAssetsAsync<GameObject>("prefab_a");
|
||||
yield return allAssetsHandle;
|
||||
Assert.AreEqual(EOperationStatus.Succeed, allAssetsHandle.Status);
|
||||
|
||||
var allAssetObjects = allAssetsHandle.AllAssetObjects;
|
||||
Assert.IsNotNull(allAssetObjects);
|
||||
|
||||
int count = allAssetObjects.Count;
|
||||
Assert.AreEqual(count, 3);
|
||||
}
|
||||
|
||||
// 同步加载所有资源
|
||||
{
|
||||
var allAssetsHandle = package.LoadAllAssetsSync<GameObject>("prefab_x");
|
||||
Assert.AreEqual(EOperationStatus.Succeed, allAssetsHandle.Status);
|
||||
|
||||
var allAssetObjects = allAssetsHandle.AllAssetObjects;
|
||||
Assert.IsNotNull(allAssetObjects);
|
||||
|
||||
int count = allAssetObjects.Count;
|
||||
Assert.AreEqual(count, 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 270615370ad21dc499a435e9bbc09269
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,48 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Collections;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityEngine.U2D;
|
||||
using UnityEngine.TestTools;
|
||||
using NUnit.Framework;
|
||||
using YooAsset;
|
||||
|
||||
public class TestLoadAsset
|
||||
{
|
||||
public IEnumerator RuntimeTester()
|
||||
{
|
||||
ResourcePackage package = YooAssets.GetPackage(TestDefine.AssetBundlePackageName);
|
||||
Assert.IsNotNull(package);
|
||||
|
||||
// 异步加载音乐
|
||||
{
|
||||
var assetHandle = package.LoadAssetAsync<AudioClip>("music_a");
|
||||
yield return assetHandle;
|
||||
Assert.AreEqual(EOperationStatus.Succeed, assetHandle.Status);
|
||||
|
||||
var audioClip = assetHandle.AssetObject as AudioClip;
|
||||
Assert.IsNotNull(audioClip);
|
||||
}
|
||||
|
||||
// 异步加载音效
|
||||
{
|
||||
var assetHandle = package.LoadAssetAsync<AudioClip>("sound_a");
|
||||
yield return assetHandle;
|
||||
Assert.AreEqual(EOperationStatus.Succeed, assetHandle.Status);
|
||||
|
||||
var audioClip = assetHandle.AssetObject as AudioClip;
|
||||
Assert.IsNotNull(audioClip);
|
||||
}
|
||||
|
||||
// 同步加载音效
|
||||
{
|
||||
var assetHandle = package.LoadAssetSync<AudioClip>("sound_b");
|
||||
Assert.AreEqual(EOperationStatus.Succeed, assetHandle.Status);
|
||||
|
||||
var audioClip = assetHandle.AssetObject as AudioClip;
|
||||
Assert.IsNotNull(audioClip);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f4add568c6b99dd439ae31ab4953d0a2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,41 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Collections;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityEngine.U2D;
|
||||
using UnityEngine.TestTools;
|
||||
using NUnit.Framework;
|
||||
using YooAsset;
|
||||
|
||||
public class TestAsyncTask
|
||||
{
|
||||
public IEnumerator RuntimeTester()
|
||||
{
|
||||
ResourcePackage package = YooAssets.GetPackage(TestDefine.AssetBundlePackageName);
|
||||
Assert.IsNotNull(package);
|
||||
|
||||
// Task异步加载面板
|
||||
{
|
||||
var assetsHandle = package.LoadAssetAsync<GameObject>("canvas");
|
||||
var handleTask = assetsHandle.Task;
|
||||
while (!handleTask.IsCompleted)
|
||||
yield return null;
|
||||
yield return null;
|
||||
Assert.AreEqual(EOperationStatus.Succeed, assetsHandle.Status);
|
||||
|
||||
var instantiateOp = assetsHandle.InstantiateAsync();
|
||||
var operationTask = instantiateOp.Task;
|
||||
while (!operationTask.IsCompleted)
|
||||
yield return null;
|
||||
yield return null;
|
||||
Assert.AreEqual(EOperationStatus.Succeed, instantiateOp.Status);
|
||||
|
||||
Assert.IsNotNull(instantiateOp.Result);
|
||||
TestLogger.Log(this, instantiateOp.Result.name);
|
||||
GameObject.Destroy(instantiateOp.Result);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3260bac2b14f0e949a2555a073cfb9fc
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,52 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Collections;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityEngine.U2D;
|
||||
using UnityEngine.TestTools;
|
||||
using NUnit.Framework;
|
||||
using YooAsset;
|
||||
|
||||
public class TestLoadRawFile
|
||||
{
|
||||
public IEnumerator RuntimeTester()
|
||||
{
|
||||
ResourcePackage package = YooAssets.GetPackage(TestDefine.RawBundlePackageName);
|
||||
Assert.IsNotNull(package);
|
||||
|
||||
// 测试异步加载
|
||||
{
|
||||
var rawFileHandle = package.LoadRawFileAsync("raw_file_a");
|
||||
yield return rawFileHandle;
|
||||
Assert.AreEqual(EOperationStatus.Succeed, rawFileHandle.Status);
|
||||
|
||||
var filePath = rawFileHandle.GetRawFilePath();
|
||||
Assert.IsNotNull(filePath);
|
||||
|
||||
var fileText = rawFileHandle.GetRawFileText();
|
||||
TestLogger.Log(this, fileText);
|
||||
Assert.IsNotNull(fileText);
|
||||
|
||||
var fileData = rawFileHandle.GetRawFileData();
|
||||
Assert.IsNotNull(fileData);
|
||||
}
|
||||
|
||||
// 测试同步加载
|
||||
{
|
||||
var rawFileHandle = package.LoadRawFileSync("raw_file_b");
|
||||
Assert.AreEqual(EOperationStatus.Succeed, rawFileHandle.Status);
|
||||
|
||||
var filePath = rawFileHandle.GetRawFilePath();
|
||||
Assert.IsNotNull(filePath);
|
||||
|
||||
var fileText = rawFileHandle.GetRawFileText();
|
||||
TestLogger.Log(this, fileText);
|
||||
Assert.IsNotNull(fileText);
|
||||
|
||||
var fileData = rawFileHandle.GetRawFileData();
|
||||
Assert.IsNotNull(fileData);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 24f8c082eecb6c042879f5913356e3b3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,60 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Collections;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityEngine.U2D;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityEngine.TestTools;
|
||||
using NUnit.Framework;
|
||||
using YooAsset;
|
||||
|
||||
public class TestLoadScene
|
||||
{
|
||||
public IEnumerator RuntimeTester()
|
||||
{
|
||||
ResourcePackage package = YooAssets.GetPackage(TestDefine.AssetBundlePackageName);
|
||||
Assert.IsNotNull(package);
|
||||
|
||||
// 异步加载主场景
|
||||
{
|
||||
var sceneHandle = package.LoadSceneAsync("scene_a", LoadSceneMode.Single);
|
||||
yield return sceneHandle;
|
||||
Assert.AreEqual(EOperationStatus.Succeed, sceneHandle.Status);
|
||||
|
||||
var scene = sceneHandle.SceneObject;
|
||||
Assert.IsNotNull(scene);
|
||||
}
|
||||
|
||||
// 同步加载附加场景
|
||||
yield return new WaitForSeconds(0.2f);
|
||||
{
|
||||
var sceneHandle = package.LoadSceneSync("scene_b", LoadSceneMode.Additive);
|
||||
Assert.AreEqual(EOperationStatus.Succeed, sceneHandle.Status);
|
||||
|
||||
var scene = sceneHandle.SceneObject;
|
||||
Assert.IsNotNull(scene);
|
||||
}
|
||||
|
||||
// 异步加载附加场景
|
||||
yield return new WaitForSeconds(0.2f);
|
||||
SceneHandle cachedHandle;
|
||||
{
|
||||
cachedHandle = package.LoadSceneSync("scene_c", LoadSceneMode.Additive);
|
||||
yield return cachedHandle;
|
||||
Assert.AreEqual(EOperationStatus.Succeed, cachedHandle.Status);
|
||||
|
||||
var scene = cachedHandle.SceneObject;
|
||||
Assert.IsNotNull(scene);
|
||||
}
|
||||
|
||||
// 异步销毁附加场景
|
||||
yield return new WaitForSeconds(0.2f);
|
||||
{
|
||||
var unloadSceneOp = cachedHandle.UnloadAsync();
|
||||
yield return unloadSceneOp;
|
||||
Assert.AreEqual(EOperationStatus.Succeed, unloadSceneOp.Status);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0d2de990b8132d043ac9e9b3c3cc881f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,41 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Collections;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityEngine.U2D;
|
||||
using UnityEngine.TestTools;
|
||||
using NUnit.Framework;
|
||||
using YooAsset;
|
||||
|
||||
public class TestLoadScriptableObject
|
||||
{
|
||||
public IEnumerator RuntimeTester()
|
||||
{
|
||||
ResourcePackage package = YooAssets.GetPackage(TestDefine.AssetBundlePackageName);
|
||||
Assert.IsNotNull(package);
|
||||
|
||||
// 异步加载序列化对象
|
||||
{
|
||||
var assetHandle = package.LoadAssetAsync("config_a");
|
||||
yield return assetHandle;
|
||||
Assert.AreEqual(EOperationStatus.Succeed, assetHandle.Status);
|
||||
|
||||
var testScriptableObject = assetHandle.AssetObject as TestScriptableObject;
|
||||
Assert.IsNotNull(testScriptableObject);
|
||||
TestLogger.Log(this, testScriptableObject.ConfigName);
|
||||
}
|
||||
|
||||
// 同步加载序列化对象
|
||||
{
|
||||
var assetHandle = package.LoadAssetSync("config_b");
|
||||
yield return assetHandle;
|
||||
Assert.AreEqual(EOperationStatus.Succeed, assetHandle.Status);
|
||||
|
||||
var testScriptableObject = assetHandle.AssetObject as TestScriptableObject;
|
||||
Assert.IsNotNull(testScriptableObject);
|
||||
TestLogger.Log(this, testScriptableObject.ConfigName);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 047c3635b9a26d7438f1cbb0c22cffaf
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,35 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Collections;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityEngine.U2D;
|
||||
using UnityEngine.TestTools;
|
||||
using NUnit.Framework;
|
||||
using YooAsset;
|
||||
|
||||
public class TestLoadSpriteAtlas
|
||||
{
|
||||
public IEnumerator RuntimeTester()
|
||||
{
|
||||
ResourcePackage package = YooAssets.GetPackage(TestDefine.AssetBundlePackageName);
|
||||
Assert.IsNotNull(package);
|
||||
|
||||
var assetHandle = package.LoadAssetAsync<SpriteAtlas>("atlas_icon");
|
||||
yield return assetHandle;
|
||||
Assert.AreEqual(EOperationStatus.Succeed, assetHandle.Status);
|
||||
|
||||
var spriteAtals = assetHandle.AssetObject as SpriteAtlas;
|
||||
Assert.IsNotNull(spriteAtals);
|
||||
|
||||
var sprite1 = spriteAtals.GetSprite("bullet");
|
||||
Assert.IsNotNull(sprite1);
|
||||
|
||||
var sprite2 = spriteAtals.GetSprite("pause");
|
||||
Assert.IsNotNull(sprite2);
|
||||
|
||||
var sprite3 = spriteAtals.GetSprite("rocket");
|
||||
Assert.IsNotNull(sprite3);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: acd8842a73aab574584f1c9676f0b46f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Collections;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityEngine.U2D;
|
||||
using UnityEngine.TestTools;
|
||||
using NUnit.Framework;
|
||||
using YooAsset;
|
||||
|
||||
public class TestLoadSubAssets
|
||||
{
|
||||
public IEnumerator RuntimeTester()
|
||||
{
|
||||
ResourcePackage package = YooAssets.GetPackage(TestDefine.AssetBundlePackageName);
|
||||
Assert.IsNotNull(package);
|
||||
|
||||
// 异步加载子对象
|
||||
{
|
||||
var subAssetsHandle = package.LoadSubAssetsAsync<Sprite>("image_a");
|
||||
yield return subAssetsHandle;
|
||||
Assert.AreEqual(EOperationStatus.Succeed, subAssetsHandle.Status);
|
||||
|
||||
var subAssetObjects = subAssetsHandle.SubAssetObjects;
|
||||
Assert.IsNotNull(subAssetObjects);
|
||||
|
||||
int count = subAssetObjects.Count;
|
||||
Assert.AreEqual(count, 3);
|
||||
}
|
||||
|
||||
// 同步加载子对象
|
||||
{
|
||||
var subAssetsHandle = package.LoadSubAssetsSync<Sprite>("image_b");
|
||||
Assert.AreEqual(EOperationStatus.Succeed, subAssetsHandle.Status);
|
||||
|
||||
var subAssetObjects = subAssetsHandle.SubAssetObjects;
|
||||
Assert.IsNotNull(subAssetObjects);
|
||||
|
||||
int count = subAssetObjects.Count;
|
||||
Assert.AreEqual(count, 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6414488620921db45a18cb6f333addb2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,39 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Collections;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityEngine.U2D;
|
||||
using UnityEngine.TestTools;
|
||||
using NUnit.Framework;
|
||||
using YooAsset;
|
||||
using UnityEngine.Video;
|
||||
|
||||
public class TestLoadVideo
|
||||
{
|
||||
public IEnumerator RuntimeTester()
|
||||
{
|
||||
ResourcePackage package = YooAssets.GetPackage(TestDefine.RawBundlePackageName);
|
||||
Assert.IsNotNull(package);
|
||||
|
||||
var rawFileHandle = package.LoadRawFileAsync("video_logo");
|
||||
yield return rawFileHandle;
|
||||
Assert.AreEqual(EOperationStatus.Succeed, rawFileHandle.Status);
|
||||
|
||||
// 获取视频文件地址
|
||||
string videoFilePath = rawFileHandle.GetRawFilePath();
|
||||
Assert.IsTrue(File.Exists(videoFilePath));
|
||||
|
||||
// 创建预制体播放视频
|
||||
GameObject go = new GameObject("video player");
|
||||
var videoPlayer = go.AddComponent<VideoPlayer>();
|
||||
videoPlayer.source = VideoSource.Url;
|
||||
videoPlayer.renderMode = VideoRenderMode.APIOnly;
|
||||
videoPlayer.url = videoFilePath;
|
||||
videoPlayer.Play();
|
||||
|
||||
yield return new WaitForSeconds(1f);
|
||||
Assert.IsTrue(videoPlayer.isPlaying);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0ec434834a510eb4d823b786b2b83927
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,13 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Collections;
|
||||
using UnityEngine;
|
||||
using UnityEngine.TestTools;
|
||||
using YooAsset;
|
||||
|
||||
// 自定义的配置文件
|
||||
public class TestScriptableObject : ScriptableObject
|
||||
{
|
||||
public string ConfigName = "yoo";
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 11ddf12cbeb412347957744c69cfc3b6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user