Update to spice2x-25-04-25 (pre-apply)
> broken commit
This commit is contained in:
+277
-20
@@ -1,6 +1,7 @@
|
||||
#include "extdev.h"
|
||||
#include <cmath>
|
||||
#include <string>
|
||||
#include <optional>
|
||||
#include <windows.h>
|
||||
#include "util/utils.h"
|
||||
#include "util/detour.h"
|
||||
@@ -9,11 +10,18 @@
|
||||
#include "misc/eamuse.h"
|
||||
#include "cfg/api.h"
|
||||
#include "acio/icca/icca.h"
|
||||
#include "games/gitadora/gitadora.h"
|
||||
#include "games/gitadora/io.h"
|
||||
#include "avs/game.h"
|
||||
|
||||
using namespace GameAPI;
|
||||
|
||||
#if SPICE64
|
||||
typedef uint64_t LED_INDEX;
|
||||
#else
|
||||
typedef uint32_t LED_INDEX;
|
||||
#endif
|
||||
|
||||
// card unit
|
||||
static size_t EXTDEV_CARDUNIT_COUNT = 0;
|
||||
static circular_buffer<int> EXTDEV_CARDUNIT_KEY[2] = {
|
||||
@@ -65,8 +73,14 @@ static std::string EXTDEV_INSTANCE_NAMES[] = {
|
||||
"libcardunit.dll",
|
||||
"libledunit.dll",
|
||||
"libgfdm_unit2.dll",
|
||||
"libshare-pj.dll",
|
||||
};
|
||||
|
||||
static void set_led_state(games::gitadora::Lights::gitadora_lights_t light, bool led_on);
|
||||
static void set_led_value(games::gitadora::Lights::gitadora_lights_t light, uint8_t value);
|
||||
|
||||
static long __cdecl gitadora_led_common(long index, uint8_t *data);
|
||||
|
||||
static void __cdecl cardunit_boot2(int a1, int a2, int a3) {
|
||||
|
||||
// default reader count to 1
|
||||
@@ -326,9 +340,9 @@ static void *__cdecl gfdm_unit_get_button_p(void *a1, int a2, size_t player) {
|
||||
memset(a1, 0, 64);
|
||||
|
||||
// irrelevant for drummania
|
||||
if (avs::game::is_model({ "J32", "K32", "L32" }) ||
|
||||
(avs::game::is_model("M32") && avs::game::SPEC[0] == 'B'))
|
||||
if (games::gitadora::is_drum()) {
|
||||
return a1;
|
||||
}
|
||||
|
||||
// get buttons
|
||||
auto &buttons = games::gitadora::get_buttons();
|
||||
@@ -414,8 +428,7 @@ static long __cdecl gfdm_unit_get_input_p(int device, size_t player) {
|
||||
auto &analogs = games::gitadora::get_analogs();
|
||||
|
||||
// drum mania
|
||||
if (avs::game::is_model({ "J32", "K32", "L32" }) ||
|
||||
(avs::game::is_model("M32") && avs::game::SPEC[0] == 'B')) {
|
||||
if (games::gitadora::is_drum()) {
|
||||
|
||||
// we don't want input for this
|
||||
if (device == 1)
|
||||
@@ -471,9 +484,7 @@ static long __cdecl gfdm_unit_get_input_p(int device, size_t player) {
|
||||
}
|
||||
|
||||
// guitar freaks
|
||||
if (avs::game::is_model({ "J33", "K33", "L33" }) ||
|
||||
(avs::game::is_model("M32") && avs::game::SPEC[0] == 'A'))
|
||||
{
|
||||
if (games::gitadora::is_guitar()) {
|
||||
auto offset = player * 11;
|
||||
|
||||
// pick up
|
||||
@@ -577,8 +588,7 @@ static long __cdecl gfdm_unit2_get_input(int device) {
|
||||
static long __cdecl gfdm_unit_get_sensor_gf_p(int a1, int a2, size_t player) {
|
||||
|
||||
// return if it's actually drum mania
|
||||
if (avs::game::is_model({ "J32", "K32", "L32" }) ||
|
||||
(avs::game::is_model("M32") && avs::game::SPEC[0] == 'B'))
|
||||
if (games::gitadora::is_drum())
|
||||
return 0;
|
||||
|
||||
// get buttons and analogs
|
||||
@@ -752,15 +762,166 @@ static int __cdecl led_unit_reset() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int __cdecl led_unit_send_custom1(int a1, unsigned char *a2) {
|
||||
static void set_led_state(games::gitadora::Lights::gitadora_lights_t light, bool led_on) {
|
||||
auto &lights = games::gitadora::get_lights();
|
||||
GameAPI::Lights::writeLight(RI_MGR, lights.at(light), (led_on ? 1.f : 0.f));
|
||||
}
|
||||
|
||||
static void set_led_value(games::gitadora::Lights::gitadora_lights_t light, uint8_t value) {
|
||||
auto &lights = games::gitadora::get_lights();
|
||||
GameAPI::Lights::writeLight(RI_MGR, lights.at(light), value / 128.f);
|
||||
}
|
||||
|
||||
static unsigned int __cdecl led_unit_send_custom1(int index, uint8_t *data) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int __cdecl led_unit_send_custom2(int a1, unsigned char *a2) {
|
||||
struct ExtDevLight {
|
||||
int data_index;
|
||||
games::gitadora::Lights::gitadora_lights_t light;
|
||||
ExtDevLight(
|
||||
int data_index, games::gitadora::Lights::gitadora_lights_t light) :
|
||||
data_index(data_index), light(light) {}
|
||||
};
|
||||
|
||||
// GITADORA series
|
||||
static unsigned int __cdecl led_unit_send_custom2(int index, uint8_t *data) {
|
||||
#ifdef SPICE64
|
||||
return gitadora_led_common(index, data);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static long __cdecl led_unit_send_direct(long a1, uint8_t *a2) {
|
||||
// XG series
|
||||
static long __cdecl led_unit_send_direct(long index, uint8_t *data) {
|
||||
#ifdef SPICE64
|
||||
return 0;
|
||||
#else
|
||||
return gitadora_led_common(index, data);
|
||||
#endif
|
||||
}
|
||||
|
||||
static long __cdecl gitadora_led_common(long index, uint8_t *data) {
|
||||
// log_info("extdev::led", "gitadora_led_common {}", index);
|
||||
// for (size_t i = 0; i < 24; i += 3) {
|
||||
// log_info("extdev::led", "gitadora_led_common ... {} {} {}", data[i], data[i+1], data[i+2]);
|
||||
// }
|
||||
|
||||
if (games::gitadora::is_drum()) {
|
||||
// Drum: index is always 0, data array has 24 elements, each value ranging [0, 128]
|
||||
static ExtDevLight mapping_dm[] = {
|
||||
{0, games::gitadora::Lights::DrumWooferR},
|
||||
{1, games::gitadora::Lights::DrumWooferG},
|
||||
{2, games::gitadora::Lights::DrumWooferB},
|
||||
|
||||
{3, games::gitadora::Lights::DrumSpotRearLeft},
|
||||
{7, games::gitadora::Lights::DrumSpotRearRight},
|
||||
{11, games::gitadora::Lights::SpotFrontLeft},
|
||||
|
||||
{12, games::gitadora::Lights::DrumStageR},
|
||||
{13, games::gitadora::Lights::DrumStageG},
|
||||
{14, games::gitadora::Lights::DrumStageB},
|
||||
|
||||
{15, games::gitadora::Lights::SpotCenterLeft},
|
||||
{19, games::gitadora::Lights::SpotCenterRight},
|
||||
{23, games::gitadora::Lights::SpotFrontRight}
|
||||
};
|
||||
if (index == 0) {
|
||||
for (const auto &map : mapping_dm) {
|
||||
set_led_value(map.light, data[map.data_index]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Guitar: index is {0,1,2}, data array has 24 elements, each value ranging [0, 128]
|
||||
static ExtDevLight mapping0[] = {
|
||||
{0, games::gitadora::Lights::GuitarLowerLeftR},
|
||||
{1, games::gitadora::Lights::GuitarLowerLeftG},
|
||||
{2, games::gitadora::Lights::GuitarLowerLeftB},
|
||||
|
||||
{3, games::gitadora::Lights::SpotFrontLeft},
|
||||
{7, games::gitadora::Lights::SpotCenterLeft},
|
||||
|
||||
{8, games::gitadora::Lights::GuitarLowerRightR},
|
||||
{9, games::gitadora::Lights::GuitarLowerRightG},
|
||||
{10, games::gitadora::Lights::GuitarLowerRightB},
|
||||
|
||||
{11, games::gitadora::Lights::SpotCenterRight},
|
||||
{15, games::gitadora::Lights::SpotFrontRight}
|
||||
};
|
||||
|
||||
static ExtDevLight mapping1[] = {
|
||||
{0, games::gitadora::Lights::GuitarLeftSpeakerUpperR},
|
||||
{1, games::gitadora::Lights::GuitarLeftSpeakerUpperG},
|
||||
{2, games::gitadora::Lights::GuitarLeftSpeakerUpperB},
|
||||
|
||||
{4, games::gitadora::Lights::GuitarLeftSpeakerMidUpLeftR},
|
||||
{5, games::gitadora::Lights::GuitarLeftSpeakerMidUpLeftG},
|
||||
{6, games::gitadora::Lights::GuitarLeftSpeakerMidUpLeftB},
|
||||
|
||||
{8, games::gitadora::Lights::GuitarLeftSpeakerMidUpRightR},
|
||||
{9, games::gitadora::Lights::GuitarLeftSpeakerMidUpRightG},
|
||||
{10, games::gitadora::Lights::GuitarLeftSpeakerMidUpRightB},
|
||||
|
||||
{12, games::gitadora::Lights::GuitarLeftSpeakerMidLowLeftR},
|
||||
{13, games::gitadora::Lights::GuitarLeftSpeakerMidLowLeftG},
|
||||
{14, games::gitadora::Lights::GuitarLeftSpeakerMidLowLeftB},
|
||||
|
||||
{16, games::gitadora::Lights::GuitarLeftSpeakerMidLowRightR},
|
||||
{17, games::gitadora::Lights::GuitarLeftSpeakerMidLowRightG},
|
||||
{18, games::gitadora::Lights::GuitarLeftSpeakerMidLowRightB},
|
||||
|
||||
{20, games::gitadora::Lights::GuitarLeftSpeakerLowerR},
|
||||
{21, games::gitadora::Lights::GuitarLeftSpeakerLowerG},
|
||||
{22, games::gitadora::Lights::GuitarLeftSpeakerLowerB}
|
||||
};
|
||||
|
||||
static ExtDevLight mapping2[] = {
|
||||
{0, games::gitadora::Lights::GuitarRightSpeakerUpperR},
|
||||
{1, games::gitadora::Lights::GuitarRightSpeakerUpperG},
|
||||
{2, games::gitadora::Lights::GuitarRightSpeakerUpperB},
|
||||
|
||||
{4, games::gitadora::Lights::GuitarRightSpeakerMidUpLeftR},
|
||||
{5, games::gitadora::Lights::GuitarRightSpeakerMidUpLeftG},
|
||||
{6, games::gitadora::Lights::GuitarRightSpeakerMidUpLeftB},
|
||||
|
||||
{8, games::gitadora::Lights::GuitarRightSpeakerMidUpRightR},
|
||||
{9, games::gitadora::Lights::GuitarRightSpeakerMidUpRightG},
|
||||
{10, games::gitadora::Lights::GuitarRightSpeakerMidUpRightB},
|
||||
|
||||
{12, games::gitadora::Lights::GuitarRightSpeakerMidLowLeftR},
|
||||
{13, games::gitadora::Lights::GuitarRightSpeakerMidLowLeftG},
|
||||
{14, games::gitadora::Lights::GuitarRightSpeakerMidLowLeftB},
|
||||
|
||||
{16, games::gitadora::Lights::GuitarRightSpeakerMidLowRightR},
|
||||
{17, games::gitadora::Lights::GuitarRightSpeakerMidLowRightG},
|
||||
{18, games::gitadora::Lights::GuitarRightSpeakerMidLowRightB},
|
||||
|
||||
{20, games::gitadora::Lights::GuitarRightSpeakerLowerR},
|
||||
{21, games::gitadora::Lights::GuitarRightSpeakerLowerG},
|
||||
{22, games::gitadora::Lights::GuitarRightSpeakerLowerB}
|
||||
};
|
||||
|
||||
switch (index) {
|
||||
case 0:
|
||||
for (const auto &map : mapping0) {
|
||||
set_led_value(map.light, data[map.data_index]);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
for (const auto &map : mapping1) {
|
||||
set_led_value(map.light, data[map.data_index]);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
for (const auto &map : mapping2) {
|
||||
set_led_value(map.light, data[map.data_index]);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -814,6 +975,72 @@ static int __cdecl sci_setparam(int a1, int a2, int a3, char a4) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void __cdecl dm_output_set_padled(LED_INDEX index, bool led_on) {
|
||||
games::gitadora::Lights::gitadora_lights_t lights[] = {
|
||||
games::gitadora::Lights::DrumHighTom,
|
||||
games::gitadora::Lights::DrumLowTom,
|
||||
games::gitadora::Lights::DrumSnare,
|
||||
games::gitadora::Lights::DrumFloorTom,
|
||||
games::gitadora::Lights::DrumLeftCymbal,
|
||||
games::gitadora::Lights::DrumRightCymbal,
|
||||
games::gitadora::Lights::DrumHiHat
|
||||
};
|
||||
|
||||
// log_info("gitadora", "dm_output_set_padled {} {}", index, led_on);
|
||||
|
||||
if (index < std::size(lights)) {
|
||||
set_led_state(lights[index], led_on);
|
||||
}
|
||||
}
|
||||
|
||||
static void __cdecl dm_output_set_startled(bool led_on) {
|
||||
set_led_state(games::gitadora::Lights::P1MenuStart, led_on);
|
||||
}
|
||||
|
||||
static void __cdecl dm_output_set_up_down(bool led_on) {
|
||||
set_led_state(games::gitadora::Lights::P1MenuUpDown, led_on);
|
||||
}
|
||||
|
||||
static void __cdecl dm_output_set_left_right(bool led_on) {
|
||||
set_led_state(games::gitadora::Lights::P1MenuLeftRight, led_on);
|
||||
}
|
||||
|
||||
static void __cdecl dm_output_set_help(bool led_on) {
|
||||
set_led_state(games::gitadora::Lights::P1MenuHelp, led_on);
|
||||
}
|
||||
|
||||
static void __cdecl gf_output_set_startlamp(LED_INDEX index, bool led_on) {
|
||||
if (index == 0) {
|
||||
set_led_state(games::gitadora::Lights::P1MenuStart, led_on);
|
||||
} else if (index == 1) {
|
||||
set_led_state(games::gitadora::Lights::P2MenuStart, led_on);
|
||||
}
|
||||
}
|
||||
|
||||
static void __cdecl gf_output_set_up_down(LED_INDEX index, bool led_on) {
|
||||
if (index == 0) {
|
||||
set_led_state(games::gitadora::Lights::P1MenuUpDown, led_on);
|
||||
} else if (index == 1) {
|
||||
set_led_state(games::gitadora::Lights::P2MenuUpDown, led_on);
|
||||
}
|
||||
}
|
||||
|
||||
static void __cdecl gf_output_set_left_right(LED_INDEX index, bool led_on) {
|
||||
if (index == 0) {
|
||||
set_led_state(games::gitadora::Lights::P1MenuLeftRight, led_on);
|
||||
} else if (index == 1) {
|
||||
set_led_state(games::gitadora::Lights::P2MenuLeftRight, led_on);
|
||||
}
|
||||
}
|
||||
|
||||
static void __cdecl gf_output_set_help(LED_INDEX index, bool led_on) {
|
||||
if (index == 0) {
|
||||
set_led_state(games::gitadora::Lights::P1MenuHelp, led_on);
|
||||
} else if (index == 1) {
|
||||
set_led_state(games::gitadora::Lights::P2MenuHelp, led_on);
|
||||
}
|
||||
}
|
||||
|
||||
void extdev_attach() {
|
||||
|
||||
// get instance
|
||||
@@ -902,7 +1129,8 @@ void extdev_attach() {
|
||||
"?gfdm_unit_get_button_gf@@YAHW4UNIT_NO@@W4GF_BUTTON_DEFINITION@@@Z"}));
|
||||
detour::inline_hook((void *) gfdm_unit_get_dm_attack_border_value, libutils::try_proc_list(
|
||||
EXTDEV_INSTANCE, {"gfdm_unit_get_dm_attack_border_value",
|
||||
"?gfdm_unit_get_dm_attack_border_value@@YAHHPEAH@Z"}));
|
||||
"?gfdm_unit_get_dm_attack_border_value@@YAHHPEAH@Z",
|
||||
"?gfdm_unit_get_dm_attack_border_value@@YAHHPAH@Z"}));
|
||||
detour::inline_hook((void *) gfdm_unit_get_errorcount, libutils::try_proc_list(
|
||||
EXTDEV_INSTANCE, {"gfdm_unit_get_errorcount",
|
||||
"?gfdm_unit_get_errorcount@@YAHH@Z"}));
|
||||
@@ -920,7 +1148,8 @@ void extdev_attach() {
|
||||
"?gfdm_unit_get_stream_errorcount@@YAHH@Z"}));
|
||||
detour::inline_hook((void *) gfdm_unit_get_version, libutils::try_proc_list(
|
||||
EXTDEV_INSTANCE, {"gfdm_unit_get_version",
|
||||
"?gfdm_unit_get_version@@YAPEBUfirm_version@@H@Z"}));
|
||||
"?gfdm_unit_get_version@@YAPEBUfirm_version@@H@Z",
|
||||
"?gfdm_unit_get_version@@YAPBUfirm_version@@H@Z"}));
|
||||
detour::inline_hook((void *) gfdm_unit_reset, libutils::try_proc_list(
|
||||
EXTDEV_INSTANCE, {"gfdm_unit_reset",
|
||||
"?gfdm_unit_reset@@YAHXZ"}));
|
||||
@@ -932,7 +1161,8 @@ void extdev_attach() {
|
||||
"?gfdm_unit_send_motor_value@@YAIHE@Z"}));
|
||||
detour::inline_hook((void *) gfdm_unit_set_dm_attack_border_value, libutils::try_proc_list(
|
||||
EXTDEV_INSTANCE, {"gfdm_unit_set_dm_attack_border_value",
|
||||
"?gfdm_unit_set_dm_attack_border_value@@YAXQEAH@Z"}));
|
||||
"?gfdm_unit_set_dm_attack_border_value@@YAXQEAH@Z",
|
||||
"?gfdm_unit_set_dm_attack_border_value@@YAXQAH@Z"}));
|
||||
detour::inline_hook((void *) gfdm_unit_shutdown, libutils::try_proc_list(
|
||||
EXTDEV_INSTANCE, {"gfdm_unit_shutdown",
|
||||
"?gfdm_unit_shutdown@@YAXXZ"}));
|
||||
@@ -976,7 +1206,8 @@ void extdev_attach() {
|
||||
"?gfdm_unit2_get_stream_errorcount@@YAHH@Z"}));
|
||||
detour::inline_hook((void *) gfdm_unit2_get_version, libutils::try_proc_list(
|
||||
EXTDEV_INSTANCE, {"gfdm_unit2_get_version",
|
||||
"?gfdm_unit2_get_version@@YAPEBUfirm_version@@H@Z"}));
|
||||
"?gfdm_unit2_get_version@@YAPEBUfirm_version@@H@Z",
|
||||
"?gfdm_unit2_get_version@@YAPBUfirm_version@@H@Z"}));
|
||||
detour::inline_hook((void *) gfdm_unit2_reset, libutils::try_proc_list(
|
||||
EXTDEV_INSTANCE, {"gfdm_unit2_reset",
|
||||
"?gfdm_unit2_reset@@YAHXZ"}));
|
||||
@@ -999,7 +1230,8 @@ void extdev_attach() {
|
||||
// led unit
|
||||
detour::inline_hook((void *) led_get_version, libutils::try_proc_list(
|
||||
EXTDEV_INSTANCE, {"led_get_version",
|
||||
"?led_get_version@@YAPEBUfirm_version@@H@Z"}));
|
||||
"?led_get_version@@YAPEBUfirm_version@@H@Z",
|
||||
"?led_get_version@@YAPBUfirm_version@@H@Z"}));
|
||||
detour::inline_hook((void *) led_unit_boot, libutils::try_proc_list(
|
||||
EXTDEV_INSTANCE, {"led_unit_boot",
|
||||
"?led_unit_boot@@YAXHH@Z"}));
|
||||
@@ -1017,13 +1249,16 @@ void extdev_attach() {
|
||||
"?led_unit_reset@@YAHXZ"}));
|
||||
detour::inline_hook((void *) led_unit_send_custom1, libutils::try_proc_list(
|
||||
EXTDEV_INSTANCE, {"led_unit_send_custom1",
|
||||
"?led_unit_send_custom1@@YAIHQEAE@Z"}));
|
||||
"?led_unit_send_custom1@@YAIHQEAE@Z",
|
||||
"?led_unit_send_custom1@@YAIHQAE@Z"}));
|
||||
detour::inline_hook((void *) led_unit_send_custom2, libutils::try_proc_list(
|
||||
EXTDEV_INSTANCE, {"led_unit_send_custom2",
|
||||
"?led_unit_send_custom2@@YAIHQEAE@Z"}));
|
||||
"?led_unit_send_custom2@@YAIHQEAE@Z",
|
||||
"?led_unit_send_custom2@@YAIHQAE@Z"}));
|
||||
detour::inline_hook((void *) led_unit_send_direct, libutils::try_proc_list(
|
||||
EXTDEV_INSTANCE, {"led_unit_send_direct",
|
||||
"?led_unit_send_direct@@YAIHQEAE@Z"}));
|
||||
"?led_unit_send_direct@@YAIHQEAE@Z",
|
||||
"?led_unit_send_direct@@YAIHQAE@Z"}));
|
||||
detour::inline_hook((void *) led_unit_shutdown, libutils::try_proc_list(
|
||||
EXTDEV_INSTANCE, {"led_unit_shutdown",
|
||||
"?led_unit_shutdown@@YAXXZ"}));
|
||||
@@ -1054,6 +1289,28 @@ void extdev_attach() {
|
||||
EXTDEV_INSTANCE, "sci_set_linebreak"));
|
||||
detour::inline_hook((void *) sci_setparam, libutils::try_proc(
|
||||
EXTDEV_INSTANCE, "sci_setparam"));
|
||||
|
||||
// libshare-pj.dll - dm_output
|
||||
detour::inline_hook((void *) dm_output_set_padled, libutils::try_proc(
|
||||
EXTDEV_INSTANCE, "dm_output_set_padled"));
|
||||
detour::inline_hook((void *) dm_output_set_startled, libutils::try_proc(
|
||||
EXTDEV_INSTANCE, "dm_output_set_startled"));
|
||||
detour::inline_hook((void *) dm_output_set_up_down, libutils::try_proc(
|
||||
EXTDEV_INSTANCE, "dm_output_set_up_down"));
|
||||
detour::inline_hook((void *) dm_output_set_left_right, libutils::try_proc(
|
||||
EXTDEV_INSTANCE, "dm_output_set_left_right"));
|
||||
detour::inline_hook((void *) dm_output_set_help, libutils::try_proc(
|
||||
EXTDEV_INSTANCE, "dm_output_set_help"));
|
||||
|
||||
// libshare-pj.dll - gf_output
|
||||
detour::inline_hook((void *) gf_output_set_startlamp, libutils::try_proc(
|
||||
EXTDEV_INSTANCE, "gf_output_set_startlamp"));
|
||||
detour::inline_hook((void *) gf_output_set_up_down, libutils::try_proc(
|
||||
EXTDEV_INSTANCE, "gf_output_set_up_down"));
|
||||
detour::inline_hook((void *) gf_output_set_left_right, libutils::try_proc(
|
||||
EXTDEV_INSTANCE, "gf_output_set_left_right"));
|
||||
detour::inline_hook((void *) gf_output_set_help, libutils::try_proc(
|
||||
EXTDEV_INSTANCE, "gf_output_set_help"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user