Beispiel #1
0
        public void FlushSendBuffer()
        {
            //lock (ClientState.SendLock)
            //{
            try
            {
                while (ClientState.SendBufferTake(out ServerPacket packet))
                {
                    Task.Run(async() =>
                    {
                        if (packet == null)
                        {
                            return;
                        }

                        if (packet.ShouldEncrypt)
                        {
                            ++ServerOrdinal;
                            packet.Ordinal = ServerOrdinal;

                            packet.GenerateFooter();
                            packet.Encrypt(this);
                        }
                        if (packet.TransmitDelay != 0)
                        {
                            await Task.Delay(packet.TransmitDelay);
                        }

                        var buffer = packet.ToArray();
                        try
                        {
                            Socket.BeginSend(buffer, 0, buffer.Length, 0, SendCallback, ClientState);
                        }
                        catch (ObjectDisposedException e)
                        {
                            GameLog.Warning($"FlushSendBuffer: {e.Message}");
                        }
                    });
                }
            }
            catch (ObjectDisposedException)
            {
                // Socket is gone, peace out
                ClientState.Dispose();
            }
            catch (Exception e)
            {
                GameLog.Error($"HALP: {e}");
            }
            //}
        }
Beispiel #2
0
 public Server(int port)
 {
     Clients                = new ConcurrentDictionary <IntPtr, Client>();
     Port                   = port;
     PacketHandlers         = new WorldPacketHandler[256];
     ControlMessageHandlers = new ControlMessageHandler[64];
     Throttles              = new Dictionary <byte, IPacketThrottle>();
     ExpectedConnections    = new ConcurrentDictionary <uint, Redirect>();
     for (int i = 0; i < 256; ++i)
     {
         PacketHandlers[i] = (c, p) => GameLog.Warning($"{GetType().Name}: Unhandled opcode 0x{p.Opcode:X2}");
     }
     Task.Run(ProcessOutbound);
 }
Beispiel #3
0
        /// <summary>
        /// Calculate loot for a given spawn.
        /// </summary>
        /// <param name="spawn">The spawn we will use to calculate Loot.</param>
        /// <returns>A Loot struct with XP, gold and items, if any</returns>
        public static Loot CalculateLoot(Xml.Spawn spawn)
        {
            // Loot calculations are not particularly complex but have a lot of components:
            // Spawns can have loot sets, loot tables, or both.
            // We resolve sets first, then tables. We keep a running tab of gold drops.
            // Lastly, we return a Loot struct with our calculations.

            var loot   = new Loot(0, 0);
            var tables = new List <Xml.LootTable>();

            // Assign base XP
            loot.Xp = spawn.Loot.Xp;
            // Sets
            foreach (var set in spawn.Loot?.Set ?? new List <Xml.LootImport>())
            {
                // Is the set present?
                GameLog.SpawnInfo("Processing loot set {Name}", set.Name);
                if (Game.World.WorldData.TryGetValueByIndex(set.Name, out Xml.LootSet lootset))
                {
                    // Set is present, does it fire?
                    // Chance is implemented as a decimalized percentage, e.g. 0.08 = 8% chance

                    // If rolls == 0, all tables fire
                    if (set.Rolls == 0)
                    {
                        tables.AddRange(lootset.Table);
                        GameLog.SpawnInfo("Processing loot set {Name}: set rolls == 0, looting", set.Name);
                        continue;
                    }

                    for (var x = 0; x < set.Rolls; x++)
                    {
                        if (Roll() <= set.Chance)
                        {
                            GameLog.SpawnInfo("Processing loot set {Name}: set hit, looting", set.Name);

                            // Ok, the set fired. Check the subtables, which can have independent chances.
                            // If no chance is present, we simply award something from each table in the set.
                            // Note that we do table processing last! We just find the tables that fire here.
                            foreach (var setTable in lootset.Table)
                            {
                                // Rolls == 0 (default) means the table is automatically used.
                                if (setTable.Rolls == 0)
                                {
                                    tables.Add(setTable);
                                    GameLog.SpawnInfo("Processing loot set {Name}: setTable rolls == 0, looting", set.Name);
                                    continue;
                                }
                                // Did the subtable hit?
                                for (var y = 0; y < setTable.Rolls; y++)
                                {
                                    if (Roll() <= setTable.Chance)
                                    {
                                        tables.Add(setTable);
                                        GameLog.SpawnInfo("Processing loot set {Name}: set subtable hit, looting ", set.Name);
                                    }
                                }
                            }
                        }
                        else
                        {
                            GameLog.SpawnInfo("Processing loot set {Name}: Set subtable missed", set.Name);
                        }
                    }
                }
                else
                {
                    GameLog.Warning("Spawn {name}: Loot set {name} missing", spawn.Base, set.Name);
                }
            }

            // Now, calculate loot for any tables attached to the spawn
            foreach (var table in spawn.Loot?.Table ?? new List <Xml.LootTable>())
            {
                if (table.Rolls == 0)
                {
                    tables.Add(table);
                    GameLog.SpawnInfo("Processing loot: spawn table for {Name}, rolls == 0, looting", spawn.Base);
                    continue;
                }
                for (var z = 0; z <= table.Rolls; z++)
                {
                    if (Roll() <= table.Chance)
                    {
                        GameLog.SpawnInfo("Processing loot: spawn table for {Name} hit, looting", spawn.Base);
                        tables.Add(table);
                    }
                    else
                    {
                        GameLog.SpawnInfo("Processing loot set {Name}: Spawn subtable missed", spawn.Base);
                    }
                }
            }

            // Now that we have all tables that fired, we need to calculate actual loot

            GameLog.SpawnInfo("Loot for {Name}: tables: {Count}", spawn.Base, tables.Count());
            foreach (var table in tables)
            {
                loot += CalculateTable(table);
            }

            GameLog.SpawnInfo("Final loot for {Name}: {Xp} xp, {Gold} gold, items [{items}]", spawn.Base, loot.Xp, loot.Gold, string.Join(",", loot.Items));
            return(loot);
        }
