mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Added graphics presets
This commit is contained in:
parent
4db88bb22c
commit
29d40cf509
@ -29,6 +29,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
- Added screen-space reflection and refraction shaders
|
- Added screen-space reflection and refraction shaders
|
||||||
- Added reflection quality setting
|
- Added reflection quality setting
|
||||||
- UI: Added a poise indicator to the player's status bars
|
- UI: Added a poise indicator to the player's status bars
|
||||||
|
- FxUpscale AA mode for higher quality graphics at reduced internal resolutions
|
||||||
|
- Graphics presets
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- Use fluent for translations
|
- Use fluent for translations
|
||||||
|
@ -111,6 +111,11 @@ hud-settings-rain_occlusion-resolution = Rain Occlusion Resolution
|
|||||||
hud-settings-lod_detail = LoD Detail
|
hud-settings-lod_detail = LoD Detail
|
||||||
hud-settings-save_window_size = Save window size
|
hud-settings-save_window_size = Save window size
|
||||||
hud-settings-reset_graphics = Reset to Defaults
|
hud-settings-reset_graphics = Reset to Defaults
|
||||||
|
hud-settings-minimal_graphics = Minimal
|
||||||
|
hud-settings-low_graphics = Low
|
||||||
|
hud-settings-medium_graphics = Medium
|
||||||
|
hud-settings-high_graphics = High
|
||||||
|
hud-settings-ultra_graphics = Ultra
|
||||||
hud-settings-bloom = Bloom
|
hud-settings-bloom = Bloom
|
||||||
hud-settings-point_glow = Point Glow
|
hud-settings-point_glow = Point Glow
|
||||||
hud-settings-master_volume = Master Volume
|
hud-settings-master_volume = Master Volume
|
||||||
|
@ -110,7 +110,7 @@ float shadow_at(vec3 wpos, vec3 wnorm) {
|
|||||||
diff.z = -sign(diff.z) * diff.z * 0.1;
|
diff.z = -sign(diff.z) * diff.z * 0.1;
|
||||||
}
|
}
|
||||||
|
|
||||||
float shade = max(pow(diff.x * diff.x + diff.y * diff.y + diff.z * diff.z, 0.25) / pow(radius * radius * 0.5, 0.25), 0.5);
|
float shade = max(pow(diff.x * diff.x + diff.y * diff.y + diff.z * diff.z, 0.35) / pow(radius * radius * 0.5, 0.5), 0.5);
|
||||||
// float shade = max(pow(dot(diff, diff) / (radius * radius * 0.5), 0.25), 0.5);
|
// float shade = max(pow(dot(diff, diff) / (radius * radius * 0.5), 0.25), 0.5);
|
||||||
// float shade = dot(diff, diff) / (radius * radius * 0.5);
|
// float shade = dot(diff, diff) / (radius * radius * 0.5);
|
||||||
|
|
||||||
|
@ -193,6 +193,7 @@ const DEFAULT_NPC: Color = Color::Rgba(1.0, 1.0, 1.0, 1.0);
|
|||||||
|
|
||||||
// UI Color-Theme
|
// UI Color-Theme
|
||||||
const UI_MAIN: Color = Color::Rgba(0.61, 0.70, 0.70, 1.0); // Greenish Blue
|
const UI_MAIN: Color = Color::Rgba(0.61, 0.70, 0.70, 1.0); // Greenish Blue
|
||||||
|
const UI_SUBTLE: Color = Color::Rgba(0.2, 0.24, 0.24, 1.0); // Dark Greenish Blue
|
||||||
//const UI_MAIN: Color = Color::Rgba(0.1, 0.1, 0.1, 0.97); // Dark
|
//const UI_MAIN: Color = Color::Rgba(0.1, 0.1, 0.1, 0.97); // Dark
|
||||||
const UI_HIGHLIGHT_0: Color = Color::Rgba(0.79, 1.09, 1.09, 1.0);
|
const UI_HIGHLIGHT_0: Color = Color::Rgba(0.79, 1.09, 1.09, 1.0);
|
||||||
// Pull-Down menu BG color
|
// Pull-Down menu BG color
|
||||||
|
@ -3,14 +3,14 @@ use super::{RESET_BUTTONS_HEIGHT, RESET_BUTTONS_WIDTH};
|
|||||||
use crate::{
|
use crate::{
|
||||||
hud::{
|
hud::{
|
||||||
img_ids::Imgs, CRITICAL_HP_COLOR, HP_COLOR, LOW_HP_COLOR, MENU_BG, STAMINA_COLOR,
|
img_ids::Imgs, CRITICAL_HP_COLOR, HP_COLOR, LOW_HP_COLOR, MENU_BG, STAMINA_COLOR,
|
||||||
TEXT_COLOR,
|
TEXT_COLOR, UI_HIGHLIGHT_0, UI_MAIN, UI_SUBTLE,
|
||||||
},
|
},
|
||||||
render::{
|
render::{
|
||||||
AaMode, BloomConfig, BloomFactor, BloomMode, CloudMode, FluidMode, LightingMode,
|
AaMode, BloomConfig, BloomFactor, BloomMode, CloudMode, FluidMode, LightingMode,
|
||||||
PresentMode, ReflectionMode, RenderMode, ShadowMapMode, ShadowMode, UpscaleMode,
|
PresentMode, ReflectionMode, RenderMode, ShadowMapMode, ShadowMode, UpscaleMode,
|
||||||
},
|
},
|
||||||
session::settings_change::Graphics as GraphicsChange,
|
session::settings_change::Graphics as GraphicsChange,
|
||||||
settings::Fps,
|
settings::{Fps, GraphicsSettings},
|
||||||
ui::{fonts::Fonts, ImageSlider, ToggleButton},
|
ui::{fonts::Fonts, ImageSlider, ToggleButton},
|
||||||
window::{FullScreenSettings, FullscreenMode},
|
window::{FullScreenSettings, FullscreenMode},
|
||||||
GlobalState,
|
GlobalState,
|
||||||
@ -25,7 +25,7 @@ use core::convert::TryFrom;
|
|||||||
use i18n::Localization;
|
use i18n::Localization;
|
||||||
|
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use std::iter::once;
|
use std::{iter::once, rc::Rc};
|
||||||
use winit::monitor::VideoMode;
|
use winit::monitor::VideoMode;
|
||||||
|
|
||||||
widget_ids! {
|
widget_ids! {
|
||||||
@ -34,6 +34,11 @@ widget_ids! {
|
|||||||
window_r,
|
window_r,
|
||||||
window_scrollbar,
|
window_scrollbar,
|
||||||
reset_graphics_button,
|
reset_graphics_button,
|
||||||
|
minimal_graphics_button,
|
||||||
|
low_graphics_button,
|
||||||
|
medium_graphics_button,
|
||||||
|
high_graphics_button,
|
||||||
|
ultra_graphics_button,
|
||||||
fps_counter,
|
fps_counter,
|
||||||
pipeline_recreation_text,
|
pipeline_recreation_text,
|
||||||
terrain_vd_slider,
|
terrain_vd_slider,
|
||||||
@ -284,9 +289,81 @@ impl<'a> Widget for Video<'a> {
|
|||||||
.set(state.ids.pipeline_recreation_text, ui);
|
.set(state.ids.pipeline_recreation_text, ui);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reset the graphics settings to the default settings
|
||||||
|
if Button::image(self.imgs.button)
|
||||||
|
.w_h(RESET_BUTTONS_WIDTH, RESET_BUTTONS_HEIGHT)
|
||||||
|
.hover_image(self.imgs.button_hover)
|
||||||
|
.press_image(self.imgs.button_press)
|
||||||
|
.top_left_with_margins_on(state.ids.window, 10.0, 10.0)
|
||||||
|
.label(
|
||||||
|
&self
|
||||||
|
.localized_strings
|
||||||
|
.get_msg("hud-settings-reset_graphics"),
|
||||||
|
)
|
||||||
|
.label_font_size(self.fonts.cyri.scale(14))
|
||||||
|
.label_color(TEXT_COLOR)
|
||||||
|
.label_font_id(self.fonts.cyri.conrod_id)
|
||||||
|
.label_y(Relative::Scalar(2.0))
|
||||||
|
.set(state.ids.reset_graphics_button, ui)
|
||||||
|
.was_clicked()
|
||||||
|
{
|
||||||
|
events.push(GraphicsChange::ResetGraphicsSettings);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Graphics presets buttons
|
||||||
|
let preset_buttons: [(_, _, fn(_) -> _); 5] = [
|
||||||
|
(
|
||||||
|
"hud-settings-minimal_graphics",
|
||||||
|
state.ids.minimal_graphics_button,
|
||||||
|
GraphicsSettings::into_minimal,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"hud-settings-low_graphics",
|
||||||
|
state.ids.low_graphics_button,
|
||||||
|
GraphicsSettings::into_low,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"hud-settings-medium_graphics",
|
||||||
|
state.ids.medium_graphics_button,
|
||||||
|
GraphicsSettings::into_medium,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"hud-settings-high_graphics",
|
||||||
|
state.ids.high_graphics_button,
|
||||||
|
GraphicsSettings::into_high,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"hud-settings-ultra_graphics",
|
||||||
|
state.ids.ultra_graphics_button,
|
||||||
|
GraphicsSettings::into_ultra,
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
let mut lhs = state.ids.reset_graphics_button;
|
||||||
|
|
||||||
|
for (msg, id, change_fn) in preset_buttons {
|
||||||
|
if Button::new()
|
||||||
|
.label(&self.localized_strings.get_msg(msg))
|
||||||
|
.w_h(80.0, 34.0)
|
||||||
|
.color(UI_SUBTLE)
|
||||||
|
.hover_color(UI_MAIN)
|
||||||
|
.press_color(UI_HIGHLIGHT_0)
|
||||||
|
.right_from(lhs, 12.0)
|
||||||
|
.label_font_size(self.fonts.cyri.scale(14))
|
||||||
|
.label_color(TEXT_COLOR)
|
||||||
|
.label_font_id(self.fonts.cyri.conrod_id)
|
||||||
|
.label_y(Relative::Scalar(2.0))
|
||||||
|
.set(id, ui)
|
||||||
|
.was_clicked()
|
||||||
|
{
|
||||||
|
events.push(GraphicsChange::ChangeGraphicsSettings(Rc::new(change_fn)));
|
||||||
|
}
|
||||||
|
lhs = id;
|
||||||
|
}
|
||||||
|
|
||||||
// View Distance
|
// View Distance
|
||||||
Text::new(&self.localized_strings.get_msg("hud-settings-view_distance"))
|
Text::new(&self.localized_strings.get_msg("hud-settings-view_distance"))
|
||||||
.top_left_with_margins_on(state.ids.window, 10.0, 10.0)
|
.down_from(state.ids.reset_graphics_button, 10.0)
|
||||||
.font_size(self.fonts.cyri.scale(14))
|
.font_size(self.fonts.cyri.scale(14))
|
||||||
.font_id(self.fonts.cyri.conrod_id)
|
.font_id(self.fonts.cyri.conrod_id)
|
||||||
.color(TEXT_COLOR)
|
.color(TEXT_COLOR)
|
||||||
@ -1671,28 +1748,6 @@ impl<'a> Widget for Video<'a> {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset the graphics settings to the default settings
|
|
||||||
if Button::image(self.imgs.button)
|
|
||||||
.w_h(RESET_BUTTONS_WIDTH, RESET_BUTTONS_HEIGHT)
|
|
||||||
.hover_image(self.imgs.button_hover)
|
|
||||||
.press_image(self.imgs.button_press)
|
|
||||||
.down_from(state.ids.fullscreen_mode_list, 12.0)
|
|
||||||
.right_from(state.ids.save_window_size_button, 12.0)
|
|
||||||
.label(
|
|
||||||
&self
|
|
||||||
.localized_strings
|
|
||||||
.get_msg("hud-settings-reset_graphics"),
|
|
||||||
)
|
|
||||||
.label_font_size(self.fonts.cyri.scale(14))
|
|
||||||
.label_color(TEXT_COLOR)
|
|
||||||
.label_font_id(self.fonts.cyri.conrod_id)
|
|
||||||
.label_y(Relative::Scalar(2.0))
|
|
||||||
.set(state.ids.reset_graphics_button, ui)
|
|
||||||
.was_clicked()
|
|
||||||
{
|
|
||||||
events.push(GraphicsChange::ResetGraphicsSettings);
|
|
||||||
}
|
|
||||||
|
|
||||||
events
|
events
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -199,7 +199,7 @@ pub enum ReflectionMode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Default for ReflectionMode {
|
impl Default for ReflectionMode {
|
||||||
fn default() -> Self { ReflectionMode::Medium }
|
fn default() -> Self { ReflectionMode::High }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Lighting modes
|
/// Lighting modes
|
||||||
|
@ -15,6 +15,7 @@ use crate::{
|
|||||||
GlobalState,
|
GlobalState,
|
||||||
};
|
};
|
||||||
use i18n::{LanguageMetadata, LocalizationHandle};
|
use i18n::{LanguageMetadata, LocalizationHandle};
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub enum Audio {
|
pub enum Audio {
|
||||||
@ -98,6 +99,7 @@ pub enum Graphics {
|
|||||||
AdjustWindowSize([u16; 2]),
|
AdjustWindowSize([u16; 2]),
|
||||||
|
|
||||||
ResetGraphicsSettings,
|
ResetGraphicsSettings,
|
||||||
|
ChangeGraphicsSettings(Rc<dyn Fn(GraphicsSettings) -> GraphicsSettings>),
|
||||||
}
|
}
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub enum Interface {
|
pub enum Interface {
|
||||||
@ -410,6 +412,8 @@ impl SettingsChange {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
SettingsChange::Graphics(graphics_change) => {
|
SettingsChange::Graphics(graphics_change) => {
|
||||||
|
let mut change_all = false;
|
||||||
|
|
||||||
match graphics_change {
|
match graphics_change {
|
||||||
Graphics::AdjustTerrainViewDistance(terrain_vd) => {
|
Graphics::AdjustTerrainViewDistance(terrain_vd) => {
|
||||||
adjust_terrain_view_distance(terrain_vd, settings, session_state)
|
adjust_terrain_view_distance(terrain_vd, settings, session_state)
|
||||||
@ -486,6 +490,15 @@ impl SettingsChange {
|
|||||||
},
|
},
|
||||||
Graphics::ResetGraphicsSettings => {
|
Graphics::ResetGraphicsSettings => {
|
||||||
settings.graphics = GraphicsSettings::default();
|
settings.graphics = GraphicsSettings::default();
|
||||||
|
change_all = true;
|
||||||
|
},
|
||||||
|
Graphics::ChangeGraphicsSettings(f) => {
|
||||||
|
settings.graphics = f(settings.graphics.clone());
|
||||||
|
change_all = true;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if change_all {
|
||||||
let graphics = &settings.graphics;
|
let graphics = &settings.graphics;
|
||||||
// View distance
|
// View distance
|
||||||
client_set_view_distance(settings, session_state);
|
client_set_view_distance(settings, session_state);
|
||||||
@ -497,6 +510,11 @@ impl SettingsChange {
|
|||||||
.compute_dependents(&session_state.client.borrow().state().terrain());
|
.compute_dependents(&session_state.client.borrow().state().terrain());
|
||||||
// LoD
|
// LoD
|
||||||
session_state.scene.lod.set_detail(graphics.lod_detail);
|
session_state.scene.lod.set_detail(graphics.lod_detail);
|
||||||
|
// LoD distance
|
||||||
|
session_state
|
||||||
|
.client
|
||||||
|
.borrow_mut()
|
||||||
|
.set_lod_distance(graphics.lod_distance);
|
||||||
// Render mode
|
// Render mode
|
||||||
global_state
|
global_state
|
||||||
.window
|
.window
|
||||||
@ -507,7 +525,6 @@ impl SettingsChange {
|
|||||||
global_state.window.set_fullscreen_mode(graphics.fullscreen);
|
global_state.window.set_fullscreen_mode(graphics.fullscreen);
|
||||||
// Window size
|
// Window size
|
||||||
global_state.window.set_size(graphics.window_size.into());
|
global_state.window.set_size(graphics.window_size.into());
|
||||||
},
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
SettingsChange::Interface(interface_change) => {
|
SettingsChange::Interface(interface_change) => {
|
||||||
|
@ -71,3 +71,144 @@ impl Default for GraphicsSettings {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl GraphicsSettings {
|
||||||
|
pub fn into_minimal(self) -> Self {
|
||||||
|
use crate::render::*;
|
||||||
|
Self {
|
||||||
|
terrain_view_distance: 4,
|
||||||
|
entity_view_distance: 4,
|
||||||
|
lod_distance: 0,
|
||||||
|
sprite_render_distance: 80,
|
||||||
|
figure_lod_render_distance: 100,
|
||||||
|
lod_detail: 80,
|
||||||
|
render_mode: RenderMode {
|
||||||
|
aa: AaMode::FxUpscale,
|
||||||
|
cloud: CloudMode::Minimal,
|
||||||
|
reflection: ReflectionMode::Low,
|
||||||
|
fluid: FluidMode::Low,
|
||||||
|
lighting: LightingMode::Lambertian,
|
||||||
|
shadow: ShadowMode::None,
|
||||||
|
rain_occlusion: ShadowMapMode { resolution: 0.25 },
|
||||||
|
bloom: BloomMode::Off,
|
||||||
|
point_glow: 0.0,
|
||||||
|
upscale_mode: UpscaleMode { factor: 0.35 },
|
||||||
|
..self.render_mode
|
||||||
|
},
|
||||||
|
..self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn into_low(self) -> Self {
|
||||||
|
use crate::render::*;
|
||||||
|
Self {
|
||||||
|
terrain_view_distance: 7,
|
||||||
|
entity_view_distance: 7,
|
||||||
|
lod_distance: 75,
|
||||||
|
sprite_render_distance: 125,
|
||||||
|
figure_lod_render_distance: 200,
|
||||||
|
lod_detail: 200,
|
||||||
|
render_mode: RenderMode {
|
||||||
|
aa: AaMode::FxUpscale,
|
||||||
|
cloud: CloudMode::Low,
|
||||||
|
reflection: ReflectionMode::Medium,
|
||||||
|
fluid: FluidMode::Low,
|
||||||
|
lighting: LightingMode::Lambertian,
|
||||||
|
shadow: ShadowMode::Cheap,
|
||||||
|
rain_occlusion: ShadowMapMode { resolution: 0.25 },
|
||||||
|
bloom: BloomMode::Off,
|
||||||
|
point_glow: 0.35,
|
||||||
|
upscale_mode: UpscaleMode { factor: 0.65 },
|
||||||
|
..self.render_mode
|
||||||
|
},
|
||||||
|
..self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn into_medium(self) -> Self {
|
||||||
|
use crate::render::*;
|
||||||
|
Self {
|
||||||
|
terrain_view_distance: 10,
|
||||||
|
entity_view_distance: 10,
|
||||||
|
lod_distance: 150,
|
||||||
|
sprite_render_distance: 250,
|
||||||
|
figure_lod_render_distance: 350,
|
||||||
|
lod_detail: 300,
|
||||||
|
render_mode: RenderMode {
|
||||||
|
aa: AaMode::Fxaa,
|
||||||
|
cloud: CloudMode::Medium,
|
||||||
|
reflection: ReflectionMode::High,
|
||||||
|
fluid: FluidMode::Medium,
|
||||||
|
lighting: LightingMode::BlinnPhong,
|
||||||
|
shadow: ShadowMode::Map(ShadowMapMode { resolution: 0.75 }),
|
||||||
|
rain_occlusion: ShadowMapMode { resolution: 0.25 },
|
||||||
|
bloom: BloomMode::On(BloomConfig {
|
||||||
|
factor: BloomFactor::Medium,
|
||||||
|
uniform_blur: false,
|
||||||
|
}),
|
||||||
|
point_glow: 0.35,
|
||||||
|
upscale_mode: UpscaleMode { factor: 0.85 },
|
||||||
|
..self.render_mode
|
||||||
|
},
|
||||||
|
..self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn into_high(self) -> Self {
|
||||||
|
use crate::render::*;
|
||||||
|
Self {
|
||||||
|
terrain_view_distance: 16,
|
||||||
|
entity_view_distance: 16,
|
||||||
|
lod_distance: 200,
|
||||||
|
sprite_render_distance: 350,
|
||||||
|
figure_lod_render_distance: 450,
|
||||||
|
lod_detail: 375,
|
||||||
|
render_mode: RenderMode {
|
||||||
|
aa: AaMode::Fxaa,
|
||||||
|
cloud: CloudMode::Medium,
|
||||||
|
reflection: ReflectionMode::High,
|
||||||
|
fluid: FluidMode::Medium,
|
||||||
|
lighting: LightingMode::Ashikhmin,
|
||||||
|
shadow: ShadowMode::Map(ShadowMapMode { resolution: 1.0 }),
|
||||||
|
rain_occlusion: ShadowMapMode { resolution: 0.5 },
|
||||||
|
bloom: BloomMode::On(BloomConfig {
|
||||||
|
factor: BloomFactor::Medium,
|
||||||
|
uniform_blur: true,
|
||||||
|
}),
|
||||||
|
point_glow: 0.35,
|
||||||
|
upscale_mode: UpscaleMode { factor: 1.0 },
|
||||||
|
..self.render_mode
|
||||||
|
},
|
||||||
|
..self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn into_ultra(self) -> Self {
|
||||||
|
use crate::render::*;
|
||||||
|
Self {
|
||||||
|
terrain_view_distance: 16,
|
||||||
|
entity_view_distance: 16,
|
||||||
|
lod_distance: 450,
|
||||||
|
sprite_render_distance: 800,
|
||||||
|
figure_lod_render_distance: 600,
|
||||||
|
lod_detail: 500,
|
||||||
|
render_mode: RenderMode {
|
||||||
|
aa: AaMode::Fxaa,
|
||||||
|
cloud: CloudMode::High,
|
||||||
|
reflection: ReflectionMode::High,
|
||||||
|
fluid: FluidMode::High,
|
||||||
|
lighting: LightingMode::Ashikhmin,
|
||||||
|
shadow: ShadowMode::Map(ShadowMapMode { resolution: 1.75 }),
|
||||||
|
rain_occlusion: ShadowMapMode { resolution: 0.5 },
|
||||||
|
bloom: BloomMode::On(BloomConfig {
|
||||||
|
factor: BloomFactor::Medium,
|
||||||
|
uniform_blur: true,
|
||||||
|
}),
|
||||||
|
point_glow: 0.35,
|
||||||
|
upscale_mode: UpscaleMode { factor: 1.25 },
|
||||||
|
..self.render_mode
|
||||||
|
},
|
||||||
|
..self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user