mirror of
https://github.com/copyrighttxt/watrbx-game-engine.git
synced 2026-09-04 20:57:49 +00:00
856 lines
30 KiB
C++
856 lines
30 KiB
C++
#include "stdafx.h"
|
|
|
|
#include "VMProtectSDK.h"
|
|
|
|
#include "V8DataModel/GuiObject.h"
|
|
#include "V8DataModel/GuiService.h"
|
|
#include "V8DataModel/PlayerGui.h"
|
|
#include "v8datamodel/ScreenGui.h"
|
|
#include "V8DataModel/JointsService.h"
|
|
#include "v8datamodel/Workspace.h"
|
|
#include "v8datamodel/MegaCluster.h"
|
|
#include "v8datamodel/ContextActionService.h"
|
|
#include "v8datamodel/GamepadService.h"
|
|
#include "Script/ScriptContext.h"
|
|
#include "Network/Players.h"
|
|
#include "V8DataModel/CollectionService.h"
|
|
#include "V8DataModel/DialogRoot.h"
|
|
#include "V8DataModel/PartInstance.h"
|
|
#include "V8DataModel/Bindable.h"
|
|
|
|
#include <boost/algorithm/string.hpp>
|
|
|
|
FASTFLAGVARIABLE(NewInGameDevConsole, false)
|
|
FASTFLAGVARIABLE(UseNewSubdomainsInCoreScripts, false)
|
|
DYNAMIC_FASTFLAG(EnableShowStatsLua)
|
|
FASTFLAGVARIABLE(UseGameLoadedInLoadingScript, true)
|
|
FASTFLAGVARIABLE(UseUserListMenu, false)
|
|
FASTFLAGVARIABLE(EnableSetCoreTopbarEnabled, false)
|
|
FASTFLAGVARIABLE(Durango3DBackground, true) // this is Xbox flag. Defined here so it is accessible in studio and xbox client
|
|
|
|
namespace RBX
|
|
{
|
|
const char* const sGuiService = "GuiService";
|
|
REFLECTION_BEGIN();
|
|
static const Reflection::PropDescriptor<GuiService, bool> prop_IsModalDialog("IsModalDialog", category_Data, &GuiService::getModalDialogStatus, NULL, Reflection::PropertyDescriptor::Attributes::deprecated());
|
|
static const Reflection::PropDescriptor<GuiService, bool> prop_IsWindows("IsWindows", category_Data, &GuiService::getIsWindows, NULL, Reflection::PropertyDescriptor::Attributes::deprecated());
|
|
|
|
static Reflection::EventDesc<GuiService, void(std::string, std::string)> event_keypressed(&GuiService::keyPressed, "KeyPressed", "key", "modifiers", Security::RobloxScript);
|
|
static Reflection::EventDesc<GuiService, void(GuiService::SpecialKey, std::string)> event_specialKeypressed(&GuiService::specialKeyPressed, "SpecialKeyPressed", "key", "modifiers", Security::RobloxScript);
|
|
static Reflection::BoundFuncDesc<GuiService, void(std::string)> func_addKey(&GuiService::addKey, "AddKey", "key", Security::RobloxScript);
|
|
static Reflection::BoundFuncDesc<GuiService, void(std::string)> func_removeKey(&GuiService::removeKey, "RemoveKey", "key", Security::RobloxScript);
|
|
static Reflection::BoundFuncDesc<GuiService, void(GuiService::SpecialKey)> func_addSpecialKey(&GuiService::addSpecialKey, "AddSpecialKey", "key", Security::RobloxScript);
|
|
static Reflection::BoundFuncDesc<GuiService, void(GuiService::SpecialKey)> func_removeSpecialKey(&GuiService::removeSpecialKey, "RemoveSpecialKey", "key", Security::RobloxScript);
|
|
|
|
static Reflection::EventDesc<GuiService, void()> event_escapeKeypressed(&GuiService::escapeKeyPressed, "EscapeKeyPressed", Security::RobloxScript);
|
|
|
|
static Reflection::BoundFuncDesc<GuiService, void(shared_ptr<Instance>, GuiService::CenterDialogType, Lua::WeakFunctionRef, Lua::WeakFunctionRef)> func_showCenterDialog(&GuiService::addCenterDialog, "AddCenterDialog", "dialog", "centerDialogType", "showFunction", "hideFunction", Security::RobloxScript);
|
|
static Reflection::BoundFuncDesc<GuiService, void(shared_ptr<Instance>)> func_hideCenterDialog(&GuiService::removeCenterDialog, "RemoveCenterDialog", "dialog", Security::RobloxScript);
|
|
|
|
static Reflection::BoundFuncDesc<GuiService, void(int, int, int, int)> func_globalGuiInset(&GuiService::setGlobalGuiInset, "SetGlobalGuiInset", "x1", "y1", "x2", "y2", Security::RobloxScript);
|
|
|
|
static Reflection::BoundYieldFuncDesc<GuiService, Vector2(void)> func_getScreenResolution(&GuiService::getScreenResolutionLua, "GetScreenResolution", Security::RobloxScript);
|
|
|
|
static Reflection::BoundFuncDesc<GuiService, void(std::string)> func_openBrowserWindow(&GuiService::openBrowserWindow, "OpenBrowserWindow", "url", Security::RobloxScript);
|
|
static Reflection::EventDesc<GuiService, void()> event_urlWindowClosed(&GuiService::urlWindowClosed, "BrowserWindowClosed", Security::RobloxScript);
|
|
|
|
static Reflection::BoundFuncDesc<GuiService, shared_ptr<Instance>(Vector3)> func_GetClosestDialogToPosition(&GuiService::getClosestDialogToPosition, "GetClosestDialogToPosition", "position", Security::RobloxScript);
|
|
|
|
static Reflection::BoundFuncDesc<GuiService, int()> func_GetBrickCount(&GuiService::getBrickCount, "GetBrickCount", Security::RobloxScript);
|
|
|
|
static Reflection::BoundFuncDesc<GuiService, void(GuiService::UiMessageType, std::string)> func_setUiMessage(&GuiService::setUiMessage, "SetUiMessage", "msgType", "uiMessage", Security::LocalUser);
|
|
static Reflection::BoundFuncDesc<GuiService, std::string()> func_getUiMessage(&GuiService::getUiMessage, "GetUiMessage", Security::RobloxScript);
|
|
static Reflection::EventDesc<GuiService, void(GuiService::UiMessageType, std::string)> event_newUiMessage(&GuiService::newUiMessageSignal, "UiMessageChanged", "msgType", "newUiMessage", Security::RobloxScript);
|
|
|
|
static Reflection::BoundFuncDesc<GuiService, void(std::string)> func_setErrorMessage(&GuiService::setErrorMessage, "SetErrorMessage", "errorMessage", Security::LocalUser, Reflection::Descriptor::Attributes::deprecated(func_setUiMessage));
|
|
static Reflection::BoundFuncDesc<GuiService, std::string()> func_getErrorMessage(&GuiService::getErrorMessage, "GetErrorMessage", Security::RobloxScript, Reflection::Descriptor::Attributes::deprecated(func_getUiMessage));
|
|
static Reflection::EventDesc<GuiService, void(std::string)> event_newError(&GuiService::newErrorSignal, "ErrorMessageChanged", "newErrorMessage", Security::RobloxScript, Reflection::Descriptor::Attributes::deprecated(event_newUiMessage));
|
|
|
|
static Reflection::EventDesc<GuiService, void()> event_showLeaveConfirmation(&GuiService::showLeaveConfirmationSignal, "ShowLeaveConfirmation", Security::RobloxScript);
|
|
|
|
static Reflection::BoundFuncDesc<GuiService, void()> func_toggleFullscreen(&GuiService::toggleFullscreen, "ToggleFullscreen", Security::RobloxScript);
|
|
|
|
static Reflection::BoundFuncDesc<GuiService, bool()> func_isTenFootInterface(&GuiService::isTenFootInterface, "IsTenFootInterface", Security::RobloxScript);
|
|
|
|
static Reflection::BoundFuncDesc<GuiService, void(std::string, shared_ptr<Instance>)> func_addSelectionGroup(&GuiService::addSelectionGroup, "AddSelectionParent", "selectionName", "selectionParent", Security::None);
|
|
static Reflection::BoundFuncDesc<GuiService, void(std::string, shared_ptr<const Reflection::Tuple>)> func_addSelectionGroupTuple(&GuiService::addSelectionGroup, "AddSelectionTuple", "selectionName", "selections", Security::None);
|
|
|
|
static Reflection::BoundFuncDesc<GuiService, void(std::string)> func_removeSelectionGroup(&GuiService::removeSelectionGroup, "RemoveSelectionGroup", "selectionName", Security::None);
|
|
|
|
Reflection::RefPropDescriptor<GuiService, GuiObject> GuiService::prop_selectedGuiObject("SelectedObject", category_Data, &GuiService::getSelectedGuiObjectLua, &GuiService::setSelectedGuiObjectLua);
|
|
Reflection::RefPropDescriptor<GuiService, GuiObject> GuiService::prop_selectedCoreGuiObject("SelectedCoreObject", category_Data, &GuiService::getSelectedCoreGuiObjectLua, &GuiService::setSelectedCoreGuiObjectLua, Reflection::PropertyDescriptor::UI, Security::RobloxScript);
|
|
|
|
static const Reflection::PropDescriptor<GuiService, bool> prop_autoGuiSelectionAllowed("AutoSelectGuiEnabled", category_Data, &GuiService::getAutoGuiSelectionAllowed, &GuiService::setAutoGuiSelectionAllowed);
|
|
static const Reflection::PropDescriptor<GuiService, bool> prop_gamepadNavigationEnabled("GuiNavigationEnabled", category_Data, &GuiService::getGamepadNavEnabled, &GuiService::setGamepadNavEnabled);
|
|
static const Reflection::PropDescriptor<GuiService, bool> prop_coreGamepadNavigationEnabled("CoreGuiNavigationEnabled", category_Data, &GuiService::getCoreGamepadNavEnabled, &GuiService::setCoreGamepadNavEnabled);
|
|
|
|
static Reflection::BoundAsyncCallbackDesc<GuiService, void(std::string, std::string)> callback_notificationCallback("SendCoreUiNotification", &GuiService::notificationCallback, "title", "text", Security::RobloxScript);
|
|
static const Reflection::PropDescriptor<GuiService, bool> prop_menuOpen("MenuIsOpen", category_Data, &GuiService::getMenuOpen, NULL);
|
|
static const Reflection::BoundFuncDesc<GuiService, void(bool)> func_setMenuOpen(&GuiService::setMenuOpen, "SetMenuIsOpen", "open", Security::RobloxScript);
|
|
|
|
static Reflection::EventDesc<GuiService, void()> event_menuOpened(&GuiService::menuOpenedSignal, "MenuOpened", Security::None);
|
|
static Reflection::EventDesc<GuiService, void()> event_menuClosed(&GuiService::menuClosedSignal, "MenuClosed", Security::None);
|
|
|
|
static Reflection::BoundFuncDesc<GuiService, bool(std::string)> func_ShowStatsBasedOnInputString(&GuiService::showStatsBasedOnInputString, "ShowStatsBasedOnInputString","input", Security::RobloxScript);
|
|
REFLECTION_END();
|
|
|
|
namespace Reflection {
|
|
template<>
|
|
EnumDesc<GuiService::SpecialKey>::EnumDesc()
|
|
:EnumDescriptor("SpecialKey")
|
|
{
|
|
addPair(GuiService::KEY_INSERT, "Insert");
|
|
addPair(GuiService::KEY_HOME, "Home");
|
|
addPair(GuiService::KEY_END, "End");
|
|
addPair(GuiService::KEY_PAGEUP, "PageUp");
|
|
addPair(GuiService::KEY_PAGEDOWN, "PageDown");
|
|
addPair(GuiService::KEY_CHATHOTKEY, "ChatHotkey");
|
|
}
|
|
|
|
template<>
|
|
GuiService::SpecialKey& Variant::convert<GuiService::SpecialKey>(void)
|
|
{
|
|
return genericConvert<GuiService::SpecialKey>();
|
|
}
|
|
|
|
template<>
|
|
EnumDesc<GuiService::CenterDialogType>::EnumDesc()
|
|
:EnumDescriptor("CenterDialogType")
|
|
{
|
|
addPair(GuiService::CENTER_DIALOG_UNSOLICITED_DIALOG , "UnsolicitedDialog");
|
|
addPair(GuiService::CENTER_DIALOG_PLAYER_INITIATED_DIALOG , "PlayerInitiatedDialog");
|
|
addPair(GuiService::CENTER_DIALOG_MODAL_DIALOG , "ModalDialog");
|
|
addPair(GuiService::CENTER_DIALOG_QUIT_DIALOG , "QuitDialog");
|
|
}
|
|
|
|
template<>
|
|
GuiService::CenterDialogType& Variant::convert<GuiService::CenterDialogType>(void)
|
|
{
|
|
return genericConvert<GuiService::CenterDialogType>();
|
|
}
|
|
|
|
template<>
|
|
EnumDesc<GuiService::UiMessageType>::EnumDesc()
|
|
:EnumDescriptor("UiMessageType")
|
|
{
|
|
addPair(GuiService::UIMESSAGE_ERROR , "UiMessageError");
|
|
addPair(GuiService::UIMESSAGE_INFO , "UiMessageInfo");
|
|
}
|
|
|
|
template<>
|
|
GuiService::UiMessageType& Variant::convert<GuiService::UiMessageType>(void)
|
|
{
|
|
return genericConvert<GuiService::UiMessageType>();
|
|
}
|
|
}//namespace Reflection
|
|
|
|
template<>
|
|
bool StringConverter<GuiService::SpecialKey>::convertToValue(const std::string& text, GuiService::SpecialKey& value)
|
|
{
|
|
return Reflection::EnumDesc<GuiService::SpecialKey>::singleton().convertToValue(text.c_str(),value);
|
|
}
|
|
template<>
|
|
bool StringConverter<GuiService::CenterDialogType>::convertToValue(const std::string& text, GuiService::CenterDialogType& value)
|
|
{
|
|
return Reflection::EnumDesc<GuiService::CenterDialogType>::singleton().convertToValue(text.c_str(),value);
|
|
}
|
|
template<>
|
|
bool StringConverter<GuiService::UiMessageType>::convertToValue(const std::string& text, GuiService::UiMessageType& value)
|
|
{
|
|
return Reflection::EnumDesc<GuiService::UiMessageType>::singleton().convertToValue(text.c_str(),value);
|
|
}
|
|
|
|
|
|
GuiService::GuiService()
|
|
:Super("GuiService")
|
|
,currentDialog(NULL)
|
|
,subscribedChars()
|
|
,subscribedSpecials()
|
|
,errorMessage("")
|
|
,gamepadNavEnabled(true)
|
|
,coreGamepadNavEnabled(true)
|
|
,menuOpen(false)
|
|
{
|
|
}
|
|
|
|
void GuiService::setMenuOpen(bool value)
|
|
{
|
|
if (value != menuOpen)
|
|
{
|
|
menuOpen = value;
|
|
menuOpen ? fireMenuOpenedSignal() : fireMenuClosedSignal();
|
|
raisePropertyChanged(prop_menuOpen);
|
|
}
|
|
}
|
|
|
|
int GuiService::getBrickCount()
|
|
{
|
|
return DataModel::get(this)->getNumPartInstances();
|
|
}
|
|
|
|
bool GuiService::shouldPreemptCurrentDialog(DialogWrapper* newDialog) const
|
|
{
|
|
if(currentDialog == NULL)
|
|
return true;
|
|
if(newDialog->dialogType > currentDialog->dialogType)
|
|
return true;
|
|
if(newDialog->dialogType < currentDialog->dialogType)
|
|
return false;
|
|
RBXASSERT(newDialog->dialogType == currentDialog->dialogType);
|
|
|
|
switch(newDialog->dialogType){
|
|
case CENTER_DIALOG_UNSOLICITED_DIALOG:
|
|
return false;
|
|
case CENTER_DIALOG_PLAYER_INITIATED_DIALOG:
|
|
case CENTER_DIALOG_MODAL_DIALOG:
|
|
case CENTER_DIALOG_QUIT_DIALOG:
|
|
return true;
|
|
default:
|
|
RBXASSERT(0);
|
|
return false;
|
|
}
|
|
}
|
|
bool GuiService::getModalDialogStatus() const
|
|
{
|
|
if(currentDialog == NULL)
|
|
return false;
|
|
switch(currentDialog->dialogType)
|
|
{
|
|
case CENTER_DIALOG_UNSOLICITED_DIALOG:
|
|
case CENTER_DIALOG_PLAYER_INITIATED_DIALOG:
|
|
return false;
|
|
case CENTER_DIALOG_MODAL_DIALOG:
|
|
case CENTER_DIALOG_QUIT_DIALOG:
|
|
return true;
|
|
default:
|
|
RBXASSERT(0);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
Vector2 GuiService::getScreenResolution()
|
|
{
|
|
if (CoreGuiService* coreGui = ServiceProvider::create<CoreGuiService>(this))
|
|
{
|
|
if (ScreenGui* screenGui = coreGui->findFirstChildOfType<ScreenGui>())
|
|
{
|
|
return screenGui->getAbsoluteSize();
|
|
}
|
|
}
|
|
return Vector2::zero();
|
|
}
|
|
|
|
void GuiService::getScreenResolutionNoRetry(boost::function<void(Vector2)> resumeFunction, boost::function<void(std::string)> errorFunction)
|
|
{
|
|
screenGuiConnection.disconnect();
|
|
resumeFunction(getScreenResolution());
|
|
}
|
|
|
|
void GuiService::getScreenResolutionLua(boost::function<void(Vector2)> resumeFunction, boost::function<void(std::string)> errorFunction)
|
|
{
|
|
// if screen res is zero then we haven't done a heartbeat yet, try one more time after heartbeat
|
|
if (getScreenResolution() == Vector2::zero())
|
|
{
|
|
if (RunService* runService = ServiceProvider::create<RunService>(this))
|
|
screenGuiConnection = runService->heartbeatSignal.connect(boost::bind(&GuiService::getScreenResolutionNoRetry,this,resumeFunction,errorFunction));
|
|
}
|
|
else
|
|
{
|
|
getScreenResolutionNoRetry(resumeFunction,errorFunction);
|
|
}
|
|
}
|
|
|
|
void GuiService::queueDialogWrapper(DialogWrapper* newDialog, bool preempted)
|
|
{
|
|
switch(newDialog->dialogType){
|
|
case CENTER_DIALOG_UNSOLICITED_DIALOG:
|
|
if(preempted)
|
|
dialogQueue[newDialog->dialogType].push_front(newDialog);
|
|
else
|
|
dialogQueue[newDialog->dialogType].push_back(newDialog);
|
|
break;
|
|
case CENTER_DIALOG_PLAYER_INITIATED_DIALOG:
|
|
case CENTER_DIALOG_MODAL_DIALOG:
|
|
case CENTER_DIALOG_QUIT_DIALOG:
|
|
dialogQueue[newDialog->dialogType].push_front(newDialog);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void InvokeCallback(boost::weak_ptr<GuiObject> weakThis, Lua::WeakFunctionRef callback, bool visible)
|
|
{
|
|
if (shared_ptr<GuiObject> strongThis = weakThis.lock())
|
|
{
|
|
if (Lua::ThreadRef threadRef = callback.lock())
|
|
{
|
|
if (ScriptContext* sc = ServiceProvider::create<ScriptContext>(strongThis.get()))
|
|
{
|
|
Reflection::Tuple args;
|
|
|
|
try
|
|
{
|
|
sc->callInNewThread(callback, args);
|
|
return;
|
|
}
|
|
catch (RBX::base_exception& e)
|
|
{
|
|
StandardOut::singleton()->printf(MESSAGE_ERROR, "Unexpected error while invoking callback: %s", e.what());
|
|
}
|
|
}
|
|
}
|
|
|
|
strongThis->setVisible(visible);
|
|
}
|
|
}
|
|
|
|
void GuiService::addCenterDialog(shared_ptr<Instance> dialogInstance, GuiService::CenterDialogType type, Lua::WeakFunctionRef show, Lua::WeakFunctionRef hide)
|
|
{
|
|
shared_ptr<GuiObject> dialog = Instance::fastSharedDynamicCast<GuiObject>(dialogInstance);
|
|
if(!dialog)
|
|
throw RBX::runtime_error("dialog must be a GuiObject instance");
|
|
|
|
weak_ptr<GuiObject> weakDialog = weak_from(dialog.get());
|
|
std::map<boost::weak_ptr<GuiObject>, DialogWrapper*>::iterator iter = dialogWrapperMap.find(weakDialog);
|
|
if(iter != dialogWrapperMap.end()){
|
|
if( DialogWrapper* wrapper = iter->second){
|
|
if(wrapper->dialogType != type){
|
|
throw RBX::runtime_error("A dialogInstance should not change CenterDialogTypes");
|
|
}
|
|
|
|
if(wrapper == currentDialog){
|
|
//Already on top -- ignore the request
|
|
return;
|
|
}
|
|
else{
|
|
//Not on top -- remove it, so we can readd it
|
|
removeCenterDialog(dialogInstance);
|
|
}
|
|
}
|
|
else{
|
|
dialogWrapperMap.erase(iter);
|
|
}
|
|
}
|
|
RBXASSERT(dialogWrapperMap.find(weakDialog) == dialogWrapperMap.end());
|
|
|
|
std::list<boost::function<void()> > callbacks;
|
|
|
|
DialogWrapper* wrapper = new DialogWrapper();
|
|
wrapper->dialog = weakDialog;
|
|
wrapper->dialogType = type;
|
|
wrapper->showFunction = boost::bind(&InvokeCallback, weakDialog, show, true);
|
|
wrapper->hideFunction = boost::bind(&InvokeCallback, weakDialog, hide, false);
|
|
|
|
dialogWrapperMap[weakDialog] = wrapper;
|
|
if(shouldPreemptCurrentDialog(wrapper)){
|
|
if(currentDialog){
|
|
//Hide/Cleanup old dialog
|
|
DataModel::get(this)->submitTask(boost::bind(currentDialog->hideFunction), DataModelJob::Write);
|
|
|
|
queueDialogWrapper(currentDialog, true);
|
|
currentDialog = NULL;
|
|
}
|
|
|
|
currentDialog = wrapper;
|
|
|
|
//Show new Dialog
|
|
DataModel::get(this)->submitTask(boost::bind(currentDialog->showFunction), DataModelJob::Write);
|
|
}
|
|
else {
|
|
queueDialogWrapper(wrapper, false);
|
|
}
|
|
}
|
|
bool GuiService::showWaitingDialog(CenterDialogType type)
|
|
{
|
|
RBXASSERT(currentDialog == NULL);
|
|
|
|
if(!dialogQueue[type].empty()){
|
|
DialogWrapper* result = dialogQueue[type].front();
|
|
dialogQueue[type].pop_front();
|
|
|
|
currentDialog = result;
|
|
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
void GuiService::removeCenterDialog(shared_ptr<Instance> dialogInstance)
|
|
{
|
|
shared_ptr<GuiObject> dialog = Instance::fastSharedDynamicCast<GuiObject>(dialogInstance);
|
|
if(!dialog)
|
|
throw RBX::runtime_error("dialog must be a GuiObject instance");
|
|
|
|
weak_ptr<GuiObject> weakDialog = weak_from(dialog.get());
|
|
if(DialogWrapper* wrapper = dialogWrapperMap[weakDialog]){
|
|
dialogWrapperMap.erase(weakDialog);
|
|
dialogQueue[wrapper->dialogType].remove(wrapper);
|
|
|
|
if(wrapper == currentDialog){
|
|
currentDialog = NULL;
|
|
|
|
if(showWaitingDialog(CENTER_DIALOG_QUIT_DIALOG) ||
|
|
showWaitingDialog(CENTER_DIALOG_MODAL_DIALOG) ||
|
|
showWaitingDialog(CENTER_DIALOG_PLAYER_INITIATED_DIALOG) ||
|
|
showWaitingDialog(CENTER_DIALOG_UNSOLICITED_DIALOG))
|
|
{
|
|
//Make it show
|
|
DataModel::get(this)->submitTask(boost::bind(currentDialog->showFunction), DataModelJob::Write);
|
|
}
|
|
}
|
|
delete wrapper;
|
|
}
|
|
}
|
|
|
|
bool GuiService::dispatchKey(GuiService::SpecialKey special)
|
|
{
|
|
if(hasSpecial(special)){
|
|
specialKeyPressed(special, "");
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool GuiService::processKeyDown(const shared_ptr<RBX::InputObject>& event)
|
|
{
|
|
// ensure we are dealing with a key down
|
|
RBXASSERT(event->isKeyDownEvent());
|
|
|
|
if(event->isTextCharacterKey() || (UserInputService::IsUsingNewKeyboardEvents() && event->getUserInputType() == RBX::InputObject::TYPE_KEYBOARD))
|
|
{
|
|
if(!event->isAltEvent() && !event->isCtrlEvent())
|
|
{
|
|
if(event->modifiedKey == '/' || (UserInputService::IsUsingNewKeyboardEvents() && event->getKeyCode() == SDLK_SLASH) )
|
|
{
|
|
if(dispatchKey(KEY_CHATHOTKEY))
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
char character = tolower(event->modifiedKey);
|
|
if(subscribedChars.find(character) != subscribedChars.end())
|
|
{
|
|
keyPressed(std::string() + character,"");
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
switch(event->getKeyCode())
|
|
{
|
|
case SDLK_INSERT: if(dispatchKey(KEY_INSERT)) return true; break;
|
|
case SDLK_HOME: if(dispatchKey(KEY_HOME)) return true; break;
|
|
case SDLK_END: if(dispatchKey(KEY_END)) return true; break;
|
|
case SDLK_PAGEUP: if(dispatchKey(KEY_PAGEUP)) return true; break;
|
|
case SDLK_PAGEDOWN: if(dispatchKey(KEY_PAGEDOWN)) return true; break;
|
|
default:
|
|
break;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void GuiService::setGlobalGuiInset(int x1, int y1, int x2, int y2)
|
|
{
|
|
guiInset = Vector4(x1, y1, x2, y2);
|
|
}
|
|
|
|
void GuiService::addKey(std::string key)
|
|
{
|
|
if(key.size() != 1)
|
|
throw RBX::runtime_error("GuiService:AddKey requires a string with a single character");
|
|
char character = tolower(key[0]);
|
|
|
|
if(subscribedChars.find(character) == subscribedChars.end()){
|
|
subscribedChars.insert(character);
|
|
}
|
|
}
|
|
void GuiService::removeKey(std::string key)
|
|
{
|
|
if(key.size() != 1)
|
|
throw RBX::runtime_error("GuiService:RemoveKey requires a string with a single character");
|
|
char character = tolower(key[0]);
|
|
|
|
std::set<char>::iterator it = subscribedChars.find(character);
|
|
if (it != subscribedChars.end())
|
|
subscribedChars.erase(it);
|
|
}
|
|
bool GuiService::hasSpecial(SpecialKey key)
|
|
{
|
|
return subscribedSpecials.find(key) != subscribedSpecials.end();
|
|
}
|
|
void GuiService::addSpecialKey(SpecialKey key)
|
|
{
|
|
if(!hasSpecial(key)){
|
|
subscribedSpecials.insert(key);
|
|
}
|
|
}
|
|
void GuiService::removeSpecialKey(SpecialKey key)
|
|
{
|
|
std::set<SpecialKey>::iterator iter = subscribedSpecials.find(key);
|
|
if (iter != subscribedSpecials.end())
|
|
{
|
|
subscribedSpecials.erase(iter);
|
|
}
|
|
}
|
|
|
|
void GuiService::openBrowserWindow(std::string url)
|
|
{
|
|
if( !RBX::Http::isRobloxSite(url.c_str()) )
|
|
{
|
|
StandardOut::singleton()->print(MESSAGE_WARNING, "GuiService::OpenBrowserWindow() was called on non-Roblox url.");
|
|
return;
|
|
}
|
|
if(!RBX::Network::Players::frontendProcessing(this))
|
|
{
|
|
StandardOut::singleton()->print(MESSAGE_WARNING, "GuiService::OpenBrowserWindow() was called on not a client (use local scripts on this call).");
|
|
return;
|
|
}
|
|
|
|
openUrlWindow(url);
|
|
}
|
|
|
|
void GuiService::setErrorMessage(std::string newErrorMessage)
|
|
{
|
|
if (newErrorMessage.compare(errorMessage) != 0)
|
|
{
|
|
errorMessage = newErrorMessage;
|
|
newErrorSignal(errorMessage);
|
|
}
|
|
}
|
|
|
|
std::string GuiService::getErrorMessage()
|
|
{
|
|
return errorMessage;
|
|
}
|
|
|
|
void GuiService::setUiMessage(GuiService::UiMessageType msgType, std::string newUiMessage)
|
|
{
|
|
if (newUiMessage.compare(uiMessage) != 0)
|
|
{
|
|
uiMessage = newUiMessage;
|
|
newUiMessageSignal(msgType, uiMessage);
|
|
}
|
|
}
|
|
|
|
std::string GuiService::getUiMessage()
|
|
{
|
|
return uiMessage;
|
|
}
|
|
|
|
void GuiService::toggleFullscreen()
|
|
{
|
|
// People were modifying verbString when it was loaded into a register by using CE.
|
|
VMProtectBeginMutation(NULL);
|
|
|
|
std::string verbString = "ToggleFullScreen";
|
|
Verb* verb = NULL;
|
|
|
|
if(Workspace* workspace = ServiceProvider::find<Workspace>(this))
|
|
{
|
|
#ifdef RBX_STUDIO_BUILD
|
|
verb = workspace->getVerb(verbString);
|
|
#else
|
|
verb = workspace->getWhitelistVerb(verbString);
|
|
if (verb && verb->getVerbSecurity())
|
|
{
|
|
RBX::Tokens::simpleToken |= HATE_VERB_SNATCH;
|
|
verb = NULL;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
if (verb && verb->isEnabled())
|
|
{
|
|
Verb::doItWithChecks(verb, RBX::DataModel::get(this));
|
|
}
|
|
|
|
VMProtectEnd();
|
|
}
|
|
|
|
bool GuiService::isTenFootInterface()
|
|
{
|
|
return UserInputService::isTenFootInterface();
|
|
}
|
|
|
|
void GuiService::setSelectedGuiObjectLua(GuiObject* value)
|
|
{
|
|
if (RBX::Network::Players* players = ServiceProvider::create<RBX::Network::Players>(this))
|
|
{
|
|
if (RBX::Network::Player* player = players->getLocalPlayer())
|
|
{
|
|
if (PlayerGui* playerGui = player->findFirstChildOfType<PlayerGui>())
|
|
{
|
|
if (value != playerGui->getSelectedObject().get())
|
|
{
|
|
playerGui->setSelectedObject(value);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void GuiService::setSelectedCoreGuiObjectLua(GuiObject* value)
|
|
{
|
|
if (CoreGuiService* coreGuiService = ServiceProvider::find<CoreGuiService>(this))
|
|
{
|
|
if (value != coreGuiService->getSelectedObject().get())
|
|
{
|
|
coreGuiService->setSelectedObject(value);
|
|
}
|
|
}
|
|
}
|
|
|
|
GuiObject* GuiService::getSelectedGuiObjectLua() const
|
|
{
|
|
if (RBX::Network::Players* players = ServiceProvider::create<RBX::Network::Players>(this))
|
|
{
|
|
if (RBX::Network::Player* player = players->getLocalPlayer())
|
|
{
|
|
if (PlayerGui* playerGui = player->findFirstChildOfType<PlayerGui>())
|
|
{
|
|
if (shared_ptr<GuiObject> selectedObject = playerGui->getSelectedObject())
|
|
{
|
|
return selectedObject.get();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
GuiObject* GuiService::getSelectedCoreGuiObjectLua() const
|
|
{
|
|
if (CoreGuiService* coreGuiService = ServiceProvider::find<CoreGuiService>(this))
|
|
{
|
|
if (shared_ptr<GuiObject> selectedCoreObject = coreGuiService->getSelectedObject())
|
|
{
|
|
return selectedCoreObject.get();
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
GuiObject* GuiService::getSelectedGuiObject()
|
|
{
|
|
if (GuiObject* selectedCoreObject = getSelectedCoreGuiObjectLua())
|
|
{
|
|
return selectedCoreObject;
|
|
}
|
|
|
|
if (GuiObject* selectedObject = getSelectedGuiObjectLua())
|
|
{
|
|
return selectedObject;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void GuiService::setCoreGamepadNavEnabled(bool value)
|
|
{
|
|
if (value != coreGamepadNavEnabled)
|
|
{
|
|
coreGamepadNavEnabled = value;
|
|
raisePropertyChanged(prop_coreGamepadNavigationEnabled);
|
|
}
|
|
}
|
|
|
|
void GuiService::setGamepadNavEnabled(bool value)
|
|
{
|
|
if (value != gamepadNavEnabled)
|
|
{
|
|
gamepadNavEnabled = value;
|
|
raisePropertyChanged(prop_gamepadNavigationEnabled);
|
|
}
|
|
}
|
|
|
|
bool GuiService::getAutoGuiSelectionAllowed() const
|
|
{
|
|
if (GamepadService* gamepadService = RBX::ServiceProvider::create<GamepadService>(this))
|
|
{
|
|
return gamepadService->getAutoGuiSelectionAllowed();
|
|
}
|
|
|
|
return false;
|
|
}
|
|
void GuiService::setAutoGuiSelectionAllowed(bool value)
|
|
{
|
|
if (GamepadService* gamepadService = RBX::ServiceProvider::create<GamepadService>(this))
|
|
{
|
|
if (gamepadService->setAutoGuiSelectionAllowed(value))
|
|
{
|
|
raisePropertyChanged(prop_autoGuiSelectionAllowed);
|
|
}
|
|
}
|
|
}
|
|
|
|
void GuiService::addSelectionGroup(std::string selectionGroupName, shared_ptr<Instance> selectionParent)
|
|
{
|
|
shared_ptr<GuiObject> guiObjectParent = shared_from( Instance::fastDynamicCast<GuiObject>(selectionParent.get()) );
|
|
if (!guiObjectParent)
|
|
{
|
|
RBX::StandardOut::singleton()->printf(MESSAGE_ERROR, "GuiService:AddSelectionParent for group name %s: parent is not a GuiObject.", selectionGroupName.c_str());
|
|
return;
|
|
}
|
|
|
|
if (selectionMap.find(selectionGroupName) != selectionMap.end())
|
|
{
|
|
RBX::StandardOut::singleton()->printf(MESSAGE_WARNING, "GuiService:AddSelectionParent already has selection group with name %s, overwriting selection group.", selectionGroupName.c_str());
|
|
removeSelectionGroup(selectionGroupName);
|
|
}
|
|
|
|
selectionMap[selectionGroupName] = SelectionGroupPair(guiObjectParent, shared_ptr<const Reflection::Tuple>());
|
|
}
|
|
void GuiService::addSelectionGroup(std::string selectionGroupName, shared_ptr<const Reflection::Tuple> selectionTuple)
|
|
{
|
|
if (selectionMap.find(selectionGroupName) != selectionMap.end())
|
|
{
|
|
RBX::StandardOut::singleton()->printf(MESSAGE_WARNING, "GuiService:AddSelectionTuple already has selection group with name %s, overwriting selection group.", selectionGroupName.c_str());
|
|
removeSelectionGroup(selectionGroupName);
|
|
}
|
|
|
|
selectionMap[selectionGroupName] = SelectionGroupPair(weak_ptr<GuiObject>(), selectionTuple);
|
|
}
|
|
|
|
void GuiService::removeSelectionGroup(std::string selectionGroupName)
|
|
{
|
|
SelectionMap::iterator iter = selectionMap.find(selectionGroupName);
|
|
if (iter != selectionMap.end())
|
|
{
|
|
selectionMap.erase(iter);
|
|
}
|
|
}
|
|
|
|
GuiService::SelectionGroupPair GuiService::getSelectedObjectGroup(shared_ptr<GuiObject> object)
|
|
{
|
|
for (SelectionMap::iterator iter = selectionMap.begin(); iter != selectionMap.end(); ++iter)
|
|
{
|
|
if (shared_ptr<GuiObject> parentSelection = (*iter).second.first.lock())
|
|
{
|
|
if (object == parentSelection || object->isDescendantOf2(parentSelection))
|
|
{
|
|
return (*iter).second;
|
|
}
|
|
}
|
|
|
|
if (shared_ptr<const Reflection::Tuple> guiObjects = (*iter).second.second)
|
|
{
|
|
if (guiObjects->values.size() > 0 )
|
|
{
|
|
Reflection::ValueArray guiObjectValues = guiObjects->values;
|
|
for (Reflection::ValueArray::iterator tupleIter = guiObjectValues.begin(); tupleIter != guiObjectValues.end(); ++tupleIter)
|
|
{
|
|
if (tupleIter->isType<shared_ptr<Instance> >())
|
|
{
|
|
shared_ptr<Instance> selectableObject = tupleIter->cast<shared_ptr<Instance> >();
|
|
if (selectableObject == object)
|
|
{
|
|
return (*iter).second;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return SelectionGroupPair();
|
|
}
|
|
|
|
shared_ptr<Instance> GuiService::getClosestDialogToPosition(Vector3 position)
|
|
{
|
|
float smallestDistance = Math::inf();
|
|
shared_ptr<Instance> currentClosest = shared_ptr<Instance>();
|
|
|
|
if (CollectionService* collectionService = ServiceProvider::create<CollectionService>(this))
|
|
{
|
|
if (shared_ptr<const Instances> collection = collectionService->getCollection("Dialog"))
|
|
{
|
|
for (Instances::const_iterator iter = collection->begin(); iter != collection->end(); ++iter)
|
|
{
|
|
if (shared_ptr<DialogRoot> dialog = Instance::fastSharedDynamicCast<DialogRoot>(*iter))
|
|
{
|
|
if (shared_ptr<PartInstance> dialogParent = Instance::fastSharedDynamicCast<PartInstance>(shared_from(dialog->getParent())))
|
|
{
|
|
float distanceFromPosition = (dialogParent->getCoordinateFrame().translation - position).magnitude();
|
|
if (distanceFromPosition < smallestDistance && distanceFromPosition < dialog->getConversationDistance())
|
|
{
|
|
smallestDistance = distanceFromPosition;
|
|
currentClosest = dialog;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return currentClosest;
|
|
}
|
|
|
|
static void doNothing(Reflection::Variant var) {}
|
|
|
|
bool GuiService::showStatsBasedOnInputString(std::string inputText)
|
|
{
|
|
if (!DFFlag::EnableShowStatsLua)
|
|
return false;
|
|
const char * text = inputText.c_str();
|
|
bool retVal = false;
|
|
|
|
shared_ptr<DataModel> dataModel = shared_from(DataModel::get(this));
|
|
|
|
if (!dataModel)
|
|
return retVal;
|
|
|
|
if (strcmp(text, "Genstats") == 0)
|
|
{
|
|
dataModel->getGuiBuilder().toggleGeneralStats();
|
|
retVal = true;
|
|
}
|
|
else if (strcmp(text, "Renstats") == 0)
|
|
{
|
|
dataModel->getGuiBuilder().toggleRenderStats();
|
|
retVal = true;
|
|
}
|
|
else if (strcmp(text, "Netstats") == 0)
|
|
{
|
|
dataModel->getGuiBuilder().toggleNetworkStats();
|
|
retVal = true;
|
|
}
|
|
else if (strcmp(text, "Phystats") == 0)
|
|
{
|
|
dataModel->getGuiBuilder().togglePhysicsStats();
|
|
retVal = true;
|
|
}
|
|
else if (strcmp(text, "Sumstats") == 0)
|
|
{
|
|
dataModel->getGuiBuilder().toggleSummaryStats();
|
|
retVal = true;
|
|
}
|
|
else if (strcmp(text, "Cusstats") == 0)
|
|
{
|
|
dataModel->getGuiBuilder().toggleCustomStats();
|
|
retVal = true;
|
|
}
|
|
else if (boost::iequals(text, "/console"))
|
|
{
|
|
if (CoreGuiService* cgs = dataModel->find<CoreGuiService>())
|
|
{
|
|
if (Instance* parent = cgs->findFirstChildByName("RobloxGui"))
|
|
{
|
|
if (Instance* controlFrame = parent->findFirstChildByName("ControlFrame"))
|
|
{
|
|
parent = controlFrame;
|
|
}
|
|
if (BindableFunction* toggle = Instance::fastDynamicCast<BindableFunction>(parent->findFirstChildByName("ToggleDevConsole")))
|
|
{
|
|
toggle->invoke(rbx::make_shared<Reflection::Tuple>(),
|
|
boost::bind(&doNothing, _1), boost::bind(&doNothing, _1));
|
|
}
|
|
}
|
|
}
|
|
retVal = true;
|
|
}
|
|
|
|
return retVal;
|
|
}
|
|
|
|
}
|