Beispiel #4
0
 public void OnDisconnectThreshold(IClientTrigger trigger)
 {
     trigger.Client.SendMessage("You have been automatically disconnected due to server abuse. Goodbye!", MessageTypes.SYSTEM_WITH_OVERHEAD);
     GameLog.Warning($"Client {trigger.Id}: disconnected due to packet spam");
     trigger.Client.Disconnect();
 }
Beispiel #5
0
        public ThrottleResult ProcessThrottle(Client client, ClientPacket packet)
        {
            ThrottleInfo   info;
            ThrottleResult result = ThrottleResult.Error;

            if (!client.ThrottleState.TryGetValue(packet.Opcode, out info))
            {
                client.ThrottleState[packet.Opcode] = new ThrottleInfo();
                info = client.ThrottleState[packet.Opcode];
            }

            Monitor.Enter(info);

            try
            {
                DateTime rightnow = DateTime.Now;
                GameLog.Warning($"Right now is {rightnow}");
                var transmitInterval = (rightnow - info.LastReceived);
                var acceptedInterval = (rightnow - info.LastAccepted);
                info.PreviousReceived = info.LastReceived;
                info.LastReceived     = rightnow;
                info.TotalReceived++;
                GameLog.Debug($"Begin: PA: {info.PreviousAccepted} LA: {info.LastAccepted} AInterval is {acceptedInterval.TotalMilliseconds} TInterval {transmitInterval.TotalMilliseconds}");

                if (info.Throttled)
                {
                    result = ThrottleResult.Throttled;
                    if (acceptedInterval.TotalMilliseconds >= ThrottleDuration && acceptedInterval.TotalMilliseconds >= Interval)
                    {
                        GameLog.Error($"Unthrottled: {acceptedInterval.TotalMilliseconds} > {ThrottleDuration} and {Interval}");
                        info.Throttled      = false;
                        info.TotalThrottled = 0;
                        result = ThrottleResult.ThrottleEnd;
                        info.PreviousAccepted = info.LastAccepted;
                        info.LastAccepted     = rightnow;
                        OnThrottleStop(new ClientTrigger(client));
                    }
                    else
                    {
                        info.TotalThrottled++;
                        GameLog.Error($"Throttled, count is {info.TotalThrottled}");

                        result = ThrottleResult.Throttled;
                        if (ThrottleDisconnectThreshold > 0 && info.TotalThrottled > ThrottleDisconnectThreshold)
                        {
                            result = ThrottleResult.Disconnect;
                            OnDisconnectThreshold(new ClientTrigger(client));
                        }
                    }
                }
                else
                {
                    if (acceptedInterval.TotalMilliseconds <= Interval && info.LastAccepted != DateTime.MinValue)
                    {
                        GameLog.Debug($"TInterval {transmitInterval}, AInterval {acceptedInterval} - maximum is {Interval}, throttled");
                        info.Throttled = true;
                        OnThrottleStart(new ClientTrigger(client));
                        result = ThrottleResult.Throttled;
                    }
                    else
                    {
                        info.PreviousAccepted = info.LastAccepted;
                        info.LastAccepted     = rightnow;
                        info.TotalAccepted++;
                        result = ThrottleResult.OK;
                        GameLog.Debug($"Packet accepted, PA: {info.PreviousAccepted} LA: {info.LastAccepted}");
                    }
                }
            }
            finally
            {
                Monitor.Exit(info);
            }
            return(result);
        }