Use compressed sound effects
This commit is contained in:
parent
041b8886a3
commit
3b994283af
@ -1 +1 @@
|
|||||||
Subproject commit d0ba87f64c610b2c1401d97576021c6ec6c09387
|
Subproject commit dbf06e89c61d33cf4dc4fede7acd31d34122dd52
|
||||||
@ -1,18 +1,7 @@
|
|||||||
[gd_scene format=3 uid="uid://cl66unms2gim0"]
|
[gd_scene format=3 uid="uid://cl66unms2gim0"]
|
||||||
|
|
||||||
[ext_resource type="AudioStream" uid="uid://bfg31e3s4jv8c" path="res://raw_assets/sfx/Hit.mp3" id="1_uh1ab"]
|
[ext_resource type="AudioStream" uid="uid://bfg31e3s4jv8c" path="res://raw_assets/sfx/Hit.mp3" id="1_uh1ab"]
|
||||||
[ext_resource type="AudioStream" uid="uid://b3xnffwvltdey" path="res://raw_assets/sfx/footsteps/zapsplat_foley_footstep_single_on_large_fallen_tree_trunk_001_23222.mp3" id="2_cdf6c"]
|
[ext_resource type="AudioStream" uid="uid://d0lpgmlqxum4u" path="res://raw_assets/sfx/footstep.mp3" id="2_orba0"]
|
||||||
[ext_resource type="AudioStream" uid="uid://c7cs50q27v680" path="res://raw_assets/sfx/footsteps/zapsplat_foley_footstep_single_on_large_fallen_tree_trunk_002_23223.mp3" id="3_fxgxg"]
|
|
||||||
[ext_resource type="AudioStream" uid="uid://bn86p7gojva0v" path="res://raw_assets/sfx/footsteps/zapsplat_foley_footstep_single_on_large_fallen_tree_trunk_011_23232.mp3" id="4_87wq6"]
|
|
||||||
[ext_resource type="AudioStream" uid="uid://cmum76yuvvigi" path="res://raw_assets/sfx/footsteps/zapsplat_foley_footstep_single_on_large_fallen_tree_trunk_012_23233.mp3" id="5_7a25g"]
|
|
||||||
[ext_resource type="AudioStream" uid="uid://bq4xb5qcy7uif" path="res://raw_assets/sfx/footsteps/zapsplat_foley_footstep_single_on_large_fallen_tree_trunk_003_23224.mp3" id="6_k2vl2"]
|
|
||||||
[ext_resource type="AudioStream" uid="uid://xj7u5c1ifip0" path="res://raw_assets/sfx/footsteps/zapsplat_foley_footstep_single_on_large_fallen_tree_trunk_004_23225.mp3" id="7_x30cj"]
|
|
||||||
[ext_resource type="AudioStream" uid="uid://kvknfhu2yuty" path="res://raw_assets/sfx/footsteps/zapsplat_foley_footstep_single_on_large_fallen_tree_trunk_006_23227.mp3" id="8_nb006"]
|
|
||||||
[ext_resource type="AudioStream" uid="uid://dqnaty4lxm4bd" path="res://raw_assets/sfx/footsteps/zapsplat_foley_footstep_single_on_large_fallen_tree_trunk_005_23226.mp3" id="9_opble"]
|
|
||||||
[ext_resource type="AudioStream" uid="uid://dqkkp8tq4ep48" path="res://raw_assets/sfx/footsteps/zapsplat_foley_footstep_single_on_large_fallen_tree_trunk_007_23228.mp3" id="10_dblfy"]
|
|
||||||
[ext_resource type="AudioStream" uid="uid://p2j4t2wyben8" path="res://raw_assets/sfx/footsteps/zapsplat_foley_footstep_single_on_large_fallen_tree_trunk_008_23229.mp3" id="11_gf6kh"]
|
|
||||||
[ext_resource type="AudioStream" uid="uid://dldkf7wdyx4j6" path="res://raw_assets/sfx/footsteps/zapsplat_foley_footstep_single_on_large_fallen_tree_trunk_009_23230.mp3" id="12_eqre1"]
|
|
||||||
[ext_resource type="AudioStream" uid="uid://b5kykwdapbulb" path="res://raw_assets/sfx/footsteps/zapsplat_foley_footstep_single_on_large_fallen_tree_trunk_010_23231.mp3" id="13_w4mf7"]
|
|
||||||
|
|
||||||
[sub_resource type="ParticleProcessMaterial" id="ParticleProcessMaterial_1cgct"]
|
[sub_resource type="ParticleProcessMaterial" id="ParticleProcessMaterial_1cgct"]
|
||||||
particle_flag_align_y = true
|
particle_flag_align_y = true
|
||||||
@ -38,21 +27,9 @@ section_rings = 10
|
|||||||
curve = SubResource("Curve_yli5f")
|
curve = SubResource("Curve_yli5f")
|
||||||
|
|
||||||
[sub_resource type="AudioStreamRandomizer" id="AudioStreamRandomizer_uh1ab"]
|
[sub_resource type="AudioStreamRandomizer" id="AudioStreamRandomizer_uh1ab"]
|
||||||
random_pitch = 1.3348398
|
random_pitch = 1.122462
|
||||||
random_volume_offset_db = 10.0
|
streams_count = 1
|
||||||
streams_count = 12
|
stream_0/stream = ExtResource("2_orba0")
|
||||||
stream_0/stream = ExtResource("2_cdf6c")
|
|
||||||
stream_1/stream = ExtResource("3_fxgxg")
|
|
||||||
stream_2/stream = ExtResource("6_k2vl2")
|
|
||||||
stream_3/stream = ExtResource("7_x30cj")
|
|
||||||
stream_4/stream = ExtResource("8_nb006")
|
|
||||||
stream_5/stream = ExtResource("9_opble")
|
|
||||||
stream_6/stream = ExtResource("10_dblfy")
|
|
||||||
stream_7/stream = ExtResource("11_gf6kh")
|
|
||||||
stream_8/stream = ExtResource("12_eqre1")
|
|
||||||
stream_9/stream = ExtResource("13_w4mf7")
|
|
||||||
stream_10/stream = ExtResource("4_87wq6")
|
|
||||||
stream_11/stream = ExtResource("5_7a25g")
|
|
||||||
|
|
||||||
[node name="player_effects" type="PlayerEffects" unique_id=1493455892 node_paths=PackedStringArray("splorch", "hit_sound", "walk_sound")]
|
[node name="player_effects" type="PlayerEffects" unique_id=1493455892 node_paths=PackedStringArray("splorch", "hit_sound", "walk_sound")]
|
||||||
splorch = NodePath("splorch")
|
splorch = NodePath("splorch")
|
||||||
|
|||||||
@ -11,7 +11,7 @@ glow_enabled = true
|
|||||||
|
|
||||||
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_oh8vq"]
|
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_oh8vq"]
|
||||||
|
|
||||||
[node name="player" type="LocalPlayer" unique_id=863055906 node_paths=PackedStringArray("camera", "soldier_mesh", "collider", "effects", "dead_cam_target", "respawn_label", "ball_origin", "weapon_node", "pause_panel", "exit_to_lobby", "settings_panel", "scoreboard", "chatbox")]
|
[node name="player" type="LocalPlayer" unique_id=863055906 node_paths=PackedStringArray("camera", "soldier_mesh", "collider", "effects", "dead_cam_target", "respawn_label", "camera_origin", "weapon_node", "pause_panel", "exit_to_lobby", "settings_panel", "scoreboard", "chatbox")]
|
||||||
look_sensitivity = 1.5
|
look_sensitivity = 1.5
|
||||||
camera = NodePath("camera_3d")
|
camera = NodePath("camera_3d")
|
||||||
move_speed = 5.0
|
move_speed = 5.0
|
||||||
@ -20,7 +20,7 @@ collider = NodePath("collision_shape_3d2")
|
|||||||
effects = NodePath("effects")
|
effects = NodePath("effects")
|
||||||
dead_cam_target = NodePath("dead_camera_target")
|
dead_cam_target = NodePath("dead_camera_target")
|
||||||
respawn_label = NodePath("respawn_label")
|
respawn_label = NodePath("respawn_label")
|
||||||
ball_origin = NodePath("camera_3d")
|
camera_origin = NodePath("camera_3d")
|
||||||
weapon_node = NodePath("camera_3d/weapon_node")
|
weapon_node = NodePath("camera_3d/weapon_node")
|
||||||
pause_panel = NodePath("pause_menu")
|
pause_panel = NodePath("pause_menu")
|
||||||
exit_to_lobby = NodePath("pause_menu/v_box_container/exit_to_lobby")
|
exit_to_lobby = NodePath("pause_menu/v_box_container/exit_to_lobby")
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
[ext_resource type="PackedScene" uid="uid://cg81784ct8gf5" path="res://mesh/raygun.tscn" id="1_ckadf"]
|
[ext_resource type="PackedScene" uid="uid://cg81784ct8gf5" path="res://mesh/raygun.tscn" id="1_ckadf"]
|
||||||
[ext_resource type="PackedScene" uid="uid://ctslratcr8h6v" path="res://scenes/player/raygun_beam.tscn" id="1_m84jv"]
|
[ext_resource type="PackedScene" uid="uid://ctslratcr8h6v" path="res://scenes/player/raygun_beam.tscn" id="1_m84jv"]
|
||||||
[ext_resource type="AudioStream" uid="uid://xxpkjhaovyd" path="res://raw_assets/sfx/LaserWithRecoveryEdited.ogg" id="2_lxble"]
|
[ext_resource type="AudioStream" uid="uid://bq553wxrelpdr" path="res://raw_assets/sfx/LaserWithRecoveryEditedCompressed.mp3" id="3_m84jv"]
|
||||||
|
|
||||||
[node name="raygun" type="Raygun" unique_id=573018429 node_paths=PackedStringArray("sound_emitter", "bullet_source")]
|
[node name="raygun" type="Raygun" unique_id=573018429 node_paths=PackedStringArray("sound_emitter", "bullet_source")]
|
||||||
sound_emitter = NodePath("sound_emitter")
|
sound_emitter = NodePath("sound_emitter")
|
||||||
@ -14,7 +14,7 @@ cooldown = 1.5
|
|||||||
|
|
||||||
[node name="sound_emitter" type="AudioStreamPlayer3D" parent="." unique_id=1572422640]
|
[node name="sound_emitter" type="AudioStreamPlayer3D" parent="." unique_id=1572422640]
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.8420726, 0)
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.8420726, 0)
|
||||||
stream = ExtResource("2_lxble")
|
stream = ExtResource("3_m84jv")
|
||||||
|
|
||||||
[node name="bullet_source" type="Node3D" parent="." unique_id=211401237]
|
[node name="bullet_source" type="Node3D" parent="." unique_id=211401237]
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.36108458, -1.490972)
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.36108458, -1.490972)
|
||||||
|
|||||||
@ -5,14 +5,14 @@
|
|||||||
|
|
||||||
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_1cgct"]
|
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_1cgct"]
|
||||||
|
|
||||||
[node name="player" type="RemotePlayer" unique_id=845968872 node_paths=PackedStringArray("soldier_mesh", "collider", "effects", "spectator_camera", "ball_origin", "name_label")]
|
[node name="player" type="RemotePlayer" unique_id=845968872 node_paths=PackedStringArray("soldier_mesh", "collider", "effects", "spectator_camera", "camera_origin", "name_label")]
|
||||||
move_speed = 5.0
|
move_speed = 5.0
|
||||||
soldier_mesh = NodePath("soldier_m")
|
soldier_mesh = NodePath("soldier_m")
|
||||||
collider = NodePath("collision_shape_3d")
|
collider = NodePath("collision_shape_3d")
|
||||||
effects = NodePath("effects")
|
effects = NodePath("effects")
|
||||||
health = 100
|
health = 100
|
||||||
spectator_camera = NodePath("spectate_root/spectate_camera")
|
spectator_camera = NodePath("spectate_root/spectate_camera")
|
||||||
ball_origin = NodePath("ball_origin")
|
camera_origin = NodePath("camera_origin")
|
||||||
name_label = NodePath("name_label")
|
name_label = NodePath("name_label")
|
||||||
collision_layer = 2
|
collision_layer = 2
|
||||||
collision_mask = 4
|
collision_mask = 4
|
||||||
@ -33,7 +33,7 @@ transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.7611488, 0)
|
|||||||
[node name="spectate_camera" type="Camera3D" parent="spectate_root" unique_id=1408688016]
|
[node name="spectate_camera" type="Camera3D" parent="spectate_root" unique_id=1408688016]
|
||||||
transform = Transform3D(1, 0, 0, 0, 0.89379096, 0.44848388, 0, -0.44848388, 0.89379096, 0, 0.6601318, 1.0407685)
|
transform = Transform3D(1, 0, 0, 0, 0.89379096, 0.44848388, 0, -0.44848388, 0.89379096, 0, 0.6601318, 1.0407685)
|
||||||
|
|
||||||
[node name="ball_origin" type="Node3D" parent="." unique_id=1445680156]
|
[node name="camera_origin" type="Node3D" parent="." unique_id=1445680156]
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.8724979, -0.2644562)
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.8724979, -0.2644562)
|
||||||
|
|
||||||
[node name="name_label" type="Label3D" parent="." unique_id=142179925]
|
[node name="name_label" type="Label3D" parent="." unique_id=142179925]
|
||||||
|
|||||||
@ -61,7 +61,7 @@ pub trait IPlayer {
|
|||||||
fn swap_weapon(&mut self, weapon: WeaponType);
|
fn swap_weapon(&mut self, weapon: WeaponType);
|
||||||
fn get_weapon(&self) -> Option<DynGd<Node3D, dyn Weapon>>;
|
fn get_weapon(&self) -> Option<DynGd<Node3D, dyn Weapon>>;
|
||||||
fn drop_ball(&mut self, with_velocity: bool) -> bool;
|
fn drop_ball(&mut self, with_velocity: bool) -> bool;
|
||||||
fn get_ball_origin(&self) -> Option<Gd<Node3D>>;
|
fn get_camera_origin(&self) -> Option<Gd<Node3D>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait PlayerCommon {
|
pub trait PlayerCommon {
|
||||||
@ -118,7 +118,7 @@ impl<T: IPlayer + ICharacterBody3D + WithBaseField> PlayerCommon for T {
|
|||||||
WeaponType::Raygun,
|
WeaponType::Raygun,
|
||||||
));
|
));
|
||||||
if let Some(mut game) = Game::singleton() {
|
if let Some(mut game) = Game::singleton() {
|
||||||
if let Some(ball_origin) = &s.get_ball_origin() {
|
if let Some(ball_origin) = &s.get_camera_origin() {
|
||||||
let velocity = if with_velocity {
|
let velocity = if with_velocity {
|
||||||
s.get_look_dir() * 20.
|
s.get_look_dir() * 20.
|
||||||
} else {
|
} else {
|
||||||
@ -144,8 +144,8 @@ impl<T: IPlayer + ICharacterBody3D + WithBaseField> PlayerCommon for T {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn get_look_dir(&self) -> Vector3 {
|
fn get_look_dir(&self) -> Vector3 {
|
||||||
if let Some(ball_origin) = self.get_ball_origin() {
|
if let Some(camera_origin) = self.get_camera_origin() {
|
||||||
ball_origin.get_global_basis().col_c().neg()
|
camera_origin.get_global_basis().col_c().neg()
|
||||||
} else {
|
} else {
|
||||||
Vector3::ZERO
|
Vector3::ZERO
|
||||||
}
|
}
|
||||||
@ -196,7 +196,7 @@ pub struct LocalPlayer {
|
|||||||
#[export]
|
#[export]
|
||||||
respawn_label: Option<Gd<Label>>,
|
respawn_label: Option<Gd<Label>>,
|
||||||
#[export]
|
#[export]
|
||||||
ball_origin: Option<Gd<Node3D>>,
|
camera_origin: Option<Gd<Node3D>>,
|
||||||
#[export]
|
#[export]
|
||||||
weapon_node: Option<Gd<Node3D>>,
|
weapon_node: Option<Gd<Node3D>>,
|
||||||
#[export]
|
#[export]
|
||||||
@ -300,10 +300,16 @@ impl IPlayer for LocalPlayer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let rid = self.base().get_rid();
|
let rid = self.base().get_rid();
|
||||||
if let Some(mut weapon) = self.get_weapon() {
|
if let Some(mut weapon) = self.get_weapon()
|
||||||
weapon
|
&& let Some(camera_origin) = &self.camera_origin
|
||||||
.dyn_bind_mut()
|
{
|
||||||
.shoot(rid, self.player_id.unwrap_or(0), to, deal_damage)
|
weapon.dyn_bind_mut().shoot(
|
||||||
|
rid,
|
||||||
|
self.player_id.unwrap_or(0),
|
||||||
|
camera_origin.get_global_position(),
|
||||||
|
to,
|
||||||
|
deal_damage,
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
@ -378,8 +384,8 @@ impl IPlayer for LocalPlayer {
|
|||||||
self.drop_ball_common(with_velocity)
|
self.drop_ball_common(with_velocity)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_ball_origin(&self) -> Option<Gd<Node3D>> {
|
fn get_camera_origin(&self) -> Option<Gd<Node3D>> {
|
||||||
self.ball_origin.clone()
|
self.camera_origin.clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -705,7 +711,7 @@ pub struct RemotePlayer {
|
|||||||
#[export]
|
#[export]
|
||||||
spectator_camera: Option<Gd<Camera3D>>,
|
spectator_camera: Option<Gd<Camera3D>>,
|
||||||
#[export]
|
#[export]
|
||||||
ball_origin: Option<Gd<Node3D>>,
|
camera_origin: Option<Gd<Node3D>>,
|
||||||
#[export]
|
#[export]
|
||||||
name_label: Option<Gd<Label3D>>,
|
name_label: Option<Gd<Label3D>>,
|
||||||
|
|
||||||
@ -789,10 +795,15 @@ impl IPlayer for RemotePlayer {
|
|||||||
let rid = self.base().get_rid();
|
let rid = self.base().get_rid();
|
||||||
if let Some(mesh) = &mut self.soldier_mesh
|
if let Some(mesh) = &mut self.soldier_mesh
|
||||||
&& let Some(mut weapon) = mesh.bind().get_weapon()
|
&& let Some(mut weapon) = mesh.bind().get_weapon()
|
||||||
|
&& let Some(camera_origin) = &self.camera_origin
|
||||||
{
|
{
|
||||||
weapon
|
weapon.dyn_bind_mut().shoot(
|
||||||
.dyn_bind_mut()
|
rid,
|
||||||
.shoot(rid, self.player_id.unwrap_or(0), to, deal_damage)
|
self.player_id.unwrap_or(0),
|
||||||
|
camera_origin.get_global_position(),
|
||||||
|
to,
|
||||||
|
deal_damage,
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
@ -858,8 +869,8 @@ impl IPlayer for RemotePlayer {
|
|||||||
self.drop_ball_common(with_velocity)
|
self.drop_ball_common(with_velocity)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_ball_origin(&self) -> Option<Gd<Node3D>> {
|
fn get_camera_origin(&self) -> Option<Gd<Node3D>> {
|
||||||
self.ball_origin.clone()
|
self.camera_origin.clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -895,7 +906,7 @@ impl ICharacterBody3D for RemotePlayer {
|
|||||||
mesh.bind_mut().update_y_look(self.look_up);
|
mesh.bind_mut().update_y_look(self.look_up);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(ball_origin) = &mut self.ball_origin {
|
if let Some(ball_origin) = &mut self.camera_origin {
|
||||||
ball_origin.set_rotation(Vector3::RIGHT * self.look_up);
|
ball_origin.set_rotation(Vector3::RIGHT * self.look_up);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -9,7 +9,14 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub trait Weapon {
|
pub trait Weapon {
|
||||||
fn shoot(&mut self, player_rid: Rid, player_id: u16, to: Vector3, deal_damage: bool) -> bool;
|
fn shoot(
|
||||||
|
&mut self,
|
||||||
|
player_rid: Rid,
|
||||||
|
player_id: u16,
|
||||||
|
from: Vector3,
|
||||||
|
to: Vector3,
|
||||||
|
deal_damage: bool,
|
||||||
|
) -> bool;
|
||||||
fn get_type(&self) -> WeaponType;
|
fn get_type(&self) -> WeaponType;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,7 +53,14 @@ impl INode3D for Raygun {
|
|||||||
|
|
||||||
#[godot_dyn]
|
#[godot_dyn]
|
||||||
impl Weapon for Raygun {
|
impl Weapon for Raygun {
|
||||||
fn shoot(&mut self, player: Rid, player_id: u16, to: Vector3, deal_damage: bool) -> bool {
|
fn shoot(
|
||||||
|
&mut self,
|
||||||
|
player: Rid,
|
||||||
|
player_id: u16,
|
||||||
|
from: Vector3,
|
||||||
|
to: Vector3,
|
||||||
|
deal_damage: bool,
|
||||||
|
) -> bool {
|
||||||
if self.cooldown_remaining > 0. {
|
if self.cooldown_remaining > 0. {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -57,7 +71,7 @@ impl Weapon for Raygun {
|
|||||||
|
|
||||||
if let Some(source) = &self.bullet_source {
|
if let Some(source) = &self.bullet_source {
|
||||||
let target = cast_ray(
|
let target = cast_ray(
|
||||||
source.get_global_position(),
|
from,
|
||||||
to,
|
to,
|
||||||
self.base().get_world_3d(),
|
self.base().get_world_3d(),
|
||||||
Array::from_iter(vec![player]),
|
Array::from_iter(vec![player]),
|
||||||
@ -168,7 +182,7 @@ pub struct BallWeapon {
|
|||||||
|
|
||||||
#[godot_dyn]
|
#[godot_dyn]
|
||||||
impl Weapon for BallWeapon {
|
impl Weapon for BallWeapon {
|
||||||
fn shoot(&mut self, _: Rid, _: u16, _: Vector3, _: bool) -> bool {
|
fn shoot(&mut self, _: Rid, _: u16, _: Vector3, _: Vector3, _: bool) -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2,8 +2,7 @@ use std::i32;
|
|||||||
|
|
||||||
use godot::{
|
use godot::{
|
||||||
classes::{
|
classes::{
|
||||||
Engine, IVBoxContainer, InputEvent, LineEdit, Panel, RichTextLabel, ScrollContainer,
|
Engine, IVBoxContainer, InputEvent, LineEdit, RichTextLabel, ScrollContainer, VBoxContainer,
|
||||||
VBoxContainer,
|
|
||||||
},
|
},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user