/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */ #include "stdafx.h" #include "V8DataModel/Commands.h" #include "V8DataModel/Workspace.h" #include "V8DataModel/PartInstance.h" #include "V8DataModel/Camera.h" #include "V8DataModel/Backpack.h" #include "V8DataModel/Feature.h" #include "V8DataModel/changehistory.h" #include "V8DataModel/MegaCluster.h" #include "V8DataModel/ToolsModel.h" #include "Humanoid/Humanoid.h" #include "Network/Players.h" #include "Tool/MegaDragger.h" #include "V8World/World.h" #include "V8Xml/Serializer.h" #include "V8Xml/SerializerBinary.h" #include "Util/SoundService.h" #include "Util/profiling.h" #include "V8World/ContactManager.h" #include "V8DataModel/CSGDictionaryService.h" #include "Script/LuaSourceContainer.h" FASTFLAG(DebugDisplayFPS) FASTFLAG(UserAllCamerasInLua) namespace RBX { BoolPropertyVerb::BoolPropertyVerb( const std::string& name, DataModel* dataModel, const char* propertyName ) : EditSelectionVerb(name, dataModel), propertyName(Name::declare(propertyName)) {} static bool HasTrueProperty(const char* propertyName, shared_ptr instance) { if (Reflection::PropertyDescriptor* desc = instance->findPropertyDescriptor(propertyName)) { Reflection::Property prop(*desc, instance.get()); if (prop.isValueType()) if (prop.getValue()) return true; } return false; } bool BoolPropertyVerb::isChecked() const { return std::find_if( selection->begin(), selection->end(), boost::bind(&HasTrueProperty, propertyName.c_str(), _1) )!=selection->end(); } class BoolPropertyVerbSetIt { const Name& propertyName; bool newState; public: BoolPropertyVerbSetIt(const Name& propertyName, bool newState) : propertyName(propertyName) , newState(newState) {} void operator()(shared_ptr instance) { if (Reflection::PropertyDescriptor* desc = instance->findPropertyDescriptor(propertyName.c_str())) { Reflection::Property prop(*desc, instance.get()); if (prop.isValueType() && prop.getValue()!=newState) { prop.setValue(newState); } } } }; void BoolPropertyVerb::doIt(IDataState* dataState) { // TODO: refactor using boost::bind BoolPropertyVerbSetIt setIt(propertyName, !isChecked()); std::for_each(selection->begin(), selection->end(), setIt); { DataModel::LegacyLock lock(dataModel, DataModelJob::Write); ChangeHistoryService::requestWaypoint(propertyName.c_str(), dataModel); } dataState->setDirty(true); } CameraCenterCommand::CameraCenterCommand(Workspace* workspace) : CameraVerb("CameraCenter", workspace) { // Force creation here, so that we don't create a service in isEnabled ServiceProvider::create< FilteredSelection >(workspace); } // TODO:: consolidate this with other camera enabled stuff bool CameraCenterCommand::isEnabled() const { if (ServiceClient< FilteredSelection >(workspace)->size() >= 1) { const Camera* worldCamera = workspace->getConstCamera(); RBXASSERT(worldCamera); if (worldCamera) { if (worldCamera->getCameraType() == Camera::FIXED_CAMERA) { return true; } } } return false; } void CameraCenterCommand::doIt(IDataState* dataState) { FASTLOG(FLog::Verbs, "Gui:CameraCenter"); RBXASSERT(isEnabled()); Vector3 center; ServiceClient< FilteredSelection > sel(workspace); bool hasFocalObject = sel->size() >= 1; if (hasFocalObject) { const std::vector& items(sel->items()); Extents extents = items[0]->computeExtentsWorld(); for (size_t i = 1; i < items.size(); ++i) { extents.unionWith(items[i]->computeExtentsWorld()); } center = extents.center(); } else { center = Vector3::zero(); } workspace->getCamera()->setCameraType(Camera::FIXED_CAMERA); workspace->getCamera()->setCameraFocusAndMaintainFocus(center, hasFocalObject); CameraVerb::doIt(dataState); // TODO: Undo/Redo dataState->setDirty(true); } void SelectAllCommand::doIt(IDataState* dataState) { FASTLOG(FLog::Verbs, "Gui:SelectAll"); dataModel->getWorkspace()->selectAllTopLevelRenderable(); } void AllCanSelectCommand::doIt(IDataState* dataState) { Workspace* workspace = dataModel->getWorkspace(); PartInstance::setLocked(workspace, false); // complete traversal // TODO: Undo/Redo { DataModel::LegacyLock lock(dataModel, DataModelJob::Write); ChangeHistoryService::requestWaypoint(getName().c_str(), workspace); } dataState->setDirty(true); } static void SetCanNotSelect(shared_ptr pv) { PartInstance::setLocked(pv.get(), true); } void CanNotSelectCommand::doIt(IDataState* dataState) { FilteredSelection* sel = ServiceProvider::create< FilteredSelection >(dataModel); std::for_each(selection->begin(), selection->end(), SetCanNotSelect); sel->clearSelection(); // TODO: Undo/Redo { DataModel::LegacyLock lock(dataModel, DataModelJob::Write); ChangeHistoryService::requestWaypoint(getName().c_str(), workspace.get()); } dataState->setDirty(true); } std::string ChatMenuCommand::getChatString(int menu1, int menu2, int menu3) { return "Chat_" + StringConverter::convertToString(menu1) + "_" + StringConverter::convertToString(menu2) + "_" + StringConverter::convertToString(menu3); } ///////////////////////////////////////////////////// ///////////////////////////////////////////////////// FirstPersonCommand::FirstPersonCommand(DataModel* dataModel) : Verb(dataModel, "FirstPersonIndicator") , dataModel(dataModel) { } bool FirstPersonCommand::isEnabled() const { if (Humanoid* h = Humanoid::getLocalHumanoidFromContext(dataModel)) { return h->isFirstPerson(); } else { return false; } } ToggleViewMode::ToggleViewMode(RBX::DataModel* dm) : Verb(dm, "ToggleViewMode") , dataModel(dm) { } bool ToggleViewMode::isChecked() const { return false; } bool ToggleViewMode::isEnabled() const { return dataModel->getNumPlayers() > 0; } bool ToggleViewMode::isSelected() const { return false; } void ToggleViewMode::doIt(RBX::IDataState* dataState) { FASTLOG(FLog::Verbs, "Gui:ToggleViewMode"); } ///////////////////////////////////////////////////// ///////////////////////////////////////////////////// StatsCommand::StatsCommand(DataModel* dataModel) : Verb(dataModel, "Stats"), dataModel(dataModel) {} void StatsCommand::doIt(IDataState* dataState) { dataModel->getGuiBuilder().toggleGeneralStats(); } bool StatsCommand::isEnabled() const { GuiRoot* guiRoot = dataModel->getGuiRoot(); return Instance::fastDynamicCast(guiRoot->findFirstChildByName("StatsHud1"))!=NULL; } bool StatsCommand::isChecked() const { GuiRoot* guiRoot = dataModel->getGuiRoot(); const TopMenuBar* statsMenu = Instance::fastDynamicCast(guiRoot->findFirstChildByName("StatsHud1")); return statsMenu!=NULL && statsMenu->isVisible(); } RenderStatsCommand::RenderStatsCommand(DataModel* dataModel) : Verb(dataModel, "RenderStats"), dataModel(dataModel) {} void RenderStatsCommand::doIt(IDataState* dataState) { dataModel->getGuiBuilder().toggleRenderStats(); } bool RenderStatsCommand::isEnabled() const { GuiRoot* guiRoot = dataModel->getGuiRoot(); return Instance::fastDynamicCast(guiRoot->findFirstChildByName("StatsHud1"))!=NULL; } bool RenderStatsCommand::isChecked() const { GuiRoot* guiRoot = dataModel->getGuiRoot(); const TopMenuBar* statsMenu = Instance::fastDynamicCast(guiRoot->findFirstChildByName("RenderStats")); return statsMenu!=NULL && statsMenu->isVisible(); } SummaryStatsCommand::SummaryStatsCommand(DataModel* dataModel) : Verb(dataModel, "SummaryStats"), dataModel(dataModel) {} void SummaryStatsCommand::doIt(IDataState* dataState) { dataModel->getGuiBuilder().toggleSummaryStats(); } bool SummaryStatsCommand::isEnabled() const { GuiRoot* guiRoot = dataModel->getGuiRoot(); return Instance::fastDynamicCast(guiRoot->findFirstChildByName("SummaryStats"))!=NULL; } bool SummaryStatsCommand::isChecked() const { GuiRoot* guiRoot = dataModel->getGuiRoot(); const TopMenuBar* statsMenu = Instance::fastDynamicCast(guiRoot->findFirstChildByName("SummaryStats")); return statsMenu!=NULL && statsMenu->isVisible(); } CustomStatsCommand::CustomStatsCommand(DataModel* dataModel) : Verb(dataModel, "CustomStats"), dataModel(dataModel) {} void CustomStatsCommand::doIt(IDataState* dataState) { dataModel->getGuiBuilder().toggleCustomStats(); } bool CustomStatsCommand::isEnabled() const { GuiRoot* guiRoot = dataModel->getGuiRoot(); return Instance::fastDynamicCast(guiRoot->findFirstChildByName("CustomStats"))!=NULL; } bool CustomStatsCommand::isChecked() const { GuiRoot* guiRoot = dataModel->getGuiRoot(); const TopMenuBar* statsMenu = Instance::fastDynamicCast(guiRoot->findFirstChildByName("CustomStats")); return statsMenu!=NULL && statsMenu->isVisible(); } NetworkStatsCommand::NetworkStatsCommand(DataModel* dataModel) : Verb(dataModel, "NetworkStats"), dataModel(dataModel) { } void NetworkStatsCommand::doIt(IDataState* dataState) { dataModel->getGuiBuilder().toggleNetworkStats(); } bool NetworkStatsCommand::isEnabled() const { GuiRoot* guiRoot = dataModel->getGuiRoot(); return Instance::fastDynamicCast(guiRoot->findFirstChildByName("NetworkStats"))!=NULL; } bool NetworkStatsCommand::isChecked() const { GuiRoot* guiRoot = dataModel->getGuiRoot(); const TopMenuBar* statsMenu = Instance::fastDynamicCast(guiRoot->findFirstChildByName("NetworkStats")); return statsMenu!=NULL && statsMenu->isVisible(); } //////////////////////////////////////////////////////////////////////////// PhysicsStatsCommand::PhysicsStatsCommand(DataModel* dataModel) : Verb(dataModel, "PhysicsStats"), dataModel(dataModel) {} void PhysicsStatsCommand::doIt(IDataState* dataState) { dataModel->getGuiBuilder().togglePhysicsStats(); } bool PhysicsStatsCommand::isEnabled() const { GuiRoot* guiRoot = dataModel->getGuiRoot(); return Instance::fastDynamicCast(guiRoot->findFirstChildByName("PhysicsStats")) != NULL || Instance::fastDynamicCast(guiRoot->findFirstChildByName("PhysicsStats2")) != NULL; } bool PhysicsStatsCommand::isChecked() const { GuiRoot* guiRoot = dataModel->getGuiRoot(); const TopMenuBar* statsMenu = Instance::fastDynamicCast(guiRoot->findFirstChildByName("PhysicsStats")); if ( statsMenu != NULL && statsMenu->isVisible() ) return true; statsMenu = Instance::fastDynamicCast(guiRoot->findFirstChildByName("PhysicsStats2")); if ( statsMenu != NULL && statsMenu->isVisible() ) return true; return false; } //////////////////////////////////////////////////////////////////////////// EngineStatsCommand::EngineStatsCommand(DataModel* dataModel) : Verb(dataModel, "EngineStats") , dataModel(dataModel) {} void EngineStatsCommand::doIt(IDataState* dataState) { FASTLOG(FLog::Verbs, "Gui:EngineStats"); // dataModel->getWorkspace()->getWorld()->getContactManager().getSpatialHash().doStats(); dataModel->getWorkspace()->getWorld()->getContactManager()->doStats(); } //////////////////////////////////////////////////////////////////////////// JoinCommand::JoinCommand(DataModel* dataModel) : Verb(dataModel, "JoinCommand") , dataModel(dataModel) {} bool JoinCommand::isEnabled() const { Selection* sel = ServiceProvider::find< Selection >(dataModel); if (sel && sel->size() == 2) { shared_ptr i0 = sel->front(); shared_ptr i1 = sel->back(); if (MotorFeature::canJoin(i0.get(), i1.get())) { return true; } } return false; } void JoinCommand::doIt(IDataState* dataState) { FASTLOG(FLog::Verbs, "Gui:JoinCommand"); Selection* sel = ServiceProvider::create< Selection >(dataModel); if (sel->size() == 2) { shared_ptr i0 = sel->front(); shared_ptr i1 = sel->back(); MotorFeature::join(i0.get(), i1.get()); } } //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// RunStateVerb::RunStateVerb(std::string name, DataModel* dataModel, bool blacklisted) : Verb(dataModel, name, blacklisted), dataModel(dataModel), runService(dataModel) { } RunStateVerb::~RunStateVerb() { } void RunStateVerb::playActionSound() { } bool RunCommand::isEnabled() const { RunState runState = runService->getRunState(); bool clientIsPresent = RBX::Network::Players::clientIsPresent(dataModel); return (!clientIsPresent && (runState != RS_RUNNING)); } void RunCommand::doIt(IDataState* dataState) { FASTLOG(FLog::Verbs, "Gui:Run"); RBXASSERT(isEnabled()); runService->run(); } bool StopCommand::isEnabled() const { RunState runState = runService->getRunState(); return (runState == RS_RUNNING); } void StopCommand::doIt(IDataState* dataState) { FASTLOG(FLog::Verbs, "Gui:Stop"); RBXASSERT(isEnabled()); runService->pause(); } bool ResetCommand::isEnabled() const { RunState runState = runService->getRunState(); return ( (runState == RS_RUNNING || runState == RS_PAUSED) && !RBX::Network::Players::findLocalPlayer(dataModel) ); } void ResetCommand::doIt(IDataState* dataState) { FASTLOG(FLog::Verbs, "Gui:Reset"); RBXASSERT(isEnabled()); runService->stop(); } /////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////// EditSelectionVerb::EditSelectionVerb(std::string name, DataModel* dataModel) :Verb(dataModel, name) ,dataModel(dataModel) ,workspace(shared_from(dataModel->getWorkspace())) ,selection(dataModel) { } EditSelectionVerb::EditSelectionVerb(VerbContainer* container, std::string name, DataModel* dataModel) :Verb(container, name) ,dataModel(dataModel) ,workspace(shared_from(ServiceProvider::find(dataModel))) ,selection(dataModel) { RBXASSERT(workspace!=NULL); } EditSelectionVerb::~EditSelectionVerb() { } bool EditSelectionVerb::isEnabled() const { return selection->size()>0; } //////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////// template static void SurfaceSwap(shared_ptr instance) { if (PartInstance* part = Instance::fastDynamicCast(instance.get())) { for (int i = 0; i < 6; ++i) { if (part->getSurfaceType(NormalId(i)) == from) { part->setSurfaceType(NormalId(i), to); } } } if (instance->getChildren()) std::for_each( instance->getChildren()->begin(), instance->getChildren()->end(), boost::bind(&SurfaceSwap, _1) ); } SnapSelectionVerb::SnapSelectionVerb(DataModel* dataModel) : EditSelectionVerb("SnapSelection", dataModel) {;} bool SnapSelectionVerb::isEnabled() const { if (!Super::isEnabled()) return false; Selection* sel = ServiceProvider::find< Selection >(dataModel); return (sel && sel->size() > 0); } void SnapSelectionVerb::doIt(IDataState* dataState) { FASTLOG(FLog::Verbs, "Gui:SnapSelection"); ServiceProvider::create< Selection >(dataModel); std::for_each(selection->begin(), selection->end(), boost::bind(&SurfaceSwap, _1)); // TODO: Undo/Redo... { DataModel::LegacyLock lock(dataModel, DataModelJob::Write); ChangeHistoryService::requestWaypoint(getName().c_str(), workspace.get()); } dataState->setDirty(true); } void UnlockAllVerb::doIt(IDataState* dataState) { Workspace* workspace = dataModel->getWorkspace(); PartInstance::setLocked(workspace, false); // complete traversal // TODO: Undo/Redo { DataModel::LegacyLock lock(dataModel, DataModelJob::Write); ChangeHistoryService::requestWaypoint(getName().c_str(), workspace); } dataState->setDirty(true); } /////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////// SelectChildrenVerb::SelectChildrenVerb(DataModel* dataModel) : EditSelectionVerb("SelectChildrenOfSelection", dataModel) { ServiceProvider::create >(dataModel); } bool hasChildren(Instance* wInstance) { return (wInstance->numChildren() > 0); } bool SelectChildrenVerb::isEnabled() const { if(!Super::isEnabled()) return false; FilteredSelection* selection = ServiceProvider::find >(dataModel); return selection && selection->find_if(hasChildren)!=NULL; } void SelectChildrenVerb::doIt(IDataState *dataState) { FASTLOG(FLog::Verbs, "Gui:SelectChildrenOfSelection"); Selection* selection = ServiceProvider::find(dataModel); shared_ptr childItems(new Instances); if (shared_ptr parentItems = selection->getSelection2()) for (std::vector >::const_iterator parentIterator = parentItems->begin(); parentIterator != parentItems->end(); ++parentIterator) if (shared_ptr children = (*parentIterator)->getChildren2()) for (Instances::const_iterator childIterator = children->begin(); childIterator != children->end(); ++childIterator) childItems->push_back(*childIterator); if(childItems->size() > 0) selection->setSelection(childItems); else debugAssertM(0, "Calling SelectChildrenOfSelection command without checking is-enabled"); } /////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////// void AddChildToRoot(XmlElement* root, shared_ptr wsi, const boost::function& isInScope, RBX::CreatorRole creatorRole) { if (XmlElement* child = wsi->writeXml(isInScope, creatorRole)) root->addChild(child); } static bool isInScope(shared_ptr selectedItem, Instance* child) { if (selectedItem.get() == child) return true; return selectedItem->isAncestorOf(child); } static bool isContainedInSelection(Selection* sel, Instance* instance) { return std::find_if( sel->begin(), sel->end(), boost::bind(isInScope, _1, instance)) != sel->end(); } void AddSelectionToRoot(XmlElement* root, Selection* selection, RBX::CreatorRole creatorRole) { boost::function scopeFunction = boost::bind(isContainedInSelection, selection, _1); std::for_each(selection->begin(), selection->end(), boost::bind(&AddChildToRoot, root, _1, scopeFunction, creatorRole)); } DeleteBase::DeleteBase(VerbContainer* verbContainer, DataModel* dataModel, std::string name) : EditSelectionVerb(verbContainer, name, dataModel) , rewardHopper(false) {} DeleteBase::DeleteBase(DataModel* dataModel, std::string name, bool rewardHopper) : EditSelectionVerb(name, dataModel) , rewardHopper(rewardHopper) {} static void checkForLockedScript(const shared_ptr& descendant) { if (const shared_ptr lsc = Instance::fastSharedDynamicCast(descendant)) { if (Instance* editor = lsc->getCurrentEditor()) { throw std::runtime_error(format("Cannot perform operation: %s is currently being edited by %s", lsc->getFullName().c_str(), editor->getName().c_str())); } } } void DeleteBase::doIt(IDataState* dataState) { FASTLOG(FLog::Verbs, "Gui:DeleteBase"); Selection* sel = ServiceProvider::create< Selection >(dataModel); bool isCloudEdit = Network::Players::isCloudEdit(dataModel); if (sel->size() > 0) { shared_ptr selectionRead = sel->getSelection().read(); if (selectionRead) { // Check for locked scripts that would be deleted, and skip the delete if they are present if (isCloudEdit) { for (const auto& instance : *selectionRead) { checkForLockedScript(instance); instance->visitDescendants(boost::bind(&checkForLockedScript, _1)); } } sel->setSelection(shared_ptr()); for (Instances::const_iterator it = selectionRead->begin(); it != selectionRead->end(); ++it) { shared_ptr instance = *it; Instance* iPtr = instance.get(); if (iPtr) { if (!iPtr->fastDynamicCast() && !iPtr->fastDynamicCast() && !dynamic_cast(iPtr) && (!isCloudEdit || !iPtr->fastDynamicCast())) { instance->setParent(NULL); //if camera is getting deleted then create new camera here itself (instead of Workspace::onHeartbeat) to correctly record change history if (iPtr->fastDynamicCast()) dataModel->getWorkspace()->replenishCamera(); } } } } { DataModel::LegacyLock lock(dataModel, DataModelJob::Write); ChangeHistoryService::requestWaypoint(getName().c_str(), workspace.get()); } dataState->setDirty(true); } } // TODO: validate that group, followed by ungroup is completely consistent..... void RotateAxisCommand::rotateAboutAxis(const G3D::Matrix3& rotMatrix, const std::vector& selectedInstances) { if (selectedInstances.empty()) { debugAssertM(0, "Command should be disabled here"); return; } else { MegaDragger megaDragger(NULL, selectedInstances, workspace.get()); megaDragger.startDragging(); megaDragger.safeRotate(rotMatrix); megaDragger.finishDragging(); } } RotateSelectionVerb::RotateSelectionVerb(DataModel* dataModel) : RotateAxisCommand("SelectionRotate", dataModel) {;} void RotateAxisCommand::doIt(IDataState* dataState) { FASTLOG(FLog::Verbs, "Gui:RotateAxis"); FilteredSelection* sel = ServiceProvider::create< FilteredSelection >(dataModel); rotateAboutAxis(getRotationAxis(), sel->items()); { DataModel::LegacyLock lock(dataModel, DataModelJob::Write); ChangeHistoryService::requestWaypoint(getName().c_str(), dataModel); } dataState->setDirty(true); } G3D::Matrix3 RotateSelectionVerb::getRotationAxis() { return Math::matrixRotateY(); } TiltSelectionVerb::TiltSelectionVerb(DataModel* dataModel) : RotateAxisCommand("SelectionTilt", dataModel) {;} G3D::Matrix3 TiltSelectionVerb::getRotationAxis() { int currentQuadrant = Math::toYAxisQuadrant(workspace->getConstCamera()->coordinateFrame()); return Math::matrixTiltQuadrant(currentQuadrant); } ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// void MoveUpSelectionVerb::doIt(IDataState* dataState) { FASTLOG(FLog::Verbs, "Gui:MoveUpSelection"); FilteredSelection* sel = ServiceProvider::create< FilteredSelection >(dataModel); if (sel->size()>0) { MegaDragger megaDragger(NULL, sel->items(), workspace.get()); megaDragger.startDragging(); megaDragger.safeMoveNoDrop(Vector3(0.0f, moveUpHeight, 0.0f)); megaDragger.finishDragging(); { DataModel::LegacyLock lock(dataModel, DataModelJob::Write); ChangeHistoryService::requestWaypoint(getName().c_str(), workspace.get()); } dataState->setDirty(true); } } MoveDownSelectionVerb::MoveDownSelectionVerb(DataModel* dataModel) : EditSelectionVerb("SelectionDown", dataModel) {;} void MoveDownSelectionVerb::doIt(IDataState* dataState) { FASTLOG(FLog::Verbs, "Gui:MoveDownSelection"); FilteredSelection* sel = ServiceProvider::create< FilteredSelection >(dataModel); if (sel->size()>0) { MegaDragger megaDragger(NULL, sel->items(), workspace.get()); megaDragger.startDragging(); megaDragger.safeMoveNoDrop(Vector3(0.0f, -1.2f, 0.0f)); megaDragger.finishDragging(); { DataModel::LegacyLock lock(dataModel, DataModelJob::Write); ChangeHistoryService::requestWaypoint(getName().c_str(), workspace.get()); } dataState->setDirty(true); } } bool CharacterCommand::isEnabled() const { return false; } ///////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////// // CAMERA CameraVerb::CameraVerb(std::string name, Workspace* _workspace) : Verb(_workspace, name) , workspace(_workspace) , selection(_workspace) {} Camera* CameraVerb::getCamera() { return workspace->getCamera(); } const Camera* CameraVerb::getCamera() const { return workspace->getConstCamera(); } void CameraVerb::doIt(IDataState* dataState) { RBXASSERT(dataState!=NULL); dataState->setDirty(true); } bool CameraPanLeftCommand::isEnabled() const {return true;} void CameraPanLeftCommand::doIt(IDataState* dataState) {FASTLOG(FLog::Verbs, "Gui:CameraPanLeft"); getCamera()->panUnits(-1); CameraVerb::doIt(dataState);} bool CameraPanRightCommand::isEnabled() const {return true;} void CameraPanRightCommand::doIt(IDataState* dataState) {FASTLOG(FLog::Verbs, "Gui:CameraPanRight"); getCamera()->panUnits(1); CameraVerb::doIt(dataState);} bool CameraTiltUpCommand::isEnabled() const {return getCamera()->canTilt(-1);} void CameraTiltUpCommand::doIt(IDataState* dataState) {FASTLOG(FLog::Verbs, "Gui:CameraTiltUp"); if (getCamera()->tiltUnits(-1)) CameraVerb::doIt(dataState);} bool CameraTiltDownCommand::isEnabled() const {return getCamera()->canTilt(1);} void CameraTiltDownCommand::doIt(IDataState* dataState) {FASTLOG(FLog::Verbs, "Gui:CameraTildDown"); if (getCamera()->tiltUnits(1)) CameraVerb::doIt(dataState);} bool CameraZoomInCommand::isEnabled() const {return getCamera()->canZoom(true);} void CameraZoomInCommand::doIt(IDataState* dataState) { FASTLOG(FLog::Verbs, "Gui:CameraZoomIn"); if (getCamera()->zoom(1)) CameraVerb::doIt(dataState); } bool CameraZoomOutCommand::isEnabled() const {return getCamera()->canZoom(false);} void CameraZoomOutCommand::doIt(IDataState* dataState) { FASTLOG(FLog::Verbs, "Gui:CameraZoomOut"); if (getCamera()->zoom(-1)) CameraVerb::doIt(dataState); } CameraZoomExtentsCommand::CameraZoomExtentsCommand(Workspace* workspace) : CameraVerb("CameraZoomExtents", workspace) { // Force creation here, so that we don't create a service in isEnabled ServiceProvider::create< FilteredSelection >(workspace); } // TODO:: consolidate this with other camera enabled stuff bool CameraZoomExtentsCommand::isEnabled() const { if (ServiceClient< FilteredSelection >(workspace)->size() >= 1) { const Camera* worldCamera = workspace->getConstCamera(); RBXASSERT(worldCamera); if (!worldCamera) return false; if (FFlag::UserAllCamerasInLua && worldCamera->hasClientPlayer()) { return false; } RBX::Network::Players* players = ServiceProvider::create(worldCamera); // If there is a local player not in fixed camera mode, dont allow zoom extents // Otherwise, do if (players && !(players->getLocalPlayer() && worldCamera->getCameraType() != Camera::FIXED_CAMERA)) return true; } return false; } void CameraZoomExtentsCommand::doIt(IDataState* dataState ) { FASTLOG(FLog::Verbs, "Gui:CameraZoomExtents"); RBXASSERT(isEnabled()); ServiceClient< FilteredSelection > sel(workspace); Extents extents(Vector3(0,0,0), Vector3(0,0,0)); if (sel->size() >= 1) { const std::vector& items(sel->items()); if(MegaClusterInstance* terrain = Instance::fastDynamicCast(items[0])) { if(terrain->getNonEmptyCellCount() > 0) extents = items[0]->computeExtentsWorld(); } else extents = items[0]->computeExtentsWorld(); for (size_t i = 1; i < items.size(); ++i) { if(MegaClusterInstance* terrain = Instance::fastDynamicCast(items[i])) { if(terrain->getNonEmptyCellCount() > 0) extents.unionWith(items[i]->computeExtentsWorld()); } else extents.unionWith(items[i]->computeExtentsWorld()); } } else { // no selection, use old behavior getCamera()->zoomExtents(); CameraVerb::doIt(dataState); return; } if(extents != Extents(Vector3(0,0,0), Vector3(0,0,0))) { workspace->getCamera()->setCameraType(Camera::FIXED_CAMERA); workspace->getCamera()->zoomExtents(extents, Camera::ZOOM_IN_OR_OUT); CameraVerb::doIt(dataState); ChangeHistoryService::requestWaypoint(getName().c_str(), workspace); dataState->setDirty(true); } } // Video recording code moved to GUI TurnOnManualJointCreation::TurnOnManualJointCreation(DataModel* dataModel) : Verb(dataModel, "TurnOnManualJointCreation") , dataModel(dataModel) { } void TurnOnManualJointCreation::doIt(IDataState* dataState) { if(AdvArrowTool::advManualJointMode) { FASTLOG(FLog::Verbs, "Gui:TurnOffManualJointCreation"); AdvArrowTool::advManualJointMode = false; } else { FASTLOG(FLog::Verbs, "Gui:TurnOnManualJointCreation"); AdvArrowTool::advManualJointMode = true; } AdvArrowTool::advCreateJointsMode = true; } SetDragGridToOne::SetDragGridToOne(DataModel* dataModel) : Verb(dataModel, "SetDragGridToOne") , dataModel(dataModel) { } SetDragGridToOneFifth::SetDragGridToOneFifth(DataModel* dataModel) : Verb(dataModel, "SetDragGridToOneFifth") , dataModel(dataModel) { } SetDragGridToOff::SetDragGridToOff(DataModel* dataModel) : Verb(dataModel, "SetDragGridToOff") , dataModel(dataModel) { } SetGridSizeToTwo::SetGridSizeToTwo(DataModel* dataModel) : Verb(dataModel, "SetGridSizeToTwo") , workspace(dataModel->getWorkspace()) { } SetGridSizeToFour::SetGridSizeToFour(DataModel* dataModel) : Verb(dataModel, "SetGridSizeToFour") , workspace(dataModel->getWorkspace()) { } SetGridSizeToSixteen::SetGridSizeToSixteen(DataModel* dataModel) : Verb(dataModel, "SetGridSizeToSixteen") , workspace(dataModel->getWorkspace()) { } SetManualJointToWeak::SetManualJointToWeak(DataModel* dataModel) : Verb(dataModel, "SetManualJointToWeak") , dataModel(dataModel) { } SetManualJointToStrong::SetManualJointToStrong(DataModel* dataModel) : Verb(dataModel, "SetManualJointToStrong") , dataModel(dataModel) { } SetManualJointToInfinite::SetManualJointToInfinite(DataModel* dataModel) : Verb(dataModel, "SetManualJointToInfinite") , dataModel(dataModel) { } bool applyColor(Instance* instance, RBX::BrickColor color) { bool applied = false; if (PartInstance* pInstance = dynamic_cast(instance)) { pInstance->setColor(color); applied = true; } else if (ModelInstance* pModelInstance = dynamic_cast(instance)) { std::vector childParts = pModelInstance->getDescendantPartInstances(); for (std::vector::const_iterator iter = childParts.begin(); iter != childParts.end(); ++iter) { applied |= applyColor(*iter, color); } } return applied; } RBX::BrickColor ColorVerb::m_currentColor = RBX::BrickColor::brick_194; void ColorVerb::doIt( IDataState* dataState ) { bool applied = false; FilteredSelection* sel = ServiceProvider::create< FilteredSelection >(dataModel); for (std::vector::const_iterator iter = sel->begin(); iter != sel->end(); ++iter) applied |= applyColor(*iter, ColorVerb::getCurrentColor()); { DataModel::LegacyLock lock(dataModel, DataModelJob::Write); ChangeHistoryService::requestWaypoint(getName().c_str(), workspace.get()); } dataState->setDirty(true); } bool applyMaterial(Instance* instance, PartMaterial material) { bool applied = false; if (PartInstance* pInstance = dynamic_cast(instance)) { pInstance->setRenderMaterial(material); applied = true; } else if (ModelInstance* pModelInstance = dynamic_cast(instance)) { std::vector childParts = pModelInstance->getDescendantPartInstances(); for (std::vector::const_iterator iter = childParts.begin(); iter != childParts.end(); ++iter) { applied |= applyMaterial(*iter, material); } } return applied; } PartMaterial MaterialVerb::m_currentMaterial = PLASTIC_MATERIAL; void MaterialVerb::doIt( IDataState* dataState ) { bool applied = false; FilteredSelection* sel = ServiceProvider::create< FilteredSelection >(dataModel); for (std::vector::const_iterator iter = sel->begin(); iter != sel->end(); ++iter) applied |= applyMaterial(*iter, MaterialVerb::getCurrentMaterial()); { DataModel::LegacyLock lock(dataModel, DataModelJob::Write); ChangeHistoryService::requestWaypoint(getName().c_str(), workspace.get()); } dataState->setDirty(true); } PartMaterial MaterialVerb::parseMaterial(const std::string materialString) { if(materialString == "Plastic") { return RBX::PLASTIC_MATERIAL; } else if(materialString == "Slate") { return RBX::SLATE_MATERIAL; } else if(materialString == "Wood") { return RBX::WOOD_MATERIAL; } else if(materialString == "Concrete") { return RBX::CONCRETE_MATERIAL; } else if(materialString =="CorrodedMetal") { return RBX::RUST_MATERIAL; } else if(materialString == "DiamondPlate") { return RBX::DIAMONDPLATE_MATERIAL; } else if(materialString == "Foil") { return RBX::ALUMINUM_MATERIAL; } else if(materialString == "Grass") { return RBX::GRASS_MATERIAL; } else if(materialString =="Ice") { return RBX::ICE_MATERIAL; } else if(materialString == "Brick") { return RBX::BRICK_MATERIAL; } else if(materialString == "Sand") { return RBX::SAND_MATERIAL; } else if(materialString == "Fabric") { return RBX::FABRIC_MATERIAL; } else if(materialString == "Granite") { return RBX::GRANITE_MATERIAL; } else if(materialString == "Marble") { return RBX::MARBLE_MATERIAL; } else if(materialString == "Pebble") { return RBX::PEBBLE_MATERIAL; } else if(materialString == "SmoothPlastic") { return RBX::SMOOTH_PLASTIC_MATERIAL; } else if(materialString == "Neon") { return NEON_MATERIAL; } else if(materialString == "WoodPlanks") { return RBX::WOODPLANKS_MATERIAL; } else if(materialString == "Cobblestone") { return RBX::COBBLESTONE_MATERIAL; } else if(materialString == "Metal") { return RBX::METAL_MATERIAL; } else return RBX::PLASTIC_MATERIAL; } bool applyAnchor(Instance* instance, bool anchor) { bool applied = false; if (PartInstance* pInstance = dynamic_cast(instance)) { pInstance->setAnchored(anchor); applied = true; } else if (ModelInstance* pModelInstance = dynamic_cast(instance)) { std::vector childParts = pModelInstance->getDescendantPartInstances(); for (std::vector::const_iterator iter = childParts.begin(); iter != childParts.end(); ++iter) { applied |= applyAnchor(*iter, anchor); } } return applied; } void AnchorVerb::doIt( IDataState* dataState ) { if (m_selection->size() > 0) { bool setAnchored = !isChecked(), applied = false; for (std::vector::const_iterator iter = m_selection->begin(); iter != m_selection->end(); ++iter) applied |= applyAnchor(*iter, setAnchored); { DataModel::LegacyLock lock(dataModel, DataModelJob::Write); ChangeHistoryService::requestWaypoint(getName().c_str(), workspace.get()); } dataState->setDirty(true); } } bool AnchorVerb::isChecked() const { if (!dataModel) return false; bool hasUnanchoredInstance = false; for (std::vector::const_iterator iter = m_selection->begin(); iter != m_selection->end(); ++iter) { if (!RBX::AnchorTool::allChildrenAnchored(*iter)) { hasUnanchoredInstance = true; break; } } return !hasUnanchoredInstance; } AnchorVerb::AnchorVerb( DataModel* dataModel ) : EditSelectionVerb("AnchorVerb", dataModel) { // Put this here to avoid requiring edit lock on isChecked m_selection = ServiceProvider::create< FilteredSelection >(dataModel); } } // namespace