mirror of
https://github.com/Laupetin/OpenAssetTools.git
synced 2026-05-25 02:51:43 +00:00
fix: do not dump iwis with format unknown
This commit is contained in:
@@ -1,7 +1,37 @@
|
|||||||
#include "ImageFormat.h"
|
#include "ImageFormat.h"
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
const char* IMAGE_FORMAT_NAMES[]{
|
||||||
|
"R8_G8_B8",
|
||||||
|
"B8_G8_R8_X8",
|
||||||
|
"R8_G8_B8_A8",
|
||||||
|
"B8_G8_R8_A8",
|
||||||
|
"A8",
|
||||||
|
"R16_G16_B16_A16_FLOAT",
|
||||||
|
"R8",
|
||||||
|
"R8_A8",
|
||||||
|
"BC1",
|
||||||
|
"BC2",
|
||||||
|
"BC3",
|
||||||
|
"BC4",
|
||||||
|
"BC5",
|
||||||
|
};
|
||||||
|
static_assert(std::extent_v<decltype(IMAGE_FORMAT_NAMES)> == static_cast<unsigned>(image::ImageFormatId::MAX));
|
||||||
|
} // namespace
|
||||||
|
|
||||||
namespace image
|
namespace image
|
||||||
{
|
{
|
||||||
|
const char* GetImageFormatName(ImageFormatId id)
|
||||||
|
{
|
||||||
|
if (id < ImageFormatId::MAX)
|
||||||
|
return IMAGE_FORMAT_NAMES[static_cast<unsigned>(id)];
|
||||||
|
|
||||||
|
return "unknown";
|
||||||
|
}
|
||||||
|
|
||||||
ImageFormat::ImageFormat(const ImageFormatId id, const oat::D3DFORMAT d3dFormat, const oat::DXGI_FORMAT dxgiFormat)
|
ImageFormat::ImageFormat(const ImageFormatId id, const oat::D3DFORMAT d3dFormat, const oat::DXGI_FORMAT dxgiFormat)
|
||||||
: m_id(id),
|
: m_id(id),
|
||||||
m_d3d_format(d3dFormat),
|
m_d3d_format(d3dFormat),
|
||||||
|
|||||||
@@ -8,9 +8,8 @@
|
|||||||
|
|
||||||
namespace image
|
namespace image
|
||||||
{
|
{
|
||||||
enum class ImageFormatId
|
enum class ImageFormatId : std::uint8_t
|
||||||
{
|
{
|
||||||
UNKNOWN = -1,
|
|
||||||
R8_G8_B8,
|
R8_G8_B8,
|
||||||
B8_G8_R8_X8,
|
B8_G8_R8_X8,
|
||||||
R8_G8_B8_A8,
|
R8_G8_B8_A8,
|
||||||
@@ -25,10 +24,13 @@ namespace image
|
|||||||
BC4,
|
BC4,
|
||||||
BC5,
|
BC5,
|
||||||
|
|
||||||
MAX
|
MAX,
|
||||||
|
UNKNOWN
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class ImageFormatType
|
const char* GetImageFormatName(ImageFormatId id);
|
||||||
|
|
||||||
|
enum class ImageFormatType : std::uint8_t
|
||||||
{
|
{
|
||||||
UNKNOWN,
|
UNKNOWN,
|
||||||
UNSIGNED,
|
UNSIGNED,
|
||||||
|
|||||||
@@ -69,10 +69,10 @@ namespace image
|
|||||||
{
|
{
|
||||||
switch (ObjWriting::Configuration.ImageOutputFormat)
|
switch (ObjWriting::Configuration.ImageOutputFormat)
|
||||||
{
|
{
|
||||||
case ObjWriting::Configuration_t::ImageOutputFormat_e::DDS:
|
case ImageOutputFormat_e::DDS:
|
||||||
m_writer = std::make_unique<DdsWriter>();
|
m_writer = std::make_unique<DdsWriter>();
|
||||||
break;
|
break;
|
||||||
case ObjWriting::Configuration_t::ImageOutputFormat_e::IWI:
|
case ImageOutputFormat_e::IWI:
|
||||||
m_writer = std::make_unique<iwi6::IwiWriter>();
|
m_writer = std::make_unique<iwi6::IwiWriter>();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -89,6 +89,15 @@ namespace image
|
|||||||
if (!texture)
|
if (!texture)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (!m_writer->SupportsImageFormat(texture->GetFormat()))
|
||||||
|
{
|
||||||
|
con::warn("Not dumping image {} as {} does not support the image format {}",
|
||||||
|
image->name,
|
||||||
|
GetImageOutputFormatName(ObjWriting::Configuration.ImageOutputFormat),
|
||||||
|
GetImageFormatName(texture->GetFormat()->GetId()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const auto assetFile = context.OpenAssetFile(GetFileNameForAsset(asset.m_name, m_writer->GetFileExtension()));
|
const auto assetFile = context.OpenAssetFile(GetFileNameForAsset(asset.m_name, m_writer->GetFileExtension()));
|
||||||
|
|
||||||
if (!assetFile)
|
if (!assetFile)
|
||||||
|
|||||||
@@ -65,10 +65,10 @@ namespace image
|
|||||||
{
|
{
|
||||||
switch (ObjWriting::Configuration.ImageOutputFormat)
|
switch (ObjWriting::Configuration.ImageOutputFormat)
|
||||||
{
|
{
|
||||||
case ObjWriting::Configuration_t::ImageOutputFormat_e::DDS:
|
case ImageOutputFormat_e::DDS:
|
||||||
m_writer = std::make_unique<DdsWriter>();
|
m_writer = std::make_unique<DdsWriter>();
|
||||||
break;
|
break;
|
||||||
case ObjWriting::Configuration_t::ImageOutputFormat_e::IWI:
|
case ImageOutputFormat_e::IWI:
|
||||||
m_writer = std::make_unique<iwi8::IwiWriter>();
|
m_writer = std::make_unique<iwi8::IwiWriter>();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -85,6 +85,15 @@ namespace image
|
|||||||
if (!texture)
|
if (!texture)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (!m_writer->SupportsImageFormat(texture->GetFormat()))
|
||||||
|
{
|
||||||
|
con::warn("Not dumping image {} as {} does not support the image format {}",
|
||||||
|
image->name,
|
||||||
|
GetImageOutputFormatName(ObjWriting::Configuration.ImageOutputFormat),
|
||||||
|
GetImageFormatName(texture->GetFormat()->GetId()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const auto assetFile = context.OpenAssetFile(GetFileNameForAsset(asset.m_name, m_writer->GetFileExtension()));
|
const auto assetFile = context.OpenAssetFile(GetFileNameForAsset(asset.m_name, m_writer->GetFileExtension()));
|
||||||
|
|
||||||
if (!assetFile)
|
if (!assetFile)
|
||||||
|
|||||||
@@ -66,10 +66,10 @@ namespace image
|
|||||||
{
|
{
|
||||||
switch (ObjWriting::Configuration.ImageOutputFormat)
|
switch (ObjWriting::Configuration.ImageOutputFormat)
|
||||||
{
|
{
|
||||||
case ObjWriting::Configuration_t::ImageOutputFormat_e::DDS:
|
case ImageOutputFormat_e::DDS:
|
||||||
m_writer = std::make_unique<DdsWriter>();
|
m_writer = std::make_unique<DdsWriter>();
|
||||||
break;
|
break;
|
||||||
case ObjWriting::Configuration_t::ImageOutputFormat_e::IWI:
|
case ImageOutputFormat_e::IWI:
|
||||||
m_writer = std::make_unique<iwi8::IwiWriter>();
|
m_writer = std::make_unique<iwi8::IwiWriter>();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -86,6 +86,15 @@ namespace image
|
|||||||
if (!texture)
|
if (!texture)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (!m_writer->SupportsImageFormat(texture->GetFormat()))
|
||||||
|
{
|
||||||
|
con::warn("Not dumping image {} as {} does not support the image format {}",
|
||||||
|
image->name,
|
||||||
|
GetImageOutputFormatName(ObjWriting::Configuration.ImageOutputFormat),
|
||||||
|
GetImageFormatName(texture->GetFormat()->GetId()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const auto assetFile = context.OpenAssetFile(GetFileNameForAsset(asset.m_name, m_writer->GetFileExtension()));
|
const auto assetFile = context.OpenAssetFile(GetFileNameForAsset(asset.m_name, m_writer->GetFileExtension()));
|
||||||
|
|
||||||
if (!assetFile)
|
if (!assetFile)
|
||||||
|
|||||||
@@ -65,10 +65,10 @@ namespace image
|
|||||||
{
|
{
|
||||||
switch (ObjWriting::Configuration.ImageOutputFormat)
|
switch (ObjWriting::Configuration.ImageOutputFormat)
|
||||||
{
|
{
|
||||||
case ObjWriting::Configuration_t::ImageOutputFormat_e::DDS:
|
case ImageOutputFormat_e::DDS:
|
||||||
m_writer = std::make_unique<DdsWriter>();
|
m_writer = std::make_unique<DdsWriter>();
|
||||||
break;
|
break;
|
||||||
case ObjWriting::Configuration_t::ImageOutputFormat_e::IWI:
|
case ImageOutputFormat_e::IWI:
|
||||||
m_writer = std::make_unique<iwi13::IwiWriter>();
|
m_writer = std::make_unique<iwi13::IwiWriter>();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -85,6 +85,15 @@ namespace image
|
|||||||
if (!texture)
|
if (!texture)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (!m_writer->SupportsImageFormat(texture->GetFormat()))
|
||||||
|
{
|
||||||
|
con::warn("Not dumping image {} as {} does not support the image format {}",
|
||||||
|
image->name,
|
||||||
|
GetImageOutputFormatName(ObjWriting::Configuration.ImageOutputFormat),
|
||||||
|
GetImageFormatName(texture->GetFormat()->GetId()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const auto assetFile = context.OpenAssetFile(GetFileNameForAsset(asset.m_name, m_writer->GetFileExtension()));
|
const auto assetFile = context.OpenAssetFile(GetFileNameForAsset(asset.m_name, m_writer->GetFileExtension()));
|
||||||
|
|
||||||
if (!assetFile)
|
if (!assetFile)
|
||||||
|
|||||||
@@ -83,10 +83,10 @@ namespace image
|
|||||||
{
|
{
|
||||||
switch (ObjWriting::Configuration.ImageOutputFormat)
|
switch (ObjWriting::Configuration.ImageOutputFormat)
|
||||||
{
|
{
|
||||||
case ObjWriting::Configuration_t::ImageOutputFormat_e::DDS:
|
case ImageOutputFormat_e::DDS:
|
||||||
m_writer = std::make_unique<DdsWriter>();
|
m_writer = std::make_unique<DdsWriter>();
|
||||||
break;
|
break;
|
||||||
case ObjWriting::Configuration_t::ImageOutputFormat_e::IWI:
|
case ImageOutputFormat_e::IWI:
|
||||||
m_writer = std::make_unique<iwi27::IwiWriter>();
|
m_writer = std::make_unique<iwi27::IwiWriter>();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -103,6 +103,15 @@ namespace image
|
|||||||
if (!texture)
|
if (!texture)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (!m_writer->SupportsImageFormat(texture->GetFormat()))
|
||||||
|
{
|
||||||
|
con::warn("Not dumping image {} as {} does not support the image format {}",
|
||||||
|
image->name,
|
||||||
|
GetImageOutputFormatName(ObjWriting::Configuration.ImageOutputFormat),
|
||||||
|
GetImageFormatName(texture->GetFormat()->GetId()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const auto assetFile = context.OpenAssetFile(GetFileNameForAsset(asset.m_name, m_writer->GetFileExtension()));
|
const auto assetFile = context.OpenAssetFile(GetFileNameForAsset(asset.m_name, m_writer->GetFileExtension()));
|
||||||
|
|
||||||
if (!assetFile)
|
if (!assetFile)
|
||||||
|
|||||||
@@ -1,7 +1,26 @@
|
|||||||
#include "ObjWriting.h"
|
#include "ObjWriting.h"
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
const char* IMAGE_OUTPUT_FORMAT_NAME[]{
|
||||||
|
"DDS",
|
||||||
|
"IWI",
|
||||||
|
};
|
||||||
|
static_assert(std::extent_v<decltype(IMAGE_OUTPUT_FORMAT_NAME)> == static_cast<unsigned>(ImageOutputFormat_e::COUNT));
|
||||||
|
} // namespace
|
||||||
|
|
||||||
ObjWriting::Configuration_t ObjWriting::Configuration;
|
ObjWriting::Configuration_t ObjWriting::Configuration;
|
||||||
|
|
||||||
|
const char* GetImageOutputFormatName(ImageOutputFormat_e imageOutputFormat)
|
||||||
|
{
|
||||||
|
if (imageOutputFormat < ImageOutputFormat_e::COUNT)
|
||||||
|
return IMAGE_OUTPUT_FORMAT_NAME[static_cast<unsigned>(imageOutputFormat)];
|
||||||
|
|
||||||
|
return "unknown";
|
||||||
|
}
|
||||||
|
|
||||||
bool ObjWriting::ShouldHandleAssetType(const asset_type_t assetType)
|
bool ObjWriting::ShouldHandleAssetType(const asset_type_t assetType)
|
||||||
{
|
{
|
||||||
if (assetType < 0)
|
if (assetType < 0)
|
||||||
|
|||||||
@@ -5,18 +5,16 @@
|
|||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
class ObjWriting
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static class Configuration_t
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
enum class ImageOutputFormat_e
|
enum class ImageOutputFormat_e
|
||||||
{
|
{
|
||||||
DDS,
|
DDS,
|
||||||
IWI
|
IWI,
|
||||||
|
|
||||||
|
COUNT
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const char* GetImageOutputFormatName(ImageOutputFormat_e imageOutputFormat);
|
||||||
|
|
||||||
enum class ModelOutputFormat_e
|
enum class ModelOutputFormat_e
|
||||||
{
|
{
|
||||||
XMODEL_EXPORT,
|
XMODEL_EXPORT,
|
||||||
@@ -26,6 +24,12 @@ public:
|
|||||||
GLB
|
GLB
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ObjWriting
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static class Configuration_t
|
||||||
|
{
|
||||||
|
public:
|
||||||
std::vector<bool> AssetTypesToHandleBitfield;
|
std::vector<bool> AssetTypesToHandleBitfield;
|
||||||
|
|
||||||
ImageOutputFormat_e ImageOutputFormat = ImageOutputFormat_e::DDS;
|
ImageOutputFormat_e ImageOutputFormat = ImageOutputFormat_e::DDS;
|
||||||
|
|||||||
@@ -553,8 +553,8 @@ namespace
|
|||||||
|
|
||||||
bool CanOmitDefaultArmature()
|
bool CanOmitDefaultArmature()
|
||||||
{
|
{
|
||||||
return ObjWriting::Configuration.ModelOutputFormat != ObjWriting::Configuration_t::ModelOutputFormat_e::XMODEL_EXPORT
|
return ObjWriting::Configuration.ModelOutputFormat != ModelOutputFormat_e::XMODEL_EXPORT
|
||||||
&& ObjWriting::Configuration.ModelOutputFormat != ObjWriting::Configuration_t::ModelOutputFormat_e::XMODEL_BIN;
|
&& ObjWriting::Configuration.ModelOutputFormat != ModelOutputFormat_e::XMODEL_BIN;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PopulateXModelWriter(XModelCommon& out, const AssetDumpingContext& context, const unsigned lod, const XModel& model)
|
void PopulateXModelWriter(XModelCommon& out, const AssetDumpingContext& context, const unsigned lod, const XModel& model)
|
||||||
@@ -666,25 +666,25 @@ namespace
|
|||||||
|
|
||||||
switch (ObjWriting::Configuration.ModelOutputFormat)
|
switch (ObjWriting::Configuration.ModelOutputFormat)
|
||||||
{
|
{
|
||||||
case ObjWriting::Configuration_t::ModelOutputFormat_e::OBJ:
|
case ModelOutputFormat_e::OBJ:
|
||||||
DumpObjLod(common, context, asset, currentLod);
|
DumpObjLod(common, context, asset, currentLod);
|
||||||
if (currentLod == 0u)
|
if (currentLod == 0u)
|
||||||
DumpObjMtl(common, context, asset);
|
DumpObjMtl(common, context, asset);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ObjWriting::Configuration_t::ModelOutputFormat_e::XMODEL_EXPORT:
|
case ModelOutputFormat_e::XMODEL_EXPORT:
|
||||||
DumpXModelExportLod(common, context, asset, currentLod);
|
DumpXModelExportLod(common, context, asset, currentLod);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ObjWriting::Configuration_t::ModelOutputFormat_e::XMODEL_BIN:
|
case ModelOutputFormat_e::XMODEL_BIN:
|
||||||
DumpXModelBinLod(common, context, asset, currentLod);
|
DumpXModelBinLod(common, context, asset, currentLod);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ObjWriting::Configuration_t::ModelOutputFormat_e::GLTF:
|
case ModelOutputFormat_e::GLTF:
|
||||||
DumpGltfLod<gltf::TextOutput>(common, context, asset, currentLod, ".gltf");
|
DumpGltfLod<gltf::TextOutput>(common, context, asset, currentLod, ".gltf");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ObjWriting::Configuration_t::ModelOutputFormat_e::GLB:
|
case ModelOutputFormat_e::GLB:
|
||||||
DumpGltfLod<gltf::BinOutput>(common, context, asset, currentLod, ".glb");
|
DumpGltfLod<gltf::BinOutput>(common, context, asset, currentLod, ".glb");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -699,15 +699,15 @@ namespace
|
|||||||
{
|
{
|
||||||
switch (ObjWriting::Configuration.ModelOutputFormat)
|
switch (ObjWriting::Configuration.ModelOutputFormat)
|
||||||
{
|
{
|
||||||
case ObjWriting::Configuration_t::ModelOutputFormat_e::XMODEL_EXPORT:
|
case ModelOutputFormat_e::XMODEL_EXPORT:
|
||||||
return ".xmodel_export";
|
return ".xmodel_export";
|
||||||
case ObjWriting::Configuration_t::ModelOutputFormat_e::XMODEL_BIN:
|
case ModelOutputFormat_e::XMODEL_BIN:
|
||||||
return ".xmodel_bin";
|
return ".xmodel_bin";
|
||||||
case ObjWriting::Configuration_t::ModelOutputFormat_e::OBJ:
|
case ModelOutputFormat_e::OBJ:
|
||||||
return ".obj";
|
return ".obj";
|
||||||
case ObjWriting::Configuration_t::ModelOutputFormat_e::GLTF:
|
case ModelOutputFormat_e::GLTF:
|
||||||
return ".gltf";
|
return ".gltf";
|
||||||
case ObjWriting::Configuration_t::ModelOutputFormat_e::GLB:
|
case ModelOutputFormat_e::GLB:
|
||||||
return ".glb";
|
return ".glb";
|
||||||
default:
|
default:
|
||||||
assert(false);
|
assert(false);
|
||||||
|
|||||||
@@ -184,13 +184,13 @@ bool UnlinkerArgs::SetImageDumpingMode() const
|
|||||||
|
|
||||||
if (specifiedValue == "dds")
|
if (specifiedValue == "dds")
|
||||||
{
|
{
|
||||||
ObjWriting::Configuration.ImageOutputFormat = ObjWriting::Configuration_t::ImageOutputFormat_e::DDS;
|
ObjWriting::Configuration.ImageOutputFormat = ImageOutputFormat_e::DDS;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (specifiedValue == "iwi")
|
if (specifiedValue == "iwi")
|
||||||
{
|
{
|
||||||
ObjWriting::Configuration.ImageOutputFormat = ObjWriting::Configuration_t::ImageOutputFormat_e::IWI;
|
ObjWriting::Configuration.ImageOutputFormat = ImageOutputFormat_e::IWI;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -206,31 +206,31 @@ bool UnlinkerArgs::SetModelDumpingMode() const
|
|||||||
|
|
||||||
if (specifiedValue == "xmodel_export")
|
if (specifiedValue == "xmodel_export")
|
||||||
{
|
{
|
||||||
ObjWriting::Configuration.ModelOutputFormat = ObjWriting::Configuration_t::ModelOutputFormat_e::XMODEL_EXPORT;
|
ObjWriting::Configuration.ModelOutputFormat = ModelOutputFormat_e::XMODEL_EXPORT;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (specifiedValue == "xmodel_bin")
|
if (specifiedValue == "xmodel_bin")
|
||||||
{
|
{
|
||||||
ObjWriting::Configuration.ModelOutputFormat = ObjWriting::Configuration_t::ModelOutputFormat_e::XMODEL_BIN;
|
ObjWriting::Configuration.ModelOutputFormat = ModelOutputFormat_e::XMODEL_BIN;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (specifiedValue == "obj")
|
if (specifiedValue == "obj")
|
||||||
{
|
{
|
||||||
ObjWriting::Configuration.ModelOutputFormat = ObjWriting::Configuration_t::ModelOutputFormat_e::OBJ;
|
ObjWriting::Configuration.ModelOutputFormat = ModelOutputFormat_e::OBJ;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (specifiedValue == "gltf")
|
if (specifiedValue == "gltf")
|
||||||
{
|
{
|
||||||
ObjWriting::Configuration.ModelOutputFormat = ObjWriting::Configuration_t::ModelOutputFormat_e::GLTF;
|
ObjWriting::Configuration.ModelOutputFormat = ModelOutputFormat_e::GLTF;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (specifiedValue == "glb")
|
if (specifiedValue == "glb")
|
||||||
{
|
{
|
||||||
ObjWriting::Configuration.ModelOutputFormat = ObjWriting::Configuration_t::ModelOutputFormat_e::GLB;
|
ObjWriting::Configuration.ModelOutputFormat = ModelOutputFormat_e::GLB;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user