mirror of
https://github.com/copyrighttxt/watrbx-game-engine.git
synced 2026-09-04 20:57:49 +00:00
1089 lines
33 KiB
C++
1089 lines
33 KiB
C++
#include "stdafx.h"
|
|
|
|
/* Copyright 2003-2009 ROBLOX Corporation, All Rights Reserved */
|
|
#include "V8DataModel/PlayerGui.h"
|
|
#include "V8DataModel/TextLabel.h"
|
|
#include "v8datamodel/ImageLabel.h"
|
|
#include "V8DataModel/Frame.h"
|
|
#include "V8DataModel/DebrisService.h"
|
|
#include "V8DataModel/ScreenGui.h"
|
|
#include "V8DataModel/Workspace.h"
|
|
#include "V8DataModel/GuiBase2d.h"
|
|
#include "v8datamodel/GuiService.h"
|
|
#include "v8datamodel/ScrollingFrame.h"
|
|
#include "GfxBase/IAdornableCollector.h"
|
|
#include "Network/Player.h"
|
|
#include "Network/Players.h"
|
|
#include "Util/LuaWebService.h"
|
|
#include "Script/Script.h"
|
|
#include "Script/ScriptContext.h"
|
|
|
|
#define START_PROJECTION_DISTANCE 50000.0f
|
|
|
|
DYNAMIC_FASTFLAGVARIABLE(SetCoreDisableNotifications, false)
|
|
DYNAMIC_FASTFLAGVARIABLE(SetCoreSendNotifications, false)
|
|
DYNAMIC_FASTFLAGVARIABLE(SetCoreMoveChat, false)
|
|
DYNAMIC_FASTFLAGVARIABLE(SetCoreDisableChatBar, false)
|
|
|
|
namespace RBX {
|
|
|
|
const char* const sBasePlayerGui = "BasePlayerGui";
|
|
|
|
static const int MAX_ON_SCREEN_MESSAGES = 3;
|
|
static const TextService::FontSize ON_SCREEN_MESSAGE_FONT_SIZE = TextService::SIZE_12;
|
|
static const int ON_SCREEN_MESSAGE_DISTANCE_TO_RIGHT = 300;
|
|
static const int ON_SCREEN_MESSAGE_DISTANCE_TO_BOTTOM = 40;
|
|
static const int ON_SCREEN_MESSAGE_DISTANCE_BETWEEN_SLOTS = 20;
|
|
|
|
BasePlayerGui::BasePlayerGui()
|
|
: Super()
|
|
, adornableCollector(new IAdornableCollector())
|
|
, mouseWasOverGui(false)
|
|
{
|
|
defaultSelectionImage = RBX::Creatable<Instance>::create<ImageLabel>();
|
|
defaultSelectionImage->setImage( TextureId("rbxasset://textures/ui/SelectionBox.png") );
|
|
defaultSelectionImage->setBackgroundTransparency(1);
|
|
defaultSelectionImage->setSliceCenter(Rect2D::xyxy(19,19,43,43));
|
|
defaultSelectionImage->setImageScale(GuiObject::SCALE_SLICED);
|
|
defaultSelectionImage->setSize(UDim2(1,14,1,14));
|
|
defaultSelectionImage->setPosition(UDim2(0,-7,0,-7));
|
|
|
|
FASTLOG1(FLog::GuiTargetLifetime, "BasePlayerGui created: %p", this);
|
|
}
|
|
|
|
BasePlayerGui::~BasePlayerGui()
|
|
{
|
|
FASTLOG1(FLog::GuiTargetLifetime, "BasePlayerGui destroyed: %p", this);
|
|
}
|
|
|
|
|
|
bool BasePlayerGui::findModalGuiObject()
|
|
{
|
|
boost::shared_ptr<const Instances> c(this->getChildren().read());
|
|
if(c)
|
|
{
|
|
for (Instances::const_iterator iter = c->begin(); iter!=c->end(); ++iter)
|
|
{
|
|
if(ScreenGui* screenGui = Instance::fastDynamicCast<ScreenGui>(iter->get()))
|
|
{
|
|
if(screenGui->hasModalDialog())
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void BasePlayerGui::setSelectedObject(GuiObject* value)
|
|
{
|
|
shared_ptr<GuiObject> currentSelectedObject = getSelectedObject();
|
|
if (!currentSelectedObject || currentSelectedObject.get() != value)
|
|
{
|
|
if (shared_ptr<GuiObject> lastSelection = selectedGuiObject.lock())
|
|
{
|
|
lastSelection->selectionLostEvent();
|
|
}
|
|
|
|
selectedGuiObject = weak_from(value);
|
|
|
|
if (shared_ptr<GuiObject> sharedSelection = selectedGuiObject.lock())
|
|
{
|
|
sharedSelection->selectionGainedEvent();
|
|
}
|
|
|
|
GuiService* guiService = ServiceProvider::find<GuiService>(this);
|
|
|
|
if (!guiService)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (Instance::fastDynamicCast<PlayerGui>(this))
|
|
{
|
|
guiService->raisePropertyChanged(GuiService::prop_selectedGuiObject);
|
|
}
|
|
else if (Instance::fastDynamicCast<CoreGuiService>(this))
|
|
{
|
|
guiService->raisePropertyChanged(GuiService::prop_selectedCoreGuiObject);
|
|
}
|
|
}
|
|
}
|
|
|
|
float getAngleBetween(const Vector2& beginPoint, const Vector2& endPoint, const Vector2& inputDirection)
|
|
{
|
|
Vector2 unitCenter = (endPoint - beginPoint);
|
|
unitCenter.unitize();
|
|
Vector2 inputUnitVector(inputDirection);
|
|
inputUnitVector.unitize();
|
|
float dotProduct = inputUnitVector.dot(unitCenter);
|
|
return acosf(dotProduct);
|
|
}
|
|
|
|
void getClosestPoints(float& aPointCenter, float& bPointCenter, const float aSize, const float bSize)
|
|
{
|
|
if ( (aPointCenter + aSize/2.0f) >= (bPointCenter - bSize/2.0f) )
|
|
{
|
|
aPointCenter = (aPointCenter + aSize/2.0f);
|
|
bPointCenter = aPointCenter;
|
|
}
|
|
else
|
|
{
|
|
float midPoint = (bPointCenter + aPointCenter)/2.0f;
|
|
|
|
if (midPoint <= (aPointCenter + aSize/2.0f))
|
|
{
|
|
aPointCenter = midPoint;
|
|
}
|
|
else
|
|
{
|
|
aPointCenter += aSize/2.0f;
|
|
}
|
|
|
|
if (midPoint >= (bPointCenter - bSize/2.0f))
|
|
{
|
|
bPointCenter = midPoint;
|
|
}
|
|
else
|
|
{
|
|
bPointCenter -= bSize/2.0f;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool getClosestGuiPoints(const Rect2D& selectedRect, const Rect2D& guiObjectRect, Vector2& selectedPoint, Vector2& objectPoint)
|
|
{
|
|
if (selectedRect.intersectsOrTouches(guiObjectRect))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (selectedPoint.y < objectPoint.y)
|
|
{
|
|
getClosestPoints(selectedPoint.y, objectPoint.y, selectedRect.height(), guiObjectRect.height());
|
|
}
|
|
else if (selectedPoint.y > objectPoint.y)
|
|
{
|
|
getClosestPoints(objectPoint.y, selectedPoint.y, guiObjectRect.height(), selectedRect.height());
|
|
}
|
|
|
|
if (selectedPoint.x < objectPoint.x)
|
|
{
|
|
getClosestPoints(selectedPoint.x, objectPoint.x, selectedRect.width(), guiObjectRect.width());
|
|
}
|
|
else if (selectedPoint.x > objectPoint.x)
|
|
{
|
|
getClosestPoints(objectPoint.x, selectedPoint.x, guiObjectRect.width(), selectedRect.width());
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool BasePlayerGui::isCloserGuiObject(const Rect2D& currentRect, const Vector2& inputDirection, const GuiObject* guiObjectToTest,
|
|
float& minIntersectDist, float& minProjection, const GuiObject* nextSelectionGuiObject)
|
|
{
|
|
if (!guiObjectToTest)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
const std::string name = guiObjectToTest->getName();
|
|
const Rect2D guiObjectRect = guiObjectToTest->getRect2D();
|
|
|
|
Vector2 beginTestPoint = currentRect.center();
|
|
Vector2 endTestPoint = guiObjectRect.center();
|
|
|
|
bool isIntersecting = !getClosestGuiPoints(currentRect, guiObjectRect, beginTestPoint, endTestPoint);
|
|
if (!isIntersecting && minIntersectDist == START_PROJECTION_DISTANCE)
|
|
{
|
|
const float maxAngle = RBX::Math::piHalff()/4.0f;
|
|
float newAngle = getAngleBetween(beginTestPoint, endTestPoint, inputDirection);
|
|
|
|
if (!boost::math::isfinite(newAngle) || newAngle > maxAngle)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
const Vector2 guiVector = endTestPoint - beginTestPoint;
|
|
const Vector2 largeInputDirection = inputDirection * 100000.0f; // make sure we get an accurate projection onto the input vector
|
|
|
|
if (largeInputDirection.length() <= 0.0f)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
float projection = (guiVector.dot(largeInputDirection)/largeInputDirection.length());
|
|
if (projection < minProjection)
|
|
{
|
|
minProjection = projection;
|
|
return true;
|
|
}
|
|
else if(projection == minProjection && nextSelectionGuiObject)
|
|
{
|
|
// we have a tie, let the one with the closest center point win
|
|
const float testDistance = (currentRect.center() - guiObjectToTest->getRect2D().center()).length();
|
|
const float nextDistance = (currentRect.center() - nextSelectionGuiObject->getRect2D().center()).length();
|
|
if (testDistance < nextDistance)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
else if (isIntersecting) // rects are intersecting, just compare center points
|
|
{
|
|
const float maxAngle = RBX::Math::piHalff()/4.0f;
|
|
const Vector2 beginPoint = currentRect.center();
|
|
const Vector2 endPoint = guiObjectRect.center();
|
|
|
|
const float newAngle = getAngleBetween(beginPoint, endPoint, inputDirection);
|
|
|
|
if (boost::math::isfinite(newAngle) && newAngle <= maxAngle)
|
|
{
|
|
const float intersectionDist = (beginPoint - endPoint).length();
|
|
if (intersectionDist < minIntersectDist)
|
|
{
|
|
minIntersectDist = intersectionDist;
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void collectGuiObjects(std::vector<GuiObject*>& guiObjectsToTest, Instance* rootObject)
|
|
{
|
|
if (!rootObject)
|
|
return;
|
|
|
|
boost::shared_ptr<const Instances> c(rootObject->getChildren().read());
|
|
if(c)
|
|
{
|
|
for (Instances::const_iterator iter = c->begin(); iter!=c->end(); ++iter)
|
|
{
|
|
if(ScreenGui* screenGui = Instance::fastDynamicCast<ScreenGui>(iter->get()))
|
|
{
|
|
screenGui->getGuiObjectsForSelection(guiObjectsToTest);
|
|
}
|
|
collectGuiObjects(guiObjectsToTest, iter->get());
|
|
}
|
|
}
|
|
}
|
|
|
|
GuiObject* checkGuiObjectForNextDirection(const shared_ptr<GuiObject>& guiObject, const Vector2& direction)
|
|
{
|
|
if (direction.y > 0.0f && guiObject->getNextSelectionDown() && guiObject->getNextSelectionDown()->isCurrentlyVisible())
|
|
{
|
|
return guiObject->getNextSelectionDown();
|
|
}
|
|
|
|
if (direction.y < 0.0f && guiObject->getNextSelectionUp() && guiObject->getNextSelectionUp()->isCurrentlyVisible())
|
|
{
|
|
return guiObject->getNextSelectionUp();
|
|
}
|
|
|
|
if (direction.x > 0.0f && guiObject->getNextSelectionRight() && guiObject->getNextSelectionRight()->isCurrentlyVisible())
|
|
{
|
|
return guiObject->getNextSelectionRight();
|
|
}
|
|
|
|
if (direction.x < 0.0f && guiObject->getNextSelectionLeft() && guiObject->getNextSelectionLeft()->isCurrentlyVisible())
|
|
{
|
|
return guiObject->getNextSelectionLeft();
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
GuiObject* BasePlayerGui::checkForTupleSelection(const Vector2& direction, const Rect2D& currentRect,
|
|
const shared_ptr<const Reflection::Tuple>& selectionTuple)
|
|
{
|
|
float minProjection = START_PROJECTION_DISTANCE;
|
|
float minIntersectionDist = minProjection;
|
|
|
|
GuiObject* nextSelectedGuiObject = NULL;
|
|
|
|
if (selectionTuple && selectionTuple->values.size() > 0)
|
|
{
|
|
Reflection::ValueArray guiObjectValues = selectionTuple->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 (GuiObject* selectableGuiObject = Instance::fastDynamicCast<GuiObject>(selectableObject.get()))
|
|
{
|
|
ScrollingFrame* ancestorScrollingFrame = selectableGuiObject->findFirstAncestorOfType<ScrollingFrame>();
|
|
|
|
if (selectableGuiObject->isCurrentlyVisible() || (ancestorScrollingFrame && ancestorScrollingFrame->isCurrentlyVisible()))
|
|
{
|
|
if (isCloserGuiObject(currentRect, direction, selectableGuiObject,
|
|
minIntersectionDist, minProjection, nextSelectedGuiObject))
|
|
{
|
|
nextSelectedGuiObject = selectableGuiObject;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return nextSelectedGuiObject;
|
|
}
|
|
|
|
GuiObject* BasePlayerGui::checkForDefaultGuiSelection(const Vector2& direction, const Rect2D& currentRect,
|
|
const shared_ptr<Instance> selectionAncestor)
|
|
{
|
|
float minProjection = START_PROJECTION_DISTANCE;
|
|
float minIntersectionDist = minProjection;
|
|
|
|
GuiObject* nextSelectedGuiObject = NULL;
|
|
|
|
std::vector<GuiObject*> guiObjectsToTest;
|
|
collectGuiObjects(guiObjectsToTest, this);
|
|
|
|
for (std::vector<GuiObject*>::iterator iter = guiObjectsToTest.begin(); iter != guiObjectsToTest.end(); ++iter)
|
|
{
|
|
if (selectionAncestor)
|
|
{
|
|
if ( ((*iter) == selectionAncestor.get() || (*iter)->isDescendantOf2(selectionAncestor)) &&
|
|
isCloserGuiObject(currentRect, direction, (*iter),
|
|
minIntersectionDist, minProjection, nextSelectedGuiObject))
|
|
{
|
|
nextSelectedGuiObject = (*iter);
|
|
}
|
|
}
|
|
else if (isCloserGuiObject(currentRect, direction, (*iter),
|
|
minIntersectionDist, minProjection, nextSelectedGuiObject))
|
|
{
|
|
nextSelectedGuiObject = (*iter);
|
|
}
|
|
}
|
|
|
|
return nextSelectedGuiObject;
|
|
}
|
|
|
|
GuiObject* BasePlayerGui::selectNewGuiObject(const Vector2& direction)
|
|
{
|
|
GuiService* guiService = RBX::ServiceProvider::find<GuiService>(this);
|
|
if (!guiService)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
Rect2D currentRect = Rect2D::xywh(Vector2::zero(), Vector2::zero());
|
|
GuiService::SelectionGroupPair selectionGroup;
|
|
|
|
const shared_ptr<GuiObject> sharedSelectedGuiObject = selectedGuiObject.lock();
|
|
|
|
if (sharedSelectedGuiObject)
|
|
{
|
|
currentRect = sharedSelectedGuiObject->getRect2D();
|
|
selectionGroup = guiService->getSelectedObjectGroup(sharedSelectedGuiObject);
|
|
}
|
|
else
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
GuiObject* closestGuiObject = NULL;
|
|
|
|
if (GuiObject* newSelectedObject = checkGuiObjectForNextDirection(sharedSelectedGuiObject, direction))
|
|
{
|
|
closestGuiObject = newSelectedObject;
|
|
}
|
|
|
|
if (!closestGuiObject)
|
|
{
|
|
shared_ptr<const Reflection::Tuple> selectionTuple = selectionGroup.second;
|
|
|
|
if (selectionTuple)
|
|
{
|
|
if (selectionTuple->values.size() > 0)
|
|
{
|
|
closestGuiObject = checkForTupleSelection(direction, currentRect, selectionGroup.second);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
closestGuiObject = checkForDefaultGuiSelection(direction, currentRect, selectionGroup.first.lock());
|
|
}
|
|
}
|
|
|
|
if (closestGuiObject)
|
|
{
|
|
setSelectedObject(closestGuiObject);
|
|
}
|
|
|
|
return closestGuiObject;
|
|
}
|
|
|
|
bool BasePlayerGui::scriptShouldRun(BaseScript* script)
|
|
{
|
|
RBXASSERT(isAncestorOf(script));
|
|
|
|
bool answer = false;
|
|
|
|
if (script->fastDynamicCast<LocalScript>())
|
|
{
|
|
{
|
|
//Either we're in the old mode (LocalScripts run on Client), or this script is elligible to be run ClientSide
|
|
RBX::Network::Player* localPlayer = Network::Players::findLocalPlayer(this);
|
|
answer = (localPlayer && (getParent() == localPlayer));
|
|
if(answer){
|
|
script->setLocalPlayer(shared_from(localPlayer));
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
answer = Network::Players::backendProcessing(this, false); // modified by db 12/2/09 - this is called when BaseScript is not in the workspace at times
|
|
}
|
|
|
|
return answer;
|
|
}
|
|
|
|
bool BasePlayerGui::askAddChild(const Instance* instance) const
|
|
{
|
|
return true;
|
|
}
|
|
|
|
void BasePlayerGui::onDescendantAdded(Instance* instance)
|
|
{
|
|
Super::onDescendantAdded(instance);
|
|
|
|
if (IAdornable* iR = dynamic_cast<IAdornable*>(instance)) {
|
|
adornableCollector->onRenderableDescendantAdded(iR);
|
|
}
|
|
}
|
|
|
|
void BasePlayerGui::onDescendantRemoving(const shared_ptr<Instance>& instance)
|
|
{
|
|
if (IAdornable* iR = dynamic_cast<IAdornable*>(instance.get())) {
|
|
adornableCollector->onRenderableDescendantRemoving(iR);
|
|
}
|
|
|
|
Super::onDescendantRemoving(instance);
|
|
}
|
|
|
|
// all descendants
|
|
void BasePlayerGui::render3dAdorn(Adorn* adorn)
|
|
{
|
|
adornableCollector->render3dAdornItems(adorn);
|
|
}
|
|
|
|
|
|
void BasePlayerGui::append3dSortedAdorn(std::vector<AdornableDepth>& sortedAdorn, const Camera* camera) const
|
|
{
|
|
adornableCollector->append3dSortedAdornItems(sortedAdorn, camera);
|
|
}
|
|
|
|
void BasePlayerGui::tryRenderSelectionFrame(Adorn* adorn)
|
|
{
|
|
if (GuiService* guiService = RBX::ServiceProvider::find<GuiService>(this))
|
|
{
|
|
if (GuiObject* selectedGuiObject = guiService->getSelectedGuiObject())
|
|
{
|
|
if (selectedGuiObject->isDescendantOf(this) && selectedGuiObject->isCurrentlyVisible())
|
|
{
|
|
if (GuiObject* imageObject = selectionImageObject.get())
|
|
{
|
|
selectedGuiObject->renderSelectionFrame(adorn, imageObject);
|
|
}
|
|
else
|
|
{
|
|
selectedGuiObject->renderSelectionFrame(adorn, defaultSelectionImage.get());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void BasePlayerGui::render2d(Adorn* adorn)
|
|
{
|
|
adornableCollector->render2dItems(adorn);
|
|
tryRenderSelectionFrame(adorn);
|
|
}
|
|
|
|
GuiResponse BasePlayerGui::processChildren(boost::function<GuiResponse(GuiBase2d*)> func)
|
|
{
|
|
if (this->getChildren())
|
|
{
|
|
boost::shared_ptr<const Instances> c(this->getChildren().read());
|
|
Instances::const_iterator end = c->end();
|
|
for (Instances::const_iterator iter = c->begin(); iter!=end; ++iter)
|
|
{
|
|
if (GuiBase2d* guiBase = fastDynamicCast<GuiBase2d>((*iter).get()))
|
|
{
|
|
GuiResponse answer = func(guiBase);
|
|
if(answer.wasSunk())
|
|
return answer;
|
|
}
|
|
}
|
|
}
|
|
|
|
return GuiResponse::notSunk();
|
|
}
|
|
|
|
GuiResponse BasePlayerGui::processInputOnChild(GuiBase2d* guiBase, const shared_ptr<InputObject>& event)
|
|
{
|
|
GuiResponse answer = guiBase->process(event);
|
|
|
|
if (answer.wasSunk() || answer.getMouseWasOver())
|
|
{
|
|
mouseWasOverGui = true;
|
|
}
|
|
|
|
return answer;
|
|
}
|
|
|
|
GuiResponse BasePlayerGui::process(const shared_ptr<InputObject>& event)
|
|
{
|
|
mouseWasOverGui = false;
|
|
Instance* mouseOverGuiBase = NULL;
|
|
|
|
boost::shared_ptr<const Instances> c(this->getChildren().read());
|
|
if (c)
|
|
{
|
|
Instances::const_reverse_iterator rend = c->rend();
|
|
|
|
for (Instances::const_reverse_iterator iter = c->rbegin(); iter!=rend; ++iter)
|
|
{
|
|
if (GuiBase* guiBase = fastDynamicCast<GuiBase>((*iter).get()))
|
|
{
|
|
GuiResponse answer = guiBase->process(event);
|
|
if (answer.wasSunk())
|
|
{
|
|
answer.setMouseWasOver();
|
|
return answer;
|
|
}
|
|
if (answer.getMouseWasOver())
|
|
{
|
|
mouseOverGuiBase = answer.getTarget().get();
|
|
mouseWasOverGui = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
GuiResponse answer = mouseWasOverGui ? GuiResponse::notSunkMouseWasOver() : GuiResponse::notSunk();
|
|
answer.setTarget(mouseOverGuiBase);
|
|
return answer;
|
|
}
|
|
|
|
GuiResponse BasePlayerGui::processGestureOnChild(GuiBase2d* guiBase, const UserInputService::Gesture gesture, shared_ptr<const RBX::Reflection::ValueArray> touchPositions, shared_ptr<const Reflection::Tuple> args)
|
|
{
|
|
return guiBase->processGesture(gesture, touchPositions, args);
|
|
}
|
|
|
|
GuiResponse BasePlayerGui::processGesture(const UserInputService::Gesture gesture, shared_ptr<const RBX::Reflection::ValueArray> touchPositions, shared_ptr<const Reflection::Tuple> args)
|
|
{
|
|
GuiResponse answer = GuiResponse::notSunk();
|
|
|
|
if (this->getChildren())
|
|
{
|
|
boost::shared_ptr<const Instances> c(this->getChildren().read());
|
|
Instances::const_iterator end = c->end();
|
|
for (Instances::const_iterator iter = c->begin(); iter!=end; ++iter)
|
|
{
|
|
if (GuiBase2d* guiBase = fastDynamicCast<GuiBase2d>((*iter).get()))
|
|
{
|
|
answer = processGestureOnChild(guiBase, gesture, touchPositions, args);
|
|
if (answer.wasSunk() || answer.getMouseWasOver())
|
|
{
|
|
return answer;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return answer;
|
|
}
|
|
|
|
|
|
REFLECTION_BEGIN();
|
|
static Reflection::RefPropDescriptor<PlayerGui, GuiObject> prop_PlayerGuiSelectionImageObject("SelectionImageObject", category_Appearance, &PlayerGui::getSelectionImageObject, &PlayerGui::setSelectionImageObject, Reflection::PropertyDescriptor::STANDARD);
|
|
static const Reflection::BoundFuncDesc<PlayerGui, void(float)> func_setTopbarTransparency(&PlayerGui::setTopbarTransparency, "SetTopbarTransparency", "transparency", Security::None);
|
|
static const Reflection::BoundFuncDesc<PlayerGui, float(void)> func_getTopbarTransparency(&PlayerGui::getTopbarTransparency, "GetTopbarTransparency", Security::None);
|
|
static Reflection::EventDesc<PlayerGui, void(float)> event_topbarTransparencyChangedSignal(&PlayerGui::topbarTransparencyChangedSignal, "TopbarTransparencyChangedSignal", "transparency", Security::None);
|
|
REFLECTION_END();
|
|
|
|
const char* const sPlayerGui = "PlayerGui";
|
|
PlayerGui::PlayerGui()
|
|
: Super(),
|
|
topbarTransparency(0.5f)
|
|
{
|
|
setName("PlayerGui");
|
|
|
|
}
|
|
|
|
void PlayerGui::onServiceProvider(ServiceProvider* oldProvider, ServiceProvider* newProvider)
|
|
{
|
|
if (TeleportService* ts = ServiceProvider::create<TeleportService>(newProvider))
|
|
{
|
|
if (ts->getTempCustomTeleportLoadingGui() && TeleportService::didTeleport())
|
|
{
|
|
if (DataModel::get(newProvider)->getCreatorID() == TeleportService::getPreviousCreatorId() && DataModel::get(newProvider)->getCreatorType() == TeleportService::getPreviousCreatorType())
|
|
{
|
|
if (RBX::ScreenGui* loadingGui = Instance::fastDynamicCast<RBX::ScreenGui>(TeleportService::getCustomTeleportLoadingGui().get()))
|
|
{
|
|
loadingGui->setParent(this);
|
|
}
|
|
}
|
|
ts->getTempCustomTeleportLoadingGui()->destroy();
|
|
}
|
|
}
|
|
Super::onServiceProvider(oldProvider, newProvider);
|
|
}
|
|
|
|
bool PlayerGui::askSetParent(const Instance* parent) const
|
|
{
|
|
return Instance::fastDynamicCast<RBX::Network::Player>(parent)!=NULL;
|
|
}
|
|
bool PlayerGui::askForbidParent(const Instance* parent) const
|
|
{
|
|
return !askSetParent(parent);
|
|
}
|
|
|
|
void PlayerGui::setTopbarTransparency(float transparency)
|
|
{
|
|
if(RBX::Network::Players::frontendProcessing(this))
|
|
{
|
|
if (G3D::isFinite(transparency))
|
|
{
|
|
float newTransparency = transparency < 0.25f ? 0.f : 0.5f;
|
|
if (newTransparency != transparency)
|
|
{
|
|
RBX::StandardOut::singleton()->printf(MESSAGE_WARNING, "PlayerGui:SetTopbarTransparency - Attempted to set to %f, but only 0 or 0.5 are valid; setting to %f.", transparency, newTransparency);
|
|
}
|
|
if (topbarTransparency != newTransparency)
|
|
{
|
|
topbarTransparency = newTransparency;
|
|
topbarTransparencyChangedSignal(topbarTransparency);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
throw std::runtime_error("PlayerGui:SetTopbarTransparency can only be set from a local script.");
|
|
}
|
|
}
|
|
|
|
float PlayerGui::getTopbarTransparency(void)
|
|
{
|
|
if(!RBX::Network::Players::frontendProcessing(this))
|
|
{
|
|
throw std::runtime_error("PlayerGui:GetTopbarTransparency should only be accessed from a local script.");
|
|
}
|
|
return topbarTransparency;
|
|
}
|
|
|
|
void PlayerGui::setSelectionImageObject(GuiObject* value)
|
|
{
|
|
if (value != selectionImageObject.get())
|
|
{
|
|
selectionImageObject = shared_from(value);
|
|
raisePropertyChanged(prop_PlayerGuiSelectionImageObject);
|
|
}
|
|
}
|
|
|
|
const char *const sStarterGuiService = "StarterGui";
|
|
|
|
REFLECTION_BEGIN();
|
|
static const Reflection::PropDescriptor<StarterGuiService, bool> prop_showGui("ShowDevelopmentGui", category_Data, &StarterGuiService::getShowGui, &StarterGuiService::setShowGui);
|
|
const Reflection::PropDescriptor<StarterGuiService, bool> StarterGuiService::prop_ResetPlayerGui("ResetPlayerGuiOnSpawn", category_Data, &StarterGuiService::getResetPlayerGui, &StarterGuiService::setResetPlayerGui, Reflection::PropertyDescriptor::STANDARD, Security::None);
|
|
|
|
static const Reflection::BoundFuncDesc<StarterGuiService, void(StarterGuiService::CoreGuiType, bool)> func_setCoreGuiEnabled(&StarterGuiService::setCoreGuiEnabled,"SetCoreGuiEnabled", "coreGuiType", "enabled", Security::None);
|
|
static const Reflection::BoundFuncDesc<StarterGuiService, bool(StarterGuiService::CoreGuiType)> func_getCoreGuiEnabled(&StarterGuiService::getCoreGuiEnabled,"GetCoreGuiEnabled", "coreGuiType", Security::None);
|
|
static Reflection::EventDesc<StarterGuiService, void(StarterGuiService::CoreGuiType,bool)> event_coreGuiChangedSignal(&StarterGuiService::coreGuiChangedSignal, "CoreGuiChangedSignal", "coreGuiType", "enabled", Security::RobloxScript);
|
|
static const Reflection::BoundFuncDesc<StarterGuiService, void(std::string, Lua::WeakFunctionRef)> func_registerSetCore(&StarterGuiService::registerSetCore,"RegisterSetCore", "parameterName", "setFunction", Security::RobloxScript);
|
|
static const Reflection::BoundFuncDesc<StarterGuiService, void(std::string, Lua::WeakFunctionRef)> func_registerGetCore(&StarterGuiService::registerGetCore,"RegisterGetCore", "parameterName", "getFunction", Security::RobloxScript);
|
|
static const Reflection::BoundFuncDesc<StarterGuiService, void(std::string, Reflection::Variant)> func_setCore(&StarterGuiService::setCore,"SetCore", "parameterName", "value", Security::None);
|
|
static const Reflection::BoundYieldFuncDesc<StarterGuiService, Reflection::Variant(std::string)> func_getCore(&StarterGuiService::getCore, "GetCore", "parameterName", Security::None);
|
|
REFLECTION_END();
|
|
|
|
namespace Reflection
|
|
{
|
|
template<>
|
|
EnumDesc<StarterGuiService::CoreGuiType>::EnumDesc():EnumDescriptor("CoreGuiType")
|
|
{
|
|
addPair(StarterGuiService::COREGUI_PLAYERLISTGUI, "PlayerList");
|
|
addPair(StarterGuiService::COREGUI_HEALTHGUI, "Health");
|
|
addPair(StarterGuiService::COREGUI_BACKPACKGUI, "Backpack");
|
|
addPair(StarterGuiService::COREGUI_CHATGUI, "Chat");
|
|
addPair(StarterGuiService::COREGUI_ALL, "All");
|
|
}
|
|
|
|
template<>
|
|
StarterGuiService::CoreGuiType& Variant::convert<StarterGuiService::CoreGuiType>(void)
|
|
{
|
|
return genericConvert<StarterGuiService::CoreGuiType>();
|
|
}
|
|
} // namespace Reflection
|
|
|
|
template<>
|
|
bool StringConverter<StarterGuiService::CoreGuiType>::convertToValue(const std::string& text, StarterGuiService::CoreGuiType& value)
|
|
{
|
|
return Reflection::EnumDesc<StarterGuiService::CoreGuiType>::singleton().convertToValue(text.c_str(),value);
|
|
}
|
|
|
|
StarterGuiService::StarterGuiService()
|
|
:showGui(true),
|
|
resetPlayerGui(true)
|
|
{
|
|
Instance::setName(sStarterGuiService);
|
|
|
|
for(int i = COREGUI_PLAYERLISTGUI; i <= COREGUI_ALL; ++i)
|
|
coreGuiEnabledState[static_cast<StarterGuiService::CoreGuiType>(i)] = true;
|
|
}
|
|
|
|
void StarterGuiService::setCoreGuiEnabled(CoreGuiType type, bool enabled)
|
|
{
|
|
if(!RBX::Network::Players::frontendProcessing(this))
|
|
StandardOut::singleton()->print(MESSAGE_WARNING, "StarterGui:SetCoreGuiEnabled called from server script. Did you mean to use a local script?");
|
|
|
|
// setting the all state resets all keys to the all state
|
|
if (type == COREGUI_ALL)
|
|
{
|
|
for(int i = COREGUI_PLAYERLISTGUI; i <= COREGUI_ALL; ++i)
|
|
coreGuiEnabledState[static_cast<CoreGuiType>(i)] = enabled;
|
|
}
|
|
else
|
|
{
|
|
coreGuiEnabledState[type] = enabled;
|
|
|
|
// check all other states to see if we have all same states
|
|
// if we do, set COREGUI_ALL key to be true or false
|
|
bool lastBool = enabled;
|
|
for (int i = COREGUI_PLAYERLISTGUI; i < COREGUI_ALL; ++i)
|
|
{
|
|
CoreGuiType iteratedType = static_cast<CoreGuiType>(i);
|
|
if (lastBool != coreGuiEnabledState[iteratedType])
|
|
{
|
|
coreGuiEnabledState[COREGUI_ALL] = false;
|
|
lastBool = coreGuiEnabledState[iteratedType];
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(lastBool == enabled)
|
|
coreGuiEnabledState[COREGUI_ALL] = lastBool;
|
|
}
|
|
|
|
coreGuiChangedSignal(type,enabled);
|
|
}
|
|
|
|
bool StarterGuiService::getCoreGuiEnabled(CoreGuiType type)
|
|
{
|
|
if(!RBX::Network::Players::frontendProcessing(this))
|
|
StandardOut::singleton()->print(MESSAGE_WARNING, "StarterGui:GetCoreGuiEnabled called from server script. Did you mean to use a local script?");
|
|
|
|
return coreGuiEnabledState[type];
|
|
}
|
|
|
|
void StarterGuiService::registerSetCore(std::string parameterName, Lua::WeakFunctionRef setFunction)
|
|
{
|
|
setCoreFunctions[parameterName] = setFunction;
|
|
}
|
|
|
|
void StarterGuiService::registerGetCore(std::string parameterName, Lua::WeakFunctionRef getFunction)
|
|
{
|
|
getCoreFunctions[parameterName] = getFunction;
|
|
}
|
|
|
|
void StarterGuiService::setCore(std::string parameterName, Reflection::Variant value)
|
|
{
|
|
FunctionMap::iterator iter = setCoreFunctions.find(parameterName);
|
|
if (iter != setCoreFunctions.end())
|
|
{
|
|
Lua::WeakFunctionRef setFunction = (*iter).second;
|
|
if (Lua::ThreadRef threadRef = setFunction.lock())
|
|
{
|
|
if (ScriptContext* sc = ServiceProvider::create<ScriptContext>(this))
|
|
{
|
|
try
|
|
{
|
|
Reflection::Tuple args = Reflection::Tuple();
|
|
args.values.push_back(value);
|
|
sc->callInNewThread(setFunction, args);
|
|
}
|
|
catch (RBX::base_exception& e)
|
|
{
|
|
StandardOut::singleton()->printf(MESSAGE_ERROR, "SetCore: Unexpected error while invoking callback: %s", e.what());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
throw RBX::runtime_error("SetCore: %s has not been registered by the CoreScripts", parameterName.c_str());
|
|
}
|
|
}
|
|
|
|
void StarterGuiService::getCore(std::string parameterName, boost::function<void(Reflection::Variant)> resumeFunction, boost::function<void(std::string)> errorFunction)
|
|
{
|
|
FunctionMap::iterator iter = getCoreFunctions.find(parameterName);
|
|
if (iter != getCoreFunctions.end())
|
|
{
|
|
Lua::WeakFunctionRef getFunction = (*iter).second;
|
|
if (Lua::ThreadRef threadRef = getFunction.lock())
|
|
{
|
|
if (ScriptContext* sc = ServiceProvider::create<ScriptContext>(this))
|
|
{
|
|
Reflection::Tuple result = Reflection::Tuple();
|
|
Reflection::Tuple args = Reflection::Tuple();
|
|
try
|
|
{
|
|
result = sc->callInNewThread(getFunction, args);
|
|
}
|
|
catch (RBX::base_exception& e)
|
|
{
|
|
errorFunction(RBX::format("GetCore: Unexpected error while invoking callback: %s", e.what()));
|
|
}
|
|
if (result.values.size() > 0)
|
|
{
|
|
resumeFunction(result.values[0].get<Reflection::Variant>());
|
|
}
|
|
else
|
|
{
|
|
errorFunction(RBX::format("GetCore: CoreScript function %s did not return a result", parameterName.c_str()));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
errorFunction(RBX::format("GetCore: %s has not been registered by the CoreScripts", parameterName.c_str()));
|
|
}
|
|
}
|
|
|
|
void StarterGuiService::setShowGui(bool value)
|
|
{
|
|
if(showGui != value){
|
|
showGui = value;
|
|
raisePropertyChanged(prop_showGui);
|
|
}
|
|
}
|
|
|
|
void StarterGuiService::setResetPlayerGui(bool value)
|
|
{
|
|
if(resetPlayerGui != value)
|
|
{
|
|
resetPlayerGui = value;
|
|
raisePropertyChanged(prop_ResetPlayerGui);
|
|
}
|
|
}
|
|
|
|
void StarterGuiService::render2d(Adorn* adorn)
|
|
{
|
|
if(showGui){
|
|
Super::render2d(adorn);
|
|
}
|
|
}
|
|
void StarterGuiService::render3dAdorn(Adorn* adorn)
|
|
{
|
|
if(showGui){
|
|
Super::render3dAdorn(adorn);
|
|
}
|
|
}
|
|
void StarterGuiService::append3dSortedAdorn(std::vector<AdornableDepth>& sortedAdorn, const Camera* camera) const
|
|
{
|
|
if(showGui){
|
|
Super::append3dSortedAdorn(sortedAdorn, camera);
|
|
}
|
|
}
|
|
GuiResponse StarterGuiService::process(const shared_ptr<InputObject>& event)
|
|
{
|
|
if(showGui){
|
|
return Super::process(event);
|
|
}
|
|
return GuiResponse::notSunk();
|
|
}
|
|
|
|
const char *const sCoreGuiService = "CoreGui";
|
|
|
|
REFLECTION_BEGIN();
|
|
static Reflection::RefPropDescriptor<CoreGuiService, GuiObject> prop_CoreSelectionImageObject("SelectionImageObject", category_Appearance, &CoreGuiService::getSelectionImageObject, &CoreGuiService::setSelectionImageObject, Reflection::PropertyDescriptor::STANDARD, Security::RobloxScript);
|
|
static const Reflection::PropDescriptor<CoreGuiService, int> prop_Version("Version", category_Data, &CoreGuiService::getGuiVersion, NULL);
|
|
REFLECTION_END();
|
|
|
|
CoreGuiService::CoreGuiService()
|
|
{
|
|
setRobloxLocked(true);
|
|
Instance::setName(sCoreGuiService);
|
|
|
|
onScreenMessages.resize(MAX_ON_SCREEN_MESSAGES);
|
|
}
|
|
|
|
int CoreGuiService::getGuiVersion() const
|
|
{
|
|
return 0;
|
|
}
|
|
void CoreGuiService::createRobloxScreenGui()
|
|
{
|
|
screenGui = Creatable<RBX::Instance>::create<ScreenGui>();
|
|
screenGui->setName("RobloxGui");
|
|
screenGui->setRobloxLocked(true);
|
|
screenGui->setParent(this);
|
|
}
|
|
|
|
shared_ptr<RBX::ScreenGui> CoreGuiService::getRobloxScreenGui()
|
|
{
|
|
if (!screenGui)
|
|
{
|
|
createRobloxScreenGui();
|
|
}
|
|
|
|
if ( RBX::ScreenGui* theScreenGui = Instance::fastDynamicCast<RBX::ScreenGui>(screenGui.get()) )
|
|
{
|
|
return shared_from(theScreenGui);
|
|
}
|
|
|
|
return shared_ptr<RBX::ScreenGui>();
|
|
}
|
|
|
|
void CoreGuiService::onDescendantAdded(Instance* instance)
|
|
{
|
|
if(instance)
|
|
{
|
|
instance->setRobloxLocked(true);
|
|
}
|
|
|
|
Super::onDescendantAdded(instance);
|
|
}
|
|
|
|
void CoreGuiService::addChild(RBX::Instance* instance)
|
|
{
|
|
if(instance)
|
|
instance->setParent(screenGui.get());
|
|
}
|
|
|
|
void CoreGuiService::removeChild(RBX::Instance* instance)
|
|
{
|
|
if(screenGui->getChildren())
|
|
{
|
|
Instances::const_iterator end = screenGui->getChildren()->end();
|
|
for (Instances::const_iterator iter = screenGui->getChildren()->begin(); iter != end; ++iter)
|
|
{
|
|
if(iter->get() == instance)
|
|
{
|
|
iter->get()->remove();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void CoreGuiService::removeChild(const std::string &Name)
|
|
{
|
|
if(screenGui->getChildren())
|
|
{
|
|
Instances::const_iterator end = screenGui->getChildren()->end();
|
|
for (Instances::const_iterator iter = screenGui->getChildren()->begin(); iter != end; ++iter)
|
|
{
|
|
if(iter->get()->getName() == Name)
|
|
{
|
|
iter->get()->remove();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Instance* CoreGuiService::findGuiChild(const std::string &Name)
|
|
{
|
|
if(screenGui->getChildren())
|
|
{
|
|
Instances::const_iterator end = screenGui->getChildren()->end();
|
|
for (Instances::const_iterator iter = screenGui->getChildren()->begin(); iter != end; ++iter)
|
|
{
|
|
if(iter->get()->getName() == Name)
|
|
return iter->get();
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void CoreGuiService::setGuiVisibility(bool visible)
|
|
{
|
|
if(screenGui->getChildren())
|
|
{
|
|
Instances::const_iterator end = screenGui->getChildren()->end();
|
|
for (Instances::const_iterator iter = screenGui->getChildren()->begin(); iter != end; ++iter)
|
|
if(RBX::GuiObject* obj = Instance::fastDynamicCast<GuiObject>(iter->get()))
|
|
obj->setVisible(visible);
|
|
}
|
|
}
|
|
|
|
void CoreGuiService::displayOnScreenMessage(int slot, const std::string &message, double duration)
|
|
{
|
|
if (slot >= MAX_ON_SCREEN_MESSAGES)
|
|
return;
|
|
|
|
clearOnScreenMessage(slot);
|
|
|
|
Rect2D rect = screenGui->fastDynamicCast<RBX::GuiBase2d>()->getRect2D();
|
|
|
|
onScreenMessages[slot] = Creatable<RBX::Instance>::create<TextLabel>();
|
|
|
|
RBX::Frame* bottomRightControl = Instance::fastDynamicCast<RBX::Frame>(screenGui->findFirstChildByName2("BottomRightControl",true).get());
|
|
if(bottomRightControl)
|
|
onScreenMessages[slot]->setParent(bottomRightControl);
|
|
else
|
|
onScreenMessages[slot]->setParent(screenGui.get());
|
|
|
|
if (RBX::TextLabel *textLabel = Instance::fastDynamicCast<RBX::TextLabel>(onScreenMessages[slot].get()))
|
|
{
|
|
textLabel->setFontSize(ON_SCREEN_MESSAGE_FONT_SIZE);
|
|
textLabel->setTextColor3(Color3::white());
|
|
textLabel->setText(message);
|
|
|
|
if(bottomRightControl)
|
|
{
|
|
onScreenMessages[slot]->setParent(bottomRightControl);
|
|
textLabel->setSize(RBX::UDim2(0,textLabel->getTextBounds().x,1,0));
|
|
textLabel->setPosition(RBX::UDim2(1, -textLabel->getTextBounds().x, -1.05 + (-slot - 0.5), 0));
|
|
}
|
|
else
|
|
{
|
|
onScreenMessages[slot]->setParent(screenGui.get());
|
|
textLabel->setSize(RBX::UDim2(0,300,0,30));
|
|
textLabel->setPosition(RBX::UDim2(1, (int)rect.x1() - ON_SCREEN_MESSAGE_DISTANCE_TO_RIGHT,
|
|
0, (int)rect.y1() - ON_SCREEN_MESSAGE_DISTANCE_TO_BOTTOM - ON_SCREEN_MESSAGE_DISTANCE_BETWEEN_SLOTS * slot));
|
|
}
|
|
|
|
textLabel->setBackgroundColor3(Color3::black());
|
|
textLabel->setBackgroundTransparency(0.5f);
|
|
textLabel->setBorderSizePixel(0);
|
|
}
|
|
|
|
if (duration != 0)
|
|
{
|
|
RBX::Security::Impersonator impersonate(RBX::Security::LocalGUI_);
|
|
RBX::DebrisService *ds = RBX::ServiceProvider::find<RBX::DebrisService>(this);
|
|
ds->addItem(onScreenMessages[slot], duration);
|
|
}
|
|
}
|
|
|
|
void CoreGuiService::clearOnScreenMessage(int slot)
|
|
{
|
|
if (slot >= MAX_ON_SCREEN_MESSAGES)
|
|
return;
|
|
|
|
if(shared_ptr<Instance> instance = onScreenMessages[slot]){
|
|
RBX::Security::Impersonator impersonate(RBX::Security::LocalGUI_);
|
|
RBX::DebrisService *ds = RBX::ServiceProvider::find<RBX::DebrisService>(this);
|
|
ds->addItem(instance, 0);
|
|
}
|
|
}
|
|
|
|
void CoreGuiService::setSelectionImageObject(GuiObject* value)
|
|
{
|
|
if (value != selectionImageObject.get())
|
|
{
|
|
selectionImageObject = shared_from(value);
|
|
raisePropertyChanged(prop_CoreSelectionImageObject);
|
|
}
|
|
}
|
|
|
|
} // Namespace
|