Brand new movement script
This commit is contained in:
@@ -9,7 +9,7 @@ dock_filesystem_v_split_offset=0
|
|||||||
dock_filesystem_display_mode=0
|
dock_filesystem_display_mode=0
|
||||||
dock_filesystem_file_sort=0
|
dock_filesystem_file_sort=0
|
||||||
dock_filesystem_file_list_display_mode=1
|
dock_filesystem_file_list_display_mode=1
|
||||||
dock_filesystem_selected_paths=PackedStringArray("res://assets/Materials/stone_pathway/textures/stone_pathway_02_nor_gl_1k.png")
|
dock_filesystem_selected_paths=PackedStringArray("res://Player.tscn")
|
||||||
dock_filesystem_uncollapsed_paths=PackedStringArray("Favorites", "res://", "res://assets/", "res://assets/Materials/", "res://assets/Materials/stone_pathway/", "res://assets/Materials/stone_pathway/textures/")
|
dock_filesystem_uncollapsed_paths=PackedStringArray("Favorites", "res://", "res://assets/", "res://assets/Materials/", "res://assets/Materials/stone_pathway/", "res://assets/Materials/stone_pathway/textures/")
|
||||||
dock_node_current_tab=0
|
dock_node_current_tab=0
|
||||||
dock_history_include_scene=true
|
dock_history_include_scene=true
|
||||||
@@ -28,8 +28,8 @@ dock_5="Inspector,Node,History"
|
|||||||
|
|
||||||
[EditorNode]
|
[EditorNode]
|
||||||
|
|
||||||
open_scenes=PackedStringArray("res://Floor.tscn")
|
open_scenes=PackedStringArray("res://Floor.tscn", "res://Player.tscn")
|
||||||
current_scene="res://Floor.tscn"
|
current_scene="res://Player.tscn"
|
||||||
center_split_offset=0
|
center_split_offset=0
|
||||||
selected_default_debugger_tab_idx=0
|
selected_default_debugger_tab_idx=0
|
||||||
selected_main_editor_idx=2
|
selected_main_editor_idx=2
|
||||||
@@ -39,7 +39,7 @@ selected_bottom_panel_item=0
|
|||||||
|
|
||||||
screen=1
|
screen=1
|
||||||
mode="fullscreen"
|
mode="fullscreen"
|
||||||
size=Vector2i(1920, 1200)
|
size=Vector2i(1908, 1163)
|
||||||
position=Vector2i(1440, 0)
|
position=Vector2i(1440, 0)
|
||||||
|
|
||||||
[ScriptEditor]
|
[ScriptEditor]
|
||||||
|
|||||||
Binary file not shown.
@@ -1,16 +1,16 @@
|
|||||||
63f7b34db8d8cdea90c76aacccf841ec
|
63f7b34db8d8cdea90c76aacccf841ec
|
||||||
::res://::1767415906
|
::res://::1767479118
|
||||||
DevTest.tscn::PackedScene::9123247578013174228::1767411651::0::1::::<><><>0<>0<><>::uid://grcsjnqdsbmj::::res://Floor.tscn<>uid://dsj41jw17qh40::::res://Player.tscn
|
DevTest.tscn::PackedScene::9123247578013174228::1767411651::0::1::::<><><>0<>0<><>::uid://grcsjnqdsbmj::::res://Floor.tscn<>uid://dsj41jw17qh40::::res://Player.tscn
|
||||||
Floor.tscn::PackedScene::456381555447325093::1767411339::0::1::::<><><>0<>0<><>::
|
Floor.tscn::PackedScene::456381555447325093::1767418994::0::1::::<><><>0<>0<><>::uid://dwdp3f073q201::::res://assets/Materials/stone_pathway/textures/stone_pathway_02_diff_1k.png<>uid://dth2ctcqe0nri::::res://assets/Materials/stone_pathway/textures/stone_pathway_02_nor_gl_1k.png<>uid://c8vnh4apwdyy6::::res://assets/Materials/stone_pathway/textures/stone_pathway_02_rough_1k.png
|
||||||
Player.tscn::PackedScene::8443048367702749007::1767415906::0::1::::<><><>0<>0<><>::uid://b8ddkhlwoiuvm::::res://Scripts/player.gd
|
Player.tscn::PackedScene::8443048367702749007::1767415906::0::1::::<><><>0<>0<><>::uid://b8ddkhlwoiuvm::::res://Scripts/player.gd
|
||||||
::res://assets/::1767416168
|
::res://assets/::1767416168
|
||||||
icon.svg::CompressedTexture2D::347234531240620840::1767410708::1767410719::1::::<><><>0<>0<>cd8caee1c8a7b4b3cbd67faa4c96c3c0<>res://.godot/imported/icon.svg-56083ea2a1f1a4f1e49773bdc6d7826c.ctex::
|
icon.svg::CompressedTexture2D::347234531240620840::1767410708::1767410719::1::::<><><>0<>0<>cd8caee1c8a7b4b3cbd67faa4c96c3c0<>res://.godot/imported/icon.svg-56083ea2a1f1a4f1e49773bdc6d7826c.ctex::
|
||||||
::res://assets/Materials/::1767416391
|
::res://assets/Materials/::1767416391
|
||||||
::res://assets/Materials/stone_pathway/::1767416379
|
::res://assets/Materials/stone_pathway/::1767416379
|
||||||
::res://assets/Materials/stone_pathway/textures/::1767416516
|
::res://assets/Materials/stone_pathway/textures/::1767416631
|
||||||
stone_pathway_02_diff_1k.png::CompressedTexture2D::8710570804227902040::1767416372::1767416409::1::::<><><>0<>0<>024744925d268103fd25f3e5fec2366c<>res://.godot/imported/stone_pathway_02_diff_1k.png-120f486f1110be0c1fbd52209fdcc8de.s3tc.ctex::
|
stone_pathway_02_diff_1k.png::CompressedTexture2D::8710570804227902040::1767416372::1767416409::1::::<><><>0<>0<>024744925d268103fd25f3e5fec2366c<>res://.godot/imported/stone_pathway_02_diff_1k.png-120f486f1110be0c1fbd52209fdcc8de.s3tc.ctex::
|
||||||
stone_pathway_02_disp_1k.png::CompressedTexture2D::6812096667217185925::1767416372::1767416391::1::::<><><>0<>0<>add6b013cee511daf3f495c87865d6f9<>res://.godot/imported/stone_pathway_02_disp_1k.png-09ca21ec1b99b1589b5d080c3969064c.ctex::
|
stone_pathway_02_disp_1k.png::CompressedTexture2D::6812096667217185925::1767416372::1767416391::1::::<><><>0<>0<>add6b013cee511daf3f495c87865d6f9<>res://.godot/imported/stone_pathway_02_disp_1k.png-09ca21ec1b99b1589b5d080c3969064c.ctex::
|
||||||
stone_pathway_02_nor_gl_1k.png::CompressedTexture2D::8508944656639413126::1767416372::1767416516::1::::<><><>0<>0<>82cd783198cdc6e8bee4a3c3fa744c24<>res://.godot/imported/stone_pathway_02_nor_gl_1k.png-90a48320dd4c9c60b9e68fa350107138.s3tc.ctex::
|
stone_pathway_02_nor_gl_1k.png::CompressedTexture2D::8508944656639413126::1767416372::1767416516::1::::<><><>0<>0<>82cd783198cdc6e8bee4a3c3fa744c24<>res://.godot/imported/stone_pathway_02_nor_gl_1k.png-90a48320dd4c9c60b9e68fa350107138.s3tc.ctex::
|
||||||
stone_pathway_02_rough_1k.png::CompressedTexture2D::7133228485628055815::1767416372::1767416631::1::::<><><>0<>0<>ca9d6e30979c45204097877beba0ef3e<>res://.godot/imported/stone_pathway_02_rough_1k.png-7bc2e60cf9d95ba7753177c3883fca73.s3tc.ctex::
|
stone_pathway_02_rough_1k.png::CompressedTexture2D::7133228485628055815::1767416372::1767416631::1::::<><><>0<>0<>ca9d6e30979c45204097877beba0ef3e<>res://.godot/imported/stone_pathway_02_rough_1k.png-7bc2e60cf9d95ba7753177c3883fca73.s3tc.ctex::
|
||||||
::res://Scripts/::1767415906
|
::res://Scripts/::1767418816
|
||||||
player.gd::GDScript::4709046051602623302::1767415906::0::1::::<>CharacterBody3D<><>0<>0<><>::
|
player.gd::GDScript::4709046051602623302::1767418816::0::1::::<>CharacterBody3D<><>0<>0<><>::
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
res://Player.tscn
|
|
||||||
res://Scripts/player.gd
|
|
||||||
res://Floor.tscn
|
res://Floor.tscn
|
||||||
|
res://Scripts/player.gd
|
||||||
|
res://Player.tscn
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ project_settings=Rect2(1800, 250, 1200, 700)
|
|||||||
|
|
||||||
[recent_files]
|
[recent_files]
|
||||||
|
|
||||||
scenes=["res://node_3d.tscn", "res://Player.tscn", "res://Floor.tscn"]
|
scenes=["res://Player.tscn", "res://node_3d.tscn", "res://Floor.tscn"]
|
||||||
scripts=["res://Scripts/player.gd"]
|
scripts=["res://Scripts/player.gd"]
|
||||||
|
|
||||||
[script_setup]
|
[script_setup]
|
||||||
|
|||||||
@@ -3,11 +3,11 @@
|
|||||||
state={
|
state={
|
||||||
"bookmarks": PackedInt32Array(),
|
"bookmarks": PackedInt32Array(),
|
||||||
"breakpoints": PackedInt32Array(),
|
"breakpoints": PackedInt32Array(),
|
||||||
"column": 8,
|
"column": 0,
|
||||||
"folded_lines": Array[int]([]),
|
"folded_lines": Array[int]([]),
|
||||||
"h_scroll_position": 0,
|
"h_scroll_position": 0,
|
||||||
"row": 108,
|
"row": 178,
|
||||||
"scroll_position": 97.0,
|
"scroll_position": 161.0,
|
||||||
"selection": false,
|
"selection": false,
|
||||||
"syntax_highlighter": "GDScript"
|
"syntax_highlighter": "GDScript"
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
@@ -1,175 +1,190 @@
|
|||||||
extends CharacterBody3D
|
extends CharacterBody3D
|
||||||
|
|
||||||
@export var mouse_sensitivity = 1
|
@export var mouse_sensitivity := 1.0
|
||||||
|
|
||||||
# ======== Movement Stuff
|
# =====================
|
||||||
var air_accel = 1.0
|
# Movement
|
||||||
var max_air_speed = 1.0
|
# =====================
|
||||||
|
@export var walk_speed := 10.0
|
||||||
|
@export var crouch_speed := 5.0
|
||||||
|
@export var slide_speed := 18.0
|
||||||
|
@export var jump_velocity := 4.5
|
||||||
|
|
||||||
|
@export var ground_friction := 25.0
|
||||||
|
@export var slide_friction := 15.0
|
||||||
|
|
||||||
|
# ===== Air Control
|
||||||
|
@export var air_turn_speed := 7.0
|
||||||
|
@export var air_input_strength := 50.0
|
||||||
|
@export var air_drag := 0.5
|
||||||
|
@export var max_air_speed := 15.0
|
||||||
|
|
||||||
|
# =====================
|
||||||
|
# Camera
|
||||||
|
# =====================
|
||||||
|
@export var base_fov := 70.0
|
||||||
|
const SLIDE_FOV_ADD := 35.0
|
||||||
|
|
||||||
|
@export var crouch_height := 0.5
|
||||||
|
@export var stand_height := 1.0
|
||||||
|
|
||||||
|
const MAX_LOOK_UP := deg_to_rad(80)
|
||||||
|
const MAX_LOOK_DOWN := deg_to_rad(-80)
|
||||||
|
|
||||||
|
# =====================
|
||||||
|
# Stuff
|
||||||
|
# =====================
|
||||||
|
var is_crouching := false
|
||||||
|
var is_sliding := false
|
||||||
|
var preserve_air_momentum := false
|
||||||
|
var just_jumped := false
|
||||||
|
|
||||||
|
var pitch := 0.0
|
||||||
|
var slide_direction := Vector3.ZERO
|
||||||
|
|
||||||
|
@onready var camera_pivot: Node3D = $CameraPivot
|
||||||
|
@onready var camera: Camera3D = $CameraPivot/Camera3D
|
||||||
|
|
||||||
|
|
||||||
var fov = 70.0
|
func _ready():
|
||||||
const sliding_fov_add = 35.0
|
mouse_sensitivity *= 0.001
|
||||||
var sliding_fov
|
camera.fov = base_fov
|
||||||
const walk_speed = 10.0
|
|
||||||
var crouch_speed = 5
|
|
||||||
var slide_speed = 15
|
|
||||||
var slide_friction =15
|
|
||||||
var slide_direction = Vector3.ZERO
|
|
||||||
const jump_velocity = 4.5
|
|
||||||
|
|
||||||
|
|
||||||
# ========= Cam Stuff
|
|
||||||
var max_look_up = deg_to_rad(80)
|
|
||||||
var max_look_down = deg_to_rad(-80)
|
|
||||||
var crouch_height = 0.5
|
|
||||||
var stand_height = 1.0
|
|
||||||
var pitch = 0
|
|
||||||
|
|
||||||
@onready var camera_pivot = $CameraPivot
|
|
||||||
|
|
||||||
# ========= Other Stuff
|
|
||||||
var is_crouching = false
|
|
||||||
var is_sliding = false
|
|
||||||
var preserve_air_momentum = false
|
|
||||||
var just_jumped = false
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
|
||||||
$CameraPivot/Camera3D.fov = fov
|
|
||||||
mouse_sensitivity = mouse_sensitivity * 0.001
|
|
||||||
Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
|
Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
|
||||||
sliding_fov = fov + sliding_fov_add
|
|
||||||
|
|
||||||
|
|
||||||
func _input(event: InputEvent) -> void:
|
|
||||||
if event.is_action_pressed("ui_cancel"):
|
|
||||||
Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE)
|
|
||||||
if event is InputEventMouseButton:
|
|
||||||
Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
func _unhandled_input(event: InputEvent) -> void:
|
func _unhandled_input(event):
|
||||||
if event is InputEventMouseMotion:
|
if event is InputEventMouseMotion:
|
||||||
rotate_y(-event.relative.x * mouse_sensitivity)
|
rotate_y(-event.relative.x * mouse_sensitivity)
|
||||||
|
|
||||||
pitch -= event.relative.y * mouse_sensitivity
|
pitch -= event.relative.y * mouse_sensitivity
|
||||||
pitch = clamp(pitch, max_look_down, max_look_up)
|
pitch = clamp(pitch, MAX_LOOK_DOWN, MAX_LOOK_UP)
|
||||||
camera_pivot.rotation.x = pitch
|
camera_pivot.rotation.x = pitch
|
||||||
|
|
||||||
func _physics_process(delta: float) -> void:
|
|
||||||
|
func _physics_process(delta):
|
||||||
|
# Camera crouch offset
|
||||||
var target_height = crouch_height if is_crouching else stand_height
|
var target_height = crouch_height if is_crouching else stand_height
|
||||||
camera_pivot.position.y = lerp(camera_pivot.position.y, target_height, 10 * delta)
|
camera_pivot.position.y = lerp(
|
||||||
|
camera_pivot.position.y,
|
||||||
|
target_height,
|
||||||
|
10.0 * delta
|
||||||
|
)
|
||||||
|
|
||||||
|
# Gravity
|
||||||
|
|
||||||
# Add the gravity.
|
|
||||||
if not is_on_floor():
|
if not is_on_floor():
|
||||||
velocity += get_gravity() * delta
|
velocity.y -= ProjectSettings.get_setting("physics/3d/default_gravity") * delta
|
||||||
|
|
||||||
# Handle jump.
|
# Jump
|
||||||
if Input.is_action_just_pressed("jump") and is_on_floor():
|
if Input.is_action_just_pressed("jump") and is_on_floor():
|
||||||
is_sliding = false
|
is_sliding = false
|
||||||
preserve_air_momentum = true
|
is_crouching = false
|
||||||
just_jumped = true
|
just_jumped = true
|
||||||
|
preserve_air_momentum = true
|
||||||
|
|
||||||
velocity.y = jump_velocity
|
velocity.y = jump_velocity
|
||||||
|
|
||||||
var input_dir = Vector3.ZERO
|
|
||||||
if Input.is_action_pressed("move_forward"):
|
|
||||||
input_dir -= transform.basis.z
|
|
||||||
if Input.is_action_pressed("move_backward"):
|
|
||||||
input_dir += transform.basis.z
|
|
||||||
if Input.is_action_pressed("move_left"):
|
|
||||||
input_dir -= transform.basis.x
|
|
||||||
if Input.is_action_pressed("move_right"):
|
|
||||||
input_dir += transform.basis.x
|
|
||||||
input_dir = input_dir.normalized()
|
|
||||||
|
|
||||||
|
var input_dir := get_input_direction()
|
||||||
move_and_slide()
|
|
||||||
|
|
||||||
if is_on_floor():
|
if is_on_floor():
|
||||||
just_jumped = false
|
just_jumped = false
|
||||||
preserve_air_momentum = false
|
preserve_air_momentum = false
|
||||||
handle_crouch(input_dir, delta)
|
handle_ground(input_dir, delta)
|
||||||
else :
|
else:
|
||||||
apply_air_control(input_dir, delta)
|
apply_air_control(input_dir, delta)
|
||||||
|
|
||||||
func handle_crouch(input_dir:Vector3, delta):
|
move_and_slide()
|
||||||
if just_jumped:
|
|
||||||
return
|
|
||||||
|
func handle_ground(input_dir: Vector3, delta):
|
||||||
|
if Input.is_action_just_pressed("crouch"):
|
||||||
if not is_on_floor() and preserve_air_momentum:
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
if Input.is_action_just_pressed("crouch") and is_on_floor():
|
|
||||||
is_crouching = true
|
is_crouching = true
|
||||||
|
|
||||||
if input_dir.length() > 0.1:
|
if input_dir.length() > 0.1:
|
||||||
start_slide(input_dir)
|
start_slide(input_dir)
|
||||||
|
|
||||||
if Input.is_action_just_released("crouch"):
|
if Input.is_action_just_released("crouch"):
|
||||||
stop_crouch()
|
stop_crouch()
|
||||||
|
|
||||||
if input_dir == Vector3.ZERO and not is_sliding:
|
|
||||||
var horizontal = velocity
|
|
||||||
horizontal.y = 0
|
|
||||||
horizontal = horizontal.move_toward(Vector3.ZERO, slide_friction * delta)
|
|
||||||
velocity.x = horizontal.x
|
|
||||||
velocity.z = horizontal.z
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if is_sliding:
|
if is_sliding:
|
||||||
|
camera.fov = lerp(camera.fov, base_fov + SLIDE_FOV_ADD, 10.0 * delta)
|
||||||
|
|
||||||
$CameraPivot/Camera3D.fov = lerp($CameraPivot/Camera3D.fov, sliding_fov, 10 * delta )
|
|
||||||
|
|
||||||
velocity.x = slide_direction.x
|
velocity.x = slide_direction.x
|
||||||
velocity.z = slide_direction.z
|
velocity.z = slide_direction.z
|
||||||
|
|
||||||
slide_direction = slide_direction.move_toward(Vector3.ZERO, slide_friction * delta)
|
slide_direction = slide_direction.move_toward(
|
||||||
|
Vector3.ZERO,
|
||||||
if slide_direction.length() < 1:
|
slide_friction * delta
|
||||||
is_sliding= false
|
)
|
||||||
|
|
||||||
|
if slide_direction.length() < 1.0:
|
||||||
|
is_sliding = false
|
||||||
|
|
||||||
elif is_crouching:
|
elif is_crouching:
|
||||||
|
camera.fov = lerp(camera.fov, base_fov, 10.0 * delta)
|
||||||
velocity.x = input_dir.x * crouch_speed
|
velocity.x = input_dir.x * crouch_speed
|
||||||
velocity.z = input_dir.z * crouch_speed
|
velocity.z = input_dir.z * crouch_speed
|
||||||
else:
|
|
||||||
$CameraPivot/Camera3D.fov = lerp($CameraPivot/Camera3D.fov, fov, 10 * delta )
|
|
||||||
velocity.x = input_dir.x * walk_speed
|
|
||||||
velocity.z = input_dir.z * walk_speed
|
|
||||||
|
|
||||||
|
else:
|
||||||
|
camera.fov = lerp(camera.fov, base_fov, 10.0 * delta)
|
||||||
|
|
||||||
|
if input_dir == Vector3.ZERO:
|
||||||
|
var horizontal := Vector3(velocity.x, 0, velocity.z)
|
||||||
|
horizontal = horizontal.move_toward(Vector3.ZERO, ground_friction * delta)
|
||||||
|
velocity.x = horizontal.x
|
||||||
|
velocity.z = horizontal.z
|
||||||
|
else:
|
||||||
|
velocity.x = input_dir.x * walk_speed
|
||||||
|
velocity.z = input_dir.z * walk_speed
|
||||||
|
|
||||||
|
# =====================
|
||||||
|
# Slide
|
||||||
|
# =====================
|
||||||
func start_slide(input_dir: Vector3):
|
func start_slide(input_dir: Vector3):
|
||||||
is_sliding = true
|
is_sliding = true
|
||||||
slide_direction = input_dir*slide_speed
|
slide_direction = input_dir.normalized() * slide_speed
|
||||||
|
|
||||||
func stop_crouch():
|
func stop_crouch():
|
||||||
is_crouching = false
|
is_crouching = false
|
||||||
is_sliding = false
|
is_sliding = false
|
||||||
|
|
||||||
|
|
||||||
func apply_air_control(input_dir: Vector3, delta):
|
func apply_air_control(input_dir: Vector3, delta):
|
||||||
if input_dir == Vector3.ZERO:
|
var horizontal := Vector3(velocity.x, 0, velocity.z)
|
||||||
return
|
|
||||||
|
|
||||||
var horizontal_vel = velocity
|
var forward := -global_transform.basis.z
|
||||||
horizontal_vel.y = 0
|
var right := global_transform.basis.x
|
||||||
|
forward.y = 0
|
||||||
var current_speed = horizontal_vel.dot(input_dir)
|
right.y = 0
|
||||||
var add_speed = max_air_speed - current_speed
|
forward = forward.normalized()
|
||||||
if add_speed <= 0:
|
right = right.normalized()
|
||||||
return
|
|
||||||
|
|
||||||
var accel_speed = air_accel * delta * max_air_speed
|
if input_dir != Vector3.ZERO:
|
||||||
accel_speed = min(accel_speed, add_speed)
|
var air_wish_dir := (forward * input_dir.dot(forward)) + (right * input_dir.dot(right))
|
||||||
|
|
||||||
velocity += input_dir * accel_speed
|
horizontal += air_wish_dir.normalized() * air_input_strength * delta
|
||||||
|
|
||||||
|
var speed := horizontal.length()
|
||||||
|
if speed > max_air_speed:
|
||||||
|
horizontal = horizontal.normalized() * lerp(
|
||||||
|
speed,
|
||||||
|
max_air_speed,
|
||||||
|
air_drag
|
||||||
|
)
|
||||||
|
|
||||||
|
velocity.x = horizontal.x
|
||||||
|
velocity.z = horizontal.z
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
func get_input_direction() -> Vector3:
|
||||||
|
var dir := Vector3.ZERO
|
||||||
|
if Input.is_action_pressed("move_forward"):
|
||||||
|
dir -= global_transform.basis.z
|
||||||
|
if Input.is_action_pressed("move_backward"):
|
||||||
|
dir += global_transform.basis.z
|
||||||
|
if Input.is_action_pressed("move_left"):
|
||||||
|
dir -= global_transform.basis.x
|
||||||
|
if Input.is_action_pressed("move_right"):
|
||||||
|
dir += global_transform.basis.x
|
||||||
|
return dir.normalized()
|
||||||
|
|||||||
Reference in New Issue
Block a user