mirror of
https://github.com/ClassiCube/ClassiCube.git
synced 2025-09-14 18:15:28 -04:00
Fix isometric blocks. Save chat font size and mouse sensitivity settings. Enter and keypad enter now do the same thing as clicking on 'OK' in menu screens.
This commit is contained in:
parent
b0091a8628
commit
ad57351cf2
@ -27,11 +27,10 @@ namespace ClassicalSharp {
|
|||||||
blockHeight = info.Height[block];
|
blockHeight = info.Height[block];
|
||||||
index = 0;
|
index = 0;
|
||||||
scale = size;
|
scale = size;
|
||||||
|
|
||||||
// screen to isometric coords
|
// screen to isometric coords
|
||||||
pos.X = x; pos.Y = -y; pos.Z = 0;
|
pos.X = x; pos.Y = y; pos.Z = 0;
|
||||||
pos = Utils.RotateX( pos, (float)Utils.DegreesToRadians( -35.264f ) );
|
pos = Utils.RotateY( Utils.RotateX( pos, -angleX ), -angleY );
|
||||||
pos = Utils.RotateY( pos, (float)Utils.DegreesToRadians( 45f ) );
|
|
||||||
|
|
||||||
if( info.IsSprite[block] ) {
|
if( info.IsSprite[block] ) {
|
||||||
DrawXFace( block, 0f, TileSide.Right );
|
DrawXFace( block, 0f, TileSide.Right );
|
||||||
@ -41,40 +40,48 @@ namespace ClassicalSharp {
|
|||||||
DrawZFace( block, -scale, TileSide.Back );
|
DrawZFace( block, -scale, TileSide.Back );
|
||||||
DrawYFace( block, scale * blockHeight, TileSide.Top );
|
DrawYFace( block, scale * blockHeight, TileSide.Top );
|
||||||
}
|
}
|
||||||
game.Graphics.DrawDynamicIndexedVb( DrawMode.Triangles, cache.vb,
|
|
||||||
|
for( int i = 0; i < index; i++ )
|
||||||
|
TransformVertex( ref cache.vertices[i] );
|
||||||
|
game.Graphics.DrawDynamicIndexedVb( DrawMode.Triangles, cache.vb,
|
||||||
cache.vertices, index, index * 6 / 4 );
|
cache.vertices, index, index * 6 / 4 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static float angleY = (float)Utils.DegreesToRadians( -45f );
|
||||||
|
static float angleX = (float)Utils.DegreesToRadians( 26.565f );
|
||||||
|
static void TransformVertex( ref VertexPos3fTex2fCol4b vertex ) {
|
||||||
|
Vector3 pos = new Vector3( vertex.X, vertex.Y, vertex.Z );
|
||||||
|
#if USE_DX
|
||||||
|
// See comment in IGraphicsApi.Draw2DTexture()
|
||||||
|
pos.X -= 0.5f;
|
||||||
|
pos.Y -= 0.5f;
|
||||||
|
#endif
|
||||||
|
pos = Utils.RotateX( Utils.RotateY( pos, angleY ), angleX );
|
||||||
|
vertex.X = pos.X; vertex.Y = pos.Y; vertex.Z = pos.Z;
|
||||||
|
}
|
||||||
|
|
||||||
public static void SetupState( IGraphicsApi graphics, bool setFog ) {
|
public static void SetupState( IGraphicsApi graphics, bool setFog ) {
|
||||||
graphics.PushMatrix();
|
if( setFog ) graphics.Fog = false;
|
||||||
Matrix4 m = Matrix4.RotateY( (float)Utils.DegreesToRadians( 45f ) ) *
|
|
||||||
Matrix4.RotateX( (float)Utils.RadiansToDegrees( -35.264f ) );
|
|
||||||
graphics.LoadMatrix( ref m );
|
|
||||||
if( setFog )
|
|
||||||
graphics.Fog = false;
|
|
||||||
graphics.BeginVbBatch( VertexFormat.Pos3fTex2fCol4b );
|
graphics.BeginVbBatch( VertexFormat.Pos3fTex2fCol4b );
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void RestoreState( IGraphicsApi graphics, bool setFog ) {
|
public static void RestoreState( IGraphicsApi graphics, bool setFog ) {
|
||||||
graphics.PopMatrix();
|
if( setFog ) graphics.Fog = true;
|
||||||
if( setFog )
|
|
||||||
graphics.Fog = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static Vector3 pos = Vector3.Zero;
|
static Vector3 pos = Vector3.Zero;
|
||||||
static void DrawYFace( byte block, float y, int side ) {
|
static void DrawYFace( byte block, float y, int side ) {
|
||||||
int texId = info.GetTextureLoc( block, side );
|
int texId = info.GetTextureLoc( block, side );
|
||||||
TextureRectangle rec = atlas.GetTexRec( texId );
|
TextureRectangle rec = atlas.GetTexRec( texId );
|
||||||
FastColour col = colNormal;
|
FastColour col = colNormal;
|
||||||
|
|
||||||
cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X - scale, pos.Y + y,
|
cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X - scale, pos.Y - y,
|
||||||
pos.Z - scale, rec.U2, rec.V2, col );
|
pos.Z - scale, rec.U2, rec.V2, col );
|
||||||
cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X - scale, pos.Y + y,
|
cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X - scale, pos.Y - y,
|
||||||
pos.Z + scale, rec.U1, rec.V2, col );
|
pos.Z + scale, rec.U1, rec.V2, col );
|
||||||
cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X + scale, pos.Y + y,
|
cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X + scale, pos.Y - y,
|
||||||
pos.Z + scale, rec.U1, rec.V1, col );
|
pos.Z + scale, rec.U1, rec.V1, col );
|
||||||
cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X + scale, pos.Y + y,
|
cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X + scale, pos.Y - y,
|
||||||
pos.Z - scale, rec.U2, rec.V1, col );
|
pos.Z - scale, rec.U2, rec.V1, col );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,14 +92,14 @@ namespace ClassicalSharp {
|
|||||||
rec.V2 = rec.V1 + blockHeight * TerrainAtlas2D.invElementSize;
|
rec.V2 = rec.V1 + blockHeight * TerrainAtlas2D.invElementSize;
|
||||||
FastColour col = colZSide;
|
FastColour col = colZSide;
|
||||||
|
|
||||||
cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X - scale, pos.Y - scale * blockHeight,
|
cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X - scale, pos.Y + scale * blockHeight,
|
||||||
pos.Z + z, rec.U1, rec.V2, col );
|
pos.Z - z, rec.U1, rec.V2, col );
|
||||||
cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X - scale, pos.Y + scale * blockHeight,
|
cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X - scale, pos.Y - scale * blockHeight,
|
||||||
pos.Z + z, rec.U1, rec.V1, col );
|
pos.Z - z, rec.U1, rec.V1, col );
|
||||||
cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X + scale, pos.Y + scale * blockHeight,
|
cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X + scale, pos.Y - scale * blockHeight,
|
||||||
pos.Z + z, rec.U2, rec.V1, col );
|
pos.Z - z, rec.U2, rec.V1, col );
|
||||||
cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X + scale, pos.Y - scale * blockHeight,
|
cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X + scale, pos.Y + scale * blockHeight,
|
||||||
pos.Z + z, rec.U2, rec.V2, col );
|
pos.Z - z, rec.U2, rec.V2, col );
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DrawXFace( byte block, float x, int side ) {
|
static void DrawXFace( byte block, float x, int side ) {
|
||||||
@ -102,13 +109,13 @@ namespace ClassicalSharp {
|
|||||||
rec.V2 = rec.V1 + blockHeight * TerrainAtlas2D.invElementSize;
|
rec.V2 = rec.V1 + blockHeight * TerrainAtlas2D.invElementSize;
|
||||||
FastColour col = colXSide;
|
FastColour col = colXSide;
|
||||||
|
|
||||||
cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X + x, pos.Y - scale * blockHeight,
|
cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X - x, pos.Y + scale * blockHeight,
|
||||||
pos.Z - scale, rec.U1, rec.V2, colNormal );
|
pos.Z - scale, rec.U1, rec.V2, colNormal );
|
||||||
cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X + x, pos.Y + scale * blockHeight,
|
cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X - x, pos.Y - scale * blockHeight,
|
||||||
pos.Z - scale, rec.U1, rec.V1, colNormal );
|
pos.Z - scale, rec.U1, rec.V1, colNormal );
|
||||||
cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X + x, pos.Y + scale * blockHeight,
|
cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X - x, pos.Y - scale * blockHeight,
|
||||||
pos.Z + scale, rec.U2, rec.V1, colNormal );
|
pos.Z + scale, rec.U2, rec.V1, colNormal );
|
||||||
cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X + x, pos.Y - scale * blockHeight,
|
cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X - x, pos.Y + scale * blockHeight,
|
||||||
pos.Z + scale, rec.U2, rec.V2, colNormal );
|
pos.Z + scale, rec.U2, rec.V2, colNormal );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,6 +42,10 @@ namespace ClassicalSharp {
|
|||||||
if( key == Key.Escape ) {
|
if( key == Key.Escape ) {
|
||||||
game.SetNewScreen( new NormalScreen( game ) );
|
game.SetNewScreen( new NormalScreen( game ) );
|
||||||
return true;
|
return true;
|
||||||
|
} else if( (key == Key.Enter || key == Key.KeypadEnter)
|
||||||
|
&& inputWidget != null ) {
|
||||||
|
ChangeSetting();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
if( inputWidget == null ) return true;
|
if( inputWidget == null ) return true;
|
||||||
return inputWidget.HandlesKeyDown( key );
|
return inputWidget.HandlesKeyDown( key );
|
||||||
@ -87,20 +91,12 @@ namespace ClassicalSharp {
|
|||||||
string text = widget.Text + ": " + widget.GetValue( game );
|
string text = widget.Text + ": " + widget.GetValue( game );
|
||||||
descWidget = TextWidget.Create( game, 0, 100, text, Docking.Centre, Docking.Centre, regularFont );
|
descWidget = TextWidget.Create( game, 0, 100, text, Docking.Centre, Docking.Centre, regularFont );
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void OnWidgetClick( Game game, ButtonWidget widget ) {
|
protected void OnWidgetClick( Game game, ButtonWidget widget ) {
|
||||||
if( widget == buttons[okayIndex] ) {
|
if( widget == buttons[okayIndex] ) {
|
||||||
string text = inputWidget.GetText();
|
ChangeSetting();
|
||||||
if( inputWidget.Validator.IsValidValue( text ) )
|
|
||||||
targetWidget.SetValue( game, text );
|
|
||||||
inputWidget.Dispose();
|
|
||||||
inputWidget = null;
|
|
||||||
UpdateDescription( targetWidget );
|
|
||||||
targetWidget = null;
|
|
||||||
buttons[okayIndex].Dispose();
|
|
||||||
buttons[okayIndex] = null;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int index = Array.IndexOf<ButtonWidget>( buttons, widget );
|
int index = Array.IndexOf<ButtonWidget>( buttons, widget );
|
||||||
MenuInputValidator validator = validators[index];
|
MenuInputValidator validator = validators[index];
|
||||||
@ -122,5 +118,17 @@ namespace ClassicalSharp {
|
|||||||
Docking.Centre, Docking.Centre, titleFont, OnWidgetClick );
|
Docking.Centre, Docking.Centre, titleFont, OnWidgetClick );
|
||||||
UpdateDescription( targetWidget );
|
UpdateDescription( targetWidget );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ChangeSetting() {
|
||||||
|
string text = inputWidget.GetText();
|
||||||
|
if( inputWidget.Validator.IsValidValue( text ) )
|
||||||
|
targetWidget.SetValue( game, text );
|
||||||
|
inputWidget.Dispose();
|
||||||
|
inputWidget = null;
|
||||||
|
UpdateDescription( targetWidget );
|
||||||
|
targetWidget = null;
|
||||||
|
buttons[okayIndex].Dispose();
|
||||||
|
buttons[okayIndex] = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -28,11 +28,13 @@ namespace ClassicalSharp {
|
|||||||
|
|
||||||
Make( 140, -50, "Mouse sensitivity", Docking.Centre, OnWidgetClick,
|
Make( 140, -50, "Mouse sensitivity", Docking.Centre, OnWidgetClick,
|
||||||
g => g.MouseSensitivity.ToString(),
|
g => g.MouseSensitivity.ToString(),
|
||||||
(g, v) => g.MouseSensitivity = Int32.Parse( v ) ),
|
(g, v) => { g.MouseSensitivity = Int32.Parse( v );
|
||||||
|
Options.Set( OptionsKey.Sensitivity, v ); } ),
|
||||||
|
|
||||||
Make( 140, 0, "Chat font size", Docking.Centre, OnWidgetClick,
|
Make( 140, 0, "Chat font size", Docking.Centre, OnWidgetClick,
|
||||||
g => g.Chat.FontSize.ToString(),
|
g => g.Chat.FontSize.ToString(),
|
||||||
(g, v) => g.Chat.FontSize = Int32.Parse( v ) ),
|
(g, v) => { g.Chat.FontSize = Int32.Parse( v );
|
||||||
|
Options.Set( OptionsKey.FontSize, v ); } ),
|
||||||
|
|
||||||
!network.IsSinglePlayer ? null :
|
!network.IsSinglePlayer ? null :
|
||||||
Make( 140, 50, "Singleplayer physics", Docking.Centre, OnWidgetClick,
|
Make( 140, 50, "Singleplayer physics", Docking.Centre, OnWidgetClick,
|
||||||
|
@ -49,7 +49,7 @@ namespace ClassicalSharp {
|
|||||||
for( int i = 0; i < hotbarCount; i++ ) {
|
for( int i = 0; i < hotbarCount; i++ ) {
|
||||||
int x = X + i * blockSize;
|
int x = X + i * blockSize;
|
||||||
IsometricBlockDrawer.Draw( game, (byte)game.Inventory.Hotbar[i], 10,
|
IsometricBlockDrawer.Draw( game, (byte)game.Inventory.Hotbar[i], 10,
|
||||||
x + blockSize / 2, game.Height - 12 );
|
x + blockSize / 2, game.Height - 18 );
|
||||||
if( i == game.Inventory.HeldBlockIndex )
|
if( i == game.Inventory.HeldBlockIndex )
|
||||||
selectedBlock.X1 = x;
|
selectedBlock.X1 = x;
|
||||||
}
|
}
|
||||||
|
@ -102,12 +102,14 @@ namespace ClassicalSharp {
|
|||||||
} catch( IOException ) {
|
} catch( IOException ) {
|
||||||
Utils.LogWarning( "Unable to load options.txt" );
|
Utils.LogWarning( "Unable to load options.txt" );
|
||||||
}
|
}
|
||||||
ViewDistance = Options.GetInt( "viewdist", 16, 8192, 512 );
|
ViewDistance = Options.GetInt( OptionsKey.ViewDist, 16, 8192, 512 );
|
||||||
Keys = new KeyMap();
|
Keys = new KeyMap();
|
||||||
InputHandler = new InputHandler( this );
|
InputHandler = new InputHandler( this );
|
||||||
Chat = new ChatLog( this );
|
Chat = new ChatLog( this );
|
||||||
|
Chat.FontSize = Options.GetInt( OptionsKey.FontSize, 6, 30, 12 );
|
||||||
Drawer2D = new GdiPlusDrawer2D( Graphics );
|
Drawer2D = new GdiPlusDrawer2D( Graphics );
|
||||||
defaultIb = Graphics.MakeDefaultIb();
|
defaultIb = Graphics.MakeDefaultIb();
|
||||||
|
MouseSensitivity = Options.GetInt( OptionsKey.Sensitivity, 1, 100, 30 );
|
||||||
|
|
||||||
ModelCache = new ModelCache( this );
|
ModelCache = new ModelCache( this );
|
||||||
ModelCache.InitCache();
|
ModelCache.InitCache();
|
||||||
@ -170,7 +172,7 @@ namespace ClassicalSharp {
|
|||||||
public void SetViewDistance( int distance ) {
|
public void SetViewDistance( int distance ) {
|
||||||
ViewDistance = distance;
|
ViewDistance = distance;
|
||||||
Utils.LogDebug( "setting view distance to: " + distance );
|
Utils.LogDebug( "setting view distance to: " + distance );
|
||||||
Options.Set( "viewdist", distance.ToString() );
|
Options.Set( OptionsKey.ViewDist, distance );
|
||||||
Events.RaiseViewDistanceChanged();
|
Events.RaiseViewDistanceChanged();
|
||||||
UpdateProjection();
|
UpdateProjection();
|
||||||
}
|
}
|
||||||
|
@ -66,7 +66,7 @@ namespace ClassicalSharp {
|
|||||||
string key = "key-" + names[i];
|
string key = "key-" + names[i];
|
||||||
string value = Options.Get( key );
|
string value = Options.Get( key );
|
||||||
if( value == null ) {
|
if( value == null ) {
|
||||||
Options.Set( key, Keys[i].ToString() );
|
Options.Set( key, Keys[i] );
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,7 +74,7 @@ namespace ClassicalSharp {
|
|||||||
try {
|
try {
|
||||||
mapping = (Key)Enum.Parse( typeof( Key ), value, true );
|
mapping = (Key)Enum.Parse( typeof( Key ), value, true );
|
||||||
} catch( ArgumentException ) {
|
} catch( ArgumentException ) {
|
||||||
Options.Set( key, Keys[i].ToString() );
|
Options.Set( key, Keys[i] );
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if( !IsReservedKey( mapping ) )
|
if( !IsReservedKey( mapping ) )
|
||||||
@ -85,7 +85,7 @@ namespace ClassicalSharp {
|
|||||||
void SaveKeyBindings() {
|
void SaveKeyBindings() {
|
||||||
string[] names = KeyMapping.GetNames( typeof( KeyMapping ) );
|
string[] names = KeyMapping.GetNames( typeof( KeyMapping ) );
|
||||||
for( int i = 0; i < names.Length; i++ ) {
|
for( int i = 0; i < names.Length; i++ ) {
|
||||||
Options.Set( "key-" + names[i], Keys[i].ToString() );
|
Options.Set( "key-" + names[i], Keys[i] );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,12 @@ using System.IO;
|
|||||||
|
|
||||||
namespace ClassicalSharp {
|
namespace ClassicalSharp {
|
||||||
|
|
||||||
|
public static class OptionsKey {
|
||||||
|
public const string ViewDist = "viewdist";
|
||||||
|
public const string FontSize = "chatfontsize";
|
||||||
|
public const string Sensitivity = "mousesensitivity";
|
||||||
|
}
|
||||||
|
|
||||||
public static class Options {
|
public static class Options {
|
||||||
|
|
||||||
static Dictionary<string, string> OptionsSet = new Dictionary<string, string>();
|
static Dictionary<string, string> OptionsSet = new Dictionary<string, string>();
|
||||||
@ -39,6 +45,11 @@ namespace ClassicalSharp {
|
|||||||
HasChanged = true;
|
HasChanged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void Set<T>( string key, T value ) {
|
||||||
|
OptionsSet[key] = value.ToString();
|
||||||
|
HasChanged = true;
|
||||||
|
}
|
||||||
|
|
||||||
public const string OptionsFile = "options.txt";
|
public const string OptionsFile = "options.txt";
|
||||||
|
|
||||||
public static void Load() {
|
public static void Load() {
|
||||||
|
@ -235,7 +235,7 @@ namespace Launcher {
|
|||||||
Options.Set( "launcher-ip", data.Ip );
|
Options.Set( "launcher-ip", data.Ip );
|
||||||
Options.Set( "launcher-port", data.Port );
|
Options.Set( "launcher-port", data.Port );
|
||||||
Options.Set( "launcher-mppass", EncodeMppass( data.Mppass, data.Username ) );
|
Options.Set( "launcher-mppass", EncodeMppass( data.Mppass, data.Username ) );
|
||||||
Options.Set( "launcher-ccskins", classiCubeSkins.ToString() );
|
Options.Set( "launcher-ccskins", classiCubeSkins );
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Options.Save();
|
Options.Save();
|
||||||
|
@ -119,6 +119,20 @@ namespace OpenTK {
|
|||||||
public static void Divide(ref Vector4 vector, ref Vector4 scale, out Vector4 result) {
|
public static void Divide(ref Vector4 vector, ref Vector4 scale, out Vector4 result) {
|
||||||
result = new Vector4(vector.X / scale.X, vector.Y / scale.Y, vector.Z / scale.Z, vector.W / scale.W);
|
result = new Vector4(vector.X / scale.X, vector.Y / scale.Y, vector.Z / scale.Z, vector.W / scale.W);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Vector4 Transform(Vector4 vec, Matrix4 mat) {
|
||||||
|
Vector4 result;
|
||||||
|
Transform(ref vec, ref mat, out result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Transform(ref Vector4 vec, ref Matrix4 mat, out Vector4 result) {
|
||||||
|
result = new Vector4(
|
||||||
|
vec.X * mat.Row0.X + vec.Y * mat.Row1.X + vec.Z * mat.Row2.X + vec.W * mat.Row3.X,
|
||||||
|
vec.X * mat.Row0.Y + vec.Y * mat.Row1.Y + vec.Z * mat.Row2.Y + vec.W * mat.Row3.Y,
|
||||||
|
vec.X * mat.Row0.Z + vec.Y * mat.Row1.Z + vec.Z * mat.Row2.Z + vec.W * mat.Row3.Z,
|
||||||
|
vec.X * mat.Row0.W + vec.Y * mat.Row1.W + vec.Z * mat.Row2.W + vec.W * mat.Row3.W);
|
||||||
|
}
|
||||||
|
|
||||||
public static Vector4 operator + (Vector4 left, Vector4 right) {
|
public static Vector4 operator + (Vector4 left, Vector4 right) {
|
||||||
left.X += right.X;
|
left.X += right.X;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user