Beispiel #1
0
        /// <summary>Part of a shuffle process.</summary>
        /// <param name="group">The group being shuffled.</param>
        /// <param name="card">An array containing the CardIdentity ids to shuffle.</param>
        public void Shuffle(Group group, int[] card)
        {
            // Array to hold the new aliases (sent to CreateAlias)
            ulong[] aliases = new ulong[card.Length];
            // Intialize the group shuffle
            group.FilledShuffleSlots = 0;
            group.HasReceivedFirstShuffledMessage = false;
            group.MyShufflePos = new short[card.Length];
            // Check if we received enough cards
            if (card.Length < group.Count / (Player.Count - 1))
            {
                Program.Trace.TraceEvent(TraceEventType.Warning, EventIds.Event, "[Shuffle] Too few cards received.");
            }
            // Do the shuffling
            var rnd = new CryptoRandom();

            for (int i = card.Length - 1; i >= 0; i--)
            {
                int r  = rnd.Next(i + 1);
                int tc = card[r];
                card[r] = card[i];
                // Create a new alias, if the card is not face up
                CardIdentity ci = CardIdentity.Find(tc);
                if (group.FindByCardIdentity(ci) != null)
                {
                    card[i]    = tc; aliases[i] = ulong.MaxValue;
                    ci.Visible = true;
                }
                else
                {
                    ci          = new CardIdentity(Program.Game.GenerateCardId());
                    ci.MySecret = ci.Alias = true;
                    ci.Key      = ((ulong)Crypto.PositiveRandom()) << 32 | (uint)tc;
                    card[i]     = ci.Id; aliases[i] = Crypto.ModExp(ci.Key);
                    ci.Visible  = false;
                }
                // Give a random position to the card
                group.MyShufflePos[i] = (short)Crypto.Random(group.Count);
            }
            // Send the results
            Program.Client.Rpc.CreateAlias(card, aliases);
            Program.Client.Rpc.Shuffled(group, card, group.MyShufflePos);
        }
Beispiel #2
0
        /// <summary>Unalias some Cards, e.g. before a shuffle</summary>
        /// <param name="card">An array containing the Card ids to unalias.</param>
        /// <param name="type">An array containing the corresponding revealed CardIdentity ids.</param>
        public void Unalias(int[] card, ulong[] type)
        {
            if (card.Length != type.Length)
            {
                Program.TraceWarning("[Unalias] Card and type lengths don't match."); return;
            }
            Pile         g     = null;
            List <int>   cards = new List <int>(card.Length);
            List <ulong> types = new List <ulong>(card.Length);

            for (int i = 0; i < card.Length; i++)
            {
                Card c = Card.Find(card[i]);
                if (c == null)
                {
                    Program.TraceWarning("[Unalias] Card not found."); continue;
                }
                if (g == null)
                {
                    g = c.Group as Pile;
                }
                else if (g != c.Group)
                {
                    Program.TraceWarning("[Unalias] Not all cards belong to the same group!"); continue;
                }
                // Check nobody cheated
                if (!c.Type.MySecret)
                {
                    if (c.Type.Key != Crypto.ModExp(type[i]))
                    {
                        Program.TraceWarning("[Unalias] Card identity doesn't match.");
                    }
                }
                // Substitue the card's identity
                CardIdentity ci = CardIdentity.Find((int)type[i]);
                if (ci == null)
                {
                    Program.TraceWarning("[Unalias] Card identity not found."); continue;
                }
                CardIdentity.Delete(c.Type.Id); c.Type = ci;
                // Propagate unaliasing
                if (ci.Alias && ci.MySecret)
                {
                    cards.Add(c.Id);
                }
                types.Add(ci.Key);
            }
            if (cards.Count > 0)
            {
                Program.Client.Rpc.Unalias(cards.ToArray(), types.ToArray());
            }
            if (g == null)
            {
                return;
            }
            if (!g.PreparingShuffle)
            {
                Program.TraceWarning("[Unalias] Cards revealed are not in a group prepared for shuffle."); return;
            }
            // If all cards are now revealed, one can proceed to shuffling
            if (!g.WantToShuffle)
            {
                return;
            }
            bool done = false;

            for (int i = 0; !done && i < g.Count; i++)
            {
                done = g[i].Type.Alias;
            }
            if (!done)
            {
                g.DoShuffle();
            }
        }
Beispiel #3
0
 public void Shuffled(Group group, int[] card, short[] pos)
 {
     // Check the args
     if (card.Length != pos.Length)
     {
         Program.TraceWarning("[Shuffled] Cards and positions lengths don't match.");
         return;
     }
     group.FilledShuffleSlots += card.Length;
     if (group.FilledShuffleSlots > group.Count)
     {
         Program.TraceWarning("[Shuffled] Too many card positions received.");
         return;
     }
     // If it's the first packet we receive for this shuffle, clear all Types
     if (!group.HasReceivedFirstShuffledMessage)
     {
         foreach (Card c in group)
         {
             c.Type = null;
         }
     }
     group.HasReceivedFirstShuffledMessage = true;
     // Check that the server didn't change our positions
     if (card[0] >> 16 == Player.LocalPlayer.Id && group.MyShufflePos != null)
     {
         if (pos.Where((t, i) => t != @group.MyShufflePos[i]).Any())
         {
             Program.TraceWarning("[Shuffled] The server has changed the order of the cards.");
         }
         group.MyShufflePos = null;
     }
     // Insert the cards
     for (int j = 0; j < card.Length; j++)
     {
         // Get the wished position
         int i = pos[j];
         // Get the card
         CardIdentity ci = CardIdentity.Find(card[j]);
         if (ci == null)
         {
             Program.TraceWarning("[Shuffled] Card not found.");
             continue;
         }
         // Check if the slot is free, otherwise choose the first free one
         if (i >= group.Count || group[i].Type != null)
         {
             i = group.FindNextFreeSlot(i);
         }
         if (i >= group.Count)
         {
             continue;
         }
         // Set the type
         group[i].Type = ci;
         group[i].SetVisibility(ci.Visible ? DataNew.Entities.GroupVisibility.Everybody : DataNew.Entities.GroupVisibility.Nobody, null);
     }
     if (group.FilledShuffleSlots == group.Count)
     {
         group.OnShuffled();
     }
 }
