mirror of
https://thingvellir.net/git/overte
synced 2025-03-27 23:52:03 +01:00
Merge branch 'master' of github.com:highfidelity/hifi into autoTesterUpdate
This commit is contained in:
commit
7aa66e4ab9
21 changed files with 420 additions and 564 deletions
|
@ -24,6 +24,7 @@ Rectangle {
|
|||
color: hifi.colors.baseGray;
|
||||
signal sendToScript(var message);
|
||||
property bool keyboardEnabled: false
|
||||
property bool keyboardRaised: false
|
||||
property bool punctuationMode: false
|
||||
property bool keyboardRasied: false
|
||||
|
||||
|
@ -235,10 +236,11 @@ Rectangle {
|
|||
|
||||
Keyboard {
|
||||
id: keyboard
|
||||
raised: parent.keyboardEnabled
|
||||
raised: parent.keyboardEnabled && parent.keyboardRaised
|
||||
numeric: parent.punctuationMode
|
||||
anchors {
|
||||
bottom: parent.bottom
|
||||
bottomMargin: 40
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
}
|
||||
|
|
|
@ -2241,9 +2241,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
DependencyManager::get<EntityTreeRenderer>()->setSetPrecisionPickingOperator([&](unsigned int rayPickID, bool value) {
|
||||
DependencyManager::get<PickManager>()->setPrecisionPicking(rayPickID, value);
|
||||
});
|
||||
EntityTreeRenderer::setRenderDebugHullsOperator([] {
|
||||
return Menu::getInstance()->isOptionChecked(MenuOption::PhysicsShowHulls);
|
||||
});
|
||||
|
||||
// Preload Tablet sounds
|
||||
DependencyManager::get<TabletScriptingInterface>()->preloadSounds();
|
||||
|
|
|
@ -205,10 +205,6 @@ void Application::runRenderFrame(RenderArgs* renderArgs) {
|
|||
|
||||
RenderArgs::DebugFlags renderDebugFlags = RenderArgs::RENDER_DEBUG_NONE;
|
||||
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::PhysicsShowHulls)) {
|
||||
renderDebugFlags = static_cast<RenderArgs::DebugFlags>(renderDebugFlags |
|
||||
static_cast<int>(RenderArgs::RENDER_DEBUG_HULLS));
|
||||
}
|
||||
renderArgs->_debugFlags = renderDebugFlags;
|
||||
}
|
||||
|
||||
|
|
|
@ -725,7 +725,6 @@ Menu::Menu() {
|
|||
addCheckableActionToQMenuAndActionHash(physicsOptionsMenu, MenuOption::PhysicsShowOwned,
|
||||
0, false, drawStatusConfig, SLOT(setShowNetwork(bool)));
|
||||
}
|
||||
addCheckableActionToQMenuAndActionHash(physicsOptionsMenu, MenuOption::PhysicsShowHulls, 0, false, qApp->getEntities().data(), SIGNAL(setRenderDebugHulls()));
|
||||
|
||||
addCheckableActionToQMenuAndActionHash(physicsOptionsMenu, MenuOption::PhysicsShowBulletWireframe, 0, false, qApp, SLOT(setShowBulletWireframe(bool)));
|
||||
addCheckableActionToQMenuAndActionHash(physicsOptionsMenu, MenuOption::PhysicsShowBulletAABBs, 0, false, qApp, SLOT(setShowBulletAABBs(bool)));
|
||||
|
|
|
@ -141,7 +141,6 @@ namespace MenuOption {
|
|||
const QString Overlays = "Show Overlays";
|
||||
const QString PackageModel = "Package Model as .fst...";
|
||||
const QString Pair = "Pair";
|
||||
const QString PhysicsShowHulls = "Draw Collision Shapes";
|
||||
const QString PhysicsShowOwned = "Highlight Simulation Ownership";
|
||||
const QString VerboseLogging = "Verbose Logging";
|
||||
const QString PhysicsShowBulletWireframe = "Show Bullet Collision";
|
||||
|
|
|
@ -42,7 +42,6 @@
|
|||
|
||||
size_t std::hash<EntityItemID>::operator()(const EntityItemID& id) const { return qHash(id); }
|
||||
std::function<bool()> EntityTreeRenderer::_entitiesShouldFadeFunction;
|
||||
std::function<bool()> EntityTreeRenderer::_renderDebugHullsOperator = [] { return false; };
|
||||
|
||||
QString resolveScriptURL(const QString& scriptUrl) {
|
||||
auto normalizedScriptUrl = DependencyManager::get<ResourceManager>()->normalizeURL(scriptUrl);
|
||||
|
|
|
@ -116,14 +116,10 @@ public:
|
|||
EntityItemPointer getEntity(const EntityItemID& id);
|
||||
void onEntityChanged(const EntityItemID& id);
|
||||
|
||||
static void setRenderDebugHullsOperator(std::function<bool()> renderDebugHullsOperator) { _renderDebugHullsOperator = renderDebugHullsOperator; }
|
||||
static bool shouldRenderDebugHulls() { return _renderDebugHullsOperator(); }
|
||||
|
||||
signals:
|
||||
void enterEntity(const EntityItemID& entityItemID);
|
||||
void leaveEntity(const EntityItemID& entityItemID);
|
||||
void collisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision);
|
||||
void setRenderDebugHulls();
|
||||
|
||||
public slots:
|
||||
void addingEntity(const EntityItemID& entityID);
|
||||
|
@ -259,8 +255,6 @@ private:
|
|||
static int _entitiesScriptEngineCount;
|
||||
static CalculateEntityLoadingPriority _calculateEntityLoadingPriorityFunc;
|
||||
static std::function<bool()> _entitiesShouldFadeFunction;
|
||||
|
||||
static std::function<bool()> _renderDebugHullsOperator;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
#include <QtCore/QUrlQuery>
|
||||
|
||||
#include <AbstractViewStateInterface.h>
|
||||
#include <CollisionRenderMeshCache.h>
|
||||
#include <Model.h>
|
||||
#include <PerfStat.h>
|
||||
#include <render/Scene.h>
|
||||
|
@ -35,8 +34,6 @@
|
|||
#include "EntitiesRendererLogging.h"
|
||||
|
||||
|
||||
static CollisionRenderMeshCache collisionMeshCache;
|
||||
|
||||
void ModelEntityWrapper::setModel(const ModelPointer& model) {
|
||||
withWriteLock([&] {
|
||||
if (_model != model) {
|
||||
|
@ -1052,10 +1049,7 @@ using namespace render;
|
|||
using namespace render::entities;
|
||||
|
||||
ModelEntityRenderer::ModelEntityRenderer(const EntityItemPointer& entity) : Parent(entity) {
|
||||
connect(DependencyManager::get<EntityTreeRenderer>().data(), &EntityTreeRenderer::setRenderDebugHulls, this, [&] {
|
||||
_needsCollisionGeometryUpdate = true;
|
||||
emit requestRenderUpdate();
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
void ModelEntityRenderer::setKey(bool didVisualGeometryRequestSucceed) {
|
||||
|
@ -1215,10 +1209,6 @@ bool ModelEntityRenderer::needsRenderUpdate() const {
|
|||
if (model->getRenderItemsNeedUpdate()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_needsCollisionGeometryUpdate) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return Parent::needsRenderUpdate();
|
||||
}
|
||||
|
@ -1285,12 +1275,7 @@ bool ModelEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPoin
|
|||
}
|
||||
|
||||
void ModelEntityRenderer::setCollisionMeshKey(const void*key) {
|
||||
if (key != _collisionMeshKey) {
|
||||
if (_collisionMeshKey) {
|
||||
collisionMeshCache.releaseMesh(_collisionMeshKey);
|
||||
}
|
||||
_collisionMeshKey = key;
|
||||
}
|
||||
_collisionMeshKey = key;
|
||||
}
|
||||
|
||||
void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) {
|
||||
|
@ -1339,7 +1324,6 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
|
|||
_didLastVisualGeometryRequestSucceed = didVisualGeometryRequestSucceed;
|
||||
});
|
||||
connect(model.get(), &Model::requestRenderUpdate, this, &ModelEntityRenderer::requestRenderUpdate);
|
||||
connect(entity.get(), &RenderableModelEntityItem::requestCollisionGeometryUpdate, this, &ModelEntityRenderer::flagForCollisionGeometryUpdate);
|
||||
model->setLoadingPriority(EntityTreeRenderer::getEntityLoadingPriority(*entity));
|
||||
entity->setModel(model);
|
||||
withWriteLock([&] { _model = model; });
|
||||
|
@ -1412,26 +1396,6 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
|
|||
model->setCanCastShadow(_canCastShadow, scene);
|
||||
}
|
||||
|
||||
if (_needsCollisionGeometryUpdate) {
|
||||
setCollisionMeshKey(entity->getCollisionMeshKey());
|
||||
_needsCollisionGeometryUpdate = false;
|
||||
ShapeType type = entity->getShapeType();
|
||||
if (DependencyManager::get<EntityTreeRenderer>()->shouldRenderDebugHulls() && type != SHAPE_TYPE_STATIC_MESH && type != SHAPE_TYPE_NONE) {
|
||||
// NOTE: it is OK if _collisionMeshKey is nullptr
|
||||
graphics::MeshPointer mesh = collisionMeshCache.getMesh(_collisionMeshKey);
|
||||
// NOTE: the model will render the collisionGeometry if it has one
|
||||
_model->setCollisionMesh(mesh);
|
||||
} else {
|
||||
if (_collisionMeshKey) {
|
||||
// release mesh
|
||||
collisionMeshCache.releaseMesh(_collisionMeshKey);
|
||||
}
|
||||
// clear model's collision geometry
|
||||
graphics::MeshPointer mesh = nullptr;
|
||||
_model->setCollisionMesh(mesh);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
DETAILED_PROFILE_RANGE(simulation_physics, "Fixup");
|
||||
if (model->needsFixupInScene()) {
|
||||
|
@ -1487,11 +1451,6 @@ void ModelEntityRenderer::setIsVisibleInSecondaryCamera(bool value) {
|
|||
setKey(_didLastVisualGeometryRequestSucceed);
|
||||
}
|
||||
|
||||
void ModelEntityRenderer::flagForCollisionGeometryUpdate() {
|
||||
_needsCollisionGeometryUpdate = true;
|
||||
emit requestRenderUpdate();
|
||||
}
|
||||
|
||||
// NOTE: this only renders the "meta" portion of the Model, namely it renders debugging items
|
||||
void ModelEntityRenderer::doRender(RenderArgs* args) {
|
||||
DETAILED_PROFILE_RANGE(render_detail, "MetaModelRender");
|
||||
|
|
|
@ -161,7 +161,6 @@ protected:
|
|||
virtual bool needsRenderUpdate() const override;
|
||||
virtual void doRender(RenderArgs* args) override;
|
||||
virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override;
|
||||
void flagForCollisionGeometryUpdate();
|
||||
void setCollisionMeshKey(const void* key);
|
||||
|
||||
render::hifi::Tag getTagMask() const override;
|
||||
|
@ -189,7 +188,6 @@ private:
|
|||
#endif
|
||||
|
||||
bool _needsJointSimulation { false };
|
||||
bool _needsCollisionGeometryUpdate { false };
|
||||
const void* _collisionMeshKey { nullptr };
|
||||
|
||||
// used on client side
|
||||
|
|
|
@ -47,7 +47,7 @@ bool CauterizedModel::updateGeometry() {
|
|||
return needsFullUpdate;
|
||||
}
|
||||
|
||||
void CauterizedModel::createVisibleRenderItemSet() {
|
||||
void CauterizedModel::createRenderItemSet() {
|
||||
if (_isCauterized) {
|
||||
assert(isLoaded());
|
||||
const auto& meshes = _renderGeometry->getMeshes();
|
||||
|
@ -94,15 +94,10 @@ void CauterizedModel::createVisibleRenderItemSet() {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
Model::createVisibleRenderItemSet();
|
||||
Model::createRenderItemSet();
|
||||
}
|
||||
}
|
||||
|
||||
void CauterizedModel::createCollisionRenderItemSet() {
|
||||
// Temporary HACK: use base class method for now
|
||||
Model::createCollisionRenderItemSet();
|
||||
}
|
||||
|
||||
void CauterizedModel::updateClusterMatrices() {
|
||||
PerformanceTimer perfTimer("CauterizedModel::updateClusterMatrices");
|
||||
|
||||
|
@ -186,12 +181,6 @@ void CauterizedModel::updateRenderItems() {
|
|||
if (!_addedToScene) {
|
||||
return;
|
||||
}
|
||||
|
||||
glm::vec3 scale = getScale();
|
||||
if (_collisionGeometry) {
|
||||
// _collisionGeometry is already scaled
|
||||
scale = glm::vec3(1.0f);
|
||||
}
|
||||
_needsUpdateClusterMatrices = true;
|
||||
_renderItemsNeedUpdate = false;
|
||||
|
||||
|
|
|
@ -31,9 +31,8 @@ public:
|
|||
void deleteGeometry() override;
|
||||
bool updateGeometry() override;
|
||||
|
||||
void createVisibleRenderItemSet() override;
|
||||
void createCollisionRenderItemSet() override;
|
||||
|
||||
void createRenderItemSet() override;
|
||||
|
||||
virtual void updateClusterMatrices() override;
|
||||
void updateRenderItems() override;
|
||||
|
||||
|
|
|
@ -47,51 +47,9 @@ int vec3VectorTypeId = qRegisterMetaType<QVector<glm::vec3> >();
|
|||
float Model::FAKE_DIMENSION_PLACEHOLDER = -1.0f;
|
||||
#define HTTP_INVALID_COM "http://invalid.com"
|
||||
|
||||
const int NUM_COLLISION_HULL_COLORS = 24;
|
||||
std::vector<graphics::MaterialPointer> _collisionMaterials;
|
||||
|
||||
void initCollisionMaterials() {
|
||||
// generates bright colors in red, green, blue, yellow, magenta, and cyan spectrums
|
||||
// (no browns, greys, or dark shades)
|
||||
float component[NUM_COLLISION_HULL_COLORS] = {
|
||||
0.0f, 0.0f, 0.0f, 0.0f,
|
||||
0.0f, 0.0f, 0.0f, 0.0f,
|
||||
0.2f, 0.4f, 0.6f, 0.8f,
|
||||
1.0f, 1.0f, 1.0f, 1.0f,
|
||||
1.0f, 1.0f, 1.0f, 1.0f,
|
||||
0.8f, 0.6f, 0.4f, 0.2f
|
||||
};
|
||||
_collisionMaterials.reserve(NUM_COLLISION_HULL_COLORS);
|
||||
|
||||
// each component gets the same cuve
|
||||
// but offset by a multiple of one third the full width
|
||||
int numComponents = 3;
|
||||
int sectionWidth = NUM_COLLISION_HULL_COLORS / numComponents;
|
||||
int greenPhase = sectionWidth;
|
||||
int bluePhase = 2 * sectionWidth;
|
||||
|
||||
// we stride through the colors to scatter adjacent shades
|
||||
// so they don't tend to group together for large models
|
||||
for (int i = 0; i < sectionWidth; ++i) {
|
||||
for (int j = 0; j < numComponents; ++j) {
|
||||
graphics::MaterialPointer material;
|
||||
material = std::make_shared<graphics::Material>();
|
||||
int index = j * sectionWidth + i;
|
||||
float red = component[index % NUM_COLLISION_HULL_COLORS];
|
||||
float green = component[(index + greenPhase) % NUM_COLLISION_HULL_COLORS];
|
||||
float blue = component[(index + bluePhase) % NUM_COLLISION_HULL_COLORS];
|
||||
material->setAlbedo(glm::vec3(red, green, blue));
|
||||
material->setMetallic(0.02f);
|
||||
material->setRoughness(0.5f);
|
||||
_collisionMaterials.push_back(material);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Model::Model(QObject* parent, SpatiallyNestable* spatiallyNestableOverride) :
|
||||
QObject(parent),
|
||||
_renderGeometry(),
|
||||
_collisionGeometry(),
|
||||
_renderWatcher(_renderGeometry),
|
||||
_spatiallyNestableOverride(spatiallyNestableOverride),
|
||||
_translation(0.0f),
|
||||
|
@ -310,16 +268,6 @@ void Model::updateRenderItems() {
|
|||
});
|
||||
}
|
||||
|
||||
Transform collisionMeshOffset;
|
||||
collisionMeshOffset.setIdentity();
|
||||
foreach(auto itemID, self->_collisionRenderItemsMap.keys()) {
|
||||
transaction.updateItem<MeshPartPayload>(itemID, [renderItemKeyGlobalFlags, modelTransform, collisionMeshOffset](MeshPartPayload& data) {
|
||||
// update the model transform for this render item.
|
||||
data.updateKey(renderItemKeyGlobalFlags);
|
||||
data.updateTransform(modelTransform, collisionMeshOffset);
|
||||
});
|
||||
}
|
||||
|
||||
AbstractViewStateInterface::instance()->getMain3DScene()->enqueueTransaction(transaction);
|
||||
});
|
||||
}
|
||||
|
@ -777,11 +725,6 @@ void Model::updateRenderItemsKey(const render::ScenePointer& scene) {
|
|||
data.updateKey(renderItemsKey);
|
||||
});
|
||||
}
|
||||
foreach(auto item, _collisionRenderItemsMap.keys()) {
|
||||
transaction.updateItem<ModelMeshPartPayload>(item, [renderItemsKey](ModelMeshPartPayload& data) {
|
||||
data.updateKey(renderItemsKey);
|
||||
});
|
||||
}
|
||||
scene->enqueueTransaction(transaction);
|
||||
}
|
||||
|
||||
|
@ -862,49 +805,37 @@ const render::ItemKey Model::getRenderItemKeyGlobalFlags() const {
|
|||
bool Model::addToScene(const render::ScenePointer& scene,
|
||||
render::Transaction& transaction,
|
||||
render::Item::Status::Getters& statusGetters) {
|
||||
bool readyToRender = _collisionGeometry || isLoaded();
|
||||
if (!_addedToScene && readyToRender) {
|
||||
createRenderItemSet();
|
||||
if (!_addedToScene && isLoaded()) {
|
||||
updateClusterMatrices();
|
||||
if (_modelMeshRenderItems.empty()) {
|
||||
createRenderItemSet();
|
||||
}
|
||||
}
|
||||
|
||||
bool somethingAdded = false;
|
||||
if (_collisionGeometry) {
|
||||
if (_collisionRenderItemsMap.empty()) {
|
||||
foreach (auto renderItem, _collisionRenderItems) {
|
||||
auto item = scene->allocateID();
|
||||
auto renderPayload = std::make_shared<MeshPartPayload::Payload>(renderItem);
|
||||
if (_collisionRenderItems.empty() && statusGetters.size()) {
|
||||
renderPayload->addStatusGetters(statusGetters);
|
||||
}
|
||||
transaction.resetItem(item, renderPayload);
|
||||
_collisionRenderItemsMap.insert(item, renderPayload);
|
||||
|
||||
if (_modelMeshRenderItemsMap.empty()) {
|
||||
|
||||
bool hasTransparent = false;
|
||||
size_t verticesCount = 0;
|
||||
foreach(auto renderItem, _modelMeshRenderItems) {
|
||||
auto item = scene->allocateID();
|
||||
auto renderPayload = std::make_shared<ModelMeshPartPayload::Payload>(renderItem);
|
||||
if (_modelMeshRenderItemsMap.empty() && statusGetters.size()) {
|
||||
renderPayload->addStatusGetters(statusGetters);
|
||||
}
|
||||
somethingAdded = !_collisionRenderItemsMap.empty();
|
||||
transaction.resetItem(item, renderPayload);
|
||||
|
||||
hasTransparent = hasTransparent || renderItem.get()->getShapeKey().isTranslucent();
|
||||
verticesCount += renderItem.get()->getVerticesCount();
|
||||
_modelMeshRenderItemsMap.insert(item, renderPayload);
|
||||
_modelMeshRenderItemIDs.emplace_back(item);
|
||||
}
|
||||
} else {
|
||||
if (_modelMeshRenderItemsMap.empty()) {
|
||||
somethingAdded = !_modelMeshRenderItemsMap.empty();
|
||||
|
||||
bool hasTransparent = false;
|
||||
size_t verticesCount = 0;
|
||||
foreach(auto renderItem, _modelMeshRenderItems) {
|
||||
auto item = scene->allocateID();
|
||||
auto renderPayload = std::make_shared<ModelMeshPartPayload::Payload>(renderItem);
|
||||
if (_modelMeshRenderItemsMap.empty() && statusGetters.size()) {
|
||||
renderPayload->addStatusGetters(statusGetters);
|
||||
}
|
||||
transaction.resetItem(item, renderPayload);
|
||||
|
||||
hasTransparent = hasTransparent || renderItem.get()->getShapeKey().isTranslucent();
|
||||
verticesCount += renderItem.get()->getVerticesCount();
|
||||
_modelMeshRenderItemsMap.insert(item, renderPayload);
|
||||
_modelMeshRenderItemIDs.emplace_back(item);
|
||||
}
|
||||
somethingAdded = !_modelMeshRenderItemsMap.empty();
|
||||
|
||||
_renderInfoVertexCount = verticesCount;
|
||||
_renderInfoDrawCalls = _modelMeshRenderItemsMap.count();
|
||||
_renderInfoHasTransparent = hasTransparent;
|
||||
}
|
||||
_renderInfoVertexCount = verticesCount;
|
||||
_renderInfoDrawCalls = _modelMeshRenderItemsMap.count();
|
||||
_renderInfoHasTransparent = hasTransparent;
|
||||
}
|
||||
|
||||
if (somethingAdded) {
|
||||
|
@ -926,11 +857,6 @@ void Model::removeFromScene(const render::ScenePointer& scene, render::Transacti
|
|||
_modelMeshMaterialNames.clear();
|
||||
_modelMeshRenderItemShapes.clear();
|
||||
|
||||
foreach(auto item, _collisionRenderItemsMap.keys()) {
|
||||
transaction.removeItem(item);
|
||||
}
|
||||
_collisionRenderItems.clear();
|
||||
_collisionRenderItemsMap.clear();
|
||||
_addedToScene = false;
|
||||
|
||||
_renderInfoVertexCount = 0;
|
||||
|
@ -1504,7 +1430,6 @@ void Model::deleteGeometry() {
|
|||
_rig.destroyAnimGraph();
|
||||
_blendedBlendshapeCoefficients.clear();
|
||||
_renderGeometry.reset();
|
||||
_collisionGeometry.reset();
|
||||
}
|
||||
|
||||
void Model::overrideModelTransformAndOffset(const Transform& transform, const glm::vec3& offset) {
|
||||
|
@ -1533,19 +1458,6 @@ const render::ItemIDs& Model::fetchRenderItemIDs() const {
|
|||
}
|
||||
|
||||
void Model::createRenderItemSet() {
|
||||
updateClusterMatrices();
|
||||
if (_collisionGeometry) {
|
||||
if (_collisionRenderItems.empty()) {
|
||||
createCollisionRenderItemSet();
|
||||
}
|
||||
} else {
|
||||
if (_modelMeshRenderItems.empty()) {
|
||||
createVisibleRenderItemSet();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void Model::createVisibleRenderItemSet() {
|
||||
assert(isLoaded());
|
||||
const auto& meshes = _renderGeometry->getMeshes();
|
||||
|
||||
|
@ -1591,41 +1503,6 @@ void Model::createVisibleRenderItemSet() {
|
|||
}
|
||||
}
|
||||
|
||||
void Model::createCollisionRenderItemSet() {
|
||||
assert((bool)_collisionGeometry);
|
||||
if (_collisionMaterials.empty()) {
|
||||
initCollisionMaterials();
|
||||
}
|
||||
|
||||
const auto& meshes = _collisionGeometry->getMeshes();
|
||||
|
||||
// We should not have any existing renderItems if we enter this section of code
|
||||
Q_ASSERT(_collisionRenderItems.isEmpty());
|
||||
|
||||
Transform identity;
|
||||
identity.setIdentity();
|
||||
Transform offset;
|
||||
offset.postTranslate(_offset);
|
||||
|
||||
// Run through all of the meshes, and place them into their segregated, but unsorted buckets
|
||||
uint32_t numMeshes = (uint32_t)meshes.size();
|
||||
for (uint32_t i = 0; i < numMeshes; i++) {
|
||||
const auto& mesh = meshes.at(i);
|
||||
if (!mesh) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Create the render payloads
|
||||
int numParts = (int)mesh->getNumParts();
|
||||
for (int partIndex = 0; partIndex < numParts; partIndex++) {
|
||||
graphics::MaterialPointer& material = _collisionMaterials[partIndex % NUM_COLLISION_HULL_COLORS];
|
||||
auto payload = std::make_shared<MeshPartPayload>(mesh, partIndex, material);
|
||||
payload->updateTransform(identity, offset);
|
||||
_collisionRenderItems << payload;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Model::isRenderable() const {
|
||||
return !_meshStates.empty() || (isLoaded() && _renderGeometry->getMeshes().empty());
|
||||
}
|
||||
|
@ -1709,15 +1586,6 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
void Model::setCollisionMesh(graphics::MeshPointer mesh) {
|
||||
if (mesh) {
|
||||
_collisionGeometry = std::make_shared<CollisionRenderGeometry>(mesh);
|
||||
} else {
|
||||
_collisionGeometry.reset();
|
||||
}
|
||||
_needsFixupInScene = true;
|
||||
}
|
||||
|
||||
ModelBlender::ModelBlender() :
|
||||
_pendingBlenders(0) {
|
||||
}
|
||||
|
|
|
@ -153,8 +153,6 @@ public:
|
|||
|
||||
/// Returns a reference to the shared geometry.
|
||||
const Geometry::Pointer& getGeometry() const { return _renderGeometry; }
|
||||
/// Returns a reference to the shared collision geometry.
|
||||
const Geometry::Pointer& getCollisionGeometry() const { return _collisionGeometry; }
|
||||
|
||||
const QVariantMap getTextures() const { assert(isLoaded()); return _renderGeometry->getTextures(); }
|
||||
Q_INVOKABLE virtual void setTextures(const QVariantMap& textures);
|
||||
|
@ -260,7 +258,6 @@ public:
|
|||
|
||||
// returns 'true' if needs fullUpdate after geometry change
|
||||
virtual bool updateGeometry();
|
||||
void setCollisionMesh(graphics::MeshPointer mesh);
|
||||
|
||||
void setLoadingPriority(float priority) { _loadingPriority = priority; }
|
||||
|
||||
|
@ -362,7 +359,6 @@ protected:
|
|||
bool getJointPosition(int jointIndex, glm::vec3& position) const;
|
||||
|
||||
Geometry::Pointer _renderGeometry; // only ever set by its watcher
|
||||
Geometry::Pointer _collisionGeometry;
|
||||
|
||||
GeometryResourceWatcher _renderWatcher;
|
||||
|
||||
|
@ -430,9 +426,7 @@ protected:
|
|||
QVector<TriangleSet> _modelSpaceMeshTriangleSets; // model space triangles for all sub meshes
|
||||
|
||||
|
||||
void createRenderItemSet();
|
||||
virtual void createVisibleRenderItemSet();
|
||||
virtual void createCollisionRenderItemSet();
|
||||
virtual void createRenderItemSet();
|
||||
|
||||
bool _isWireframe;
|
||||
bool _useDualQuaternionSkinning { false };
|
||||
|
@ -443,9 +437,6 @@ protected:
|
|||
|
||||
static AbstractViewStateInterface* _viewState;
|
||||
|
||||
QVector<std::shared_ptr<MeshPartPayload>> _collisionRenderItems;
|
||||
QMap<render::ItemID, render::PayloadPointer> _collisionRenderItemsMap;
|
||||
|
||||
QVector<std::shared_ptr<ModelMeshPartPayload>> _modelMeshRenderItems;
|
||||
QMap<render::ItemID, render::PayloadPointer> _modelMeshRenderItemsMap;
|
||||
render::ItemIDs _modelMeshRenderItemIDs;
|
||||
|
|
|
@ -432,10 +432,13 @@ bool ScriptEngines::stopScript(const QString& rawScriptURL, bool restart) {
|
|||
ScriptEngine::Type type = scriptEngine->getType();
|
||||
auto scriptCache = DependencyManager::get<ScriptCache>();
|
||||
scriptCache->deleteScript(scriptURL);
|
||||
connect(scriptEngine.data(), &ScriptEngine::finished,
|
||||
this, [this, isUserLoaded, type](QString scriptName, ScriptEnginePointer engine) {
|
||||
reloadScript(scriptName, isUserLoaded)->setType(type);
|
||||
});
|
||||
|
||||
if (!scriptEngine->isStopping()) {
|
||||
connect(scriptEngine.data(), &ScriptEngine::finished,
|
||||
this, [this, isUserLoaded, type](QString scriptName, ScriptEnginePointer engine) {
|
||||
reloadScript(scriptName, isUserLoaded)->setType(type);
|
||||
});
|
||||
}
|
||||
}
|
||||
scriptEngine->stop();
|
||||
stoppedScript = true;
|
||||
|
@ -594,7 +597,7 @@ void ScriptEngines::onScriptFinished(const QString& rawScriptURL, ScriptEnginePo
|
|||
}
|
||||
}
|
||||
|
||||
if (removed) {
|
||||
if (removed && !_isReloading) {
|
||||
// Update settings with removed script
|
||||
saveScripts();
|
||||
emit scriptCountChanged();
|
||||
|
|
|
@ -177,6 +177,10 @@ function goActive() {
|
|||
|
||||
UserActivityLogger.toggledAway(false);
|
||||
MyAvatar.isAway = false;
|
||||
|
||||
if (!Window.hasFocus()) {
|
||||
Window.setFocus();
|
||||
}
|
||||
}
|
||||
|
||||
MyAvatar.wentAway.connect(setAwayProperties);
|
||||
|
|
|
@ -101,12 +101,15 @@
|
|||
this.isReady = function(controllerData, deltaTime) {
|
||||
var now = Date.now();
|
||||
this.triggersPressed(controllerData, now);
|
||||
if ((HMD.active && !this.mouseActivity.expired(now)) && _this.handControllerActivity.expired()) {
|
||||
Reticle.visible = true;
|
||||
return ControllerDispatcherUtils.makeRunningValues(true, [], []);
|
||||
}
|
||||
if (HMD.active) {
|
||||
Reticle.visible = false;
|
||||
if (!this.mouseActivity.expired(now) && _this.handControllerActivity.expired()) {
|
||||
Reticle.visible = true;
|
||||
return ControllerDispatcherUtils.makeRunningValues(true, [], []);
|
||||
} else {
|
||||
Reticle.visible = false;
|
||||
}
|
||||
} else if (!Reticle.visible) {
|
||||
Reticle.visible = true;
|
||||
}
|
||||
|
||||
return ControllerDispatcherUtils.makeRunningValues(false, [], []);
|
||||
|
|
|
@ -1,309 +1,315 @@
|
|||
print("Loading hfudt")
|
||||
|
||||
-- create the HFUDT protocol
|
||||
p_hfudt = Proto("hfudt", "HFUDT Protocol")
|
||||
|
||||
-- create fields shared between packets in HFUDT
|
||||
local f_data = ProtoField.string("hfudt.data", "Data")
|
||||
|
||||
-- create the fields for data packets in HFUDT
|
||||
local f_length = ProtoField.uint16("hfudt.length", "Length", base.DEC)
|
||||
local f_control_bit = ProtoField.uint8("hfudt.control", "Control Bit", base.DEC)
|
||||
local f_reliable_bit = ProtoField.uint8("hfudt.reliable", "Reliability Bit", base.DEC)
|
||||
local f_message_bit = ProtoField.uint8("hfudt.message", "Message Bit", base.DEC)
|
||||
local f_obfuscation_level = ProtoField.uint8("hfudt.obfuscation_level", "Obfuscation Level", base.DEC)
|
||||
local f_sequence_number = ProtoField.uint32("hfudt.sequence_number", "Sequence Number", base.DEC)
|
||||
local f_message_position = ProtoField.uint8("hfudt.message_position", "Message Position", base.DEC)
|
||||
local f_message_number = ProtoField.uint32("hfudt.message_number", "Message Number", base.DEC)
|
||||
local f_message_part_number = ProtoField.uint32("hfudt.message_part_number", "Message Part Number", base.DEC)
|
||||
local f_type = ProtoField.uint8("hfudt.type", "Type", base.DEC)
|
||||
local f_version = ProtoField.uint8("hfudt.version", "Version", base.DEC)
|
||||
local f_type_text = ProtoField.string("hfudt.type_text", "TypeText")
|
||||
local f_sender_id = ProtoField.uint16("hfudt.sender_id", "Sender ID", base.DEC)
|
||||
local f_hmac_hash = ProtoField.bytes("hfudt.hmac_hash", "HMAC Hash")
|
||||
|
||||
-- create the fields for control packets in HFUDT
|
||||
local f_control_type = ProtoField.uint16("hfudt.control_type", "Control Type", base.DEC)
|
||||
local f_control_type_text = ProtoField.string("hfudt.control_type_text", "Control Type Text", base.ASCII)
|
||||
local f_ack_sequence_number = ProtoField.uint32("hfudt.ack_sequence_number", "ACKed Sequence Number", base.DEC)
|
||||
local f_control_sub_sequence = ProtoField.uint32("hfudt.control_sub_sequence", "Control Sub-Sequence Number", base.DEC)
|
||||
local f_nak_sequence_number = ProtoField.uint32("hfudt.nak_sequence_number", "NAKed Sequence Number", base.DEC)
|
||||
local f_nak_range_end = ProtoField.uint32("hfudt.nak_range_end", "NAK Range End", base.DEC)
|
||||
|
||||
local SEQUENCE_NUMBER_MASK = 0x07FFFFFF
|
||||
|
||||
p_hfudt.fields = {
|
||||
f_length,
|
||||
f_control_bit, f_reliable_bit, f_message_bit, f_sequence_number, f_type, f_type_text, f_version,
|
||||
f_sender_id, f_hmac_hash,
|
||||
f_message_position, f_message_number, f_message_part_number, f_obfuscation_level,
|
||||
f_control_type, f_control_type_text, f_control_sub_sequence, f_ack_sequence_number, f_nak_sequence_number, f_nak_range_end,
|
||||
f_data
|
||||
}
|
||||
|
||||
local control_types = {
|
||||
[0] = { "ACK", "Acknowledgement" },
|
||||
[1] = { "ACK2", "Acknowledgement of acknowledgement" },
|
||||
[2] = { "LightACK", "Light Acknowledgement" },
|
||||
[3] = { "NAK", "Loss report (NAK)" },
|
||||
[4] = { "TimeoutNAK", "Loss report re-transmission (TimeoutNAK)" },
|
||||
[5] = { "Handshake", "Handshake" },
|
||||
[6] = { "HandshakeACK", "Acknowledgement of Handshake" },
|
||||
[7] = { "ProbeTail", "Probe tail" },
|
||||
[8] = { "HandshakeRequest", "Request a Handshake" }
|
||||
}
|
||||
|
||||
local message_positions = {
|
||||
[0] = "ONLY",
|
||||
[1] = "LAST",
|
||||
[2] = "FIRST",
|
||||
[3] = "MIDDLE"
|
||||
}
|
||||
|
||||
local packet_types = {
|
||||
[0] = "Unknown",
|
||||
[1] = "StunResponse",
|
||||
[2] = "DomainList",
|
||||
[3] = "Ping",
|
||||
[4] = "PingReply",
|
||||
[5] = "KillAvatar",
|
||||
[6] = "AvatarData",
|
||||
[7] = "InjectAudio",
|
||||
[8] = "MixedAudio",
|
||||
[9] = "MicrophoneAudioNoEcho",
|
||||
[10] = "MicrophoneAudioWithEcho",
|
||||
[11] = "BulkAvatarData",
|
||||
[12] = "SilentAudioFrame",
|
||||
[13] = "DomainListRequest",
|
||||
[14] = "RequestAssignment",
|
||||
[15] = "CreateAssignment",
|
||||
[16] = "DomainConnectionDenied",
|
||||
[17] = "MuteEnvironment",
|
||||
[18] = "AudioStreamStats",
|
||||
[19] = "DomainServerPathQuery",
|
||||
[20] = "DomainServerPathResponse",
|
||||
[21] = "DomainServerAddedNode",
|
||||
[22] = "ICEServerPeerInformation",
|
||||
[23] = "ICEServerQuery",
|
||||
[24] = "OctreeStats",
|
||||
[25] = "Jurisdiction",
|
||||
[26] = "JurisdictionRequest",
|
||||
[27] = "AssignmentClientStatus",
|
||||
[28] = "NoisyMute",
|
||||
[29] = "AvatarIdentity",
|
||||
[30] = "AvatarBillboard",
|
||||
[31] = "DomainConnectRequest",
|
||||
[32] = "DomainServerRequireDTLS",
|
||||
[33] = "NodeJsonStats",
|
||||
[34] = "OctreeDataNack",
|
||||
[35] = "StopNode",
|
||||
[36] = "AudioEnvironment",
|
||||
[37] = "EntityEditNack",
|
||||
[38] = "ICEServerHeartbeat",
|
||||
[39] = "ICEPing",
|
||||
[40] = "ICEPingReply",
|
||||
[41] = "EntityData",
|
||||
[42] = "EntityQuery",
|
||||
[43] = "EntityAdd",
|
||||
[44] = "EntityErase",
|
||||
[45] = "EntityEdit",
|
||||
[46] = "DomainServerConnectionToken",
|
||||
[47] = "DomainSettingsRequest",
|
||||
[48] = "DomainSettings",
|
||||
[49] = "AssetGet",
|
||||
[50] = "AssetGetReply",
|
||||
[51] = "AssetUpload",
|
||||
[52] = "AssetUploadReply",
|
||||
[53] = "AssetGetInfo",
|
||||
[54] = "AssetGetInfoReply"
|
||||
}
|
||||
|
||||
local unsourced_packet_types = {
|
||||
["DomainList"] = true
|
||||
}
|
||||
|
||||
function p_hfudt.dissector(buf, pinfo, tree)
|
||||
|
||||
-- make sure this isn't a STUN packet - those don't follow HFUDT format
|
||||
if pinfo.dst == Address.ip("stun.highfidelity.io") then return end
|
||||
|
||||
-- validate that the packet length is at least the minimum control packet size
|
||||
if buf:len() < 4 then return end
|
||||
|
||||
-- create a subtree for HFUDT
|
||||
subtree = tree:add(p_hfudt, buf(0))
|
||||
|
||||
-- set the packet length
|
||||
subtree:add(f_length, buf:len())
|
||||
|
||||
-- pull out the entire first word
|
||||
local first_word = buf(0, 4):le_uint()
|
||||
|
||||
-- pull out the control bit and add it to the subtree
|
||||
local control_bit = bit32.rshift(first_word, 31)
|
||||
subtree:add(f_control_bit, control_bit)
|
||||
|
||||
local data_length = 0
|
||||
|
||||
if control_bit == 1 then
|
||||
-- dissect the control packet
|
||||
pinfo.cols.protocol = p_hfudt.name .. " Control"
|
||||
|
||||
-- remove the control bit and shift to the right to get the type value
|
||||
local shifted_type = bit32.rshift(bit32.lshift(first_word, 1), 17)
|
||||
local type = subtree:add(f_control_type, shifted_type)
|
||||
|
||||
if control_types[shifted_type] ~= nil then
|
||||
-- if we know this type then add the name
|
||||
type:append_text(" (".. control_types[shifted_type][1] .. ")")
|
||||
|
||||
subtree:add(f_control_type_text, control_types[shifted_type][1])
|
||||
end
|
||||
|
||||
if shifted_type == 0 or shifted_type == 1 then
|
||||
|
||||
-- this has a sub-sequence number
|
||||
local second_word = buf(4, 4):le_uint()
|
||||
subtree:add(f_control_sub_sequence, bit32.band(second_word, SEQUENCE_NUMBER_MASK))
|
||||
|
||||
local data_index = 8
|
||||
|
||||
if shifted_type == 0 then
|
||||
-- if this is an ACK let's read out the sequence number
|
||||
local sequence_number = buf(8, 4):le_uint()
|
||||
subtree:add(f_ack_sequence_number, bit32.band(sequence_number, SEQUENCE_NUMBER_MASK))
|
||||
|
||||
data_index = data_index + 4
|
||||
end
|
||||
|
||||
data_length = buf:len() - data_index
|
||||
|
||||
-- set the data from whatever is left in the packet
|
||||
subtree:add(f_data, buf(data_index, data_length))
|
||||
|
||||
elseif shifted_type == 2 then
|
||||
-- this is a Light ACK let's read out the sequence number
|
||||
local sequence_number = buf(4, 4):le_uint()
|
||||
subtree:add(f_ack_sequence_number, bit32.band(sequence_number, SEQUENCE_NUMBER_MASK))
|
||||
|
||||
data_length = buf:len() - 4
|
||||
|
||||
-- set the data from whatever is left in the packet
|
||||
subtree:add(f_data, buf(4, data_length))
|
||||
elseif shifted_type == 3 or shifted_type == 4 then
|
||||
if buf:len() <= 12 then
|
||||
-- this is a NAK pull the sequence number or range
|
||||
local sequence_number = buf(4, 4):le_uint()
|
||||
subtree:add(f_nak_sequence_number, bit32.band(sequence_number, SEQUENCE_NUMBER_MASK))
|
||||
|
||||
data_length = buf:len() - 4
|
||||
|
||||
if buf:len() > 8 then
|
||||
local range_end = buf(8, 4):le_uint()
|
||||
subtree:add(f_nak_range_end, bit32.band(range_end, SEQUENCE_NUMBER_MASK))
|
||||
|
||||
data_length = data_length - 4
|
||||
end
|
||||
end
|
||||
else
|
||||
data_length = buf:len() - 4
|
||||
|
||||
-- no sub-sequence number, just read the data
|
||||
subtree:add(f_data, buf(4, data_length))
|
||||
end
|
||||
else
|
||||
-- dissect the data packet
|
||||
pinfo.cols.protocol = p_hfudt.name
|
||||
|
||||
-- set the reliability bit
|
||||
subtree:add(f_reliable_bit, bit32.rshift(first_word, 30))
|
||||
|
||||
local message_bit = bit32.band(0x01, bit32.rshift(first_word, 29))
|
||||
|
||||
-- set the message bit
|
||||
subtree:add(f_message_bit, message_bit)
|
||||
|
||||
-- read the obfuscation level
|
||||
local obfuscation_bits = bit32.band(0x03, bit32.rshift(first_word, 27))
|
||||
subtree:add(f_obfuscation_level, obfuscation_bits)
|
||||
|
||||
-- read the sequence number
|
||||
subtree:add(f_sequence_number, bit32.band(first_word, SEQUENCE_NUMBER_MASK))
|
||||
|
||||
local payload_offset = 4
|
||||
|
||||
-- if the message bit is set, handle the second word
|
||||
if message_bit == 1 then
|
||||
payload_offset = 12
|
||||
|
||||
local second_word = buf(4, 4):le_uint()
|
||||
|
||||
-- read message position from upper 2 bits
|
||||
local message_position = bit32.rshift(second_word, 30)
|
||||
local position = subtree:add(f_message_position, message_position)
|
||||
|
||||
if message_positions[message_position] ~= nil then
|
||||
-- if we know this position then add the name
|
||||
position:append_text(" (".. message_positions[message_position] .. ")")
|
||||
end
|
||||
|
||||
-- read message number from lower 30 bits
|
||||
subtree:add(f_message_number, bit32.band(second_word, 0x3FFFFFFF))
|
||||
|
||||
-- read the message part number
|
||||
subtree:add(f_message_part_number, buf(8, 4):le_uint())
|
||||
end
|
||||
|
||||
-- read the type
|
||||
local packet_type = buf(payload_offset, 1):le_uint()
|
||||
local ptype = subtree:add_le(f_type, buf(payload_offset, 1))
|
||||
local packet_type_text = packet_types[packet_type]
|
||||
if packet_type_text ~= nil then
|
||||
subtree:add(f_type_text, packet_type_text)
|
||||
-- if we know this packet type then add the name
|
||||
ptype:append_text(" (".. packet_type_text .. ")")
|
||||
end
|
||||
|
||||
-- read the version
|
||||
subtree:add_le(f_version, buf(payload_offset + 1, 1))
|
||||
|
||||
local i = payload_offset + 2
|
||||
|
||||
if unsourced_packet_types[packet_type_text] == nil then
|
||||
-- read node local ID
|
||||
local sender_id = buf(payload_offset + 2, 2)
|
||||
subtree:add_le(f_sender_id, sender_id)
|
||||
i = i + 2
|
||||
|
||||
-- read HMAC MD5 hash
|
||||
subtree:add(f_hmac_hash, buf(i, 16))
|
||||
i = i + 16
|
||||
end
|
||||
|
||||
-- Domain packets
|
||||
if packet_type_text == "DomainList" then
|
||||
Dissector.get("hf-domain"):call(buf(i):tvb(), pinfo, tree)
|
||||
end
|
||||
|
||||
-- AvatarData or BulkAvatarDataPacket
|
||||
if packet_type_text == "AvatarData" or packet_type_text == "BulkAvatarData" then
|
||||
Dissector.get("hf-avatar"):call(buf(i):tvb(), pinfo, tree)
|
||||
end
|
||||
|
||||
if packet_type_text == "EntityEdit" then
|
||||
Dissector.get("hf-entity"):call(buf(i):tvb(), pinfo, tree)
|
||||
end
|
||||
end
|
||||
|
||||
-- return the size of the header
|
||||
return buf:len()
|
||||
|
||||
end
|
||||
|
||||
function p_hfudt.init()
|
||||
local udp_dissector_table = DissectorTable.get("udp.port")
|
||||
|
||||
for port=1000, 65000 do
|
||||
udp_dissector_table:add(port, p_hfudt)
|
||||
end
|
||||
end
|
||||
print("Loading hfudt")
|
||||
|
||||
-- create the HFUDT protocol
|
||||
p_hfudt = Proto("hfudt", "HFUDT Protocol")
|
||||
|
||||
-- create fields shared between packets in HFUDT
|
||||
local f_data = ProtoField.string("hfudt.data", "Data")
|
||||
|
||||
-- create the fields for data packets in HFUDT
|
||||
local f_length = ProtoField.uint16("hfudt.length", "Length", base.DEC)
|
||||
local f_control_bit = ProtoField.uint8("hfudt.control", "Control Bit", base.DEC)
|
||||
local f_reliable_bit = ProtoField.uint8("hfudt.reliable", "Reliability Bit", base.DEC)
|
||||
local f_message_bit = ProtoField.uint8("hfudt.message", "Message Bit", base.DEC)
|
||||
local f_obfuscation_level = ProtoField.uint8("hfudt.obfuscation_level", "Obfuscation Level", base.DEC)
|
||||
local f_sequence_number = ProtoField.uint32("hfudt.sequence_number", "Sequence Number", base.DEC)
|
||||
local f_message_position = ProtoField.uint8("hfudt.message_position", "Message Position", base.DEC)
|
||||
local f_message_number = ProtoField.uint32("hfudt.message_number", "Message Number", base.DEC)
|
||||
local f_message_part_number = ProtoField.uint32("hfudt.message_part_number", "Message Part Number", base.DEC)
|
||||
local f_type = ProtoField.uint8("hfudt.type", "Type", base.DEC)
|
||||
local f_version = ProtoField.uint8("hfudt.version", "Version", base.DEC)
|
||||
local f_type_text = ProtoField.string("hfudt.type_text", "TypeText")
|
||||
local f_sender_id = ProtoField.uint16("hfudt.sender_id", "Sender ID", base.DEC)
|
||||
local f_hmac_hash = ProtoField.bytes("hfudt.hmac_hash", "HMAC Hash")
|
||||
|
||||
-- create the fields for control packets in HFUDT
|
||||
local f_control_type = ProtoField.uint16("hfudt.control_type", "Control Type", base.DEC)
|
||||
local f_control_type_text = ProtoField.string("hfudt.control_type_text", "Control Type Text", base.ASCII)
|
||||
local f_ack_sequence_number = ProtoField.uint32("hfudt.ack_sequence_number", "ACKed Sequence Number", base.DEC)
|
||||
local f_control_sub_sequence = ProtoField.uint32("hfudt.control_sub_sequence", "Control Sub-Sequence Number", base.DEC)
|
||||
local f_nak_sequence_number = ProtoField.uint32("hfudt.nak_sequence_number", "NAKed Sequence Number", base.DEC)
|
||||
local f_nak_range_end = ProtoField.uint32("hfudt.nak_range_end", "NAK Range End", base.DEC)
|
||||
|
||||
local SEQUENCE_NUMBER_MASK = 0x07FFFFFF
|
||||
|
||||
p_hfudt.fields = {
|
||||
f_length,
|
||||
f_control_bit, f_reliable_bit, f_message_bit, f_sequence_number, f_type, f_type_text, f_version,
|
||||
f_sender_id, f_hmac_hash,
|
||||
f_message_position, f_message_number, f_message_part_number, f_obfuscation_level,
|
||||
f_control_type, f_control_type_text, f_control_sub_sequence, f_ack_sequence_number, f_nak_sequence_number, f_nak_range_end,
|
||||
f_data
|
||||
}
|
||||
|
||||
local control_types = {
|
||||
[0] = { "ACK", "Acknowledgement" },
|
||||
[1] = { "ACK2", "Acknowledgement of acknowledgement" },
|
||||
[2] = { "LightACK", "Light Acknowledgement" },
|
||||
[3] = { "NAK", "Loss report (NAK)" },
|
||||
[4] = { "TimeoutNAK", "Loss report re-transmission (TimeoutNAK)" },
|
||||
[5] = { "Handshake", "Handshake" },
|
||||
[6] = { "HandshakeACK", "Acknowledgement of Handshake" },
|
||||
[7] = { "ProbeTail", "Probe tail" },
|
||||
[8] = { "HandshakeRequest", "Request a Handshake" }
|
||||
}
|
||||
|
||||
local message_positions = {
|
||||
[0] = "ONLY",
|
||||
[1] = "LAST",
|
||||
[2] = "FIRST",
|
||||
[3] = "MIDDLE"
|
||||
}
|
||||
|
||||
local packet_types = {
|
||||
[0] = "Unknown",
|
||||
[1] = "StunResponse",
|
||||
[2] = "DomainList",
|
||||
[3] = "Ping",
|
||||
[4] = "PingReply",
|
||||
[5] = "KillAvatar",
|
||||
[6] = "AvatarData",
|
||||
[7] = "InjectAudio",
|
||||
[8] = "MixedAudio",
|
||||
[9] = "MicrophoneAudioNoEcho",
|
||||
[10] = "MicrophoneAudioWithEcho",
|
||||
[11] = "BulkAvatarData",
|
||||
[12] = "SilentAudioFrame",
|
||||
[13] = "DomainListRequest",
|
||||
[14] = "RequestAssignment",
|
||||
[15] = "CreateAssignment",
|
||||
[16] = "DomainConnectionDenied",
|
||||
[17] = "MuteEnvironment",
|
||||
[18] = "AudioStreamStats",
|
||||
[19] = "DomainServerPathQuery",
|
||||
[20] = "DomainServerPathResponse",
|
||||
[21] = "DomainServerAddedNode",
|
||||
[22] = "ICEServerPeerInformation",
|
||||
[23] = "ICEServerQuery",
|
||||
[24] = "OctreeStats",
|
||||
[25] = "Jurisdiction",
|
||||
[26] = "JurisdictionRequest",
|
||||
[27] = "AssignmentClientStatus",
|
||||
[28] = "NoisyMute",
|
||||
[29] = "AvatarIdentity",
|
||||
[30] = "AvatarBillboard",
|
||||
[31] = "DomainConnectRequest",
|
||||
[32] = "DomainServerRequireDTLS",
|
||||
[33] = "NodeJsonStats",
|
||||
[34] = "OctreeDataNack",
|
||||
[35] = "StopNode",
|
||||
[36] = "AudioEnvironment",
|
||||
[37] = "EntityEditNack",
|
||||
[38] = "ICEServerHeartbeat",
|
||||
[39] = "ICEPing",
|
||||
[40] = "ICEPingReply",
|
||||
[41] = "EntityData",
|
||||
[42] = "EntityQuery",
|
||||
[43] = "EntityAdd",
|
||||
[44] = "EntityErase",
|
||||
[45] = "EntityEdit",
|
||||
[46] = "DomainServerConnectionToken",
|
||||
[47] = "DomainSettingsRequest",
|
||||
[48] = "DomainSettings",
|
||||
[49] = "AssetGet",
|
||||
[50] = "AssetGetReply",
|
||||
[51] = "AssetUpload",
|
||||
[52] = "AssetUploadReply",
|
||||
[53] = "AssetGetInfo",
|
||||
[54] = "AssetGetInfoReply"
|
||||
}
|
||||
|
||||
local unsourced_packet_types = {
|
||||
["DomainList"] = true
|
||||
}
|
||||
|
||||
function p_hfudt.dissector(buf, pinfo, tree)
|
||||
|
||||
-- make sure this isn't a STUN packet - those don't follow HFUDT format
|
||||
if pinfo.dst == Address.ip("stun.highfidelity.io") then return end
|
||||
|
||||
-- validate that the packet length is at least the minimum control packet size
|
||||
if buf:len() < 4 then return end
|
||||
|
||||
-- create a subtree for HFUDT
|
||||
subtree = tree:add(p_hfudt, buf(0))
|
||||
|
||||
-- set the packet length
|
||||
subtree:add(f_length, buf:len())
|
||||
|
||||
-- pull out the entire first word
|
||||
local first_word = buf(0, 4):le_uint()
|
||||
|
||||
-- pull out the control bit and add it to the subtree
|
||||
local control_bit = bit32.rshift(first_word, 31)
|
||||
subtree:add(f_control_bit, control_bit)
|
||||
|
||||
local data_length = 0
|
||||
|
||||
if control_bit == 1 then
|
||||
-- dissect the control packet
|
||||
pinfo.cols.protocol = p_hfudt.name .. " Control"
|
||||
|
||||
-- remove the control bit and shift to the right to get the type value
|
||||
local shifted_type = bit32.rshift(bit32.lshift(first_word, 1), 17)
|
||||
local type = subtree:add(f_control_type, shifted_type)
|
||||
|
||||
if control_types[shifted_type] ~= nil then
|
||||
-- if we know this type then add the name
|
||||
type:append_text(" (".. control_types[shifted_type][1] .. ")")
|
||||
|
||||
subtree:add(f_control_type_text, control_types[shifted_type][1])
|
||||
end
|
||||
|
||||
if shifted_type == 0 or shifted_type == 1 then
|
||||
|
||||
-- this has a sub-sequence number
|
||||
local second_word = buf(4, 4):le_uint()
|
||||
subtree:add(f_control_sub_sequence, bit32.band(second_word, SEQUENCE_NUMBER_MASK))
|
||||
|
||||
local data_index = 8
|
||||
|
||||
if shifted_type == 0 then
|
||||
-- if this is an ACK let's read out the sequence number
|
||||
local sequence_number = buf(8, 4):le_uint()
|
||||
subtree:add(f_ack_sequence_number, bit32.band(sequence_number, SEQUENCE_NUMBER_MASK))
|
||||
|
||||
data_index = data_index + 4
|
||||
end
|
||||
|
||||
data_length = buf:len() - data_index
|
||||
|
||||
-- set the data from whatever is left in the packet
|
||||
subtree:add(f_data, buf(data_index, data_length))
|
||||
|
||||
elseif shifted_type == 2 then
|
||||
-- this is a Light ACK let's read out the sequence number
|
||||
local sequence_number = buf(4, 4):le_uint()
|
||||
subtree:add(f_ack_sequence_number, bit32.band(sequence_number, SEQUENCE_NUMBER_MASK))
|
||||
|
||||
data_length = buf:len() - 4
|
||||
|
||||
-- set the data from whatever is left in the packet
|
||||
subtree:add(f_data, buf(4, data_length))
|
||||
elseif shifted_type == 3 or shifted_type == 4 then
|
||||
if buf:len() <= 12 then
|
||||
-- this is a NAK pull the sequence number or range
|
||||
local sequence_number = buf(4, 4):le_uint()
|
||||
subtree:add(f_nak_sequence_number, bit32.band(sequence_number, SEQUENCE_NUMBER_MASK))
|
||||
|
||||
data_length = buf:len() - 4
|
||||
|
||||
if buf:len() > 8 then
|
||||
local range_end = buf(8, 4):le_uint()
|
||||
subtree:add(f_nak_range_end, bit32.band(range_end, SEQUENCE_NUMBER_MASK))
|
||||
|
||||
data_length = data_length - 4
|
||||
end
|
||||
end
|
||||
else
|
||||
data_length = buf:len() - 4
|
||||
|
||||
-- no sub-sequence number, just read the data
|
||||
subtree:add(f_data, buf(4, data_length))
|
||||
end
|
||||
else
|
||||
-- dissect the data packet
|
||||
pinfo.cols.protocol = p_hfudt.name
|
||||
|
||||
-- set the reliability bit
|
||||
subtree:add(f_reliable_bit, bit32.rshift(first_word, 30))
|
||||
|
||||
local message_bit = bit32.band(0x01, bit32.rshift(first_word, 29))
|
||||
|
||||
-- set the message bit
|
||||
subtree:add(f_message_bit, message_bit)
|
||||
|
||||
-- read the obfuscation level
|
||||
local obfuscation_bits = bit32.band(0x03, bit32.rshift(first_word, 27))
|
||||
subtree:add(f_obfuscation_level, obfuscation_bits)
|
||||
|
||||
-- read the sequence number
|
||||
subtree:add(f_sequence_number, bit32.band(first_word, SEQUENCE_NUMBER_MASK))
|
||||
|
||||
local payload_offset = 4
|
||||
|
||||
-- if the message bit is set, handle the second word
|
||||
if message_bit == 1 then
|
||||
payload_offset = 12
|
||||
|
||||
local second_word = buf(4, 4):le_uint()
|
||||
|
||||
-- read message position from upper 2 bits
|
||||
local message_position = bit32.rshift(second_word, 30)
|
||||
local position = subtree:add(f_message_position, message_position)
|
||||
|
||||
if message_positions[message_position] ~= nil then
|
||||
-- if we know this position then add the name
|
||||
position:append_text(" (".. message_positions[message_position] .. ")")
|
||||
end
|
||||
|
||||
-- read message number from lower 30 bits
|
||||
subtree:add(f_message_number, bit32.band(second_word, 0x3FFFFFFF))
|
||||
|
||||
-- read the message part number
|
||||
subtree:add(f_message_part_number, buf(8, 4):le_uint())
|
||||
end
|
||||
|
||||
-- read the type
|
||||
local packet_type = buf(payload_offset, 1):le_uint()
|
||||
local ptype = subtree:add_le(f_type, buf(payload_offset, 1))
|
||||
local packet_type_text = packet_types[packet_type]
|
||||
if packet_type_text ~= nil then
|
||||
subtree:add(f_type_text, packet_type_text)
|
||||
-- if we know this packet type then add the name
|
||||
ptype:append_text(" (".. packet_type_text .. ")")
|
||||
end
|
||||
|
||||
-- read the version
|
||||
subtree:add_le(f_version, buf(payload_offset + 1, 1))
|
||||
|
||||
local i = payload_offset + 2
|
||||
|
||||
if unsourced_packet_types[packet_type_text] == nil then
|
||||
-- read node local ID
|
||||
local sender_id = buf(payload_offset + 2, 2)
|
||||
subtree:add_le(f_sender_id, sender_id)
|
||||
i = i + 2
|
||||
|
||||
-- read HMAC MD5 hash
|
||||
subtree:add(f_hmac_hash, buf(i, 16))
|
||||
i = i + 16
|
||||
end
|
||||
|
||||
-- Domain packets
|
||||
if packet_type_text == "DomainList" then
|
||||
Dissector.get("hf-domain"):call(buf(i):tvb(), pinfo, tree)
|
||||
end
|
||||
|
||||
-- AvatarData or BulkAvatarDataPacket
|
||||
if packet_type_text == "AvatarData" or packet_type_text == "BulkAvatarData" then
|
||||
Dissector.get("hf-avatar"):call(buf(i):tvb(), pinfo, tree)
|
||||
end
|
||||
|
||||
if packet_type_text == "EntityEdit" then
|
||||
Dissector.get("hf-entity"):call(buf(i):tvb(), pinfo, tree)
|
||||
end
|
||||
|
||||
if packet_types[packet_type] == "MicrophoneAudioNoEcho" or
|
||||
packet_types[packet_type] == "MicrophoneAudioWithEcho" or
|
||||
packet_types[packet_type] == "SilentAudioFrame" then
|
||||
Dissector.get("hf-audio"):call(buf(i):tvb(), pinfo, tree)
|
||||
end
|
||||
end
|
||||
|
||||
-- return the size of the header
|
||||
return buf:len()
|
||||
|
||||
end
|
||||
|
||||
function p_hfudt.init()
|
||||
local udp_dissector_table = DissectorTable.get("udp.port")
|
||||
|
||||
for port=1000, 65000 do
|
||||
udp_dissector_table:add(port, p_hfudt)
|
||||
end
|
||||
end
|
46
tools/dissectors/2-hf-audio.lua
Normal file
46
tools/dissectors/2-hf-audio.lua
Normal file
|
@ -0,0 +1,46 @@
|
|||
print("Loading hf-audio")
|
||||
|
||||
-- create the audio protocol
|
||||
p_hf_audio = Proto("hf-audio", "HF Audio Protocol")
|
||||
|
||||
-- audio packet fields
|
||||
local f_audio_sequence_number = ProtoField.uint16("hf_audio.sequence_number", "Sequence Number")
|
||||
local f_audio_codec_size = ProtoField.uint32("hf_audio.codec_size", "Codec Size")
|
||||
local f_audio_codec = ProtoField.string("hf_audio.codec", "Codec")
|
||||
local f_audio_is_stereo = ProtoField.bool("hf_audio.is_stereo", "Is Stereo")
|
||||
local f_audio_num_silent_samples = ProtoField.uint16("hf_audio.num_silent_samples", "Num Silent Samples")
|
||||
|
||||
p_hf_audio.fields = {
|
||||
f_audio_sequence_number, f_audio_codec_size, f_audio_codec,
|
||||
f_audio_is_stereo, f_audio_num_silent_samples
|
||||
}
|
||||
|
||||
local packet_type_extractor = Field.new('hfudt.type_text')
|
||||
|
||||
function p_hf_audio.dissector(buf, pinfo, tree)
|
||||
pinfo.cols.protocol = p_hf_audio.name
|
||||
|
||||
audio_subtree = tree:add(p_hf_audio, buf())
|
||||
|
||||
local i = 0
|
||||
|
||||
audio_subtree:add_le(f_audio_sequence_number, buf(i, 2))
|
||||
i = i + 2
|
||||
|
||||
-- figure out the number of bytes the codec name takes
|
||||
local codec_name_bytes = buf(i, 4):le_uint()
|
||||
audio_subtree:add_le(f_audio_codec_size, buf(i, 4))
|
||||
i = i + 4
|
||||
|
||||
audio_subtree:add(f_audio_codec, buf(i, codec_name_bytes))
|
||||
i = i + codec_name_bytes
|
||||
|
||||
local packet_type = packet_type_extractor().value
|
||||
if packet_type == "SilentAudioFrame" then
|
||||
audio_subtree:add_le(f_audio_num_silent_samples, buf(i, 2))
|
||||
i = i + 2
|
||||
else
|
||||
audio_subtree:add_le(f_audio_is_stereo, buf(i, 1))
|
||||
i = i + 1
|
||||
end
|
||||
end
|
|
@ -1,3 +1,5 @@
|
|||
print("Loading hf-avatar")
|
||||
|
||||
-- create the avatar protocol
|
||||
p_hf_avatar = Proto("hf-avatar", "HF Avatar Protocol")
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
print("Loading hf-entity")
|
||||
|
||||
-- create the entity protocol
|
||||
p_hf_entity = Proto("hf-entity", "HF Entity Protocol")
|
||||
|
Loading…
Reference in a new issue