mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-03 10:22:45 -04:00
oops, broke bam loading
This commit is contained in:
parent
20655d0303
commit
97cf47b0da
@ -991,7 +991,7 @@ fillin(DatagramIterator &scan, BamReader *manager) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_primitive_type = (PrimitiveType)scan.get_uint8();
|
_primitive_type = (PrimitiveType)scan.get_uint8();
|
||||||
_shade_model = (ShadeModel)scan.get_uint16();
|
_shade_model = (ShadeModel)scan.get_uint8();
|
||||||
_geom_rendering = scan.get_uint16();
|
_geom_rendering = scan.get_uint16();
|
||||||
_got_usage_hint = false;
|
_got_usage_hint = false;
|
||||||
_modified = qpGeom::get_next_modified();
|
_modified = qpGeom::get_next_modified();
|
||||||
|
@ -414,6 +414,31 @@ complete_pointers(TypedWritable **p_list, BamReader *manager) {
|
|||||||
return pi;
|
return pi;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: qpGeomVertexArrayData::finalize
|
||||||
|
// Access: Public, Virtual
|
||||||
|
// Description: Called by the BamReader to perform any final actions
|
||||||
|
// needed for setting up the object after all objects
|
||||||
|
// have been read and all pointers have been completed.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void qpGeomVertexArrayData::
|
||||||
|
finalize(BamReader *manager) {
|
||||||
|
// Now we need to register the format that we have read from the bam
|
||||||
|
// file (since it doesn't come out of the bam file automatically
|
||||||
|
// registered). This may change the format's pointer, which we
|
||||||
|
// should then update our own data to reflect. But since this may
|
||||||
|
// cause the unregistered object to destruct, we have to also tell
|
||||||
|
// the BamReader to return the new object from now on.
|
||||||
|
|
||||||
|
CDWriter cdata(_cycler);
|
||||||
|
|
||||||
|
CPT(qpGeomVertexArrayFormat) new_array_format =
|
||||||
|
qpGeomVertexArrayFormat::register_format(_array_format);
|
||||||
|
|
||||||
|
manager->change_pointer(_array_format, new_array_format);
|
||||||
|
_array_format = new_array_format;
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: qpGeomVertexArrayData::make_from_bam
|
// Function: qpGeomVertexArrayData::make_from_bam
|
||||||
// Access: Protected, Static
|
// Access: Protected, Static
|
||||||
@ -430,6 +455,7 @@ make_from_bam(const FactoryParams ¶ms) {
|
|||||||
|
|
||||||
parse_params(params, scan, manager);
|
parse_params(params, scan, manager);
|
||||||
object->fillin(scan, manager);
|
object->fillin(scan, manager);
|
||||||
|
manager->register_finalize(object);
|
||||||
|
|
||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
|
@ -135,6 +135,8 @@ public:
|
|||||||
static PTA_uchar read_raw_data(DatagramIterator &source);
|
static PTA_uchar read_raw_data(DatagramIterator &source);
|
||||||
virtual int complete_pointers(TypedWritable **plist, BamReader *manager);
|
virtual int complete_pointers(TypedWritable **plist, BamReader *manager);
|
||||||
|
|
||||||
|
virtual void finalize(BamReader *manager);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static TypedWritable *make_from_bam(const FactoryParams ¶ms);
|
static TypedWritable *make_from_bam(const FactoryParams ¶ms);
|
||||||
void fillin(DatagramIterator &scan, BamReader *manager);
|
void fillin(DatagramIterator &scan, BamReader *manager);
|
||||||
|
@ -414,6 +414,44 @@ add_transform(TransformPalette *palette, const VertexTransform *transform,
|
|||||||
return (*(result.first)).second;
|
return (*(result.first)).second;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: qpGeomVertexData::CacheEntry::Constructor
|
||||||
|
// Access: Public
|
||||||
|
// Description:
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
INLINE qpGeomVertexData::CacheEntry::
|
||||||
|
CacheEntry(const qpGeomVertexFormat *modifier) :
|
||||||
|
_source(NULL),
|
||||||
|
_modifier(modifier),
|
||||||
|
_result(NULL)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: qpGeomVertexData::CacheEntry::Constructor
|
||||||
|
// Access: Public
|
||||||
|
// Description:
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
INLINE qpGeomVertexData::CacheEntry::
|
||||||
|
CacheEntry(qpGeomVertexData *source,
|
||||||
|
const qpGeomVertexFormat *modifier,
|
||||||
|
const qpGeomVertexData *result) :
|
||||||
|
_source(source),
|
||||||
|
_modifier(modifier),
|
||||||
|
_result(result)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: qpGeomVertexData::CacheEntry::operator <
|
||||||
|
// Access: Public
|
||||||
|
// Description: Provides a unique ordering within the set.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
INLINE bool qpGeomVertexData::CacheEntry::
|
||||||
|
operator < (const CacheEntry &other) const {
|
||||||
|
return _modifier < other._modifier;
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: qpGeomVertexData::CData::Constructor
|
// Function: qpGeomVertexData::CData::Constructor
|
||||||
// Access: Public
|
// Access: Public
|
||||||
|
@ -107,6 +107,7 @@ operator = (const qpGeomVertexData ©) {
|
|||||||
_cull_char_pcollector = copy._cull_char_pcollector;
|
_cull_char_pcollector = copy._cull_char_pcollector;
|
||||||
|
|
||||||
CDWriter cdata(_cycler);
|
CDWriter cdata(_cycler);
|
||||||
|
clear_cache();
|
||||||
cdata->_modified = qpGeom::get_next_modified();
|
cdata->_modified = qpGeom::get_next_modified();
|
||||||
cdata->_animated_vertices_modified = UpdateSeq();
|
cdata->_animated_vertices_modified = UpdateSeq();
|
||||||
}
|
}
|
||||||
@ -118,6 +119,23 @@ operator = (const qpGeomVertexData ©) {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
qpGeomVertexData::
|
qpGeomVertexData::
|
||||||
~qpGeomVertexData() {
|
~qpGeomVertexData() {
|
||||||
|
// When we destruct, we should ensure that all of our cached
|
||||||
|
// entries, across all pipeline stages, are properly removed from
|
||||||
|
// the cache manager.
|
||||||
|
int num_stages = _cycler.get_num_stages();
|
||||||
|
for (int i = 0; i < num_stages; i++) {
|
||||||
|
if (_cycler.is_stage_unique(i)) {
|
||||||
|
CData *cdata = _cycler.write_stage(i);
|
||||||
|
for (Cache::iterator ci = cdata->_cache.begin();
|
||||||
|
ci != cdata->_cache.end();
|
||||||
|
++ci) {
|
||||||
|
CacheEntry *entry = (*ci);
|
||||||
|
entry->erase();
|
||||||
|
}
|
||||||
|
cdata->_cache.clear();
|
||||||
|
_cycler.release_write_stage(i, cdata);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -141,6 +159,7 @@ set_usage_hint(qpGeomVertexData::UsageHint usage_hint) {
|
|||||||
}
|
}
|
||||||
(*ai)->set_usage_hint(usage_hint);
|
(*ai)->set_usage_hint(usage_hint);
|
||||||
}
|
}
|
||||||
|
clear_cache();
|
||||||
cdata->_modified = qpGeom::get_next_modified();
|
cdata->_modified = qpGeom::get_next_modified();
|
||||||
cdata->_animated_vertices_modified = UpdateSeq();
|
cdata->_animated_vertices_modified = UpdateSeq();
|
||||||
}
|
}
|
||||||
@ -187,6 +206,7 @@ clear_rows() {
|
|||||||
}
|
}
|
||||||
(*ai)->clear_rows();
|
(*ai)->clear_rows();
|
||||||
}
|
}
|
||||||
|
clear_cache();
|
||||||
cdata->_modified = qpGeom::get_next_modified();
|
cdata->_modified = qpGeom::get_next_modified();
|
||||||
cdata->_animated_vertices.clear();
|
cdata->_animated_vertices.clear();
|
||||||
}
|
}
|
||||||
@ -212,6 +232,7 @@ modify_array(int i) {
|
|||||||
if (cdata->_arrays[i]->get_ref_count() > 1) {
|
if (cdata->_arrays[i]->get_ref_count() > 1) {
|
||||||
cdata->_arrays[i] = new qpGeomVertexArrayData(*cdata->_arrays[i]);
|
cdata->_arrays[i] = new qpGeomVertexArrayData(*cdata->_arrays[i]);
|
||||||
}
|
}
|
||||||
|
clear_cache();
|
||||||
cdata->_modified = qpGeom::get_next_modified();
|
cdata->_modified = qpGeom::get_next_modified();
|
||||||
cdata->_animated_vertices_modified = UpdateSeq();
|
cdata->_animated_vertices_modified = UpdateSeq();
|
||||||
|
|
||||||
@ -231,6 +252,7 @@ set_array(int i, const qpGeomVertexArrayData *array) {
|
|||||||
CDWriter cdata(_cycler);
|
CDWriter cdata(_cycler);
|
||||||
nassertv(i >= 0 && i < (int)cdata->_arrays.size());
|
nassertv(i >= 0 && i < (int)cdata->_arrays.size());
|
||||||
cdata->_arrays[i] = (qpGeomVertexArrayData *)array;
|
cdata->_arrays[i] = (qpGeomVertexArrayData *)array;
|
||||||
|
clear_cache();
|
||||||
cdata->_modified = qpGeom::get_next_modified();
|
cdata->_modified = qpGeom::get_next_modified();
|
||||||
cdata->_animated_vertices_modified = UpdateSeq();
|
cdata->_animated_vertices_modified = UpdateSeq();
|
||||||
}
|
}
|
||||||
@ -250,6 +272,7 @@ set_transform_palette(const TransformPalette *palette) {
|
|||||||
|
|
||||||
CDWriter cdata(_cycler);
|
CDWriter cdata(_cycler);
|
||||||
cdata->_transform_palette = (TransformPalette *)palette;
|
cdata->_transform_palette = (TransformPalette *)palette;
|
||||||
|
clear_cache();
|
||||||
cdata->_modified = qpGeom::get_next_modified();
|
cdata->_modified = qpGeom::get_next_modified();
|
||||||
cdata->_animated_vertices_modified = UpdateSeq();
|
cdata->_animated_vertices_modified = UpdateSeq();
|
||||||
}
|
}
|
||||||
@ -272,6 +295,7 @@ modify_transform_blend_palette() {
|
|||||||
if (cdata->_transform_blend_palette->get_ref_count() > 1) {
|
if (cdata->_transform_blend_palette->get_ref_count() > 1) {
|
||||||
cdata->_transform_blend_palette = new TransformBlendPalette(*cdata->_transform_blend_palette);
|
cdata->_transform_blend_palette = new TransformBlendPalette(*cdata->_transform_blend_palette);
|
||||||
}
|
}
|
||||||
|
clear_cache();
|
||||||
cdata->_modified = qpGeom::get_next_modified();
|
cdata->_modified = qpGeom::get_next_modified();
|
||||||
cdata->_animated_vertices_modified = UpdateSeq();
|
cdata->_animated_vertices_modified = UpdateSeq();
|
||||||
|
|
||||||
@ -291,6 +315,7 @@ void qpGeomVertexData::
|
|||||||
set_transform_blend_palette(const TransformBlendPalette *palette) {
|
set_transform_blend_palette(const TransformBlendPalette *palette) {
|
||||||
CDWriter cdata(_cycler);
|
CDWriter cdata(_cycler);
|
||||||
cdata->_transform_blend_palette = (TransformBlendPalette *)palette;
|
cdata->_transform_blend_palette = (TransformBlendPalette *)palette;
|
||||||
|
clear_cache();
|
||||||
cdata->_modified = qpGeom::get_next_modified();
|
cdata->_modified = qpGeom::get_next_modified();
|
||||||
cdata->_animated_vertices_modified = UpdateSeq();
|
cdata->_animated_vertices_modified = UpdateSeq();
|
||||||
}
|
}
|
||||||
@ -312,6 +337,7 @@ set_slider_table(const SliderTable *table) {
|
|||||||
|
|
||||||
CDWriter cdata(_cycler);
|
CDWriter cdata(_cycler);
|
||||||
cdata->_slider_table = (SliderTable *)table;
|
cdata->_slider_table = (SliderTable *)table;
|
||||||
|
clear_cache();
|
||||||
cdata->_modified = qpGeom::get_next_modified();
|
cdata->_modified = qpGeom::get_next_modified();
|
||||||
cdata->_animated_vertices_modified = UpdateSeq();
|
cdata->_animated_vertices_modified = UpdateSeq();
|
||||||
}
|
}
|
||||||
@ -550,6 +576,22 @@ convert_to(const qpGeomVertexFormat *new_format) const {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Look up the new format in our cache--maybe we've recently applied
|
||||||
|
// it.
|
||||||
|
{
|
||||||
|
CDReader cdata(_cycler);
|
||||||
|
CacheEntry temp_entry(new_format);
|
||||||
|
temp_entry.local_object();
|
||||||
|
Cache::const_iterator ci = cdata->_cache.find(&temp_entry);
|
||||||
|
if (ci != cdata->_cache.end()) {
|
||||||
|
CacheEntry *entry = (*ci);
|
||||||
|
// Record a cache hit, so this element will stay in the cache a
|
||||||
|
// while longer.
|
||||||
|
entry->refresh();
|
||||||
|
return entry->_result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Okay, convert the data to the new format.
|
// Okay, convert the data to the new format.
|
||||||
if (gobj_cat.is_debug()) {
|
if (gobj_cat.is_debug()) {
|
||||||
gobj_cat.debug()
|
gobj_cat.debug()
|
||||||
@ -564,6 +606,23 @@ convert_to(const qpGeomVertexFormat *new_format) const {
|
|||||||
new_data->set_slider_table(get_slider_table());
|
new_data->set_slider_table(get_slider_table());
|
||||||
|
|
||||||
new_data->copy_from(*this, false);
|
new_data->copy_from(*this, false);
|
||||||
|
|
||||||
|
{
|
||||||
|
// Record the new result in the cache.
|
||||||
|
CacheEntry *entry;
|
||||||
|
{
|
||||||
|
CDWriter cdata(((qpGeomVertexData *)this)->_cycler);
|
||||||
|
entry = new CacheEntry((qpGeomVertexData *)this, new_format, new_data);
|
||||||
|
bool inserted = cdata->_cache.insert(entry).second;
|
||||||
|
nassertr(inserted, new_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// And tell the cache manager about the new entry. (It might
|
||||||
|
// immediately request a delete from the cache of the thing we
|
||||||
|
// just added.)
|
||||||
|
entry->record();
|
||||||
|
}
|
||||||
|
|
||||||
return new_data;
|
return new_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -834,6 +893,26 @@ write(ostream &out, int indent_level) const {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: qpGeomVertexData::clear_cache
|
||||||
|
// Access: Published
|
||||||
|
// Description: Removes all of the previously-cached results of
|
||||||
|
// convert_to().
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void qpGeomVertexData::
|
||||||
|
clear_cache() {
|
||||||
|
// Probably we shouldn't do anything at all here unless we are
|
||||||
|
// running in pipeline stage 0.
|
||||||
|
CData *cdata = CDWriter(_cycler);
|
||||||
|
for (Cache::iterator ci = cdata->_cache.begin();
|
||||||
|
ci != cdata->_cache.end();
|
||||||
|
++ci) {
|
||||||
|
CacheEntry *entry = (*ci);
|
||||||
|
entry->erase();
|
||||||
|
}
|
||||||
|
cdata->_cache.clear();
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: qpGeomVertexData::get_array_info
|
// Function: qpGeomVertexData::get_array_info
|
||||||
// Access: Public
|
// Access: Public
|
||||||
@ -1147,6 +1226,7 @@ do_set_num_rows(int n, qpGeomVertexData::CDWriter &cdata) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (any_changed) {
|
if (any_changed) {
|
||||||
|
clear_cache();
|
||||||
cdata->_modified = qpGeom::get_next_modified();
|
cdata->_modified = qpGeom::get_next_modified();
|
||||||
cdata->_animated_vertices.clear();
|
cdata->_animated_vertices.clear();
|
||||||
}
|
}
|
||||||
@ -1457,6 +1537,37 @@ fillin(DatagramIterator &scan, BamReader *manager) {
|
|||||||
manager->read_cdata(scan, _cycler);
|
manager->read_cdata(scan, _cycler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: qpGeomVertexData::CacheEntry::evict_callback
|
||||||
|
// Access: Public, Virtual
|
||||||
|
// Description: Called when the entry is evicted from the cache, this
|
||||||
|
// should clean up the owning object appropriately.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void qpGeomVertexData::CacheEntry::
|
||||||
|
evict_callback() {
|
||||||
|
// We have to operate on stage 0 of the pipeline, since that's where
|
||||||
|
// the cache really counts. Because of the multistage pipeline, we
|
||||||
|
// might not actually have a cache entry there (it might have been
|
||||||
|
// added to stage 1 instead). No big deal if we don't.
|
||||||
|
CData *cdata = _source->_cycler.write_stage(0);
|
||||||
|
Cache::iterator ci = cdata->_cache.find(this);
|
||||||
|
if (ci != cdata->_cache.end()) {
|
||||||
|
cdata->_cache.erase(ci);
|
||||||
|
}
|
||||||
|
_source->_cycler.release_write_stage(0, cdata);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: qpGeomVertexData::CacheEntry::output
|
||||||
|
// Access: Public, Virtual
|
||||||
|
// Description:
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void qpGeomVertexData::CacheEntry::
|
||||||
|
output(ostream &out) const {
|
||||||
|
out << "vertex data " << (void *)_source << " to "
|
||||||
|
<< *_modifier;
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: qpGeomVertexData::CData::make_copy
|
// Function: qpGeomVertexData::CData::make_copy
|
||||||
// Access: Public, Virtual
|
// Access: Public, Virtual
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
#include "qpgeomVertexColumn.h"
|
#include "qpgeomVertexColumn.h"
|
||||||
#include "qpgeomVertexArrayData.h"
|
#include "qpgeomVertexArrayData.h"
|
||||||
#include "qpgeomEnums.h"
|
#include "qpgeomEnums.h"
|
||||||
|
#include "qpgeomCacheEntry.h"
|
||||||
#include "transformPalette.h"
|
#include "transformPalette.h"
|
||||||
#include "transformBlendPalette.h"
|
#include "transformBlendPalette.h"
|
||||||
#include "sliderTable.h"
|
#include "sliderTable.h"
|
||||||
@ -140,6 +141,8 @@ PUBLISHED:
|
|||||||
void output(ostream &out) const;
|
void output(ostream &out) const;
|
||||||
void write(ostream &out, int indent_level = 0) const;
|
void write(ostream &out, int indent_level = 0) const;
|
||||||
|
|
||||||
|
void clear_cache();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
INLINE CPT(qpGeomVertexData) animate_vertices_cull() const;
|
INLINE CPT(qpGeomVertexData) animate_vertices_cull() const;
|
||||||
|
|
||||||
@ -198,6 +201,23 @@ private:
|
|||||||
|
|
||||||
typedef pvector< PT(qpGeomVertexArrayData) > Arrays;
|
typedef pvector< PT(qpGeomVertexArrayData) > Arrays;
|
||||||
|
|
||||||
|
class CacheEntry : public qpGeomCacheEntry {
|
||||||
|
public:
|
||||||
|
INLINE CacheEntry(const qpGeomVertexFormat *modifier);
|
||||||
|
INLINE CacheEntry(qpGeomVertexData *source,
|
||||||
|
const qpGeomVertexFormat *modifier,
|
||||||
|
const qpGeomVertexData *result);
|
||||||
|
INLINE bool operator < (const CacheEntry &other) const;
|
||||||
|
|
||||||
|
virtual void evict_callback();
|
||||||
|
virtual void output(ostream &out) const;
|
||||||
|
|
||||||
|
qpGeomVertexData *_source;
|
||||||
|
CPT(qpGeomVertexFormat) _modifier;
|
||||||
|
CPT(qpGeomVertexData) _result;
|
||||||
|
};
|
||||||
|
typedef pset<PT(CacheEntry), IndirectLess<CacheEntry> > Cache;
|
||||||
|
|
||||||
// This is the data that must be cycled between pipeline stages.
|
// This is the data that must be cycled between pipeline stages.
|
||||||
class EXPCL_PANDA CData : public CycleData {
|
class EXPCL_PANDA CData : public CycleData {
|
||||||
public:
|
public:
|
||||||
@ -216,6 +236,7 @@ private:
|
|||||||
PT(qpGeomVertexData) _animated_vertices;
|
PT(qpGeomVertexData) _animated_vertices;
|
||||||
UpdateSeq _animated_vertices_modified;
|
UpdateSeq _animated_vertices_modified;
|
||||||
UpdateSeq _modified;
|
UpdateSeq _modified;
|
||||||
|
Cache _cache;
|
||||||
};
|
};
|
||||||
|
|
||||||
PipelineCycler<CData> _cycler;
|
PipelineCycler<CData> _cycler;
|
||||||
@ -263,6 +284,8 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
static TypeHandle _type_handle;
|
static TypeHandle _type_handle;
|
||||||
|
|
||||||
|
friend class CacheEntry;
|
||||||
};
|
};
|
||||||
|
|
||||||
INLINE ostream &operator << (ostream &out, const qpGeomVertexData &obj);
|
INLINE ostream &operator << (ostream &out, const qpGeomVertexData &obj);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user