private void UpdateUserBodyTint() { VoosActor playerActor = GetPlayerActor(); if (playerActor == null || userBody == null) { return; } if (lastTintPushedToUserBody != null && playerActor.GetTint() == lastTintPushedToUserBody.Value) { // Already up to date. return; } Color newTint = playerActor.GetTint(); userBody.SetTint(newTint); lastTintPushedToUserBody = newTint; }
void OnColorWheelChanged(Color color) { // Set tint, but preserve alpha. color.a = actor.GetTint().a; Color prevColor = actor.GetTint(); undoStack.PushUndoForActor( actor, $"Set tint for {actor.GetDisplayName()}", actor => { actor.SetTint(color); actor.ApplyPropertiesToClones(); }, actor => { actor.SetTint(prevColor); actor.ApplyPropertiesToClones(); }); }
public IEnumerator TestBasic() { yield return(Setup()); VoosActor actor = voosEngine.CreateActor(new Vector3(1, 2, 3), Quaternion.identity, _ => { }); Assert.NotNull(actor); Assert.AreEqual(1.0, actor.GetTint().r, 1e-4); string brainId = actor.GetBrainName(); string behaviorId = NewGUID(); string js = @" export function onTick(api) { setTint(0.12, 0.34, 0.56); } "; behaviorSystem.PutBehavior(behaviorId, new Behavior { javascript = js }); var use = new BehaviorUse { id = NewGUID(), behaviorUri = IdToEmbeddedBehaviorUri(behaviorId) }; var brain = new Brain { behaviorUses = new BehaviorUse[] { use } }; behaviorSystem.PutBrain(brainId, brain); // Let it run at least one voos update yield return(new WaitForEndOfFrame()); yield return(new WaitForEndOfFrame()); Assert.AreEqual(0.12, actor.GetTint().r, 1e-4); }
public IEnumerator TestHandleMultipleInOneFrame() { yield return(Setup()); VoosActor actor = voosEngine.CreateActor(new Vector3(1, 2, 3), Quaternion.identity, newActor => { }); actor.SetTint(new Color(0.1f, 0.1f, 0.1f)); Assert.NotNull(actor); Assert.AreEqual(1.0, actor.transform.position.x, 1e-4); string brainId = actor.GetBrainName(); string behaviorId = behaviorSystem.GenerateUniqueId(); string js = @" export function onMoveRight() { const c = getTint(); c.r += 0.1; setTint(c.r, c.g, c.b); } "; behaviorSystem.PutBehavior(behaviorId, new Behaviors.Behavior { javascript = js }); PutTestUse(new TestUse { behaviorUri = IdToEmbeddedBehaviorUri(behaviorId), brainId = brainId }); // We expect x to increment by 2.. voosEngine.EnqueueMessage(new VoosEngine.ActorMessage { name = "MoveRight", targetActor = actor.GetName() }); voosEngine.EnqueueMessage(new VoosEngine.ActorMessage { name = "MoveRight", targetActor = actor.GetName() }); // Let it run at least one voos update yield return(new WaitForEndOfFrame()); yield return(new WaitForEndOfFrame()); Assert.AreEqual(0.3, actor.GetTint().r, 1e-4); }
public void AddActor(VoosActor va) { #if USE_PUN if (va.reliablePhotonView == null) { throw new System.Exception("GlobalUnreliableData only accepts actors with reliablePhotonView (not local drafts)"); } if (actors.ContainsKey((short)va.reliablePhotonView.viewID)) { Debug.LogWarning("Adding an actor that is already added. Is this an ownership transfer?"); return; } NetworkedActor na = new NetworkedActor(); na.actor = va; na.lastPosition = va.transform.position; na.lastRotation = va.transform.rotation; na.lastColor = va.GetTint(); na.lastTransformUpdateFrame = Time.frameCount; na.messagesSinceLastUpdate = 0; actors.Add((short)va.reliablePhotonView.viewID, na); #endif }
byte[] Serialize() { serializationBytes.Clear(); VoosNetworkTypes.ShortToBytes stb = new VoosNetworkTypes.ShortToBytes(); VoosNetworkTypes.UintToBytes utb = new VoosNetworkTypes.UintToBytes(); int totalCount = 0; float totalProbability = 0; foreach (KeyValuePair <short, NetworkedActor> na in actors) { VoosActor va = na.Value.actor; if (va != null && va.reliablePhotonView.isMine && !va.IsParented()) { Vector3 p = va.transform.position; Quaternion q = va.transform.rotation; if (na.Value.lastPosition != p || na.Value.lastRotation != q || na.Value.lastColor != va.GetTint()) { na.Value.lastPosition = p; na.Value.lastRotation = q; na.Value.lastColor = va.GetTint(); na.Value.lastTransformUpdateFrame = Time.frameCount; na.Value.messagesSinceLastUpdate = 0; } na.Value.updateProbability = Mathf.Clamp(1.0f / (float)(1 + na.Value.messagesSinceLastUpdate), minimumProbabilityOfUpdate, 1); totalProbability += na.Value.updateProbability; } totalCount++; } float probabilityOfPositionUpdate = 1; if (totalCount > MaxPositionUpdatesPerTick) { probabilityOfPositionUpdate = (float)MaxPositionUpdatesPerTick / totalProbability; } /// Message Header /// Transform count - will modify after the fact. serializationBytes.Add(0); serializationBytes.Add(0); /// Timestamp for prediction. utb.data = VoosNetworkTypes.CompressFloatToUint24(Time.time); serializationBytes.Add(utb.byte0); serializationBytes.Add(utb.byte1); serializationBytes.Add(utb.byte2); int index = 0; foreach (KeyValuePair <short, NetworkedActor> na in actors) { VoosActor va = na.Value.actor; if (va != null && va.reliablePhotonView.isMine && !va.IsParented()) { if (Random.value > (probabilityOfPositionUpdate * na.Value.updateProbability)) { continue; } na.Value.messagesSinceLastUpdate++; /// View ID stb.data = (short)va.reliablePhotonView.viewID; serializationBytes.Add(stb.byte0); serializationBytes.Add(stb.byte1); /// Network data bitmask UnreliableBitmask mask = UnreliableBitmask.None; mask |= va.GetTeleport() ? UnreliableBitmask.Teleport : UnreliableBitmask.None; mask |= va.GetEnablePhysics() ? UnreliableBitmask.EnablePhysics : UnreliableBitmask.None; serializationBytes.Add((byte)mask); // Unset the "teleport" flag, as it's transient and should only be used for one network packet. va.SetTeleport(false); // SUBTLE: If physics is not enabled, then pos/rot is not likely to // change. However, any inaccuracies are also more likely to be noticed // (such as static walls being slightly tilted). So given this, always // send full precision updates for static objects. Sure, this is less // efficient for things like moving platforms which do not have physics // but often change, but that's likely to be a minority. /// Local Position utb.WriteUint24(serializationBytes, VoosNetworkTypes.CompressFloatToUint24(na.Value.lastPosition.x)); utb.WriteUint24(serializationBytes, VoosNetworkTypes.CompressFloatToUint24(na.Value.lastPosition.y)); utb.WriteUint24(serializationBytes, VoosNetworkTypes.CompressFloatToUint24(na.Value.lastPosition.z)); // Static - send full precision rotation on change. TODO I'm sure // there's some way to compress it to 8 bytes without loss. var ftb = new VoosNetworkTypes.FloatToBytes(); Quaternion q = na.Value.lastRotation; ftb.SerializeTo(serializationBytes, q.x); ftb.SerializeTo(serializationBytes, q.y); ftb.SerializeTo(serializationBytes, q.z); ftb.SerializeTo(serializationBytes, q.w); //Color serializationBytes.Add(na.Value.lastColor.r); serializationBytes.Add(na.Value.lastColor.g); serializationBytes.Add(na.Value.lastColor.b); serializationBytes.Add(na.Value.lastColor.a); /// Linear Velocity Rigidbody rb = va.GetComponent <Rigidbody>(); Vector3 lv = Vector3.zero; if (rb != null && !rb.isKinematic) { lv = rb.velocity; } utb.data = VoosNetworkTypes.CompressFloatToUint24(lv.x); serializationBytes.Add(utb.byte0); serializationBytes.Add(utb.byte1); serializationBytes.Add(utb.byte2); utb.data = VoosNetworkTypes.CompressFloatToUint24(lv.y); serializationBytes.Add(utb.byte0); serializationBytes.Add(utb.byte1); serializationBytes.Add(utb.byte2); utb.data = VoosNetworkTypes.CompressFloatToUint24(lv.z); serializationBytes.Add(utb.byte0); serializationBytes.Add(utb.byte1); serializationBytes.Add(utb.byte2); index++; } } stb.data = (short)index; serializationBytes[0] = stb.byte0; serializationBytes[1] = stb.byte1; if (index == 0) { return(null); } return(serializationBytes.ToArray()); }