private void Enable(ScriptEventData data) { if (subscriptions == null) { IEventSubscription sub = ScenePrivate.User.Subscribe(User.AddUser, (UserData ud) => { SimpleData sd = new SimpleData(this); sd.SourceObjectId = ObjectPrivate.ObjectId; sd.AgentInfo = ScenePrivate.FindAgent(ud.User)?.AgentInfo; if (sd.AgentInfo != null) { sd.ObjectId = sd.AgentInfo.ObjectId; } visitors[ud.User] = sd.AgentInfo; SendToAll(OnAgentEnter, sd); }); subscriptions = sub.Unsubscribe; sub = ScenePrivate.User.Subscribe(User.RemoveUser, (UserData ud) => { SimpleData sd = new SimpleData(this); sd.SourceObjectId = ObjectPrivate.ObjectId; AgentInfo agentInfo = null; if (visitors.TryGetValue(ud.User, out agentInfo)) { sd.AgentInfo = agentInfo; visitors.Remove(ud.User); } SendToAll(OnAgentExit, sd); }); subscriptions += sub.Unsubscribe; } }
protected override void SimpleInit() { rnd = new Random(); bool noTimerSet = (InitialDelay <= 0.0f) && (RandomInitialDelayMax <= 0.0f) && (Interval <= 0.0f) && (RandomIntervalMax <= 0.0f); if (noTimerSet) { Log.Write(LogLevel.Warning, "Delay and Interval are both zero in SimpleTimedEvents, no messages will be sent."); return; } thisObjectData = new SimpleData(this); thisObjectData.SourceObjectId = ObjectPrivate.ObjectId; thisObjectData.AgentInfo = null; thisObjectData.ObjectId = ObjectPrivate.ObjectId; if (StartEnabled) { Enable(); } SubscribeToAll(EnableEvent, (Data) => { Enable(); }); SubscribeToAll(DisableEvent, (Data) => { Disable(); }); }
protected SimpleData GetEventData(AgentInfo agentInfo) { SimpleData data = new SimpleData(this); data.AgentInfo = agentInfo; return(data); }
protected override void SimpleInit() { thisObjectData = new SimpleData(this); thisObjectData.SourceObjectId = ObjectPrivate.ObjectId; thisObjectData.AgentInfo = null; thisObjectData.ObjectId = ObjectPrivate.ObjectId; timerEventsBySeconds = new SortedDictionary <int, string>(); if (!TryParseTimePropertyToSeconds(StartingTime, out startingTimeInSeconds)) { Log.Write(LogLevel.Error, __SimpleTag, "Could not convert start time '" + StartingTime + "' to seconds!"); return; } ParseTimeCommand(CommandATime, CommandAMessage, "Command A"); ParseTimeCommand(CommandBTime, CommandBMessage, "Command B"); ParseTimeCommand(CommandCTime, CommandCMessage, "Command C"); ParseTimeCommand(CommandDTime, CommandDMessage, "Command D"); ParseTimeCommand(CommandETime, CommandEMessage, "Command E"); if (StartEnabled) { Enable(); } SubscribeToAll(EnableEvent, (Data) => { Enable(); }); SubscribeToAll(DisableEvent, (Data) => { Disable(); }); }
private SimpleData GetEventData(AgentInfo agentInfo) { SimpleData eventData = new SimpleData(this); eventData.SourceObjectId = ObjectPrivate.ObjectId; eventData.AgentInfo = agentInfo; eventData.ObjectId = ObjectPrivate.ObjectId; return(eventData); }
protected SimpleData GetEventData(SessionId session, ObjectId source) { SimpleData data = new SimpleData(this); data.SourceObjectId = source; data.AgentInfo = ScenePrivate.FindAgent(session)?.AgentInfo; data.ObjectId = data.AgentInfo != null ? data.AgentInfo.ObjectId : source; return(data); }
protected SimpleData GetEventData(AgentInfo agentInfo) { SimpleData data = new SimpleData(this); data.AgentInfo = agentInfo; data.ObjectId = agentInfo != null ? agentInfo.ObjectId : ObjectPrivate.ObjectId; data.SourceObjectId = ObjectPrivate.ObjectId; return(data); }
protected override void SimpleInit() { // Any \n put in the parameter will not get converted to newlines, so convert them here. string prompt = MyInteraction.GetPrompt(); if (prompt.Contains("\\n")) { MyInteraction.SetPrompt(prompt.Replace("\\n", "\n")); } if (!StartEnabled) { MyInteraction.SetEnabled(false); } SubscribeToAll(DisableEvent, (data) => { MyInteraction.SetEnabled(false); }); SubscribeToAll(EnableEvent, (data) => { MyInteraction.SetEnabled(true); }); SubscribeToAll(ResetEvent, (data) => { Reset(OnClick); }); if (!string.IsNullOrWhiteSpace(OnClick)) { if (MaxEventsPerSecond >= 100 || MaxEventsPerSecond <= 0) { MyInteraction.Subscribe((InteractionData data) => { if (DisableOnClick) { MyInteraction.SetEnabled(data.AgentId, false); } SimpleData sd = new SimpleData(this); sd.SourceObjectId = ObjectPrivate.ObjectId; sd.AgentInfo = ScenePublic.FindAgent(data.AgentId)?.AgentInfo; sd.ObjectId = sd.AgentInfo != null ? sd.AgentInfo.ObjectId : ObjectId.Invalid; SendToAll(OnClick, sd); }); } else { TimeSpan waitTime = TimeSpan.FromSeconds(1.0 / MaxEventsPerSecond); while (true) { InteractionData data = (InteractionData)WaitFor(MyInteraction.Subscribe); if (DisableOnClick) { MyInteraction.SetEnabled(data.AgentId, false); } SimpleData sd = new SimpleData(this); sd.SourceObjectId = ObjectPrivate.ObjectId; sd.AgentInfo = ScenePublic.FindAgent(data.AgentId)?.AgentInfo; sd.ObjectId = sd.AgentInfo != null ? sd.AgentInfo.ObjectId : ObjectId.Invalid; SendToAll(OnClick, sd); Wait(waitTime); } } } }
private SimpleData GrabReleaseData(HeldObjectData holdData) { SimpleData sd = new SimpleData(this); sd.ObjectId = holdData.ObjectId; sd.SourceObjectId = ObjectPrivate.ObjectId; // expected to equal sd.ObjectId sd.AgentInfo = ScenePublic.FindAgent(holdData.HeldObjectInfo.SessionId)?.AgentInfo; return(sd); }
private SimpleData SitStandData(SitObjectData sitData) { SimpleData sd = new SimpleData(this); sd.ObjectId = sitData.ObjectId; sd.SourceObjectId = ObjectPrivate.ObjectId; // expected to equal sd.ObjectId sd.AgentInfo = ScenePrivate.FindAgent(sitData.SitObjectInfo.SessionId)?.AgentInfo; return(sd); }
internal void SendToAll(SimpleData data) { Next(); ThisScript.SimpleLog(LogLevel.Info, "Sending " + Current.Events.Length + " events: " + string.Join(", ", Current.Events)); foreach (string eventName in Current.Events) { ThisScript.PostSimpleEvent(eventName, data); } }
public int Hit(AgentInfo agent, CommandData data) { try { SimpleData simpleData = new SimpleData(this); simpleData.AgentInfo = agent; simpleData.ObjectId = agent.ObjectId; simpleData.SourceObjectId = ObjectPrivate.ObjectId; SendToAll(ShotHitEvent, simpleData); } catch (System.Exception) { } return(PointValue); }
void OnCommand(CommandData data) { if (!Enabled) { return; } CommandFlag currentHotkey = flagFromString(data.Command); if (currentHotkey == CommandFlag.Invalid) { return; } if (data.Action == CommandAction.Pressed) { if ((currentHotkey & HeldKeys[data.SessionId]) == 0x0) { string sendEvents; if (CommandEvents.TryGetValue(currentHotkey, out sendEvents)) { SimpleData sd = new SimpleData(this); sd.SourceObjectId = ObjectPrivate.ObjectId; sd.AgentInfo = ScenePrivate.FindAgent(data.SessionId)?.AgentInfo; sd.ObjectId = (sd.AgentInfo != null) ? sd.AgentInfo.ObjectId : ObjectId.Invalid; SendToAll(sendEvents, sd); } HeldKeys[data.SessionId] |= currentHotkey; } } else if (data.Action == CommandAction.Released) { if ((currentHotkey & HeldKeys[data.SessionId]) != 0x0) { string sendEvents; if (CommandReleaseEvents.TryGetValue(currentHotkey, out sendEvents)) { SimpleData sd = new SimpleData(this); sd.SourceObjectId = ObjectPrivate.ObjectId; sd.AgentInfo = ScenePrivate.FindAgent(data.SessionId)?.AgentInfo; sd.ObjectId = (sd.AgentInfo != null) ? sd.AgentInfo.ObjectId : ObjectId.Invalid; SendToAll(sendEvents, sd); } HeldKeys[data.SessionId] &= ~currentHotkey; } } }
protected override void SimpleInit() { if (!ObjectPrivate.TryGetFirstComponent(out RigidBody)) { Log.Write(LogLevel.Error, "Could not start " + GetType().Name + " because no RigidBodyComponent was found."); return; } SubscribeToAll(DisableEvent, (data) => { enabled = false; }); SubscribeToAll(EnableEvent, (data) => { enabled = true; }); enabled = StartEnabled; // Always subscribe to collisions to manage the agentsInTrigger list. // enabled will determine whether events are sent. if (collisionSubscription == null) { collisionSubscription = RigidBody.Subscribe(CollisionEventType.AllCollisions, OnCollision); } ScenePrivate.User.Subscribe(User.RemoveUser, (UserData data) => { foreach (var agent in agentsInTrigger.Where((kvp) => kvp.Value.SessionId == data.User)) { SimpleData sd = new SimpleData(this); sd.ObjectId = agent.Value.ObjectId; sd.AgentInfo = agent.Value; sd.SourceObjectId = ObjectPrivate.ObjectId; agentsInTrigger.Remove(agent.Key); if (enabled) { SendToAll(OnAgentExit, sd); ++userLoggedOut; if (agentsInTrigger.Count == 0) { SendToAll(OnLastAgentTriggerExit, sd); } } break; // should only ever be 1 or none. } }); agentsInTrigger = new Dictionary <ObjectId, AgentInfo>(); }
protected override void SimpleInit() { CollisionSimpleData = new SimpleData(this); CollisionSimpleData.ObjectId = ObjectPrivate.ObjectId; CollisionSimpleData.SourceObjectId = ObjectPrivate.ObjectId; if (StartEnabled) { Subscribe(null); } if (TextString.Length > cMaxTextLength) { Log.Write(LogLevel.Warning, "HintText", "TextString too long: length is " + TextString.Length + " characters, truncating to " + cMaxTextLength); m_textString = TextString.Substring(0, cMaxTextLength); } else { m_textString = TextString; } m_vrStringEnabled = !string.IsNullOrWhiteSpace(VRTextString); if (VRTextString.Length > cMaxTextLength) { Log.Write(LogLevel.Warning, "HintText", "VRTextString too long: length is " + VRTextString.Length + " characters, truncating to " + cMaxTextLength); m_vrTextString = VRTextString.Substring(0, cMaxTextLength); } else { m_vrTextString = VRTextString; } foreach (var trigger in Triggers) { if (trigger != null && trigger.IsValid && trigger.IsTriggerVolume()) { trigger.Subscribe(CollisionEventType.Trigger, (data) => OnCollide(data, trigger)); } } SubscribeToAll(EnableEvent, Subscribe); SubscribeToAll(DisableEvent, Unsubscribe); }
private void OnDialogResponse(string response, SessionId agentId) { SimpleData sd = new SimpleData(this); sd.SourceObjectId = ObjectPrivate.ObjectId; sd.AgentInfo = ScenePrivate.FindAgent(agentId)?.AgentInfo; sd.ObjectId = sd.AgentInfo != null ? sd.AgentInfo.ObjectId : ObjectId.Invalid; if ((response == LeftButtonText) && !string.IsNullOrWhiteSpace(LeftButtonClickMessage)) { SendToAll(LeftButtonClickMessage, sd); } if ((response == RightButtonText) && !string.IsNullOrWhiteSpace(RightButtonClickMessage)) { SendToAll(RightButtonClickMessage, sd); } }
protected override void SimpleInit() { if (!ObjectPrivate.IsMovable) { Log.Write(LogLevel.Error, "Object is not movable"); return; } mover = ObjectPrivate.Mover; thisObjectData = new SimpleData(this); thisObjectData.SourceObjectId = ObjectPrivate.ObjectId; thisObjectData.AgentInfo = null; thisObjectData.ObjectId = ObjectPrivate.ObjectId; Quaternion rotation = Quaternion.FromEulerAngles(Mathf.RadiansPerDegree * RotationOffset); returnRotation = ObjectPrivate.InitialRotation; movedRotation = returnRotation * rotation; returnPosition = ObjectPrivate.InitialPosition; movedPosition = returnPosition + PositionOffset.Rotate(returnRotation); if (StartMoved) { mover.StopAndClear(); mover.AddMove(movedPosition, movedRotation); state = State.Moved; } else { mover.StopAndClear(); mover.AddMove(returnPosition, returnRotation); state = State.Returned; } if (StartEnabled) { Subscribe(null); } SubscribeToAll(EnableEvent, Subscribe); SubscribeToAll(DisableEvent, Unsubscribe); }
private void SetupInteraction(Interaction interaction, string events) { EnableAll += interaction.SetEnabled; interaction.SetEnabled(StartEnabled); if (MaxEventsPerSecond >= 100 || MaxEventsPerSecond <= 0) { interaction.Subscribe((InteractionData data) => { if (DisableOnClick) { interaction.SetEnabled(data.AgentId, false); } SimpleData sd = new SimpleData(this); sd.SourceObjectId = ObjectPrivate.ObjectId; sd.AgentInfo = ScenePrivate.FindAgent(data.AgentId)?.AgentInfo; sd.ObjectId = sd.AgentInfo != null ? sd.AgentInfo.ObjectId : ObjectId.Invalid; SendToAll(events, sd); }); } else { TimeSpan waitTime = TimeSpan.FromSeconds(1.0 / MaxEventsPerSecond); while (true) { InteractionData data = (InteractionData)WaitFor(interaction.Subscribe); if (DisableOnClick) { interaction.SetEnabled(data.AgentId, false); } SimpleData sd = new SimpleData(this); sd.SourceObjectId = ObjectPrivate.ObjectId; sd.AgentInfo = ScenePrivate.FindAgent(data.AgentId)?.AgentInfo; sd.ObjectId = sd.AgentInfo != null ? sd.AgentInfo.ObjectId : ObjectId.Invalid; SendToAll(events, sd); Wait(waitTime); } } }
protected override void SimpleInit() { simpleData = new SimpleData(this); simpleData.SourceObjectId = ObjectPrivate.ObjectId; RigidBodyComponent RigidBody; if (ObjectPrivate.TryGetFirstComponent(out RigidBody)) { if (!RigidBody.GetCanGrab()) { RigidBody.SetCanGrab(true, (data) => { if (data.Success == false) { Log.Write("Could not set selector to grabbable - won't be able to pick up the gun."); } }); } RigidBody.SubscribeToHeldObject(HeldObjectEventType.Grab, OnPickup); RigidBody.SubscribeToHeldObject(HeldObjectEventType.Release, OnDrop); } }
void OnChat(ChatData data) { if (!enabled) { return; } // If this chat message is a relevant command if (commands.ContainsKey(data.Message)) { var agent = ScenePrivate.FindAgent(data.SourceId); if (IsAccessAllowed(agent)) { SimpleData sd = new SimpleData(this); sd.SourceObjectId = ObjectPrivate.ObjectId; sd.AgentInfo = agent?.AgentInfo; if (sd.AgentInfo != null) { sd.ObjectId = sd.AgentInfo.ObjectId; } SendToAll(commands[data.Message], sd); } } // Else if it is the help command (and help not overridden by creator) else if (IsHelpCommand(data.Message) && (commands.Keys.Count > 0)) { var agent = ScenePrivate.FindAgent(data.SourceId); if (IsAccessAllowed(agent) && (agent != null)) { agent.SendChat(GetHelpText()); } } }
private void OnCollision(CollisionData data) { SimpleData sd = new SimpleData(this); sd.ObjectId = data.HitComponentId.ObjectId; sd.AgentInfo = ScenePublic.FindAgent(sd.ObjectId)?.AgentInfo; sd.SourceObjectId = ObjectPrivate.ObjectId; bool isAgentPunch = (data.HitControlPoint != ControlPointType.Invalid); if (!enabled) { // No events are sent while disabled, just manage agentsInTrigger if (data.Phase == CollisionEventPhase.TriggerExit) { if (agentsInTrigger.ContainsKey(sd.ObjectId) && !isAgentPunch) { agentsInTrigger.Remove(sd.ObjectId); } } else if (data.Phase == CollisionEventPhase.TriggerEnter) { if (sd.AgentInfo != null && !isAgentPunch && !agentsInTrigger.ContainsKey(sd.ObjectId)) { agentsInTrigger[sd.ObjectId] = sd.AgentInfo; } } return; } if (data.Phase == CollisionEventPhase.TriggerExit) { if (sd.ObjectId == ObjectId.Invalid) { if (userLoggedOut > 0) { // This object has left the scene and it was a user whose events were managed in the user subscription. --userLoggedOut; } else { // Object that was destroyed while inside the collision volume SendToAll(OnObjectExit, sd); } return; } // We determine agent or not on exit by whether they are in the agentsInTrigger Dictionary // This helps handle the case where a user logs out from within the trigger volume - after which their AgentInfo will be null. AgentInfo storedInfo; if (agentsInTrigger.TryGetValue(sd.ObjectId, out storedInfo)) { // Use the stored info, in case the user has logged out. sd.AgentInfo = storedInfo; if (isAgentPunch) { SendToAll(OnAgentPunchExit, sd); } else { SendToAll(OnAgentExit, sd); agentsInTrigger.Remove(sd.ObjectId); } } else { SendToAll(OnObjectExit, sd); } } else if (data.Phase == CollisionEventPhase.TriggerEnter || data.Phase == CollisionEventPhase.Invalid) { if (sd.AgentInfo != null) { if (isAgentPunch) { SendToAll(OnAgentPunchEnter, sd); } else { SendToAll(OnAgentEnter, sd); // Only track agents in the object if it is an enter event. if (data.Phase == CollisionEventPhase.TriggerEnter) { agentsInTrigger[sd.ObjectId] = sd.AgentInfo; } } } else { SendToAll(OnObjectEnter, sd); } } }
void OnTrigger(CommandData command) { try { if (!FreeCamEnabled && command.CameraControlMode == CameraControlMode.FlyCam) { AgentPrivate user = ScenePrivate.FindAgent(holdingAgent.SessionId); user.SendChat("This device does not work in Free Cam mode, return to 1st or 3rd person views to use this device."); return; } switch (command.ControlPoint) { case ControlPointType.DesktopGrab: if (!MouseLookEnabled && command.MouseLookMode) { AgentPrivate user = ScenePrivate.FindAgent(holdingAgent.SessionId); user.SendChat("This device does not work in desktop Mouse Look Mode: press Escape to enter or exit Mouse Look."); return; } if (!FreeClickEnabled && !command.MouseLookMode) { AgentPrivate user = ScenePrivate.FindAgent(holdingAgent.SessionId); user.SendChat("This device does not work in desktop Free Click Mode: press Escape to enter or exit Mouse Look."); return; } break; case ControlPointType.LeftTool: case ControlPointType.RightTool: if (!VREnabled) { AgentPrivate user = ScenePrivate.FindAgent(holdingAgent.SessionId); user.SendChat("This device does not work in VR."); return; } // If they grabbed it in desktop let them use it from whichever hand now? I guess? if (heldHand != ControlPointType.DesktopGrab && command.ControlPoint != heldHand) { return; } break; default: break; } if (ClipSize > 0 && ammo <= 0) { SendToAll(OutOfAmmoEvent, simpleData); return; } SendToAll(ShotFiredEvent, simpleData); shotsFired++; ammo--; var targetAgent = ScenePrivate.FindAgent(command.TargetingComponent.ObjectId); if (targetAgent != null) { shotsHit++; score += PointsPerPlayer; SendToAll(PlayerHitEvent, simpleData); SimpleData targetSimpleData = new SimpleData(this); targetSimpleData.AgentInfo = targetAgent.AgentInfo; targetSimpleData.ObjectId = targetSimpleData.AgentInfo.ObjectId; targetSimpleData.SourceObjectId = simpleData.SourceObjectId; SendToAll(ShotHitEvent, targetSimpleData); } else { ObjectPrivate targetObject = ScenePrivate.FindObject(command.TargetingComponent.ObjectId); if (targetObject != null) { ITarget target = targetObject.FindScripts <ITarget>("Simple.Target").FirstOrDefault(); if (target != null && (!SameGroupRequired || target.GetGroupTag() == Group)) { SimpleData targetSimpleData = new SimpleData(this); targetSimpleData.AgentInfo = null; targetSimpleData.ObjectId = targetObject.ObjectId; targetSimpleData.SourceObjectId = simpleData.SourceObjectId; SendToAll(ShotHitEvent, targetSimpleData); score += target.Hit(holdingAgent, command); shotsHit++; return; } } SendToAll(ShotMissEvent, simpleData); } } catch (System.Exception) { } // ignore exceptions for not found agents. }
void OnSelect(CommandData command) { try { if (!FreeCamEnabled && command.CameraControlMode == CameraControlMode.FlyCam) { AgentPrivate user = ScenePrivate.FindAgent(holdingAgent.SessionId); user.SendChat("This device does not work in Free Cam mode, return to 1st or 3rd person views to use this device."); return; } switch (command.ControlPoint) { case ControlPointType.DesktopGrab: if (!MouseLookEnabled && command.MouseLookMode) { AgentPrivate user = ScenePrivate.FindAgent(holdingAgent.SessionId); user.SendChat("This device does not work in desktop Mouse Look Mode: press Escape to enter or exit Mouse Look."); return; } if (!FreeClickEnabled && !command.MouseLookMode) { AgentPrivate user = ScenePrivate.FindAgent(holdingAgent.SessionId); user.SendChat("This device does not work in desktop Free Click Mode: press Escape to enter or exit Mouse Look."); return; } break; case ControlPointType.LeftTool: case ControlPointType.RightTool: if (!VREnabled) { AgentPrivate user = ScenePrivate.FindAgent(holdingAgent.SessionId); user.SendChat("This device does not work in VR."); return; } // Check hand after CheckReload which handles "shooting yourself to reload" // If they grabbed it in desktop let them use it from whichever hand now? I guess? if (heldHand != ControlPointType.DesktopGrab && command.ControlPoint != heldHand) { return; } break; default: break; } SendToAll(EveryCommandEvent, simpleData); var targetAgent = ScenePrivate.FindAgent(command.TargetingComponent.ObjectId); if (targetAgent != null) { SimpleData targetSimpleData = new SimpleData(this); targetSimpleData.AgentInfo = targetAgent.AgentInfo; targetSimpleData.ObjectId = targetSimpleData.AgentInfo.ObjectId; targetSimpleData.SourceObjectId = simpleData.SourceObjectId; SendToAll(PlayerSelectedEvent, targetSimpleData); } else { ObjectPrivate targetObject = ScenePrivate.FindObject(command.TargetingComponent.ObjectId); if (targetObject != null) { SimpleData targetSimpleData = new SimpleData(this); targetSimpleData.AgentInfo = null; targetSimpleData.ObjectId = targetObject.ObjectId; targetSimpleData.SourceObjectId = simpleData.SourceObjectId; ITarget target = targetObject.FindScripts <ITarget>("Simple.Target").FirstOrDefault(); if (target == null || (SameGroupRequired && target.GetGroupTag() != base.Group)) { SendToAll(ObjectSelectedEvent, targetSimpleData); return; } else { target.Hit(holdingAgent, command); SendToAll(TargetSelectedEvent, targetSimpleData); return; } } SendToAll(NothingSelectedEvent, simpleData); } } catch (System.Exception) { } // ignore exceptions for not found agents. }
protected void SendToAll(string csv, SimpleData data) { GetWrapper(csv)?.SendToAll(data); }
public void PostSimpleEvent(string name, SimpleData data) { PostScriptEvent(name, data); }
protected override void SimpleInit() { if (!ObjectPrivate.TryGetFirstComponent(out RigidBody)) { Log.Write(LogLevel.Error, __SimpleTag, "Simple Mover requires a Rigidbody set to motion type Keyframed"); return; } if (RigidBody.GetMotionType() != RigidBodyMotionType.MotionTypeKeyframed) { Log.Write(LogLevel.Error, __SimpleTag, "Simple Mover requires a Rigidbody set to motion type Keyframed"); return; } thisObjectData = new SimpleData(this); thisObjectData.SourceObjectId = ObjectPrivate.ObjectId; thisObjectData.AgentInfo = null; thisObjectData.ObjectId = ObjectPrivate.ObjectId; RigidBody.SetCenterOfMass(RotationPivot); Subscribe(null); Quaternion rotation = Quaternion.FromEulerAngles(Mathf.RadiansPerDegree * RotationOffset); returnRotation = ObjectPrivate.InitialRotation; movedRotation = returnRotation * rotation; numTurns = (int)((RotationOffset.Length() + 179.0f) / 360f); bool noRotation = RotationOffset.Length() < 0.5f; if (noRotation) { worldRotationAxis = Vector.Up; } else { float rotationAngle; rotation.ToAngleAxis(out rotationAngle, out localRotationAxis); if (Math.Abs(rotationAngle % TwoPI) < 0.001f) { // rotation axis won't be calculated correctly for exact multiple of 360 rotation // adjust euler angles slightly and re-calculate float x = RotationOffset.X; float y = RotationOffset.Y; float z = RotationOffset.Z; if (x != 0) { x = Math.Sign(x) * (Math.Abs(x) - 1.0f); } if (y != 0) { y = Math.Sign(y) * (Math.Abs(y) - 1.0f); } if (z != 0) { z = Math.Sign(z) * (Math.Abs(z) - 1.0f); } Vector adjustedOffset = new Vector(x, y, z); Quaternion adjustedRotation = Quaternion.FromEulerAngles(Mathf.RadiansPerDegree * adjustedOffset); float tempAngle; adjustedRotation.ToAngleAxis(out tempAngle, out localRotationAxis); } worldRotationAxis = localRotationAxis.Rotate(ref returnRotation); } float moveAngle = GetAngleFromZero(movedRotation); rotateSpeed = Math.Abs(moveAngle + numTurns * TwoPI) / (MoveDuration * SpeedCurveAverage()); if (!noRotation) { Quaternion unitRotation = Quaternion.FromAngleAxis(1f, localRotationAxis); turnDirection = Math.Sign(GetAngleFromZero(returnRotation * unitRotation)); } returnPosition = ObjectPrivate.InitialPosition + RotationPivot.Rotate(ref returnRotation); movedPosition = returnPosition + (PositionOffset).Rotate(ref returnRotation); translateSpeed = (movedPosition - returnPosition).Length() / (MoveDuration * SpeedCurveAverage()); if (StartMoved) { RigidBody.SetOrientation(movedRotation, (e) => { SetPositionOfCOM(movedPosition); }); turnCount = numTurns; state = State.Moved; } else { SetPositionOfCOM(returnPosition); state = State.Returned; } if (__SimpleDebugging) { Log.Write("rotation angle:" + moveAngle + " around:" + localRotationAxis + " world space axis:" + worldRotationAxis + " revolutions:" + numTurns); } }