diff --git a/assignment-client/src/entities/EntityServer.cpp b/assignment-client/src/entities/EntityServer.cpp
index 06632dabb0..dde8a01b26 100644
--- a/assignment-client/src/entities/EntityServer.cpp
+++ b/assignment-client/src/entities/EntityServer.cpp
@@ -17,7 +17,6 @@
 #include <QJsonDocument>
 
 #include <EntityTree.h>
-#include <SimpleEntitySimulation.h>
 #include <ResourceCache.h>
 #include <ScriptCache.h>
 #include <EntityEditFilters.h>
@@ -36,7 +35,7 @@ const char* LOCAL_MODELS_PERSIST_FILE = "resources/models.svo";
 
 EntityServer::EntityServer(ReceivedMessage& message) :
     OctreeServer(message),
-    _entitySimulation(NULL),
+    _entitySimulation(nullptr),
     _dynamicDomainVerificationTimer(this)
 {
     DependencyManager::set<ResourceManager>();
diff --git a/assignment-client/src/entities/EntityServer.h b/assignment-client/src/entities/EntityServer.h
index 4d3f1ee89f..9bb3a237e0 100644
--- a/assignment-client/src/entities/EntityServer.h
+++ b/assignment-client/src/entities/EntityServer.h
@@ -16,9 +16,11 @@
 
 #include <memory>
 
-#include "EntityItem.h"
+#include <EntityItem.h>
+#include <EntityTree.h>
+#include <SimpleEntitySimulation.h>
+
 #include "EntityServerConsts.h"
-#include "EntityTree.h"
 
 /// Handles assignments of type EntityServer - sending entities to various clients.
 
@@ -27,9 +29,6 @@ struct ViewerSendingStats {
     quint64 lastEdited;
 };
 
-class SimpleEntitySimulation;
-using SimpleEntitySimulationPointer = std::shared_ptr<SimpleEntitySimulation>;
-
 class EntityServer : public OctreeServer, public NewlyCreatedEntityHook {
     Q_OBJECT
 public:
diff --git a/assignment-client/src/scripts/EntityScriptServer.cpp b/assignment-client/src/scripts/EntityScriptServer.cpp
index f1a6c97831..514eb62380 100644
--- a/assignment-client/src/scripts/EntityScriptServer.cpp
+++ b/assignment-client/src/scripts/EntityScriptServer.cpp
@@ -301,10 +301,17 @@ void EntityScriptServer::run() {
 
     entityScriptingInterface->setEntityTree(_entityViewer.getTree());
 
-    DependencyManager::set<AssignmentParentFinder>(_entityViewer.getTree());
+    auto treePtr = _entityViewer.getTree();
+    DependencyManager::set<AssignmentParentFinder>(treePtr);
 
+    if (!_entitySimulation) {
+        SimpleEntitySimulationPointer simpleSimulation { new SimpleEntitySimulation() };
+        simpleSimulation->setEntityTree(treePtr);
+        treePtr->setSimulation(simpleSimulation);
+        _entitySimulation = simpleSimulation;
+    }
 
-    auto tree = _entityViewer.getTree().get();
+    auto tree = treePtr.get();
     connect(tree, &EntityTree::deletingEntity, this, &EntityScriptServer::deletingEntity, Qt::QueuedConnection);
     connect(tree, &EntityTree::addingEntity, this, &EntityScriptServer::addingEntity, Qt::QueuedConnection);
     connect(tree, &EntityTree::entityServerScriptChanging, this, &EntityScriptServer::entityServerScriptChanging, Qt::QueuedConnection);
@@ -451,6 +458,7 @@ void EntityScriptServer::resetEntitiesScriptEngine() {
 
     connect(newEngine.data(), &ScriptEngine::update, this, [this] {
         _entityViewer.queryOctree();
+        _entityViewer.getTree()->preUpdate();
         _entityViewer.getTree()->update();
     });
 
diff --git a/assignment-client/src/scripts/EntityScriptServer.h b/assignment-client/src/scripts/EntityScriptServer.h
index 944fee36a3..b795339174 100644
--- a/assignment-client/src/scripts/EntityScriptServer.h
+++ b/assignment-client/src/scripts/EntityScriptServer.h
@@ -21,6 +21,7 @@
 #include <EntityEditPacketSender.h>
 #include <plugins/CodecPlugin.h>
 #include <ScriptEngine.h>
+#include <SimpleEntitySimulation.h>
 #include <ThreadedAssignment.h>
 #include "../entities/EntityTreeHeadlessViewer.h"
 
@@ -75,6 +76,7 @@ private:
 
     static int _entitiesScriptEngineCount;
     ScriptEnginePointer _entitiesScriptEngine;
+    SimpleEntitySimulationPointer _entitySimulation;
     EntityEditPacketSender _entityEditSender;
     EntityTreeHeadlessViewer _entityViewer;
 
diff --git a/interface/src/avatar/OtherAvatar.cpp b/interface/src/avatar/OtherAvatar.cpp
index 8c8c42679b..5673c2443f 100755
--- a/interface/src/avatar/OtherAvatar.cpp
+++ b/interface/src/avatar/OtherAvatar.cpp
@@ -512,13 +512,13 @@ void OtherAvatar::handleChangedAvatarEntityData() {
                 entity->setParentID(NULL_ID);
                 entity->setParentID(oldParentID);
 
-                if (entity->stillHasMyGrabAction()) {
+                if (entity->stillHasMyGrab()) {
                     // For this case: we want to ignore transform+velocities coming from authoritative OtherAvatar
                     // because the MyAvatar is grabbing and we expect the local grab state
                     // to have enough information to prevent simulation drift.
                     //
                     // Clever readers might realize this could cause problems.  For example,
-                    // if an ignored OtherAvagtar were to simultanously grab the object then there would be
+                    // if an ignored OtherAvatar were to simultanously grab the object then there would be
                     // a noticeable discrepancy between participants in the distributed physics simulation,
                     // however the difference would be stable and would not drift.
                     properties.clearTransformOrVelocityChanges();
diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp
index 747d1e9a77..53afb34de5 100644
--- a/libraries/entities/src/EntityItem.cpp
+++ b/libraries/entities/src/EntityItem.cpp
@@ -798,7 +798,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
     auto lastEdited = lastEditedFromBufferAdjusted;
     bool otherOverwrites = overwriteLocalData && !weOwnSimulation;
     // calculate hasGrab once outside the lambda rather than calling it every time inside
-    bool hasGrab = stillHasGrabAction();
+    bool hasGrab = stillHasGrab();
     auto shouldUpdate = [lastEdited, otherOverwrites, filterRejection, hasGrab](quint64 updatedTimestamp, bool valueChanged) {
         if (hasGrab) {
             return false;
@@ -1444,7 +1444,7 @@ void EntityItem::getTransformAndVelocityProperties(EntityItemProperties& propert
 
 void EntityItem::upgradeScriptSimulationPriority(uint8_t priority) {
     uint8_t newPriority = glm::max(priority, _scriptSimulationPriority);
-    if (newPriority < SCRIPT_GRAB_SIMULATION_PRIORITY && stillHasMyGrabAction()) {
+    if (newPriority < SCRIPT_GRAB_SIMULATION_PRIORITY && stillHasMyGrab()) {
         newPriority = SCRIPT_GRAB_SIMULATION_PRIORITY;
     }
     if (newPriority != _scriptSimulationPriority) {
@@ -1457,7 +1457,7 @@ void EntityItem::upgradeScriptSimulationPriority(uint8_t priority) {
 void EntityItem::clearScriptSimulationPriority() {
     // DO NOT markDirtyFlags(Simulation::DIRTY_SIMULATION_OWNERSHIP_PRIORITY) here, because this
     // is only ever called from the code that actually handles the dirty flags, and it knows best.
-    _scriptSimulationPriority = stillHasMyGrabAction() ? SCRIPT_GRAB_SIMULATION_PRIORITY : 0;
+    _scriptSimulationPriority = stillHasMyGrab() ? SCRIPT_GRAB_SIMULATION_PRIORITY : 0;
 }
 
 void EntityItem::setPendingOwnershipPriority(uint8_t priority) {
@@ -2204,7 +2204,7 @@ void EntityItem::enableNoBootstrap() {
 }
 
 void EntityItem::disableNoBootstrap() {
-    if (!stillHasMyGrabAction()) {
+    if (!stillHasMyGrab()) {
         _flags &= ~Simulation::SPECIAL_FLAG_NO_BOOTSTRAPPING;
         _flags |= Simulation::DIRTY_COLLISION_GROUP; // may need to not collide with own avatar
 
@@ -2290,33 +2290,25 @@ bool EntityItem::removeAction(EntitySimulationPointer simulation, const QUuid& a
     return success;
 }
 
-bool EntityItem::stillHasGrabAction() const {
-    return !_grabActions.empty();
+bool EntityItem::stillHasGrab() const {
+    return !(_grabs.empty());
 }
 
-// retutrns 'true' if there exists an action that returns 'true' for EntityActionInterface::isMine()
+// returns 'true' if there exists an action that returns 'true' for EntityActionInterface::isMine()
 // (e.g. the action belongs to the MyAvatar instance)
-bool EntityItem::stillHasMyGrabAction() const {
-    QList<EntityDynamicPointer> holdActions = getActionsOfType(DYNAMIC_TYPE_HOLD);
-    QList<EntityDynamicPointer>::const_iterator i = holdActions.begin();
-    while (i != holdActions.end()) {
-        EntityDynamicPointer action = *i;
-        if (action->isMine()) {
-            return true;
-        }
-        i++;
+bool EntityItem::stillHasMyGrab() const {
+    bool foundGrab = false;
+    if (!_grabs.empty()) {
+        _grabsLock.withReadLock([&] {
+            foreach (const GrabPointer &grab, _grabs) {
+                if (grab->getOwnerID() == Physics::getSessionUUID()) {
+                    foundGrab = true;
+                    break;
+                }
+            }
+        });
     }
-    QList<EntityDynamicPointer> farGrabActions = getActionsOfType(DYNAMIC_TYPE_FAR_GRAB);
-    i = farGrabActions.begin();
-    while (i != farGrabActions.end()) {
-        EntityDynamicPointer action = *i;
-        if (action->isMine()) {
-            return true;
-        }
-        i++;
-    }
-
-    return false;
+    return foundGrab;
 }
 
 bool EntityItem::removeActionInternal(const QUuid& actionID, EntitySimulationPointer simulation) {
diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h
index 5c7596f6dc..3274379ee9 100644
--- a/libraries/entities/src/EntityItem.h
+++ b/libraries/entities/src/EntityItem.h
@@ -569,7 +569,7 @@ public:
     static void setPrimaryViewFrustumPositionOperator(std::function<glm::vec3()> getPrimaryViewFrustumPositionOperator) { _getPrimaryViewFrustumPositionOperator = getPrimaryViewFrustumPositionOperator; }
     static glm::vec3 getPrimaryViewFrustumPosition() { return _getPrimaryViewFrustumPositionOperator(); }
 
-    bool stillHasMyGrabAction() const;
+    bool stillHasMyGrab() const;
 
     bool needsRenderUpdate() const { return resultWithReadLock<bool>([&] { return _needsRenderUpdate; }); }
     void setNeedsRenderUpdate(bool needsRenderUpdate) { withWriteLock([&] { _needsRenderUpdate = needsRenderUpdate; }); }
@@ -585,7 +585,7 @@ protected:
     void setSimulated(bool simulated) { _simulated = simulated; }
 
     const QByteArray getDynamicDataInternal() const;
-    bool stillHasGrabAction() const;
+    bool stillHasGrab() const;
     void setDynamicDataInternal(QByteArray dynamicData);
 
     virtual void dimensionsChanged() override;
diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp
index dca3ac595a..6c12c6d019 100644
--- a/libraries/entities/src/EntityTree.cpp
+++ b/libraries/entities/src/EntityTree.cpp
@@ -2246,8 +2246,8 @@ void EntityTree::preUpdate() {
 void EntityTree::update(bool simulate) {
     PROFILE_RANGE(simulation_physics, "UpdateTree");
     PerformanceTimer perfTimer("updateTree");
-    withWriteLock([&] {
-        if (simulate && _simulation) {
+    if (simulate && _simulation) {
+        withWriteLock([&] {
             _simulation->updateEntities();
             {
                 PROFILE_RANGE(simulation_physics, "Deletes");
@@ -2265,8 +2265,8 @@ void EntityTree::update(bool simulate) {
                     deleteEntities(idsToDelete, true);
                 }
             }
-        }
-    });
+        });
+    }
 }
 
 quint64 EntityTree::getAdjustedConsiderSince(quint64 sinceTime) {
diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h
index dc1c79e0eb..52a8c8db16 100644
--- a/libraries/networking/src/udt/PacketHeaders.h
+++ b/libraries/networking/src/udt/PacketHeaders.h
@@ -274,6 +274,7 @@ enum class EntityVersion : PacketVersion {
     TextUnlit,
     ShadowBiasAndDistance,
     TextEntityFonts,
+    ScriptServerKinematicMotion,
 
     // Add new versions above here
     NUM_PACKET_TYPE,
diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp
index 67aa7d2d7d..68c8266e9f 100644
--- a/libraries/physics/src/EntityMotionState.cpp
+++ b/libraries/physics/src/EntityMotionState.cpp
@@ -740,7 +740,8 @@ bool EntityMotionState::shouldSendBid() const {
         && (_region == workload::Region::R1)
         && _ownershipState != EntityMotionState::OwnershipState::Unownable
         && glm::max(glm::max(VOLUNTEER_SIMULATION_PRIORITY, _bumpedPriority), _entity->getScriptSimulationPriority()) >= _entity->getSimulationPriority()
-        && !_entity->getLocked();
+        && !_entity->getLocked()
+        && (!_body->isStaticOrKinematicObject() || _entity->stillHasMyGrab());
 }
 
 void EntityMotionState::setRigidBody(btRigidBody* body) {