From 6e4b4d98da1adf1f3c8ddbd4f334dd20bcffe074 Mon Sep 17 00:00:00 2001 From: sorket <133731034+sorket@users.noreply.github.com> Date: Wed, 19 Jul 2023 02:23:27 -0400 Subject: [PATCH 1/4] I'm the fixer-upper :-) --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index ac204a1..fc79773 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ [![Star](https://img.shields.io/github/stars/lrre-foss/RNR?style=social)](https://github.com/lrre-foss/RNR/stargazers) [Discord](https://discord.gg/89WagAUr) -RNR (**R**NR's **N**ot **R**oblox) is a project that aims to recreate the look and feel of classic Roblox with new features while remaining fully compatible with clients from that era. It is built upon an engine that closely resembles Roblox's own at the time, referencing disassemblies of legacy client binaries. +RNR (**R**NR's **N**ot **R**oblox) is a project that aims to recreate the look and feel of classic Roblox with new features while remaining partially compatible with clients from that era. It is built upon an engine that closely resembles Roblox's own at the time, referencing disassemblies of legacy client binaries. Interested in contributing? [Feel free to make a pull request!](https://github.com/lrre-foss/RNR/pulls) @@ -13,7 +13,6 @@ There are several goals that RNR seeks to accomplish, them being; - Easy-to-use (simple CLI options to launch and host games, as well as a level editor with a modern UI) - Fully compatible with Roblox versions up to 0.3.744.0 (dated April 2008) in areas such as hosting, joining, levels, etc. - Incorporates all the various facets of the Roblox engine, plus a little bit extra (e.g. a network replication whitelist, fancy shader support, etc.) -- Made using clean-room reverse engineering - Uses Roblox's [Luau](https://luau-lang.org/) as its scripting language while remaining fully compatible with classic Roblox scripts written using Lua 5.1 - As free and open-source as possible (with client code licensed under the GPL and the engine itself being released into the public domain, void of any copyright) - Patching all the security vulnerabilities and fixing bugs/inefficiencies that legacy Roblox clients had From ad9376f7e04884251804c4ddd8139a63ec91d531 Mon Sep 17 00:00:00 2001 From: floralrainfall Date: Wed, 19 Jul 2023 07:23:26 -0400 Subject: [PATCH 2/4] readd instancing alongside static geometry --- Content/RNR/materials/partinstanced.material | 1 + Projects/Client/Common/Source/OgreWidget.cpp | 3 +- Projects/Client/Studio/Source/MainWindow.cpp | 20 +++- .../Client/Studio/Source/PropertyViewer.cpp | 13 +++ Projects/Engine/Header/App/BrickColor.hpp | 1 + Projects/Engine/Header/App/GUI/TopMenuBar.hpp | 13 ++- .../Header/App/Script/ReflectionProperty.hpp | 1 + .../Engine/Header/App/V8/DataModel/Light.hpp | 11 +++ .../Header/App/V8/DataModel/PartInstance.hpp | 2 + .../Header/App/V8/DataModel/Workspace.hpp | 16 +++- .../Engine/Header/App/V8/Tree/Instance.hpp | 6 ++ Projects/Engine/Header/App/V8/World/World.hpp | 1 + Projects/Engine/Source/App/BrickColor.cpp | 12 +++ Projects/Engine/Source/App/GUI/TopMenuBar.cpp | 41 ++++++-- .../Source/App/Script/ReflectionProperty.cpp | 3 + .../Engine/Source/App/V8/DataModel/Light.cpp | 41 +++++++- .../Source/App/V8/DataModel/PartInstance.cpp | 19 ++++ .../Source/App/V8/DataModel/Workspace.cpp | 94 ++++++++----------- .../Engine/Source/App/V8/Tree/Instance.cpp | 40 +++++++- Projects/Engine/Source/App/V8/World/World.cpp | 6 +- 20 files changed, 275 insertions(+), 69 deletions(-) diff --git a/Content/RNR/materials/partinstanced.material b/Content/RNR/materials/partinstanced.material index c74c162..7ec2dcb 100644 --- a/Content/RNR/materials/partinstanced.material +++ b/Content/RNR/materials/partinstanced.material @@ -16,6 +16,7 @@ material materials/partinstanced rtshader_system { + transform_stage instanced lighting_stage per_pixel } } diff --git a/Projects/Client/Common/Source/OgreWidget.cpp b/Projects/Client/Common/Source/OgreWidget.cpp index 680bf72..911fa75 100644 --- a/Projects/Client/Common/Source/OgreWidget.cpp +++ b/Projects/Client/Common/Source/OgreWidget.cpp @@ -59,9 +59,10 @@ namespace RNR ogreCamera = ogreSceneManager->createCamera("myCam"); ogreCamera->setNearClipDistance(0.1); // specific to this sample - ogreCamera->setFarClipDistance(5000.f); + ogreCamera->setFarClipDistance(1000.f); ogreCamera->setAutoAspectRatio(true); ogreCamera->setFOVy(Ogre::Degree(70.f)); + ogreCamera->setUseRenderingDistance(true); camNode->attachObject(ogreCamera); ogreViewport = ogreWindow->addViewport(ogreCamera); diff --git a/Projects/Client/Studio/Source/MainWindow.cpp b/Projects/Client/Studio/Source/MainWindow.cpp index 83aad9d..c92d1b0 100644 --- a/Projects/Client/Studio/Source/MainWindow.cpp +++ b/Projects/Client/Studio/Source/MainWindow.cpp @@ -1,7 +1,10 @@ #include #include #include +#include +#include #include +#include MainWindow::MainWindow() { @@ -130,7 +133,22 @@ void MainWindow::pause() void MainWindow::dbg_pointlight() { - + if(!ogreWidget->selectedInstance) + { + QMessageBox::about(this, "selectedInstance = NULL", "Please select an instance in the explorer"); + return; + } + + printf("MainWindow::dbg_pointlight: inserting Light\n"); + RNR::Light* dbg_light = new RNR::Light(); + dbg_light->setParent(ogreWidget->selectedInstance); + + double r = QInputDialog::getDouble(this, "Red", "Set red component [0.0-1.0]", 1.0, 0.0, 1.0, 2); + double g = QInputDialog::getDouble(this, "Blue", "Set blue component [0.0-1.0]", 1.0, 0.0, 1.0, 2); + double b = QInputDialog::getDouble(this, "Green", "Set green component [0.0-1.0]", 1.0, 0.0, 1.0, 2); + dbg_light->setColor(Ogre::Vector3(r,g,b)); + + updateTree(ogreWidget->world->getDatamodel()); } void MainWindow::closeEvent(QCloseEvent* event) diff --git a/Projects/Client/Studio/Source/PropertyViewer.cpp b/Projects/Client/Studio/Source/PropertyViewer.cpp index 2f09d6d..691da6a 100644 --- a/Projects/Client/Studio/Source/PropertyViewer.cpp +++ b/Projects/Client/Studio/Source/PropertyViewer.cpp @@ -3,6 +3,8 @@ #include #include +#include + PropertyViewer::PropertyViewer() : QWidget() { prop_table = new QTableWidget(); @@ -88,6 +90,17 @@ void PropertyViewer::view(RNR::Instance* instance) new_property_itemval->setData(Qt::DecorationRole, QPixmap::fromImage(image)); } break; + case RNR::PROPERTY_BRICKCOLOR: + { + int brickcolor = *(int*)property.rawGetter(); + Ogre::Vector3 color = RNR::BrickColor::color(brickcolor); + new_property_itemval->setBackground(QBrush(QColor( + (int)floorf(color.x * 255), + (int)floorf(color.y * 255), + (int)floorf(color.z * 255) + ))); + } + break; } prop_table->setItem(property_count, 0, new_property_item); diff --git a/Projects/Engine/Header/App/BrickColor.hpp b/Projects/Engine/Header/App/BrickColor.hpp index 2dfe81e..d7ae92b 100644 --- a/Projects/Engine/Header/App/BrickColor.hpp +++ b/Projects/Engine/Header/App/BrickColor.hpp @@ -18,6 +18,7 @@ namespace RNR BrickColor(int color_id, std::string name, Ogre::Vector3 color); static Ogre::Vector3 color(int brickcolor); static bool valid(int brickcolor); + static std::string name(int brickcolor); static Ogre::MaterialPtr material(int brickcolor); }; } \ No newline at end of file diff --git a/Projects/Engine/Header/App/GUI/TopMenuBar.hpp b/Projects/Engine/Header/App/GUI/TopMenuBar.hpp index 8f3f10c..98f6360 100644 --- a/Projects/Engine/Header/App/GUI/TopMenuBar.hpp +++ b/Projects/Engine/Header/App/GUI/TopMenuBar.hpp @@ -1,12 +1,23 @@ #pragma once #include +#include +#include +#include +#include +#include namespace RNR { + class World; + class TopMenuBar { + Ogre::TextAreaOverlayElement* m_debugText; + World* m_world; public: - TopMenuBar(); + TopMenuBar(World* world); + + void frame(); }; } \ No newline at end of file diff --git a/Projects/Engine/Header/App/Script/ReflectionProperty.hpp b/Projects/Engine/Header/App/Script/ReflectionProperty.hpp index 56d2231..1f5fbb9 100644 --- a/Projects/Engine/Header/App/Script/ReflectionProperty.hpp +++ b/Projects/Engine/Header/App/Script/ReflectionProperty.hpp @@ -41,6 +41,7 @@ namespace RNR PROPERTY_CFRAME, PROPERTY_INSTANCE, PROPERTY_FLOAT, + PROPERTY_BRICKCOLOR, }; class ReflectionProperty diff --git a/Projects/Engine/Header/App/V8/DataModel/Light.hpp b/Projects/Engine/Header/App/V8/DataModel/Light.hpp index f85bfb2..e4c591b 100644 --- a/Projects/Engine/Header/App/V8/DataModel/Light.hpp +++ b/Projects/Engine/Header/App/V8/DataModel/Light.hpp @@ -12,5 +12,16 @@ namespace RNR bool m_shadows; public: Light(); + + virtual void setupLight(Ogre::Light* light); + virtual void onSetParent(RNR::Instance* newParent); + virtual std::string getClassName() { return std::string("Light"); } + + void setColor(Ogre::Vector3 color) { m_color = color; setupLight((Ogre::Light*)getObject()); } + Ogre::Vector3 getColor() { return m_color; } + void setEnabled(bool enabled) { m_enabled = enabled; setupLight((Ogre::Light*)getObject()); } + bool getEnabled() { return m_enabled; } + void setShadows(bool shadows) { m_shadows = shadows; setupLight((Ogre::Light*)getObject()); } + bool getShadows() { return m_shadows; } }; } \ No newline at end of file diff --git a/Projects/Engine/Header/App/V8/DataModel/PartInstance.hpp b/Projects/Engine/Header/App/V8/DataModel/PartInstance.hpp index c88c466..9314c72 100644 --- a/Projects/Engine/Header/App/V8/DataModel/PartInstance.hpp +++ b/Projects/Engine/Header/App/V8/DataModel/PartInstance.hpp @@ -28,6 +28,8 @@ namespace RNR Ogre::Vector3 getSize() { return m_size; } Ogre::Vector4 getColor() { return m_color; } + Ogre::Vector3 getOgreCenter() { return m_position + (m_size / 2.f); } + void setBrickColor(int brickcolor) { m_brickColor = brickcolor; } int getBrickColor() { return m_brickColor; } }; diff --git a/Projects/Engine/Header/App/V8/DataModel/Workspace.hpp b/Projects/Engine/Header/App/V8/DataModel/Workspace.hpp index bc19c8d..792e7ab 100644 --- a/Projects/Engine/Header/App/V8/DataModel/Workspace.hpp +++ b/Projects/Engine/Header/App/V8/DataModel/Workspace.hpp @@ -11,26 +11,38 @@ namespace RNR { class Camera; + enum WorkspaceBatchingMode + { + BATCH_INSTANCED, + BATCH_STATIC_GEOMETRY, + }; + class Workspace : public ModelInstance { + friend class TopMenuBar; public: Workspace(); virtual std::string getClassName() { return "Workspace"; } - virtual void onChildAdded(RNR::Instance* childAdded); - virtual void onChildRemoved(RNR::Instance* childRemoved); + virtual void onDescendantAdded(RNR::Instance* childAdded); + virtual void onDescendantRemoved(RNR::Instance* childRemoved); void buildGeom(); Camera* getCurrentCamera() const; void setCurrentCamera(Camera *value); + void setDirty() { m_geomDirty = true; } private: + enum WorkspaceBatchingMode m_batchMode; + virtual void addProperties(std::vector& properties); virtual void deserializeProperty(char* prop_name, pugi::xml_node prop); + void buildGeomInstance(Instance* instance); bool m_geomDirty; Ogre::StaticGeometry* m_geom; + Ogre::InstanceManager* m_instanceManager; Ogre::SceneNode* m_worldspawn; Ogre::Entity* m_partEntity; diff --git a/Projects/Engine/Header/App/V8/Tree/Instance.hpp b/Projects/Engine/Header/App/V8/Tree/Instance.hpp index e1cb17f..23f10c6 100644 --- a/Projects/Engine/Header/App/V8/Tree/Instance.hpp +++ b/Projects/Engine/Header/App/V8/Tree/Instance.hpp @@ -30,6 +30,9 @@ namespace RNR RNR::Instance* m_parent; std::vector m_children; bool m_archivable; + + void descendantAddedChildren(Instance* p, Instance* c); + void descendantRemovedChildren(Instance* p, Instance* c); public: Instance(); @@ -69,6 +72,9 @@ namespace RNR int numChildren() { return this->m_children.size(); }; virtual void onChildAdded(RNR::Instance* childAdded); + virtual void onDescendantAdded(RNR::Instance* descendantAdded); // make sure this is called in any derived versions of this virtual void onChildRemoved(RNR::Instance* childRemoved); + virtual void onDescendantRemoved(RNR::Instance* descendantRemoved); // make sure this is called in any derived versions of this + virtual void onSetParent(RNR::Instance* newParent); }; } \ No newline at end of file diff --git a/Projects/Engine/Header/App/V8/World/World.hpp b/Projects/Engine/Header/App/V8/World/World.hpp index 4c2da01..7595e06 100644 --- a/Projects/Engine/Header/App/V8/World/World.hpp +++ b/Projects/Engine/Header/App/V8/World/World.hpp @@ -18,6 +18,7 @@ namespace RNR struct WorldUndeserialized { Instance* instance; + Instance* parent; pugi::xml_node node; }; diff --git a/Projects/Engine/Source/App/BrickColor.cpp b/Projects/Engine/Source/App/BrickColor.cpp index 870422a..b8b3b4f 100644 --- a/Projects/Engine/Source/App/BrickColor.cpp +++ b/Projects/Engine/Source/App/BrickColor.cpp @@ -151,4 +151,16 @@ namespace RNR } return false; } + + std::string BrickColor::name(int brickcolor) + { + for(int i = 0; i < sizeof(brickcolors) / sizeof(BrickColor); i++) + { + if(brickcolors[i].color_id == brickcolor) + { + return brickcolors[i].color_name; + } + } + return brickcolors[0].color_name; + } } \ No newline at end of file diff --git a/Projects/Engine/Source/App/GUI/TopMenuBar.cpp b/Projects/Engine/Source/App/GUI/TopMenuBar.cpp index daf8853..0a87dfc 100644 --- a/Projects/Engine/Source/App/GUI/TopMenuBar.cpp +++ b/Projects/Engine/Source/App/GUI/TopMenuBar.cpp @@ -1,14 +1,12 @@ #include -#include -#include -#include -#include -#include +#include namespace RNR { - TopMenuBar::TopMenuBar() + TopMenuBar::TopMenuBar(World* world) { + m_world = world; + Ogre::OverlayManager* overlayManager = Ogre::OverlayManager::getSingletonPtr(); Ogre::MaterialPtr material = Ogre::MaterialManager::getSingleton().create("Background", "General"); material->getTechnique(0)->getPass(0)->createTextureUnitState("placeholder.png"); @@ -33,12 +31,43 @@ namespace RNR textArea->setFontName("ComicSans"); textArea->setColour(Ogre::ColourValue(0.f,0.f,0.f)); + m_debugText = static_cast(overlayManager->createOverlayElement("TextArea", "DebugTextArea")); + m_debugText->setMetricsMode(Ogre::GMM_PIXELS); + m_debugText->setPosition(0, 300); + m_debugText->setDimensions(420, 500); + m_debugText->setCaption("Debug text!"); + m_debugText->setCharHeight(24); + m_debugText->setFontName("ComicSans"); + m_debugText->setColour(Ogre::ColourValue(0.5f,0.f,0.5f)); + + Ogre::Overlay* overlay = overlayManager->create("OverlayName"); overlay->add2D(panel); overlay->setZOrder(500); panel->addChild(textArea); + panel->addChild(m_debugText); + overlay->show(); } + + void TopMenuBar::frame() + { + Workspace* workspace = m_world->getWorkspace(); + + char debugtext[512]; + char render_debugtext[255]; + switch(workspace->m_batchMode) + { + case BATCH_INSTANCED: + snprintf(render_debugtext, 255, "using BATCH_INSTANCED"); + break; + case BATCH_STATIC_GEOMETRY: + snprintf(render_debugtext, 255, "using BATCH_STATIC_GEOMETRY\nGeom Regions: %i", workspace->m_geom->getRegions().size()); + break; + } + snprintf(debugtext, 512, "Render\nLast DT = %f\n%s\n",m_world->getLastDelta(),render_debugtext,m_world->getOgreSceneManager()); + m_debugText->setCaption(debugtext); + } } \ No newline at end of file diff --git a/Projects/Engine/Source/App/Script/ReflectionProperty.cpp b/Projects/Engine/Source/App/Script/ReflectionProperty.cpp index 77dfa92..6342ee6 100644 --- a/Projects/Engine/Source/App/Script/ReflectionProperty.cpp +++ b/Projects/Engine/Source/App/Script/ReflectionProperty.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include @@ -64,6 +65,8 @@ namespace RNR cframe_rotation.z, cframe_rotation.w); } + case PROPERTY_BRICKCOLOR: + return std::string(BrickColor::name(*(int*)m_getter(m_object))); default: return std::string("???"); } diff --git a/Projects/Engine/Source/App/V8/DataModel/Light.cpp b/Projects/Engine/Source/App/V8/DataModel/Light.cpp index 49133ca..9d51261 100644 --- a/Projects/Engine/Source/App/V8/DataModel/Light.cpp +++ b/Projects/Engine/Source/App/V8/DataModel/Light.cpp @@ -1,4 +1,6 @@ #include +#include +#include namespace RNR { @@ -7,6 +9,43 @@ namespace RNR m_brightness = 1.f; m_enabled = true; m_shadows = true; - m_color = Ogre::Vector3(1.f,1.f,1.f); + m_color = Ogre::Vector3(75.f/255.f,151.f/255.f,75.f/255.f); + + setNode(world->getOgreSceneManager()->getRootSceneNode()->createChildSceneNode()); + setObject(world->getOgreSceneManager()->createLight(Ogre::Light::LT_POINT)); + getNode()->attachObject(getObject()); + + Ogre::Light* light_object = (Ogre::Light*)getObject(); + } + + void Light::onSetParent(Instance* newParent) + { + Ogre::Light* light_object = (Ogre::Light*)getObject(); + + if(!newParent) + { + light_object->setVisible(false); + return; + } + + PartInstance* part = dynamic_cast(newParent); + if(!part) + { + light_object->setVisible(false); + return; + } + + getNode()->setPosition(part->getPosition()); + setupLight(light_object); + } + + void Light::setupLight(Ogre::Light* light) + { + light->setVisible(m_enabled); + light->setCastShadows(m_shadows); + light->setDiffuseColour(Ogre::ColourValue(m_color.x, m_color.y, m_color.z)); + //light->setAttenuation(100, 1.0, 0.045, 0.0075); + light->setRenderingDistance(500.f); + light->setShadowFarDistance(100); } } \ No newline at end of file diff --git a/Projects/Engine/Source/App/V8/DataModel/PartInstance.cpp b/Projects/Engine/Source/App/V8/DataModel/PartInstance.cpp index 8ef18f8..a971852 100644 --- a/Projects/Engine/Source/App/V8/DataModel/PartInstance.cpp +++ b/Projects/Engine/Source/App/V8/DataModel/PartInstance.cpp @@ -10,6 +10,10 @@ namespace RNR m_color = Ogre::Vector4(0.63, 0.64, 0.63, 1.0); + setNode(world->getOgreSceneManager()->getRootSceneNode()->createChildSceneNode()); + setObject(world->getOgreSceneManager()->createEntity("fonts/Cube.mesh")); + getNode()->attachObject(getObject()); + updateMatrix(); } @@ -17,6 +21,16 @@ namespace RNR { m_matrix = m_cframe.getMatrix(); m_position = m_cframe.getPosition(); + + getNode()->setOrientation(Ogre::Quaternion(m_cframe.getRotation())); + getNode()->setPosition(m_position); + getNode()->setScale(m_size); + + Ogre::Entity* entity = (Ogre::Entity*)getObject(); + for(auto& subentity : entity->getSubEntities()) + { + subentity->getMaterial()->setManualCullingMode(Ogre::ManualCullingMode::MANUAL_CULL_BACK); + } } void PartInstance::deserializeProperty(char* prop_name, pugi::xml_node node) @@ -35,6 +49,7 @@ namespace RNR } else PVInstance::deserializeProperty(prop_name, node); + updateMatrix(); } void PartInstance::addProperties(std::vector& properties) @@ -44,6 +59,10 @@ namespace RNR ACCESS_NONE, OPERATION_READWRITE, PROPERTY_VECTOR3, REFLECTION_GETTER(PartInstance* instance = (PartInstance*)object; return &instance->m_size; ), REFLECTION_SETTER(PartInstance* instance = (PartInstance*)object; instance->setSize(*(Ogre::Vector3*)value); ) }, + { this, std::string("BrickColor"), std::string(""), + ACCESS_NONE, OPERATION_READWRITE, PROPERTY_BRICKCOLOR, + REFLECTION_GETTER(PartInstance* instance = (PartInstance*)object; return &instance->m_brickColor; ), + REFLECTION_SETTER(PartInstance* instance = (PartInstance*)object; instance->setBrickColor(*(int*)value); ) }, }; PVInstance::addProperties(properties); diff --git a/Projects/Engine/Source/App/V8/DataModel/Workspace.cpp b/Projects/Engine/Source/App/V8/DataModel/Workspace.cpp index 8c76c52..ed31561 100644 --- a/Projects/Engine/Source/App/V8/DataModel/Workspace.cpp +++ b/Projects/Engine/Source/App/V8/DataModel/Workspace.cpp @@ -8,81 +8,67 @@ namespace RNR Workspace::Workspace() : ModelInstance() { setName("Workspace"); + m_batchMode = BATCH_STATIC_GEOMETRY; + m_worldspawn = world->getOgreSceneManager()->getRootSceneNode()->createChildSceneNode(); - m_geom = world->getOgreSceneManager()->createStaticGeometry("workspaceGeom"); - m_geom->setCastShadows(true); - m_partEntity = world->getOgreSceneManager()->createEntity("fonts/Cube.mesh"); - m_partEntity->setCastShadows(true); - - for(int i = 0; i < m_partEntity->getNumSubEntities(); i++) + + switch(m_batchMode) { - Ogre::SubEntity* surface = m_partEntity->getSubEntity(i); - Ogre::TextureUnitState* texture = surface->getMaterial()->getTechnique(0)->getPass(0)->createTextureUnitState("textures/stud_top.png"); - - surface->getMaterial()->setShininess(1.0); + case BATCH_INSTANCED: + m_instanceManager = world->getOgreSceneManager()->createInstanceManager("workspaceInstanceManager", "fonts/Cube.mesh", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::InstanceManager::InstancingTechnique::HWInstancingBasic, 255); + break; + case BATCH_STATIC_GEOMETRY: + m_geom = world->getOgreSceneManager()->createStaticGeometry("workspaceGeom"); + m_geom->setRegionDimensions(Ogre::Vector3(255,255,255)); + m_geom->setCastShadows(true); + break; } } - void Workspace::onChildAdded(Instance* childAdded) + void Workspace::onDescendantAdded(Instance* childAdded) { - m_geomDirty = true; + PartInstance* part = dynamic_cast(childAdded); + if(part) + { + Ogre::SceneNode* child_node = childAdded->getNode(); + switch(m_batchMode) + { + case BATCH_INSTANCED: + { + Ogre::InstancedEntity* replica = m_instanceManager->createInstancedEntity("materials/partinstanced"); + replica->setPosition(part->getPosition()); + replica->setOrientation(part->getCFrame().getRotation()); + replica->setScale(part->getSize()); + } + break; + case BATCH_STATIC_GEOMETRY: + m_geom->addEntity((Ogre::Entity*)childAdded->getObject(), + part->getPosition(), + part->getCFrame().getRotation(), + part->getSize()); + break; + } + child_node->setVisible(false); + m_geomDirty = true; + } } void Workspace::buildGeomInstance(Instance* instance) { - PartInstance* child_part = dynamic_cast(instance); - if(child_part) - { - Ogre::Vector3 part_size = child_part->getSize(); - for(int i = 0; i < m_partEntity->getNumSubEntities(); i++) - { - m_partEntity->setMaterial(BrickColor::material(child_part->getBrickColor())); - /* - Ogre::SubMesh* surface = m_partEntity->getMesh()->getSubMesh(i); - surface->setMaterial(); - Ogre::TextureUnitState* texture = surface->getMaterial()->getTechnique(0)->getPass(0)->getTextureUnitState(0); - - Ogre::Vector2 uvs; - std::string surf_name = std::string(surface->getMaterialName().c_str()); - if(surf_name == "TopMaterial") - uvs = Ogre::Vector2(part_size.x, part_size.z); - else if(surf_name == "BottomMaterial") - uvs = Ogre::Vector2(-part_size.x, part_size.z); - else if(surf_name == "LeftMaterial") - uvs = Ogre::Vector2(part_size.y, part_size.z); - else if(surf_name == "RightMaterial") - uvs = Ogre::Vector2(-part_size.y, part_size.z); - else if(surf_name == "BackMaterial") - uvs = Ogre::Vector2(part_size.x, part_size.z); - else if(surf_name == "FrontMaterial") - uvs = Ogre::Vector2(-part_size.x, part_size.z);*/ - - - } - m_geom->addEntity(m_partEntity, - child_part->getCFrame().getPosition(), - Ogre::Quaternion(child_part->getCFrame().getRotation()), - child_part->getSize()); - } - for(auto& child : *instance->getChildren()) - buildGeomInstance(child); } void Workspace::buildGeom() { - if(!m_geomDirty) + if(!m_geomDirty || m_batchMode != BATCH_STATIC_GEOMETRY) return; - m_geom->reset(); - for(auto& child : *getChildren()) - buildGeomInstance(child); m_geom->build(); m_geomDirty = false; } - void Workspace::onChildRemoved(Instance* childRemoved) + void Workspace::onDescendantRemoved(Instance* childRemoved) { - m_geomDirty = true; + m_geomDirty = true; } Camera* Workspace::getCurrentCamera() const diff --git a/Projects/Engine/Source/App/V8/Tree/Instance.cpp b/Projects/Engine/Source/App/V8/Tree/Instance.cpp index 21e757a..c3680ca 100644 --- a/Projects/Engine/Source/App/V8/Tree/Instance.cpp +++ b/Projects/Engine/Source/App/V8/Tree/Instance.cpp @@ -132,6 +132,9 @@ namespace RNR { children->erase(child_it); m_parent->onChildRemoved(this); + m_parent->onDescendantRemoved(this); + for(auto& child : m_children) + descendantRemovedChildren(m_parent, child); if (m_parent->numChildren() == 0) { @@ -140,24 +143,59 @@ namespace RNR } } + onSetParent(newParent); m_parent = newParent; + if(m_parent) { m_parent->m_children.push_back(this); newParent->onChildAdded(this); + newParent->onDescendantAdded(this); + for(auto& child : m_children) + descendantAddedChildren(m_parent, child); } } } + void Instance::descendantAddedChildren(Instance* p, Instance* c) + { + for(auto& child : *c->getChildren()) + descendantAddedChildren(p, child); + p->onDescendantAdded(c); + } + + void Instance::descendantRemovedChildren(Instance* p, Instance* c) + { + for(auto& child : *c->getChildren()) + descendantRemovedChildren(p, child); + p->onDescendantRemoved(c); + } + void Instance::onChildAdded(Instance* childAdded) { // } + void Instance::onDescendantAdded(Instance* descendantAdded) + { + if(m_parent) + m_parent->onDescendantAdded(descendantAdded); + } void Instance::onChildRemoved(RNR::Instance* childRemoved) { - + + } + + void Instance::onDescendantRemoved(Instance* descendantRemoved) + { + if(m_parent) + m_parent->onDescendantRemoved(descendantRemoved); + } + + void Instance::onSetParent(Instance* newParent) + { + } bool Instance::isA(std::string type) diff --git a/Projects/Engine/Source/App/V8/World/World.cpp b/Projects/Engine/Source/App/V8/World/World.cpp index 2da69ed..5228445 100644 --- a/Projects/Engine/Source/App/V8/World/World.cpp +++ b/Projects/Engine/Source/App/V8/World/World.cpp @@ -32,7 +32,7 @@ namespace RNR m_workspace = (Workspace*)m_datamodel->getService("Workspace"); m_runService = (RunService*)m_datamodel->getService("RunService"); - m_tmb = new TopMenuBar(); + m_tmb = new TopMenuBar(this); Camera* start_cam = new Camera(); start_cam->setParent(m_workspace); @@ -70,9 +70,9 @@ namespace RNR m_refs[referent.as_string()] = instance; WorldUndeserialized s; s.instance = instance; + s.parent = parent; s.node = node; m_undeserialized.push(s); - instance->setParent(parent); for(pugi::xml_node item = node.child("Item"); item; item = item.next_sibling("Item")) xmlAddItem(item, instance); @@ -111,6 +111,7 @@ namespace RNR s.instance->deserializeXmlProperty(prop); } + s.instance->setParent(s.parent); if(s.instance->getClassName() == "Model") { ModelInstance* m = (ModelInstance*)s.instance; @@ -129,6 +130,7 @@ namespace RNR { if(m_inputManager) m_inputManager->frame(); + m_tmb->frame(); } double World::step(float timestep) From 611f0e8d0f4ff0bd8130693169e381a8acad9219 Mon Sep 17 00:00:00 2001 From: floralrainfall Date: Wed, 19 Jul 2023 07:55:34 -0400 Subject: [PATCH 3/4] make TopMenuBar look a little bit more accurate --- Projects/Engine/Source/App/GUI/TopMenuBar.cpp | 76 ++++++++++++++----- .../Source/App/V8/DataModel/PartInstance.cpp | 2 +- .../Source/App/V8/DataModel/Workspace.cpp | 3 +- 3 files changed, 62 insertions(+), 19 deletions(-) diff --git a/Projects/Engine/Source/App/GUI/TopMenuBar.cpp b/Projects/Engine/Source/App/GUI/TopMenuBar.cpp index 0a87dfc..1733f12 100644 --- a/Projects/Engine/Source/App/GUI/TopMenuBar.cpp +++ b/Projects/Engine/Source/App/GUI/TopMenuBar.cpp @@ -9,46 +9,88 @@ namespace RNR Ogre::OverlayManager* overlayManager = Ogre::OverlayManager::getSingletonPtr(); Ogre::MaterialPtr material = Ogre::MaterialManager::getSingleton().create("Background", "General"); - material->getTechnique(0)->getPass(0)->createTextureUnitState("placeholder.png"); + material->getTechnique(0)->getPass(0)->createTextureUnitState("textures/placeholder.png"); + material->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setColourOperationEx(Ogre::LBX_MODULATE, Ogre::LBS_MANUAL, Ogre::LBS_CURRENT, Ogre::ColourValue(0.5, 0.5, 0.5)); material->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setAlphaOperation(Ogre::LBX_MODULATE, Ogre::LBS_MANUAL, Ogre::LBS_CURRENT, 0.5f); - material->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setColourOperationEx(Ogre::LBX_MODULATE, Ogre::LBS_MANUAL, Ogre::LBS_CURRENT, Ogre::ColourValue(1.0, 1.0, 1.0)); material->getTechnique(0)->getPass(0)->setDepthCheckEnabled(false); material->getTechnique(0)->getPass(0)->setDepthWriteEnabled(false); material->getTechnique(0)->getPass(0)->setLightingEnabled(false); + material->getTechnique(0)->getPass(0)->setSceneBlending(Ogre::SceneBlendType::SBT_TRANSPARENT_COLOUR); - Ogre::OverlayContainer* panel = static_cast(overlayManager->createOverlayElement("Panel", "PanelName")); + Ogre::OverlayContainer* panel = static_cast(overlayManager->createOverlayElement("Panel", "TopMenuBarPanel")); panel->setMetricsMode(Ogre::GMM_PIXELS); panel->setPosition(0,0); - panel->setDimensions(320, 24); + panel->setDimensions(128 * 5, 20); panel->setMaterial(material); - Ogre::TextAreaOverlayElement* textArea = static_cast(overlayManager->createOverlayElement("TextArea", "TextAreaName")); - textArea->setMetricsMode(Ogre::GMM_PIXELS); - textArea->setPosition(0, 0); - textArea->setDimensions(320, 24); - textArea->setCaption("Hello, World!"); - textArea->setCharHeight(24); - textArea->setFontName("ComicSans"); - textArea->setColour(Ogre::ColourValue(0.f,0.f,0.f)); + Ogre::ColourValue text_color = Ogre::ColourValue(0.25, 0.25, 0.25); + + Ogre::TextAreaOverlayElement* toolsTextArea = static_cast(overlayManager->createOverlayElement("TextArea", "TopMenuBarTools")); + toolsTextArea->setMetricsMode(Ogre::GMM_PIXELS); + toolsTextArea->setPosition(0, 0); + toolsTextArea->setDimensions(128, 24); + toolsTextArea->setCaption("Tools"); + toolsTextArea->setCharHeight(24); + toolsTextArea->setFontName("ComicSans"); + toolsTextArea->setColour(text_color); + + Ogre::TextAreaOverlayElement* insertTextArea = static_cast(overlayManager->createOverlayElement("TextArea", "TopMenuBarInsert")); + insertTextArea->setMetricsMode(Ogre::GMM_PIXELS); + insertTextArea->setPosition(128, 0); + insertTextArea->setDimensions(128, 24); + insertTextArea->setCaption("Insert"); + insertTextArea->setCharHeight(24); + insertTextArea->setFontName("ComicSans"); + insertTextArea->setColour(text_color); + + Ogre::TextAreaOverlayElement* fullscreenTextArea = static_cast(overlayManager->createOverlayElement("TextArea", "TopMenuBarFullscreen")); + fullscreenTextArea->setMetricsMode(Ogre::GMM_PIXELS); + fullscreenTextArea->setPosition(128*2, 0); + fullscreenTextArea->setDimensions(128, 24); + fullscreenTextArea->setCaption("Fullscreen"); + fullscreenTextArea->setCharHeight(24); + fullscreenTextArea->setFontName("ComicSans"); + fullscreenTextArea->setColour(text_color); + + Ogre::TextAreaOverlayElement* helpTextArea = static_cast(overlayManager->createOverlayElement("TextArea", "TopMenuBarHelp")); + helpTextArea->setMetricsMode(Ogre::GMM_PIXELS); + helpTextArea->setPosition(128*3, 0); + helpTextArea->setDimensions(128, 24); + helpTextArea->setCaption("Help..."); + helpTextArea->setCharHeight(24); + helpTextArea->setFontName("ComicSans"); + helpTextArea->setColour(text_color); + + Ogre::TextAreaOverlayElement* exitTextArea = static_cast(overlayManager->createOverlayElement("TextArea", "TopMenuBarExit")); + exitTextArea->setMetricsMode(Ogre::GMM_PIXELS); + exitTextArea->setPosition(128*4, 0); + exitTextArea->setDimensions(128, 24); + exitTextArea->setCaption("Exit"); + exitTextArea->setCharHeight(24); + exitTextArea->setFontName("ComicSans"); + exitTextArea->setColour(text_color); + + panel->addChild(toolsTextArea); + panel->addChild(insertTextArea); + panel->addChild(fullscreenTextArea); + panel->addChild(helpTextArea); + panel->addChild(exitTextArea); m_debugText = static_cast(overlayManager->createOverlayElement("TextArea", "DebugTextArea")); m_debugText->setMetricsMode(Ogre::GMM_PIXELS); m_debugText->setPosition(0, 300); m_debugText->setDimensions(420, 500); m_debugText->setCaption("Debug text!"); - m_debugText->setCharHeight(24); + m_debugText->setCharHeight(16); m_debugText->setFontName("ComicSans"); m_debugText->setColour(Ogre::ColourValue(0.5f,0.f,0.5f)); + panel->addChild(m_debugText); Ogre::Overlay* overlay = overlayManager->create("OverlayName"); overlay->add2D(panel); overlay->setZOrder(500); - panel->addChild(textArea); - - panel->addChild(m_debugText); - overlay->show(); } diff --git a/Projects/Engine/Source/App/V8/DataModel/PartInstance.cpp b/Projects/Engine/Source/App/V8/DataModel/PartInstance.cpp index a971852..8fb0f38 100644 --- a/Projects/Engine/Source/App/V8/DataModel/PartInstance.cpp +++ b/Projects/Engine/Source/App/V8/DataModel/PartInstance.cpp @@ -29,7 +29,7 @@ namespace RNR Ogre::Entity* entity = (Ogre::Entity*)getObject(); for(auto& subentity : entity->getSubEntities()) { - subentity->getMaterial()->setManualCullingMode(Ogre::ManualCullingMode::MANUAL_CULL_BACK); + subentity->setMaterial(BrickColor::material(m_brickColor)); } } diff --git a/Projects/Engine/Source/App/V8/DataModel/Workspace.cpp b/Projects/Engine/Source/App/V8/DataModel/Workspace.cpp index ed31561..ac9dd77 100644 --- a/Projects/Engine/Source/App/V8/DataModel/Workspace.cpp +++ b/Projects/Engine/Source/App/V8/DataModel/Workspace.cpp @@ -35,7 +35,8 @@ namespace RNR { case BATCH_INSTANCED: { - Ogre::InstancedEntity* replica = m_instanceManager->createInstancedEntity("materials/partinstanced"); + Ogre::Entity* childEntity = (Ogre::Entity*)childAdded->getObject(); + Ogre::InstancedEntity* replica = m_instanceManager->createInstancedEntity(childEntity->getSubEntity(0)->getMaterialName()); replica->setPosition(part->getPosition()); replica->setOrientation(part->getCFrame().getRotation()); replica->setScale(part->getSize()); From 21b436877863c39ea1d48b424ac90d80671069e6 Mon Sep 17 00:00:00 2001 From: floralrainfall Date: Wed, 19 Jul 2023 11:03:49 -0400 Subject: [PATCH 4/4] Play Solo, Player & Players --- Content/RNR/textures/studio/icons/Player.png | Bin 0 -> 1212 bytes Content/RNR/textures/studio/icons/Players.png | Bin 0 -> 1322 bytes Content/RNR/textures/studio/icons/play.png | Bin 0 -> 2353 bytes Projects/Client/Studio/Header/MainWindow.hpp | 1 + Projects/Client/Studio/Source/MainWindow.cpp | 16 ++++- Projects/Engine/CMakeLists.txt | 7 +++ Projects/Engine/Header/App/GUI/TopMenuBar.hpp | 3 + .../Header/App/Script/ScriptContext.hpp | 9 +++ .../Header/App/V8/DataModel/PartInstance.hpp | 7 +++ Projects/Engine/Header/App/V8/World/World.hpp | 2 + Projects/Engine/Header/Network/Player.hpp | 19 ++++++ Projects/Engine/Header/Network/Players.hpp | 21 +++++++ Projects/Engine/Source/App/GUI/TopMenuBar.cpp | 55 +++++++++++++++--- .../Source/App/V8/DataModel/PartInstance.cpp | 19 ++++++ .../Source/App/V8/DataModel/Workspace.cpp | 3 +- Projects/Engine/Source/App/V8/World/World.cpp | 4 ++ Projects/Engine/Source/Network/Player.cpp | 25 ++++++++ Projects/Engine/Source/Network/Players.cpp | 34 +++++++++++ 18 files changed, 213 insertions(+), 12 deletions(-) create mode 100644 Content/RNR/textures/studio/icons/Player.png create mode 100644 Content/RNR/textures/studio/icons/Players.png create mode 100644 Content/RNR/textures/studio/icons/play.png create mode 100644 Projects/Engine/Header/App/Script/ScriptContext.hpp create mode 100644 Projects/Engine/Header/Network/Player.hpp create mode 100644 Projects/Engine/Header/Network/Players.hpp create mode 100644 Projects/Engine/Source/Network/Player.cpp create mode 100644 Projects/Engine/Source/Network/Players.cpp diff --git a/Content/RNR/textures/studio/icons/Player.png b/Content/RNR/textures/studio/icons/Player.png new file mode 100644 index 0000000000000000000000000000000000000000..f3ae27445d80992320bf1d08059542b564f00353 GIT binary patch literal 1212 zcmV;t1Vj6YP)EX>4Tx04R}tkv&MmKpe$iQ>7yH1MMKf)s6A|?JWDYS_3;J6>}?mh0_0Yam~RI@7vsG4P@ z6LB${TNMMZ2%sNBh+U4&e3JS*_Gq>z@3D!MwJz%ypV$NMI35NI`^*8p^1^LWEY06ccIMk9+t>9e;{kGP%lN zIZc;D~bidg4$2bt!1)6o+{yw(t<_X|`2ClTWzuEwzpQP8@ zTKEVU*aj}H+nT%wT$gU400009a7bBm001r{001r{0eGc9b^rhX2XskI zMF-~x6Ad;m9SoX;0000PbVXQnLvL+uWo~o;Lvm$dbY)~9cWHEJAV*0}P*;Ht7XSbP zrb$FWR5;6hlFg4(RTzh#b3b~yZKuq%$;eDlCd5R(F)@TmKwYRYBQ8nQE&l*++!Nx$ zzyda~At4a95YVsz6AcT98ck#@&sP+xGEo1QF~{M8#VMT+&S*J&4|EAI4YPn_4=c5b zU7f0|&HmBQ>8eiy2%n2!n)ZSr@?(O$ig-4ej5`=2r!qCo-W`RxqYGji@Dbo_T+m%Q z?ixaWA#^?gfY!*UMcTiQN<9D^v&$PZ8J`~!2Z3$C9DoI|9<+6(sAnvn=NiC&s9uN({N;#e+KWppL1YAVeR?0J#D8g3YwMH9q~I zv{10w0~9TQ?FX;wxL#e>6i0t6{848u&yB>*wMp|)(^ErhOoKjX{CZ^~ccPc6?FV|zYsu2+=(JY-%52A<9GqxfEU(~hjHI<9 z33`BjF3N@7HEX>4Tx04R}tkv&MmKpe$iQ>7yH1MMKf)s6A|?JWDYS_3;J6>}?mh0_0Yam~RI@7vsG4P@ z6LB${TNMMZ2%sNBh+U4&e3JS*_Gq>z@3D!MwJz%ypV$NMI35NI`^*8p^1^LWEY06ccIMk9+t>9e;{kGP%lN zIZc;D~bidg4$2bt!1)6o+{yw(t<_X|`2ClTWzuEwzpQP8@ zTKEVU*aj}H+nT%wT$gU400009a7bBm001r{001r{0eGc9b^rhX2XskI zMF-~x6Ad^Mtl-Oy0000PbVXQnLvL+uWo~o;Lvm$dbY)~9cWHEJAV*0}P*;Ht7XSbQ z6iGxuR5;6Blg(=!WdO#1?>jTQvmeb8Nn?_J5K1>zg$hDJp(>$dTU0#sBzW^yqaX;q zi75IH2)zm(6g}93Z6#Eq(k?;8)cTQ{$_kBG`Amlkcm*4O7 zJa8bULdsOQY$`083I%iRSk92YY{)Mf@&!Xa!J&vlg7<*W0koF1em}mDyqUZ-au?W; ztWS)7@+fN;fns5;=mXe?gr5QgVTyWd6f>?adZz_(K49&ab2qegf(s8Uulbr*o}(14t^RX&MET@V>tQSu zw3-QVGZx$_tQ8;bbGE5430zy+`QhXDYp;Ho*UwJA5HAsm>_l^1znHkX^2C+5msr?4 zKT&m)$KUwPG|an=>%hFARJVbzw2`wYasqDAR z9;u0|>2sH^d_8u?2r=!a-O1a>&c7vrGyOq^?RIbGc~x>#CT1f}uv_im?+)0hO%a4C zqH2wo%bToErze7xOFfr9D-G{RAkta_21gI^_k6;Rk5LAIT7MkRPhpz@IXz@&Oh;bI z0ZiJ}W=zJ)UTb&LNZC)h-gdav3JBUh02x9~j+Tg(BqU2Wl0#>8)A$0k5S}OKS+CDc zJC?=SM%!8bvpO}is-7Vi4UClxM7H-G8~JrkcN+ZCo~Hb3MJ(T1Ss1N{lj~{g=he{j z#O-fp3c$tgFiw8Ck)Ch$ULm8bK#eTAm`4oCW0)Wlyp#&v=uw@Orqw8whCj|_Cz|*A z?Z0f`E-<*!XvyAC&0B*lVkH%+KB|``-Swf`w|CWmP$Y33F&H~xkAG3A-UD2_@aCEi z6lXtkE*PBz1Fz=l01J8mxOntw(zgIYh3BYS>o gyWHsg1k`}&Kjv(PD7rIPGXMYp07*qoM6N<$f+&7uFaQ7m literal 0 HcmV?d00001 diff --git a/Content/RNR/textures/studio/icons/play.png b/Content/RNR/textures/studio/icons/play.png new file mode 100644 index 0000000000000000000000000000000000000000..66fd4b7438ab335cb40e925d2a222efca876daf1 GIT binary patch literal 2353 zcmV-13C{M3P)EX>4Tx04R}tkv&MmKpe$iQ>7yH1MMKf)s6A|?JWDYS_3;J6>}?mh0_0Yam~RI@7vsG4P@ z6LB${TNMMZ2%sNBh+U4&e3JS*_Gq>z@3D!MwJz%ypV$NMI35NI`^*8p^1^LWEY06ccIMk9+t>9e;{kGP%lN zIZc;D~bidg4$2bt!1)6o+{yw(t<_X|`2ClTWzuEwzpQP8@ zTKEVU*aj}H+nT%wT$gU400009a7bBm001r{001r{0eGc9b^rhX2XskI zMF-~x6AlIzp9z{K0000PbVXQnLvL+uWo~o;Lvm$dbY)~9cWHEJAV*0}P*;Ht7XSbU z8%ab#R9M69mPw3UR~3f8bKg`|Jys8Lap2b8 z1ASe)`-hTUe<~<&V>Y|)eL8_7~p1vDK3duIC96c`JmV7OSxeq@Mm z#fi2q=rQN64BEXw3HZ-_1BgyKUBD*sH@+c3-zwwf5hn`@nvA1q8I2Z0T11om08SM9 zomX$RcUD7ZMQ3X*S~A}`@loDjZ3b~b z9K`s5g9HyCZWqu2>3PIhO4SUds*4!M>FJa%*P*uWaBZMrdMPjfjNKK$8{1cY&14>b zQ-Vd9Ob=p$nHw|)kvfe`01`lA5&e|rTu8B!BZ?fX_)cesKYvlL4gYZ@y52bbNFx=Y zGso>86!+m@Nw8?133@<0&=e&_q;W)3K*2`!h@jZ$4CoL>l)zVp3R%L);JJ>wu-BQN z^}|a?PuXI_&7oNVL?@jtoK-tb_R%Ly&{e-302Wm105nE5nN~{%jE86zO|An~;@D@n zki}XdRYAn~g6+I~Ejl$kswr?27&Nm4;9+rkpB29YOm-^bs`b2Ug4(za2vJZ-3W_G+ zb zLRtn@(PSL0{2S~A0LK_hcYB%k<`@x3Ei~nPcg-Ws3m5d53F9s1_V7#ar61t6gId&v zXk3_jxA9CKR?efEprrN4Xko^8V=S)G$#s$nL11cE2JJ-tiZgUTyeGGa-`hRq!GiHn zP45VlCS%~XHpmECIWlqkyK1dky)~y0Y5ZX~;s7fUlLaSx8$(C1(KXNr?5&2u(FRBF zbgn9-=}ZJFs&`YuvPK`&--4xJtB{PM@l8~#ke&k_ncTduTUl9z&YC1Li>j8Z0o9tr zgi8V1nw`p=0K!_P+jSG%=mRtv00OY5=9KEcwkmIRDz6o#wt3jNZMCV0r`Av?1z3f| z3aa2bN+QwlG!ywr0DE>W%byvjZEVdY%URQ zL7aFLt1h+JpbFLs3WQ-iJtyJxDo7Rlv69EYU@L`k^F0AfB(ns(@4)x+%C^3gz4PE| zlqE`pWEuzJ1kPMcdZ(Efo(`bgmWxl-V#CO|&)I=?#!Jmau}_lD-Zb?#hL?bM9eAZH z<%eG^aQF)qDmmLINyT++?dpvQ*51Z}7q^{H%f~anbltY^ULMS4RfVfJTgU_{j#0YW z%LIOe>m<`6ptAz20{wo%{^digT`(|3^T+o7V#EB z>5g77Jl1~Qrskc%Q$!SzdTB*Ty_Awvh+;#z>QJ%fGYz0B2sye~!1sZdXC287f1FSA z&B@`8wrD8uv^z=!6r6^pTPuy@+aqIM zu9lifHA~W|@=NYxsCE>!F-1Mc5q`%-_Hc}I%-^^!IK5-%g2Zi%+f6{(U!8_8Zabgs z*}3d&vEux~2p2t1Us7}xxXn@OnKTs;x32TEPug`Q$EXvUV&!adkX@YO_snM$zWF>0 zAKD_1zwk6!F9<6Vopk;Qv;gk_zxG$B0`vf<_v~DjJ8pln)=Kbd#?;m+`gv4?)QWM5 zdG}ktmHkaeW;o7ihVJq@IQg87-m9G%?cdiQ9_nAbd?DeFUKh4LZJzZ#=@gTTZjLrp zU0|)MpejEfE4u5x@l~##A8tB*N*)7m6OZ2ZZwbOTkCydc+~eDqrR&u)S`f5B||0jUfBLBm;Uhg z_3_9jW<_*wkLs~2s5?aRl$zW(%MEe&lR8F}5T?v*QUq=4$X0k{7kkDl|VQkZgmp4?_ zv^3S%wb*B*&@?qQRl@8Yhn9E#MV7SQo8i5?zeDc83Zy!_bAWC_T&L1Av944zGrs>9 X<@7ym@${A*00000NkvXXu0mjfvHWQ6 literal 0 HcmV?d00001 diff --git a/Projects/Client/Studio/Header/MainWindow.hpp b/Projects/Client/Studio/Header/MainWindow.hpp index e437512..abaf421 100644 --- a/Projects/Client/Studio/Header/MainWindow.hpp +++ b/Projects/Client/Studio/Header/MainWindow.hpp @@ -39,6 +39,7 @@ class MainWindow : public QMainWindow void selectInstance(QTreeWidgetItem *item, int column); void run(); void pause(); + void playSolo(); void dbg_pointlight(); protected: diff --git a/Projects/Client/Studio/Source/MainWindow.cpp b/Projects/Client/Studio/Source/MainWindow.cpp index c92d1b0..41163b6 100644 --- a/Projects/Client/Studio/Source/MainWindow.cpp +++ b/Projects/Client/Studio/Source/MainWindow.cpp @@ -114,6 +114,7 @@ void MainWindow::createToolbar() QAction* run_action = toolbar->addAction(QIcon("content/textures/studio/icons/run.png"), "", this, SLOT(run())); QAction* pause_action = toolbar->addAction(QIcon("content/textures/studio/icons/pause.png"), "", this, SLOT(pause())); + QAction* playSolo_action = toolbar->addAction(QIcon("content/textures/studio/icons/play.png"), "", this, SLOT(playSolo())); #ifndef NDEBUG toolbar->addSeparator(); @@ -131,6 +132,17 @@ void MainWindow::pause() this->ogreWidget->world->getRunService()->pause(); } +void MainWindow::playSolo() +{ + this->ogreWidget->world->getRunService()->run(); + + RNR::Players* players = (RNR::Players*)this->ogreWidget->world->getDatamodel()->getService("Players"); + RNR::Player* player = players->createLocalPlayer(0); + player->setName(QInputDialog::getText(this, "Player Name", "Enter your player name").toLocal8Bit().data()); + + updateTree(ogreWidget->world->getDatamodel()); +} + void MainWindow::dbg_pointlight() { if(!ogreWidget->selectedInstance) @@ -144,8 +156,8 @@ void MainWindow::dbg_pointlight() dbg_light->setParent(ogreWidget->selectedInstance); double r = QInputDialog::getDouble(this, "Red", "Set red component [0.0-1.0]", 1.0, 0.0, 1.0, 2); - double g = QInputDialog::getDouble(this, "Blue", "Set blue component [0.0-1.0]", 1.0, 0.0, 1.0, 2); - double b = QInputDialog::getDouble(this, "Green", "Set green component [0.0-1.0]", 1.0, 0.0, 1.0, 2); + double g = QInputDialog::getDouble(this, "Green", "Set green component [0.0-1.0]", 1.0, 0.0, 1.0, 2); + double b = QInputDialog::getDouble(this, "Blue", "Set blue component [0.0-1.0]", 1.0, 0.0, 1.0, 2); dbg_light->setColor(Ogre::Vector3(r,g,b)); updateTree(ogreWidget->world->getDatamodel()); diff --git a/Projects/Engine/CMakeLists.txt b/Projects/Engine/CMakeLists.txt index 09cd9a0..78f0797 100644 --- a/Projects/Engine/CMakeLists.txt +++ b/Projects/Engine/CMakeLists.txt @@ -4,6 +4,8 @@ add_library(Engine STATIC Header/Helpers/XML.hpp Header/Helpers/NormalId.hpp Header/App/Script/ReflectionProperty.hpp + Header/App/Script/Script.hpp + Header/App/Script/ScriptContext.hpp Header/App/GUI/GuiBase3d.hpp Header/App/GUI/InstanceAdornment.hpp Header/App/GUI/SelectionBox.hpp @@ -26,6 +28,8 @@ add_library(Engine STATIC Header/App/BrickColor.hpp Header/App/InputManager.hpp Header/Network/GUID.hpp + Header/Network/Player.hpp + Header/Network/Players.hpp Header/Rendering/Adorn.hpp Source/Helpers/Name.cpp @@ -33,6 +37,7 @@ add_library(Engine STATIC Source/Helpers/XML.cpp Source/Helpers/NormalId.cpp Source/App/Script/ReflectionProperty.cpp + Source/App/Script/Script.cpp Source/App/GUI/GuiBase3d.cpp Source/App/GUI/InstanceAdornment.cpp Source/App/GUI/SelectionBox.cpp @@ -55,6 +60,8 @@ add_library(Engine STATIC Source/App/InputManager.cpp Source/App/V8/World/World.cpp Source/Network/GUID.cpp + Source/Network/Player.cpp + Source/Network/Players.cpp Source/Rendering/Adorn.cpp ) diff --git a/Projects/Engine/Header/App/GUI/TopMenuBar.hpp b/Projects/Engine/Header/App/GUI/TopMenuBar.hpp index 98f6360..12734fd 100644 --- a/Projects/Engine/Header/App/GUI/TopMenuBar.hpp +++ b/Projects/Engine/Header/App/GUI/TopMenuBar.hpp @@ -14,6 +14,9 @@ namespace RNR class TopMenuBar { Ogre::TextAreaOverlayElement* m_debugText; + Ogre::TextAreaOverlayElement* m_playerList; + Ogre::OverlayContainer* m_playerPanel; + Ogre::OverlayManager* m_overlayManager; World* m_world; public: TopMenuBar(World* world); diff --git a/Projects/Engine/Header/App/Script/ScriptContext.hpp b/Projects/Engine/Header/App/Script/ScriptContext.hpp new file mode 100644 index 0000000..8411fbf --- /dev/null +++ b/Projects/Engine/Header/App/Script/ScriptContext.hpp @@ -0,0 +1,9 @@ +#pragma once + +namespace RNR +{ + class ScriptContext + { + + }; +} \ No newline at end of file diff --git a/Projects/Engine/Header/App/V8/DataModel/PartInstance.hpp b/Projects/Engine/Header/App/V8/DataModel/PartInstance.hpp index 9314c72..ca1657d 100644 --- a/Projects/Engine/Header/App/V8/DataModel/PartInstance.hpp +++ b/Projects/Engine/Header/App/V8/DataModel/PartInstance.hpp @@ -11,6 +11,8 @@ namespace RNR { protected: int m_brickColor; + float m_transparency; + float m_reflectance; Ogre::Matrix4 m_matrix; Ogre::Vector3 m_position; Ogre::Vector3 m_size; @@ -28,6 +30,11 @@ namespace RNR Ogre::Vector3 getSize() { return m_size; } Ogre::Vector4 getColor() { return m_color; } + void setReflectance(float reflectance) { m_reflectance = reflectance; } + float getReflectance() { return m_reflectance; } + void setTransparency(float transparency) { m_transparency = transparency; } + float getTransparency() { return m_transparency; } + Ogre::Vector3 getOgreCenter() { return m_position + (m_size / 2.f); } void setBrickColor(int brickcolor) { m_brickColor = brickcolor; } diff --git a/Projects/Engine/Header/App/V8/World/World.hpp b/Projects/Engine/Header/App/V8/World/World.hpp index 7595e06..ff2e87f 100644 --- a/Projects/Engine/Header/App/V8/World/World.hpp +++ b/Projects/Engine/Header/App/V8/World/World.hpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -30,6 +31,7 @@ namespace RNR DataModel* m_datamodel; Workspace* m_workspace; RunService* m_runService; + Players* m_players; Ogre::Root* m_ogreRoot; Ogre::SceneManager* m_ogreSceneManager; TopMenuBar* m_tmb; diff --git a/Projects/Engine/Header/Network/Player.hpp b/Projects/Engine/Header/Network/Player.hpp new file mode 100644 index 0000000..6354492 --- /dev/null +++ b/Projects/Engine/Header/Network/Player.hpp @@ -0,0 +1,19 @@ +#pragma once +#include +#include + +namespace RNR +{ + class Player : public Instance + { + ModelInstance* m_character; + int m_userId; + public: + Player(); + + ModelInstance* getCharacter() { return m_character; } + void setCharacter(ModelInstance* model) { m_character = model; } + virtual std::string getClassName() { return "Player"; } + virtual void addProperties(std::vector& properties); + }; +} \ No newline at end of file diff --git a/Projects/Engine/Header/Network/Players.hpp b/Projects/Engine/Header/Network/Players.hpp new file mode 100644 index 0000000..1539efa --- /dev/null +++ b/Projects/Engine/Header/Network/Players.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include +#include + +namespace RNR +{ + class Players : public Instance + { + private: + Player* m_localPlayer; + public: + Players(); + + virtual std::string getClassName() { return "Players"; } + + Player* getLocalPlayer() { return m_localPlayer; }; + Player* createLocalPlayer(int userId); + virtual void addProperties(std::vector& properties); + }; +} \ No newline at end of file diff --git a/Projects/Engine/Source/App/GUI/TopMenuBar.cpp b/Projects/Engine/Source/App/GUI/TopMenuBar.cpp index 1733f12..59164a8 100644 --- a/Projects/Engine/Source/App/GUI/TopMenuBar.cpp +++ b/Projects/Engine/Source/App/GUI/TopMenuBar.cpp @@ -7,7 +7,7 @@ namespace RNR { m_world = world; - Ogre::OverlayManager* overlayManager = Ogre::OverlayManager::getSingletonPtr(); + m_overlayManager = Ogre::OverlayManager::getSingletonPtr(); Ogre::MaterialPtr material = Ogre::MaterialManager::getSingleton().create("Background", "General"); material->getTechnique(0)->getPass(0)->createTextureUnitState("textures/placeholder.png"); material->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setColourOperationEx(Ogre::LBX_MODULATE, Ogre::LBS_MANUAL, Ogre::LBS_CURRENT, Ogre::ColourValue(0.5, 0.5, 0.5)); @@ -17,7 +17,7 @@ namespace RNR material->getTechnique(0)->getPass(0)->setLightingEnabled(false); material->getTechnique(0)->getPass(0)->setSceneBlending(Ogre::SceneBlendType::SBT_TRANSPARENT_COLOUR); - Ogre::OverlayContainer* panel = static_cast(overlayManager->createOverlayElement("Panel", "TopMenuBarPanel")); + Ogre::OverlayContainer* panel = static_cast(m_overlayManager->createOverlayElement("Panel", "TopMenuBarPanel")); panel->setMetricsMode(Ogre::GMM_PIXELS); panel->setPosition(0,0); panel->setDimensions(128 * 5, 20); @@ -25,7 +25,7 @@ namespace RNR Ogre::ColourValue text_color = Ogre::ColourValue(0.25, 0.25, 0.25); - Ogre::TextAreaOverlayElement* toolsTextArea = static_cast(overlayManager->createOverlayElement("TextArea", "TopMenuBarTools")); + Ogre::TextAreaOverlayElement* toolsTextArea = static_cast(m_overlayManager->createOverlayElement("TextArea", "TopMenuBarTools")); toolsTextArea->setMetricsMode(Ogre::GMM_PIXELS); toolsTextArea->setPosition(0, 0); toolsTextArea->setDimensions(128, 24); @@ -34,7 +34,7 @@ namespace RNR toolsTextArea->setFontName("ComicSans"); toolsTextArea->setColour(text_color); - Ogre::TextAreaOverlayElement* insertTextArea = static_cast(overlayManager->createOverlayElement("TextArea", "TopMenuBarInsert")); + Ogre::TextAreaOverlayElement* insertTextArea = static_cast(m_overlayManager->createOverlayElement("TextArea", "TopMenuBarInsert")); insertTextArea->setMetricsMode(Ogre::GMM_PIXELS); insertTextArea->setPosition(128, 0); insertTextArea->setDimensions(128, 24); @@ -43,7 +43,7 @@ namespace RNR insertTextArea->setFontName("ComicSans"); insertTextArea->setColour(text_color); - Ogre::TextAreaOverlayElement* fullscreenTextArea = static_cast(overlayManager->createOverlayElement("TextArea", "TopMenuBarFullscreen")); + Ogre::TextAreaOverlayElement* fullscreenTextArea = static_cast(m_overlayManager->createOverlayElement("TextArea", "TopMenuBarFullscreen")); fullscreenTextArea->setMetricsMode(Ogre::GMM_PIXELS); fullscreenTextArea->setPosition(128*2, 0); fullscreenTextArea->setDimensions(128, 24); @@ -52,7 +52,7 @@ namespace RNR fullscreenTextArea->setFontName("ComicSans"); fullscreenTextArea->setColour(text_color); - Ogre::TextAreaOverlayElement* helpTextArea = static_cast(overlayManager->createOverlayElement("TextArea", "TopMenuBarHelp")); + Ogre::TextAreaOverlayElement* helpTextArea = static_cast(m_overlayManager->createOverlayElement("TextArea", "TopMenuBarHelp")); helpTextArea->setMetricsMode(Ogre::GMM_PIXELS); helpTextArea->setPosition(128*3, 0); helpTextArea->setDimensions(128, 24); @@ -61,7 +61,7 @@ namespace RNR helpTextArea->setFontName("ComicSans"); helpTextArea->setColour(text_color); - Ogre::TextAreaOverlayElement* exitTextArea = static_cast(overlayManager->createOverlayElement("TextArea", "TopMenuBarExit")); + Ogre::TextAreaOverlayElement* exitTextArea = static_cast(m_overlayManager->createOverlayElement("TextArea", "TopMenuBarExit")); exitTextArea->setMetricsMode(Ogre::GMM_PIXELS); exitTextArea->setPosition(128*4, 0); exitTextArea->setDimensions(128, 24); @@ -76,7 +76,7 @@ namespace RNR panel->addChild(helpTextArea); panel->addChild(exitTextArea); - m_debugText = static_cast(overlayManager->createOverlayElement("TextArea", "DebugTextArea")); + m_debugText = static_cast(m_overlayManager->createOverlayElement("TextArea", "DebugTextArea")); m_debugText->setMetricsMode(Ogre::GMM_PIXELS); m_debugText->setPosition(0, 300); m_debugText->setDimensions(420, 500); @@ -87,8 +87,26 @@ namespace RNR panel->addChild(m_debugText); - Ogre::Overlay* overlay = overlayManager->create("OverlayName"); + m_playerPanel = static_cast(m_overlayManager->createOverlayElement("Panel", "PlayerListPanel")); + m_playerPanel->setMetricsMode(Ogre::GMM_PIXELS); + m_playerPanel->setDimensions(128, 20); + m_playerPanel->setMaterial(material); + + m_playerList = static_cast(m_overlayManager->createOverlayElement("TextArea", "PlayerListTextArea")); + m_playerList->setMetricsMode(Ogre::GMM_PIXELS); + m_playerList->setPosition(0, 0); + m_playerList->setDimensions(1000, 1000); + m_playerList->setCaption("Player List"); + m_playerList->setCharHeight(24); + m_playerList->setFontName("ComicSans"); + m_playerList->setColour(Ogre::ColourValue(1.0f, 1.0f, 1.0f)); + + m_playerPanel->addChild(m_playerList); + m_playerPanel->setVisible(false); + + Ogre::Overlay* overlay = m_overlayManager->create("TopMenuBarOverlay"); overlay->add2D(panel); + overlay->add2D(m_playerPanel); overlay->setZOrder(500); overlay->show(); @@ -111,5 +129,24 @@ namespace RNR } snprintf(debugtext, 512, "Render\nLast DT = %f\n%s\n",m_world->getLastDelta(),render_debugtext,m_world->getOgreSceneManager()); m_debugText->setCaption(debugtext); + + Players* players = (Players*)m_world->getDatamodel()->getService("Players"); + auto player_list = players->getChildren(); + if(player_list->size() == 0) + { + m_playerPanel->setVisible(false); + } + else + { + m_playerPanel->setVisible(true); + m_playerPanel->setPosition(m_overlayManager->getViewportWidth() - 128 - 5,5); + std::string player_list_text = "Player List\n"; + for(auto player : *player_list) + { + player_list_text += player->getName() + "\n"; + } + m_playerList->setCaption(player_list_text); + m_playerPanel->setDimensions(128, 20 * (player_list->size() + 1)); + } } } \ No newline at end of file diff --git a/Projects/Engine/Source/App/V8/DataModel/PartInstance.cpp b/Projects/Engine/Source/App/V8/DataModel/PartInstance.cpp index 8fb0f38..bec7c7c 100644 --- a/Projects/Engine/Source/App/V8/DataModel/PartInstance.cpp +++ b/Projects/Engine/Source/App/V8/DataModel/PartInstance.cpp @@ -9,6 +9,8 @@ namespace RNR setName("Part"); m_color = Ogre::Vector4(0.63, 0.64, 0.63, 1.0); + m_transparency = 0.0; + m_reflectance = 0.0; setNode(world->getOgreSceneManager()->getRootSceneNode()->createChildSceneNode()); setObject(world->getOgreSceneManager()->createEntity("fonts/Cube.mesh")); @@ -30,6 +32,7 @@ namespace RNR for(auto& subentity : entity->getSubEntities()) { subentity->setMaterial(BrickColor::material(m_brickColor)); + subentity->getMaterial()->setShininess(64); } } @@ -47,6 +50,14 @@ namespace RNR printf("PartInstance::deserializeProperty: BrickColor not valid number (%i)\n", getBrickColor()); } } + else if(prop_name == std::string("Reflectance")) + { + setReflectance(node.text().as_float()); + } + else if(prop_name == std::string("Transparency")) + { + setTransparency(node.text().as_float()); + } else PVInstance::deserializeProperty(prop_name, node); updateMatrix(); @@ -63,6 +74,14 @@ namespace RNR ACCESS_NONE, OPERATION_READWRITE, PROPERTY_BRICKCOLOR, REFLECTION_GETTER(PartInstance* instance = (PartInstance*)object; return &instance->m_brickColor; ), REFLECTION_SETTER(PartInstance* instance = (PartInstance*)object; instance->setBrickColor(*(int*)value); ) }, + { this, std::string("Reflectance"), std::string(""), + ACCESS_NONE, OPERATION_READWRITE, PROPERTY_FLOAT, + REFLECTION_GETTER(PartInstance* instance = (PartInstance*)object; return &instance->m_reflectance; ), + REFLECTION_SETTER(PartInstance* instance = (PartInstance*)object; instance->setReflectance(*(float*)value); ) }, + { this, std::string("Transparency"), std::string(""), + ACCESS_NONE, OPERATION_READWRITE, PROPERTY_FLOAT, + REFLECTION_GETTER(PartInstance* instance = (PartInstance*)object; return &instance->m_transparency; ), + REFLECTION_SETTER(PartInstance* instance = (PartInstance*)object; instance->setTransparency(*(float*)value); ) }, }; PVInstance::addProperties(properties); diff --git a/Projects/Engine/Source/App/V8/DataModel/Workspace.cpp b/Projects/Engine/Source/App/V8/DataModel/Workspace.cpp index ac9dd77..b314c73 100644 --- a/Projects/Engine/Source/App/V8/DataModel/Workspace.cpp +++ b/Projects/Engine/Source/App/V8/DataModel/Workspace.cpp @@ -19,7 +19,7 @@ namespace RNR break; case BATCH_STATIC_GEOMETRY: m_geom = world->getOgreSceneManager()->createStaticGeometry("workspaceGeom"); - m_geom->setRegionDimensions(Ogre::Vector3(255,255,255)); + m_geom->setRegionDimensions(Ogre::Vector3(512,512,512)); m_geom->setCastShadows(true); break; } @@ -40,6 +40,7 @@ namespace RNR replica->setPosition(part->getPosition()); replica->setOrientation(part->getCFrame().getRotation()); replica->setScale(part->getSize()); + childAdded->setObject(replica); } break; case BATCH_STATIC_GEOMETRY: diff --git a/Projects/Engine/Source/App/V8/World/World.cpp b/Projects/Engine/Source/App/V8/World/World.cpp index 5228445..38bc843 100644 --- a/Projects/Engine/Source/App/V8/World/World.cpp +++ b/Projects/Engine/Source/App/V8/World/World.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -24,6 +25,8 @@ namespace RNR m_instanceFactory->registerInstance("Workspace", InstanceFactory::instanceBuilder); m_instanceFactory->registerInstance("Humanoid", InstanceFactory::instanceBuilder); m_instanceFactory->registerInstance("RunService", InstanceFactory::instanceBuilder); + m_instanceFactory->registerInstance("Players", InstanceFactory::instanceBuilder); + m_instanceFactory->registerInstance("Player", InstanceFactory::instanceBuilder); m_ogreRoot = ogre; m_ogreSceneManager = ogreSceneManager; @@ -31,6 +34,7 @@ namespace RNR m_datamodel->setName("DataModel"); m_workspace = (Workspace*)m_datamodel->getService("Workspace"); m_runService = (RunService*)m_datamodel->getService("RunService"); + m_players = (Players*)m_datamodel->getService("Players"); m_tmb = new TopMenuBar(this); diff --git a/Projects/Engine/Source/Network/Player.cpp b/Projects/Engine/Source/Network/Player.cpp new file mode 100644 index 0000000..352b7fe --- /dev/null +++ b/Projects/Engine/Source/Network/Player.cpp @@ -0,0 +1,25 @@ +#include +#include + +namespace RNR +{ + Player::Player() + { + setName("Player"); + setParent(world->getDatamodel()->getService("Players")); + + m_character = NULL; + } + + void Player::addProperties(std::vector& properties) + { + ReflectionProperty _properties[] = { + { this, std::string("Character"), std::string(""), + ACCESS_NONE, OPERATION_READWRITE, PROPERTY_INSTANCE, + REFLECTION_GETTER(Player* instance = (Player*)object; return instance->m_character; ), + REFLECTION_SETTER(Player* instance = (Player*)object; instance->setCharacter((ModelInstance*)value); ) }, + }; + + properties.insert(properties.end(), _properties, _properties+(sizeof(_properties)/sizeof(ReflectionProperty))); + } +} diff --git a/Projects/Engine/Source/Network/Players.cpp b/Projects/Engine/Source/Network/Players.cpp new file mode 100644 index 0000000..186610b --- /dev/null +++ b/Projects/Engine/Source/Network/Players.cpp @@ -0,0 +1,34 @@ +#include + +namespace RNR +{ + Players::Players() + { + setName("Players"); + m_localPlayer = 0; + } + + Player* Players::createLocalPlayer(int userId) + { + if(m_localPlayer) + { + printf("Players::createLocalPlayer: attempt to create another local player\n", userId); + return m_localPlayer; + } + printf("Players::createLocalPlayer: created player %i\n", userId); + m_localPlayer = new Player(); + return m_localPlayer; + } + + void Players::addProperties(std::vector& properties) + { + ReflectionProperty _properties[] = { + { this, std::string("LocalPlayer"), std::string(""), + ACCESS_NONE, OPERATION_READ, PROPERTY_INSTANCE, + REFLECTION_GETTER(Players* instance = (Players*)object; return instance->m_localPlayer; ), + REFLECTION_SETTER( ) }, + }; + + properties.insert(properties.end(), _properties, _properties+(sizeof(_properties)/sizeof(ReflectionProperty))); + } +} \ No newline at end of file