private Quaternion renderableRotation = Quaternion.identity; // GENERATED public void SetRenderableRotation(Quaternion newRenderableRotation) // GENERATED { newRenderableRotation = newRenderableRotation.normalized; // GENERATED if (renderableRotation.ApproxEquals(newRenderableRotation)) // GENERATED { return; // GENERATED } renderableRotation = newRenderableRotation; // GENERATED UpdateRenderableRotation(); // GENERATED }
/// <summary> /// Does the actual movement of the bot /// </summary> /// <param name="pos"></param> protected void walkTo(ScenePresence presence, Vector3 pos) { Vector3 bot_forward = new Vector3(2, 0, 0); Vector3 bot_toward = Vector3.Zero; Vector3 dif = pos - presence.AbsolutePosition; bool isJumping = (Math.Abs(dif.X) < 2 && Math.Abs(dif.Y) < 2 && Math.Abs(dif.Z) > 1.5f) || _amountOfTimesLeftToJump > 0; if (dif != Vector3.Zero) { try { bot_toward = Util.GetNormalizedVector(dif); Quaternion rot_result = llRotBetween(bot_forward, bot_toward); m_bodyDirection = rot_result; } catch (ArgumentException) { } } //if the bot is being forced to turn around 180 degrees, it won't be able to and it will get stuck // and eventually teleport (mantis 2898). This detects when the vector is too close to zero and // needs to have help being turned around so that it can then go in the correct direction if (m_bodyDirection.ApproxEquals(new Quaternion(), 0.01f)) { //Turn to the right until we move far enough away from zero that we will turn around on our own bot_toward = new Vector3(0, 1, 0); Quaternion rot_result = llRotBetween(bot_forward, bot_toward); m_bodyDirection = rot_result; } if (isJumping) { //Add UP_POS as well (meaning that we need to be able to move freely up as well as along the ground) m_movementFlag = (uint)(AgentManager.ControlFlags.AGENT_CONTROL_AT_POS | AgentManager.ControlFlags.AGENT_CONTROL_UP_POS); presence.ShouldJump = true; if (_amountOfTimesLeftToJump == 0) { _amountOfTimesLeftToJump = 10;//Because we need the bot to apply force over multiple frames (just like agents do) } _amountOfTimesLeftToJump--; //Make sure that we aren't jumping too far (apply a constant to make sure of this) const double JUMP_CONST = 0.3; bot_toward = Util.GetNormalizedVector(dif); if (Math.Abs(bot_toward.X) < JUMP_CONST) { bot_toward.X = (float)JUMP_CONST * (bot_toward.X < 0 ? -1 : 1); } if (Math.Abs(bot_toward.Y) < JUMP_CONST) { bot_toward.Y = (float)JUMP_CONST * (bot_toward.Y < 0 ? -1 : 1); } if (presence.PhysicsActor.IsColliding)//After they leave the ground, don't use as much force so we don't send the bot flying into the air { bot_forward = new Vector3(4, 0, 4); } else { bot_forward = new Vector3(2, 0, 2); } Quaternion rot_result = llRotBetween(bot_forward, bot_toward); m_bodyDirection = rot_result; } else { m_movementFlag = (uint)(AgentManager.ControlFlags.AGENT_CONTROL_AT_POS); } if (presence.AllowMovement) { OnBotAgentUpdate(presence, bot_toward, m_movementFlag, m_bodyDirection); } else { OnBotAgentUpdate(presence, Vector3.Zero, (uint)AgentManager.ControlFlags.AGENT_CONTROL_STOP, Quaternion.Identity); } if (!isJumping) { m_movementFlag = (uint)AgentManager.ControlFlags.NONE; } }
public bool ApproxEquals(Pose other) { return(position.ApproxEquals(other.position) && rotation.ApproxEquals(other.rotation)); }
/// <summary> /// Compare the value (not "reference") of the given property. /// Assumption: the caller has already checked if PhysActor exists /// if there are physics properties updated. /// If the value maintained here is different from that in SP data, /// synchronize the two: /// (1) if the cached value has a timestamp newer than lastUpdateByLocalTS /// overwrite the SP's property with the cached value (effectively /// undoing the local write operation that just happened). /// (2) otherwise, copy SP's data and update timestamp and syncID /// as indicated by "lastUpdateByLocalTS" and "syncID". /// </summary> /// <param name="sp"></param> /// <param name="property"></param> /// <param name="lastUpdateByLocalTS"></param> /// <param name="syncID"></param> /// <returns>Return true if the property's value maintained in this /// RegionSyncModule is replaced by SP's data.</returns> private bool CompareValue_UpdateByLocal(ScenePresence sp, SyncableProperties.Type property, long lastUpdateByLocalTS, string syncID) { //DebugLog.WarnFormat("[SYNC INFO PRESENCE] CompareValue_UpdateByLocal: Updating property {0} on sp {1}", property.ToString(), sp.UUID); // Check to see if this property is in the sync cache for this object. // If not, add it and initialize value to value in ScenePresence. bool ret = false; SyncedProperty syncedProperty; CurrentlySyncedProperties.TryGetValue(property, out syncedProperty); // If synced property is not in cache, add it now if (syncedProperty == null) { Object initValue = GetPropertyValue(sp, property); if (initValue != null) { CurrentlySyncedProperties.Add(property, new SyncedProperty(property, initValue, lastUpdateByLocalTS, syncID)); ret = true; } return(ret); } // First, check if the value maintained here is different from that in SP's. // If different, next check if the timestamp in SyncInfo is newer than lastUpdateByLocalTS; // if so (although ideally should not happen, but due to things likc clock not so perfectly // sync'ed, it might happen), overwrite SP's value with what's maintained // in SyncInfo; otherwise, copy SP's data to SyncInfo. Object value = GetPropertyValue(sp, property); // If both null, no update needed if (syncedProperty.LastUpdateValue == null && value == null) { return(false); } switch (property) { default: // If one is null and the other is not, or if the references are different, the property was changed. // This will perform a value comparison for strings in C#. We could use String.Clone instead for string properties. if ((value == null && syncedProperty.LastUpdateValue != null) || (value != null && syncedProperty.LastUpdateValue == null) || (!value.Equals(syncedProperty.LastUpdateValue))) { if (value != null) { // Some values, even if they are not 'equal', might be close enough to be equal. // Note that the 'Equals()' above will most always return 'false' for lists and OSDMaps // since they are probably not the same object. // Returning a 'false' here means the values don't need any updating (they are equal enough). switch (property) { case SyncableProperties.Type.AvatarAppearance: String stringValue = OSDParser.SerializeJsonString((OSDMap)value); String lastStringValue = OSDParser.SerializeJsonString((OSDMap)syncedProperty.LastUpdateValue); if (stringValue == lastStringValue) { return(false); } break; case SyncableProperties.Type.Animations: if (syncedProperty.LastUpdateValue != null) { AnimationSet lastAnimations = new AnimationSet((OSDArray)syncedProperty.LastUpdateValue); // Get the home region for this presence (the client manager the presence is connected to). string cachedRealRegionName = (string)(CurrentlySyncedProperties[SyncableProperties.Type.RealRegion].LastUpdateValue); if (cachedRealRegionName != Scene.Name && sp.Animator.Animations.ToArray().Length == 0) { // If this is not the originating region for this presence and there is no additional // animations being added, this simulator does not change the animation. // THIS IS A HORRIBLE KLUDGE. FIGURE OUT THE REAL SOLUTION!! // The problem is that animations are changed by every simulator (setting default // sit and stand when parentID changes) and the updates conflict/override the real // settings (like a scripted sit animation). // DebugLog.DebugFormat("{0} CompareValue_UpdateByLocal. Not home sim or no anim change. spID={1}, homeSim={2}, thisSim={3}, anims={4}", // LogHeader, sp.LocalId, cachedRealRegionName, Scene.Name, sp.Animator.Animations.ToArray().Length); // DEBUG DEBUG return(false); } if (lastAnimations.Equals(sp.Animator.Animations)) { // DebugLog.DebugFormat("{0} CompareValue_UpdateByLocal. Equal anims. spID={1}, sp.Anim={2}, lastAnim={3}", // LogHeader, sp.LocalId, sp.Animator.Animations, lastAnimations); // DEBUG DEBUG return(false); } else { // If locally storing a new value of the animation, don't check for the time. // DebugLog.DebugFormat("{0} CompareValue_UpdateByLocal. Not equal anims. spID={1}, sp.Anim={2}, lastAnim={3}", // LogHeader, sp.LocalId, sp.Animator.Animations, lastAnimations); // DEBUG DEBUG syncedProperty.UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, value); return(true); } } break; case SyncableProperties.Type.Velocity: case SyncableProperties.Type.PA_Velocity: case SyncableProperties.Type.PA_TargetVelocity: case SyncableProperties.Type.RotationalVelocity: case SyncableProperties.Type.AngularVelocity: { Vector3 partVal = (Vector3)value; Vector3 lastVal = (Vector3)syncedProperty.LastUpdateValue; // If velocity difference is small but not zero, don't update if (partVal.ApproxEquals(lastVal, VELOCITY_TOLERANCE) && !partVal.Equals(Vector3.Zero)) { return(false); } break; } case SyncableProperties.Type.RotationOffset: case SyncableProperties.Type.Orientation: { Quaternion partVal = (Quaternion)value; Quaternion lastVal = (Quaternion)syncedProperty.LastUpdateValue; if (partVal.ApproxEquals(lastVal, ROTATION_TOLERANCE)) { return(false); } break; } case SyncableProperties.Type.OffsetPosition: case SyncableProperties.Type.AbsolutePosition: case SyncableProperties.Type.Position: case SyncableProperties.Type.GroupPosition: { Vector3 partVal = (Vector3)value; Vector3 lastVal = (Vector3)syncedProperty.LastUpdateValue; if (partVal.ApproxEquals(lastVal, POSITION_TOLERANCE)) { return(false); } break; } } } // If we get here, the values are not equal and we need to update the cached value if the // new value is timestamp newer. if (lastUpdateByLocalTS >= syncedProperty.LastUpdateTimeStamp) { // DebugLog.DebugFormat("{0} CompareValue_UpdateByLocal (property={1}): TS >= lastTS (updating SyncInfo)", LogHeader, property); syncedProperty.UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, value); return(true); } } break; } return(false); }