early-access version 2636
This commit is contained in:
parent
f2c0175302
commit
0d49569ca5
@ -1,7 +1,7 @@
|
|||||||
yuzu emulator early access
|
yuzu emulator early access
|
||||||
=============
|
=============
|
||||||
|
|
||||||
This is the source code for early-access 2635.
|
This is the source code for early-access 2636.
|
||||||
|
|
||||||
## Legal Notice
|
## Legal Notice
|
||||||
|
|
||||||
|
@ -25,9 +25,9 @@
|
|||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
SessionRequestHandler::SessionRequestHandler(KernelCore& kernel_, const char* service_name_,
|
SessionRequestHandler::SessionRequestHandler(KernelCore& kernel_, const char* service_name_,
|
||||||
bool create_service_thread_)
|
ServiceThreadType thread_type)
|
||||||
: kernel{kernel_} {
|
: kernel{kernel_} {
|
||||||
if (create_service_thread_) {
|
if (thread_type == ServiceThreadType::CreateNew) {
|
||||||
service_thread = kernel.CreateServiceThread(service_name_);
|
service_thread = kernel.CreateServiceThread(service_name_);
|
||||||
} else {
|
} else {
|
||||||
service_thread = kernel.GetDefaultServiceThread();
|
service_thread = kernel.GetDefaultServiceThread();
|
||||||
|
@ -33,6 +33,11 @@ namespace Service {
|
|||||||
class ServiceFrameworkBase;
|
class ServiceFrameworkBase;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum class ServiceThreadType {
|
||||||
|
Default,
|
||||||
|
CreateNew,
|
||||||
|
};
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
class Domain;
|
class Domain;
|
||||||
@ -58,7 +63,7 @@ enum class ThreadWakeupReason;
|
|||||||
class SessionRequestHandler : public std::enable_shared_from_this<SessionRequestHandler> {
|
class SessionRequestHandler : public std::enable_shared_from_this<SessionRequestHandler> {
|
||||||
public:
|
public:
|
||||||
SessionRequestHandler(KernelCore& kernel_, const char* service_name_,
|
SessionRequestHandler(KernelCore& kernel_, const char* service_name_,
|
||||||
bool create_service_thread_);
|
ServiceThreadType thread_type);
|
||||||
virtual ~SessionRequestHandler();
|
virtual ~SessionRequestHandler();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1091,7 +1091,7 @@ std::weak_ptr<Kernel::ServiceThread> KernelCore::CreateServiceThread(const std::
|
|||||||
return impl->CreateServiceThread(*this, name);
|
return impl->CreateServiceThread(*this, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::weak_ptr<Kernel::ServiceThread> KernelCore::GetDefaultServiceThread() {
|
std::weak_ptr<Kernel::ServiceThread> KernelCore::GetDefaultServiceThread() const {
|
||||||
return impl->default_service_thread;
|
return impl->default_service_thread;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -294,7 +294,7 @@ public:
|
|||||||
* creating a new service thread.
|
* creating a new service thread.
|
||||||
* @returns The a weak pointer for the default service thread.
|
* @returns The a weak pointer for the default service thread.
|
||||||
*/
|
*/
|
||||||
std::weak_ptr<Kernel::ServiceThread> GetDefaultServiceThread();
|
std::weak_ptr<Kernel::ServiceThread> GetDefaultServiceThread() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Releases a HLE service thread, instructing KernelCore to free it. This should be called when
|
* Releases a HLE service thread, instructing KernelCore to free it. This should be called when
|
||||||
|
@ -446,6 +446,14 @@ void WebBrowser::ExecuteLogin() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void WebBrowser::ExecuteOffline() {
|
void WebBrowser::ExecuteOffline() {
|
||||||
|
// TODO (Morph): This is a hack for WebSession foreground web applets such as those used by
|
||||||
|
// Super Mario 3D All-Stars.
|
||||||
|
// TODO (Morph): Implement WebSession.
|
||||||
|
if (applet_mode == LibraryAppletMode::AllForegroundInitiallyHidden) {
|
||||||
|
LOG_WARNING(Service_AM, "WebSession is not implemented");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const auto main_url = GetMainURL(Common::FS::PathToUTF8String(offline_document));
|
const auto main_url = GetMainURL(Common::FS::PathToUTF8String(offline_document));
|
||||||
|
|
||||||
if (!Common::FS::Exists(main_url)) {
|
if (!Common::FS::Exists(main_url)) {
|
||||||
|
@ -41,7 +41,7 @@ public:
|
|||||||
explicit IAudioOut(Core::System& system_, AudoutParams audio_params_,
|
explicit IAudioOut(Core::System& system_, AudoutParams audio_params_,
|
||||||
AudioCore::AudioOut& audio_core_, std::string&& device_name_,
|
AudioCore::AudioOut& audio_core_, std::string&& device_name_,
|
||||||
std::string&& unique_name)
|
std::string&& unique_name)
|
||||||
: ServiceFramework{system_, "IAudioOut", true /*create_service_thread*/},
|
: ServiceFramework{system_, "IAudioOut", ServiceThreadType::CreateNew},
|
||||||
audio_core{audio_core_}, device_name{std::move(device_name_)},
|
audio_core{audio_core_}, device_name{std::move(device_name_)},
|
||||||
audio_params{audio_params_}, main_memory{system.Memory()}, service_context{system_,
|
audio_params{audio_params_}, main_memory{system.Memory()}, service_context{system_,
|
||||||
"IAudioOut"} {
|
"IAudioOut"} {
|
||||||
|
@ -24,7 +24,7 @@ public:
|
|||||||
explicit IAudioRenderer(Core::System& system_,
|
explicit IAudioRenderer(Core::System& system_,
|
||||||
const AudioCommon::AudioRendererParameter& audren_params,
|
const AudioCommon::AudioRendererParameter& audren_params,
|
||||||
const std::size_t instance_number)
|
const std::size_t instance_number)
|
||||||
: ServiceFramework{system_, "IAudioRenderer", true /*create_service_thread*/},
|
: ServiceFramework{system_, "IAudioRenderer", ServiceThreadType::CreateNew},
|
||||||
service_context{system_, "IAudioRenderer"} {
|
service_context{system_, "IAudioRenderer"} {
|
||||||
// clang-format off
|
// clang-format off
|
||||||
static const FunctionInfo functions[] = {
|
static const FunctionInfo functions[] = {
|
||||||
|
@ -58,7 +58,7 @@ enum class FileSystemType : u8 {
|
|||||||
class IStorage final : public ServiceFramework<IStorage> {
|
class IStorage final : public ServiceFramework<IStorage> {
|
||||||
public:
|
public:
|
||||||
explicit IStorage(Core::System& system_, FileSys::VirtualFile backend_)
|
explicit IStorage(Core::System& system_, FileSys::VirtualFile backend_)
|
||||||
: ServiceFramework{system_, "IStorage", true /*create_service_thread*/},
|
: ServiceFramework{system_, "IStorage", ServiceThreadType::CreateNew},
|
||||||
backend(std::move(backend_)) {
|
backend(std::move(backend_)) {
|
||||||
static const FunctionInfo functions[] = {
|
static const FunctionInfo functions[] = {
|
||||||
{0, &IStorage::Read, "Read"},
|
{0, &IStorage::Read, "Read"},
|
||||||
@ -117,7 +117,7 @@ private:
|
|||||||
class IFile final : public ServiceFramework<IFile> {
|
class IFile final : public ServiceFramework<IFile> {
|
||||||
public:
|
public:
|
||||||
explicit IFile(Core::System& system_, FileSys::VirtualFile backend_)
|
explicit IFile(Core::System& system_, FileSys::VirtualFile backend_)
|
||||||
: ServiceFramework{system_, "IFile", true /*create_service_thread*/},
|
: ServiceFramework{system_, "IFile", ServiceThreadType::CreateNew},
|
||||||
backend(std::move(backend_)) {
|
backend(std::move(backend_)) {
|
||||||
static const FunctionInfo functions[] = {
|
static const FunctionInfo functions[] = {
|
||||||
{0, &IFile::Read, "Read"},
|
{0, &IFile::Read, "Read"},
|
||||||
@ -254,7 +254,7 @@ static void BuildEntryIndex(std::vector<FileSys::Entry>& entries, const std::vec
|
|||||||
class IDirectory final : public ServiceFramework<IDirectory> {
|
class IDirectory final : public ServiceFramework<IDirectory> {
|
||||||
public:
|
public:
|
||||||
explicit IDirectory(Core::System& system_, FileSys::VirtualDir backend_)
|
explicit IDirectory(Core::System& system_, FileSys::VirtualDir backend_)
|
||||||
: ServiceFramework{system_, "IDirectory", true /*create_service_thread*/},
|
: ServiceFramework{system_, "IDirectory", ServiceThreadType::CreateNew},
|
||||||
backend(std::move(backend_)) {
|
backend(std::move(backend_)) {
|
||||||
static const FunctionInfo functions[] = {
|
static const FunctionInfo functions[] = {
|
||||||
{0, &IDirectory::Read, "Read"},
|
{0, &IDirectory::Read, "Read"},
|
||||||
@ -311,7 +311,7 @@ private:
|
|||||||
class IFileSystem final : public ServiceFramework<IFileSystem> {
|
class IFileSystem final : public ServiceFramework<IFileSystem> {
|
||||||
public:
|
public:
|
||||||
explicit IFileSystem(Core::System& system_, FileSys::VirtualDir backend_, SizeGetter size_)
|
explicit IFileSystem(Core::System& system_, FileSys::VirtualDir backend_, SizeGetter size_)
|
||||||
: ServiceFramework{system_, "IFileSystem", true /*create_service_thread*/},
|
: ServiceFramework{system_, "IFileSystem", ServiceThreadType::CreateNew},
|
||||||
backend{std::move(backend_)}, size{std::move(size_)} {
|
backend{std::move(backend_)}, size{std::move(size_)} {
|
||||||
static const FunctionInfo functions[] = {
|
static const FunctionInfo functions[] = {
|
||||||
{0, &IFileSystem::CreateFile, "CreateFile"},
|
{0, &IFileSystem::CreateFile, "CreateFile"},
|
||||||
|
@ -262,11 +262,6 @@ void Controller_NPad::OnInit() {
|
|||||||
service_context.CreateEvent(fmt::format("npad:NpadStyleSetChanged_{}", i));
|
service_context.CreateEvent(fmt::format("npad:NpadStyleSetChanged_{}", i));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hid_core.GetSupportedStyleTag().raw == Core::HID::NpadStyleSet::None) {
|
|
||||||
// We want to support all controllers
|
|
||||||
hid_core.SetSupportedStyleTag({Core::HID::NpadStyleSet::All});
|
|
||||||
}
|
|
||||||
|
|
||||||
supported_npad_id_types.resize(npad_id_list.size());
|
supported_npad_id_types.resize(npad_id_list.size());
|
||||||
std::memcpy(supported_npad_id_types.data(), npad_id_list.data(),
|
std::memcpy(supported_npad_id_types.data(), npad_id_list.data(),
|
||||||
npad_id_list.size() * sizeof(Core::HID::NpadIdType));
|
npad_id_list.size() * sizeof(Core::HID::NpadIdType));
|
||||||
@ -288,14 +283,6 @@ void Controller_NPad::OnInit() {
|
|||||||
WriteEmptyEntry(npad);
|
WriteEmptyEntry(npad);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Connect controllers
|
|
||||||
for (auto& controller : controller_data) {
|
|
||||||
const auto& device = controller.device;
|
|
||||||
if (device->IsConnected()) {
|
|
||||||
AddNewControllerAt(device->GetNpadStyleIndex(), device->GetNpadIdType());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Controller_NPad::WriteEmptyEntry(NpadInternalState& npad) {
|
void Controller_NPad::WriteEmptyEntry(NpadInternalState& npad) {
|
||||||
@ -320,6 +307,7 @@ void Controller_NPad::WriteEmptyEntry(NpadInternalState& npad) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Controller_NPad::OnRelease() {
|
void Controller_NPad::OnRelease() {
|
||||||
|
is_controller_initialized = false;
|
||||||
for (std::size_t i = 0; i < controller_data.size(); ++i) {
|
for (std::size_t i = 0; i < controller_data.size(); ++i) {
|
||||||
auto& controller = controller_data[i];
|
auto& controller = controller_data[i];
|
||||||
service_context.CloseEvent(controller.styleset_changed_event);
|
service_context.CloseEvent(controller.styleset_changed_event);
|
||||||
@ -651,9 +639,27 @@ void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing
|
|||||||
|
|
||||||
void Controller_NPad::SetSupportedStyleSet(Core::HID::NpadStyleTag style_set) {
|
void Controller_NPad::SetSupportedStyleSet(Core::HID::NpadStyleTag style_set) {
|
||||||
hid_core.SetSupportedStyleTag(style_set);
|
hid_core.SetSupportedStyleTag(style_set);
|
||||||
|
|
||||||
|
if (is_controller_initialized) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Once SetSupportedStyleSet is called controllers are fully initialized
|
||||||
|
is_controller_initialized = true;
|
||||||
|
|
||||||
|
// Connect all active controllers
|
||||||
|
for (auto& controller : controller_data) {
|
||||||
|
const auto& device = controller.device;
|
||||||
|
if (device->IsConnected()) {
|
||||||
|
AddNewControllerAt(device->GetNpadStyleIndex(), device->GetNpadIdType());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Core::HID::NpadStyleTag Controller_NPad::GetSupportedStyleSet() const {
|
Core::HID::NpadStyleTag Controller_NPad::GetSupportedStyleSet() const {
|
||||||
|
if (!is_controller_initialized) {
|
||||||
|
return {Core::HID::NpadStyleSet::None};
|
||||||
|
}
|
||||||
return hid_core.GetSupportedStyleTag();
|
return hid_core.GetSupportedStyleTag();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -511,7 +511,8 @@ private:
|
|||||||
NpadHandheldActivationMode handheld_activation_mode{NpadHandheldActivationMode::Dual};
|
NpadHandheldActivationMode handheld_activation_mode{NpadHandheldActivationMode::Dual};
|
||||||
NpadCommunicationMode communication_mode{NpadCommunicationMode::Default};
|
NpadCommunicationMode communication_mode{NpadCommunicationMode::Default};
|
||||||
bool permit_vibration_session_enabled{false};
|
bool permit_vibration_session_enabled{false};
|
||||||
bool analog_stick_use_center_clamp{};
|
bool analog_stick_use_center_clamp{false};
|
||||||
bool is_in_lr_assignment_mode{false};
|
bool is_in_lr_assignment_mode{false};
|
||||||
|
bool is_controller_initialized{false};
|
||||||
};
|
};
|
||||||
} // namespace Service::HID
|
} // namespace Service::HID
|
||||||
|
@ -64,10 +64,6 @@ IAppletResource::IAppletResource(Core::System& system_,
|
|||||||
MakeController<Controller_Gesture>(HidController::Gesture);
|
MakeController<Controller_Gesture>(HidController::Gesture);
|
||||||
MakeController<Controller_ConsoleSixAxis>(HidController::ConsoleSixAxisSensor);
|
MakeController<Controller_ConsoleSixAxis>(HidController::ConsoleSixAxisSensor);
|
||||||
|
|
||||||
// Homebrew doesn't try to activate some controllers, so we activate them by default
|
|
||||||
GetController<Controller_NPad>(HidController::NPad).ActivateController();
|
|
||||||
GetController<Controller_Touchscreen>(HidController::Touchscreen).ActivateController();
|
|
||||||
|
|
||||||
GetController<Controller_Stubbed>(HidController::HomeButton).SetCommonHeaderOffset(0x4C00);
|
GetController<Controller_Stubbed>(HidController::HomeButton).SetCommonHeaderOffset(0x4C00);
|
||||||
GetController<Controller_Stubbed>(HidController::SleepButton).SetCommonHeaderOffset(0x4E00);
|
GetController<Controller_Stubbed>(HidController::SleepButton).SetCommonHeaderOffset(0x4E00);
|
||||||
GetController<Controller_Stubbed>(HidController::CaptureButton).SetCommonHeaderOffset(0x5000);
|
GetController<Controller_Stubbed>(HidController::CaptureButton).SetCommonHeaderOffset(0x5000);
|
||||||
|
@ -230,7 +230,7 @@ void NVDRV::DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
NVDRV::NVDRV(Core::System& system_, std::shared_ptr<Module> nvdrv_, const char* name)
|
NVDRV::NVDRV(Core::System& system_, std::shared_ptr<Module> nvdrv_, const char* name)
|
||||||
: ServiceFramework{system_, name}, nvdrv{std::move(nvdrv_)} {
|
: ServiceFramework{system_, name, ServiceThreadType::CreateNew}, nvdrv{std::move(nvdrv_)} {
|
||||||
static const FunctionInfo functions[] = {
|
static const FunctionInfo functions[] = {
|
||||||
{0, &NVDRV::Open, "Open"},
|
{0, &NVDRV::Open, "Open"},
|
||||||
{1, &NVDRV::Ioctl1, "Ioctl"},
|
{1, &NVDRV::Ioctl1, "Ioctl"},
|
||||||
|
@ -91,11 +91,10 @@ namespace Service {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ServiceFrameworkBase::ServiceFrameworkBase(Core::System& system_, const char* service_name_,
|
ServiceFrameworkBase::ServiceFrameworkBase(Core::System& system_, const char* service_name_,
|
||||||
bool create_service_thread_, u32 max_sessions_,
|
ServiceThreadType thread_type, u32 max_sessions_,
|
||||||
InvokerFn* handler_invoker_)
|
InvokerFn* handler_invoker_)
|
||||||
: SessionRequestHandler(system_.Kernel(), service_name_, create_service_thread_),
|
: SessionRequestHandler(system_.Kernel(), service_name_, thread_type), system{system_},
|
||||||
system{system_}, service_name{service_name_}, max_sessions{max_sessions_},
|
service_name{service_name_}, max_sessions{max_sessions_}, handler_invoker{handler_invoker_} {}
|
||||||
handler_invoker{handler_invoker_} {}
|
|
||||||
|
|
||||||
ServiceFrameworkBase::~ServiceFrameworkBase() {
|
ServiceFrameworkBase::~ServiceFrameworkBase() {
|
||||||
// Wait for other threads to release access before destroying
|
// Wait for other threads to release access before destroying
|
||||||
|
@ -114,7 +114,7 @@ private:
|
|||||||
Kernel::HLERequestContext& ctx);
|
Kernel::HLERequestContext& ctx);
|
||||||
|
|
||||||
explicit ServiceFrameworkBase(Core::System& system_, const char* service_name_,
|
explicit ServiceFrameworkBase(Core::System& system_, const char* service_name_,
|
||||||
bool create_service_thread_, u32 max_sessions_,
|
ServiceThreadType thread_type, u32 max_sessions_,
|
||||||
InvokerFn* handler_invoker_);
|
InvokerFn* handler_invoker_);
|
||||||
~ServiceFrameworkBase() override;
|
~ServiceFrameworkBase() override;
|
||||||
|
|
||||||
@ -179,16 +179,15 @@ protected:
|
|||||||
*
|
*
|
||||||
* @param system_ The system context to construct this service under.
|
* @param system_ The system context to construct this service under.
|
||||||
* @param service_name_ Name of the service.
|
* @param service_name_ Name of the service.
|
||||||
* @param create_service_thread_ Creates a service thread for this if true, otherwise use the
|
* @param thread_type Specifies the thread type for this service. If this is set to CreateNew,
|
||||||
* default service thread.
|
* it creates a new thread for it, otherwise this uses the default thread.
|
||||||
* @param max_sessions_ Maximum number of sessions that can be connected to this service at the
|
* @param max_sessions_ Maximum number of sessions that can be connected to this service at the
|
||||||
* same time.
|
* same time.
|
||||||
*/
|
*/
|
||||||
explicit ServiceFramework(Core::System& system_, const char* service_name_,
|
explicit ServiceFramework(Core::System& system_, const char* service_name_,
|
||||||
bool create_service_thread_ = false,
|
ServiceThreadType thread_type = ServiceThreadType::Default,
|
||||||
u32 max_sessions_ = ServerSessionCountMax)
|
u32 max_sessions_ = ServerSessionCountMax)
|
||||||
: ServiceFrameworkBase(system_, service_name_, create_service_thread_, max_sessions_,
|
: ServiceFrameworkBase(system_, service_name_, thread_type, max_sessions_, Invoker) {}
|
||||||
Invoker) {}
|
|
||||||
|
|
||||||
/// Registers handlers in the service.
|
/// Registers handlers in the service.
|
||||||
template <std::size_t N>
|
template <std::size_t N>
|
||||||
|
@ -206,7 +206,7 @@ void SM::UnregisterService(Kernel::HLERequestContext& ctx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SM::SM(ServiceManager& service_manager_, Core::System& system_)
|
SM::SM(ServiceManager& service_manager_, Core::System& system_)
|
||||||
: ServiceFramework{system_, "sm:", false /*create_service_thread*/, 4},
|
: ServiceFramework{system_, "sm:", ServiceThreadType::Default, 4},
|
||||||
service_manager{service_manager_}, kernel{system_.Kernel()} {
|
service_manager{service_manager_}, kernel{system_.Kernel()} {
|
||||||
RegisterHandlers({
|
RegisterHandlers({
|
||||||
{0, &SM::Initialize, "Initialize"},
|
{0, &SM::Initialize, "Initialize"},
|
||||||
|
@ -838,7 +838,7 @@ void BSD::BuildErrnoResponse(Kernel::HLERequestContext& ctx, Errno bsd_errno) co
|
|||||||
}
|
}
|
||||||
|
|
||||||
BSD::BSD(Core::System& system_, const char* name)
|
BSD::BSD(Core::System& system_, const char* name)
|
||||||
: ServiceFramework{system_, name, true /*create_service_thread*/} {
|
: ServiceFramework{system_, name, ServiceThreadType::CreateNew} {
|
||||||
// clang-format off
|
// clang-format off
|
||||||
static const FunctionInfo functions[] = {
|
static const FunctionInfo functions[] = {
|
||||||
{0, &BSD::RegisterClient, "RegisterClient"},
|
{0, &BSD::RegisterClient, "RegisterClient"},
|
||||||
|
@ -77,7 +77,7 @@ static_assert(sizeof(NativeWindow) == 0x28, "NativeWindow has wrong size");
|
|||||||
class IHOSBinderDriver final : public ServiceFramework<IHOSBinderDriver> {
|
class IHOSBinderDriver final : public ServiceFramework<IHOSBinderDriver> {
|
||||||
public:
|
public:
|
||||||
explicit IHOSBinderDriver(Core::System& system_, NVFlinger::HosBinderDriverServer& server_)
|
explicit IHOSBinderDriver(Core::System& system_, NVFlinger::HosBinderDriverServer& server_)
|
||||||
: ServiceFramework{system_, "IHOSBinderDriver", true /*create_service_thread*/},
|
: ServiceFramework{system_, "IHOSBinderDriver", ServiceThreadType::CreateNew},
|
||||||
server(server_) {
|
server(server_) {
|
||||||
static const FunctionInfo functions[] = {
|
static const FunctionInfo functions[] = {
|
||||||
{0, &IHOSBinderDriver::TransactParcel, "TransactParcel"},
|
{0, &IHOSBinderDriver::TransactParcel, "TransactParcel"},
|
||||||
|
Loading…
Reference in New Issue
Block a user