Beispiel #4
0
        /// <summary>Reveal a card's identity to one player only.</summary>
        /// <param name="players"> </param>
        /// <param name="card">The card, whose identity is revealed.</param>
        /// <param name="encrypted">Either a ulong[2] containing an encrypted aliased CardIdentity id. Or a ulong[5] containing an encrypted CardModel guid.</param>
        public void RevealTo(Player[] players, Card card, ulong[] encrypted)
        {
            var   oldType = card.Type;
            ulong alias   = 0;
            Guid  id      = Guid.Empty;

            players = players.Where(x => x != null).ToArray();
            switch (encrypted.Length)
            {
            case 2:
                alias = Crypto.Decrypt(encrypted);
                break;

            case 5:
                id = Crypto.DecryptGuid(encrypted);
                break;

            default:
                Program.TraceWarning("[RevealTo] Invalid data received.");
                return;
            }

            if (!players.All(p => (card.Group.Visibility == DataNew.Entities.GroupVisibility.Custom && card.Group.Viewers.Contains(p)) ||
                             card.PlayersLooking.Contains(p) || card.PeekingPlayers.Contains(p)))
            {
                Program.TraceWarning("[RevealTo] Revealing a card to a player, who isn't allowed to see it. This indicates a bug or cheating.");
            }

            // If it's an alias, we must revealed it to the final recipient
            bool sendToMyself = true;

            if (alias != 0)
            {
                sendToMyself = false;
                CardIdentity ci = CardIdentity.Find((int)alias);
                if (ci == null)
                {
                    Program.TraceWarning("[RevealTo] Identity not found."); return;
                }

                // If the revealed type is an alias, pass it to the one who owns it to continue the RevealTo chain.
                if (ci.Alias)
                {
                    Player p = Player.Find((byte)(ci.Key >> 16));
                    Program.Client.Rpc.RevealToReq(p, players, card, Crypto.Encrypt(ci.Key, p.PublicKey));
                }
                // Else revealed the card model to the ones, who must see it
                else
                {
                    Player[] pArray = new Player[1];
                    foreach (Player p in players)
                    {
                        if (p != Player.LocalPlayer)
                        {
                            pArray[0] = p;
                            Program.Client.Rpc.RevealToReq(p, pArray, card, Crypto.Encrypt(ci.Model.Id, p.PublicKey));
                        }
                        else
                        {
                            sendToMyself = true;
                            id           = ci.Model.Id;
                        }
                    }
                }
            }
            // Else it's a type and we are the final recipients
            if (!sendToMyself)
            {
                return;
            }
            if (card.Type.Model == null)
            {
                card.SetModel(Program.GameEngine.Definition.GetCardById(id));
            }
            // Raise a notification
            oldType.OnRevealed(card.Type);
        }
Beispiel #5
0
        /// <summary>Reveal one card's identity</summary>
        /// <param name="card">The card, whose identity is revealed</param>
        /// <param name="revealed">Either the salted CardIdentity id (in the case of an alias), or the salted, condensed Card GUID.</param>
        /// <param name="guid"> </param>
        public void Reveal(Card card, ulong revealed, Guid guid)
        {
            // Save old id
            CardIdentity oldType = card.Type;

            // Check if the card is rightfully revealed
            if (!card.Type.Revealing)
            {
                Program.Trace.TraceEvent(TraceEventType.Warning, EventIds.Event, "Someone tries to reveal a card which is not visible to everybody.");
            }
            // Check if we can trust other clients
            if (!card.Type.MySecret)
            {
                if (guid != Guid.Empty && (uint)revealed != guid.Condense())
                {
                    Program.Trace.TraceEvent(TraceEventType.Warning, EventIds.Event, "[Reveal] Alias and id aren't the same. One client is buggy or tries to cheat.");
                }
                if (Crypto.ModExp(revealed) != card.Type.Key)
                {
                    Program.Trace.TraceEvent(TraceEventType.Warning, EventIds.Event, "[Reveal] Card identity doesn't match. One client is buggy or tries to cheat.");
                }
            }
            else
            {
                card.Type.MySecret = false;
            }
            // Reveal an alias
            if (guid == Guid.Empty)
            {
                // Find the new type
                CardIdentity newId = CardIdentity.Find((int)revealed);
                // HACK: it is unclear to me how the CardIdentity could not be found and newId ends up null
                // see this bug report: https://octgn.16bugs.com/projects/3602/bugs/192070
                // for now I'm just doing nothing (supposing that it means the type was already revealed).
                if (newId == null)
                {
                    card.Reveal(); return;
                }
                // Possibly copy the model, if it was known and isn't anymore
                // (possible when the alias has beeen locally revealed)
                if (newId.Model == null)
                {
                    newId.Model = card.Type.Model;
                }
                // Set the new type
                card.Type = newId;
                // Delete the old identity
                CardIdentity.Delete(oldType.Id);
                // Possibly reveal the alias further
                card.Reveal();
                // Raise a notification
                oldType.OnRevealed(newId);
            }
            // Reveal a card's type
            else if (card.Type.Model == null)
            {
                card.SetModel(Program.GameEngine.Definition.GetCardById(guid));
                // Raise a notification
                oldType.OnRevealed(oldType);
            }
        }