コード例 #1
0
ファイル: ObjectScript.cs プロジェクト: UchuServer/Uchu
        /// <summary>
        /// Sets a networked variable of the script.
        /// </summary>
        /// <param name="name">Name of the variable to store.</param>
        /// <param name="value">Value of the variable to store.</param>
        public void SetNetworkVar(string name, object value)
        {
            // Set the variable.
            this.SetVar(name, value);

            if (this._variableChangeTransactions.ContainsKey(Thread.CurrentThread))
            {
                // Add to the transaction.
                PrepareDictionary(name, value, this._variableChangeTransactions[Thread.CurrentThread]);
            }
            else
            {
                // Create the LDF.
                var ldf = new LegoDataDictionary();
                PrepareDictionary(name, value, ldf);

                // Broadcast the variable changes.
                Task.Run(() =>
                {
                    this.Zone.BroadcastMessage(new ScriptNetworkVarUpdateMessage
                    {
                        Associate = this.GameObject,
                        Data      = ldf,
                    });
                });
            }
        }
コード例 #2
0
        public override void Deserialize(BitReader reader)
        {
            base.Deserialize(reader);

            Configs = new LegoDataDictionary();
            Configs.DeserializePathConfigs(reader);
        }
コード例 #3
0
        public async Task AddItemAsync(Lot lot, uint count, LegoDataDictionary extraInfo = default)
        {
            await using var cdClient = new CdClientContext();

            var componentId = await cdClient.ComponentsRegistryTable.FirstOrDefaultAsync(
                r => r.Id == lot && r.Componenttype == (int)ComponentId.ItemComponent
                );

            if (componentId == default)
            {
                Logger.Error($"{lot} does not have a Item component");
                return;
            }

            var component = await cdClient.ItemComponentTable.FirstOrDefaultAsync(
                i => i.Id == componentId.Componentid
                );

            if (component == default)
            {
                Logger.Error(
                    $"{lot} has a corrupted component registry. There is no Item component of Id: {componentId.Componentid}"
                    );
                return;
            }

            Debug.Assert(component.ItemType != null, "component.ItemType != null");

            await AddItemAsync(lot, count, ((ItemType)component.ItemType).GetInventoryType(), extraInfo);
        }
コード例 #4
0
        /// <summary>
        /// Build a LegoDataDictionary from path config values. Path configs have a different serialization than LDF in
        /// Lvl files has.
        /// </summary>
        /// <remarks>
        /// Some config entries have no type defined, for example `pathspeed=0.8` or `delay=5`.
        /// This code tries to interpret those values first as an int, then as a float, and if
        /// neither succeeds, stores it as a string.
        /// </remarks>
        /// <seealso cref="SerializePathConfigs"/>
        public static void DeserializePathConfigs(this LegoDataDictionary @this, BitReader reader)
        {
            var configCount = reader.Read <uint>();

            for (var i = 0; i < configCount; i++)
            {
                var key          = reader.ReadNiString(true, true);
                var typeAndValue = reader.ReadNiString(true, true);
                var firstColon   = typeAndValue.IndexOf(':');
                if (firstColon == -1)
                {
                    if (int.TryParse(typeAndValue, out var intValue))
                    {
                        @this.Add(key, intValue);
                    }
                    else if (float.TryParse(typeAndValue, out var floatVal))
                    {
                        @this.Add(key, floatVal);
                    }
                    else
                    {
                        @this.Add(key, typeAndValue);
                    }

                    continue;
                }
                var type = int.Parse(typeAndValue[..firstColon]);
コード例 #5
0
 /// <summary>
 /// Instantiates an item using saved information from the player (e.g. the count, slot and LDD)
 /// </summary>
 /// <param name="itemInstance">An item as fetched from the Uchu database to base this item on</param>
 /// <param name="owner">The owner (generally player) of this item</param>
 /// <param name="inventory">The inventory to add the item to</param>
 /// <returns>The instantiated item</returns>
 public static async Task <Item> Instantiate(InventoryItem itemInstance,
                                             GameObject owner, Inventory inventory)
 {
     return(await Instantiate(owner, itemInstance.Lot, inventory, (uint)itemInstance.Count,
                              (uint)itemInstance.Slot, LegoDataDictionary.FromString(itemInstance.ExtraInfo),
                              (ObjectId)itemInstance.Id, isEquipped : itemInstance.IsEquipped, isBound : itemInstance.IsBound,
                              rootItem : inventory.ManagerComponent.Items.FirstOrDefault(i => i.Id == itemInstance.ParentId)));
 }
コード例 #6
0
        public override void Deserialize(BitReader reader)
        {
            base.Deserialize(reader);

            Rotation = reader.ReadNiQuaternion();

            Configs = new LegoDataDictionary();
            Configs.DeserializePathConfigs(reader);
        }
コード例 #7
0
        public override void Deserialize(BitReader reader)
        {
            Confirmed  = reader.ReadBit();
            DeleteItem = reader.ReadBit();
            OutSuccess = reader.ReadBit();

            if (reader.ReadBit())
            {
                InventoryType = (InventoryType)reader.Read <int>();
            }

            if (reader.ReadBit())
            {
                ItemType = (ItemType)reader.Read <int>();
            }

            var len = reader.Read <uint>();

            if (len > 0)
            {
                var info = reader.ReadString((int)len, true);
                ExtraInfo = LegoDataDictionary.FromString(info);
            }

            ForceDeletion = reader.ReadBit();

            if (reader.ReadBit())
            {
                Source = reader.ReadGameObject(Associate.Zone);
            }

            if (reader.ReadBit())
            {
                Item = reader.ReadGameObject <Item>(Associate.Zone);
            }

            if (reader.ReadBit())
            {
                Requesting = reader.ReadGameObject(Associate.Zone);
            }

            if (reader.ReadBit())
            {
                TotalItems = reader.Read <uint>();
            }

            if (reader.ReadBit())
            {
                SubKey = reader.Read <long>();
            }

            if (reader.ReadBit())
            {
                TradeId = reader.Read <long>();
            }
        }
コード例 #8
0
        public override void Serialize(BitWriter writer)
        {
            writer.WriteBit(true);

            writer.Write((uint)Items.Count);

            foreach (var(_, item) in Items)
            {
                writer.Write(item.InventoryItemId);
                writer.Write(item.LOT);

                writer.WriteBit(false);

                var stack = item.Count > 1;

                writer.WriteBit(stack);

                if (stack)
                {
                    writer.Write((uint)item.Count);
                }

                var hasSlot = item.Slot != -1;

                writer.WriteBit(hasSlot);

                if (hasSlot)
                {
                    writer.Write((ushort)item.Slot);
                }

                var hasInventoryType = item.InventoryType != -1;

                writer.WriteBit(hasInventoryType);

                if (hasInventoryType)
                {
                    writer.Write((uint)item.InventoryType);
                }

                var hasExtraData = !string.IsNullOrWhiteSpace(item.ExtraInfo);

                writer.WriteBit(hasExtraData);

                if (hasExtraData)
                {
                    writer.WriteLdfCompressed(LegoDataDictionary.FromString(item.ExtraInfo));
                }

                writer.WriteBit(true);
            }

            writer.WriteBit(true);
            writer.Write <uint>(0);
        }
コード例 #9
0
        /// <summary>
        /// Launches the client.
        /// </summary>
        /// <param name="host">Host to launch.</param>
        /// <returns>Process that was started.</returns>
        public Process Launch(ServerEntry host)
        {
            // Set up the runtime if it isn't installed.
            if (!this.Runtime.IsInstalled)
            {
                if (this.Runtime.CanInstall)
                {
                    // Install the runtime.
                    this.Runtime.Install();
                }
                else
                {
                    // Stop the launch if a valid runtime isn't set up.
                    return(null);
                }
            }

            // Modify the boot file.
            var bootConfigLocation        = Path.Combine(this.systemInfo.ClientLocation, "boot.cfg");
            LegoDataDictionary bootConfig = null;

            try
            {
                bootConfig = LegoDataDictionary.FromString(File.ReadAllText(bootConfigLocation).Trim().Replace("\n", ""), ',');
            }
            catch (FormatException)
            {
                bootConfig = LegoDataDictionary.FromString(File.ReadAllText(Path.Combine(this.systemInfo.ClientLocation, "boot_backup.cfg")).Trim().Replace("\n", ""), ',');
            }
            bootConfig["SERVERNAME"]   = host.ServerName;
            bootConfig["AUTHSERVERIP"] = host.ServerAddress;
            File.WriteAllText(bootConfigLocation, bootConfig.ToString(","));

            // Apply any pre-launch patches.
            foreach (var patch in Patcher.Patches)
            {
                if (patch is IPreLaunchPatch preLaunchPatch)
                {
                    if (!patch.Installed)
                    {
                        continue;
                    }
                    preLaunchPatch.OnClientRequestLaunch();
                }
            }

            // Launch the client.
            var clientProcess = this.Runtime.RunApplication(Path.Combine(this.systemInfo.ClientLocation, "legouniverse.exe"), this.systemInfo.ClientLocation);

            clientProcess.Start();

            // Return the output.
            return(clientProcess);
        }
コード例 #10
0
        public override void Deserialize(BitReader reader)
        {
            Type = reader.Read <int>();

            Value = reader.Read <int>();

            Activator = reader.ReadGameObject(Associate.Zone);

            var ldl = reader.ReadString((int)reader.Read <uint>(), true);

            Settings = LegoDataDictionary.FromString(ldl);
        }
コード例 #11
0
        public override void Deserialize(BitReader reader)
        {
            base.Deserialize(reader);

            UnknownQuaternion = reader.ReadNiQuaternion();

            if (Version >= 17)
            {
                Speed = reader.Read <float>();
            }

            Configs = new LegoDataDictionary();
            Configs.DeserializePathConfigs(reader);
        }
コード例 #12
0
ファイル: Item.cs プロジェクト: kulaj/Uchu
        public static Item Instantiate(Lot lot, Inventory inventory, uint count, LegoDataDictionary extraInfo = default)
        {
            uint slot = default;

            for (var index = 0; index < inventory.Size; index++)
            {
                if (inventory.Items.All(i => i.Slot != index))
                {
                    break;
                }

                slot++;
            }

            return(Instantiate(lot, inventory, count, slot, extraInfo));
        }
コード例 #13
0
ファイル: Item.cs プロジェクト: kulaj/Uchu
        private async Task UpdateCountAsync(uint count)
        {
            if (count >= Count)
            {
                AddCount(count);
            }
            else
            {
                RemoveCount(count);
            }

            if (count > 0)
            {
                return;
            }

            await using var ctx = new UchuContext();

            var item = await ctx.InventoryItems.FirstOrDefaultAsync(
                i => i.Id == Id
                );

            if (item == default)
            {
                return;
            }

            if (await IsEquippedAsync())
            {
                await UnEquipAsync();
            }

            ctx.InventoryItems.Remove(item);

            await ctx.SaveChangesAsync();

            // Disassemble item.
            if (LegoDataDictionary.FromString(item.ExtraInfo).TryGetValue("assemblyPartLOTs", out var list))
            {
                foreach (var part in (LegoDataList)list)
                {
                    await Inventory.ManagerComponent.AddItemAsync((int)part, 1);
                }
            }

            Destroy(this);
        }
コード例 #14
0
ファイル: ModularBuilderComponent.cs プロジェクト: kulaj/Uchu
        public async Task FinishBuilding(Lot[] models)
        {
            var inventory = GameObject.GetComponent <InventoryManagerComponent>();

            foreach (var module in models)
            {
                inventory.RemoveItem(module, 1, InventoryType.TemporaryModels);
            }

            var model = new LegoDataDictionary
            {
                ["assemblyPartLOTs"] = LegoDataList.FromEnumerable(models.Select(s => s.Id))
            };

            await inventory.AddItemAsync(6416, 1, InventoryType.Models, model);

            await ConfirmFinish();
        }
コード例 #15
0
        public static void WriteLdfCompressed(this BitWriter @this, LegoDataDictionary dict)
        {
            using var stream = new MemoryStream();
            using var temp   = new BitWriter(stream);

            Core.BitWriterExtensions.Write(temp, dict);

            var buffer = stream.ToArray();

            var compressed = Zlib.CompressBytes(buffer);

            @this.Write((uint)(compressed.Length + 9));

            @this.Write <byte>(1);
            @this.Write((uint)buffer.Length);
            @this.Write((uint)compressed.Length);
            Core.BitWriterExtensions.Write(@this, compressed);
        }
コード例 #16
0
        public void Deserialize(BitReader reader)
        {
            ObjectId = reader.Read <ulong>();

            Lot = reader.Read <int>();

            if (LvlVersion >= 0x26)
            {
                AssetType = reader.Read <uint>();
            }

            if (LvlVersion >= 0x20)
            {
                UnknownInt = reader.Read <uint>();
            }

            Position = reader.Read <Vector3>();

            Rotation = reader.ReadNiQuaternion();

            Scale = reader.Read <float>();

            var legoInfo = reader.ReadNiString(true);

            if (legoInfo.Length > 0)
            {
                try
                {
                    LegoInfo = LegoDataDictionary.FromString(legoInfo);
                }
                catch (Exception e)
                {
                    Console.WriteLine(legoInfo);

                    Console.WriteLine(e);
                    throw;
                }
            }

            if (LvlVersion >= 0x7)
            {
                UnknownInt1 = reader.Read <uint>();
            }
        }
コード例 #17
0
ファイル: Item.cs プロジェクト: kulaj/Uchu
        public async Task SetCountSilentAsync(uint count)
        {
            await using var ctx = new UchuContext();

            if (count > ItemComponent.StackSize && ItemComponent.StackSize > 0)
            {
                Logger.Error(
                    $"Trying to set {Lot} count to {Count}, this is beyond the item's stack-size; Setting it to stack-size"
                    );

                count = (uint)ItemComponent.StackSize;
            }

            var item = await ctx.InventoryItems.FirstAsync(i => i.Id == Id);

            item.Count = count;

            Logger.Debug($"Setting {this}'s stack size to {item.Count}");

            if (count <= 0)
            {
                if (await IsEquippedAsync())
                {
                    await UnEquipAsync();
                }

                ctx.InventoryItems.Remove(item);

                Destroy(this);

                // Disassemble item.
                if (LegoDataDictionary.FromString(item.ExtraInfo).TryGetValue("assemblyPartLOTs", out var list))
                {
                    foreach (var part in (LegoDataList)list)
                    {
                        await Inventory.ManagerComponent.AddItemAsync((int)part, 1);
                    }
                }
            }

            await ctx.SaveChangesAsync();
        }
コード例 #18
0
ファイル: Item.cs プロジェクト: kulaj/Uchu
        public static Item Instantiate(long itemId, Inventory inventory)
        {
            using var cdClient = new CdClientContext();
            using var ctx      = new UchuContext();

            var item = ctx.InventoryItems.FirstOrDefault(
                i => i.Id == itemId && i.Character.Id == inventory.ManagerComponent.GameObject.Id
                );

            if (item == default)
            {
                Logger.Error($"{itemId} is not an item on {inventory.ManagerComponent.GameObject}");
                return(null);
            }

            var cdClientObject = cdClient.ObjectsTable.FirstOrDefault(
                o => o.Id == item.Lot
                );

            var itemRegistryEntry = ((Lot)item.Lot).GetComponentId(ComponentId.ItemComponent);

            if (cdClientObject == default || itemRegistryEntry == default)
            {
                Logger.Error($"{itemId} [{item.Lot}] is not a valid item");
                return(null);
            }

            var instance = Instantiate <Item>
                           (
                inventory.ManagerComponent.Zone, cdClientObject.Name, objectId: itemId, lot: item.Lot
                           );

            if (!string.IsNullOrWhiteSpace(item.ExtraInfo))
            {
                instance.Settings = LegoDataDictionary.FromString(item.ExtraInfo);
            }

            instance.Inventory = inventory;
            instance.Player    = inventory.ManagerComponent.GameObject as Player;

            return(instance);
        }
コード例 #19
0
        public void SendCharacterData(Connection connection, Character character)
        {
            var info = new LegoDataDictionary
            {
                ["accountID"]      = character.AccountId,
                ["objid"]          = character.ObjectId,
                ["template"]       = 1,
                ["editor_enabled"] = true,
                ["editor_level"]   = 9,
                ["name"]           = character.Name,
                ["position.x"]     = -629f,
                ["position.y"]     = 613.4f,
                ["position.z"]     = -30f
            };

            connection.Send(new ClientCreateCharacterPacket
            {
                Info = info
            });
        }
コード例 #20
0
ファイル: InventoryComponent.cs プロジェクト: kulaj/Uchu
        public override void Serialize(BitWriter writer)
        {
            writer.WriteBit(true);

            var items = Items.Values.ToArray();

            writer.Write((uint)items.Length);

            foreach (var item in items)
            {
                writer.Write(item.Id);
                writer.Write(item.Lot);

                writer.WriteBit(false);

                writer.WriteBit(false);

                writer.WriteBit(false);

                writer.WriteBit(false);

                var info = item.Id.FindItem();

                if (info == default)
                {
                    writer.WriteBit(false);
                }
                else
                {
                    if (writer.Flag(!string.IsNullOrWhiteSpace(info.ExtraInfo)))
                    {
                        writer.WriteLdfCompressed(LegoDataDictionary.FromString(info.ExtraInfo));
                    }
                }

                writer.WriteBit(true);
            }

            writer.WriteBit(false);
        }
コード例 #21
0
ファイル: ObjectScript.cs プロジェクト: UchuServer/Uchu
        /// <summary>
        /// Prepares an LDF wot use with ScriptNetworkVarUpdateMessage and
        /// sets the internal LDF data of the script component.
        /// </summary>
        /// <param name="name">Name of the variable to store.</param>
        /// <param name="value">Value of the variable to store.</param>
        /// <param name="ldf">Dictionary to set up for sending with ScriptNetworkVarUpdateMessage.</param>
        private void PrepareDictionary(string name, object value, LegoDataDictionary ldf)
        {
            // Add the value.
            if (value is IList list)
            {
                // Add the list entries.
                // These aren't stored in the script.
                for (var i = 0; i < list.Count; i++)
                {
                    var subValue = list[i];
                    var key      = name + "." + (i + 1);
                    if (subValue is GameObject gameObject)
                    {
                        ldf.Add(key, gameObject.Id);
                    }
                    else
                    {
                        ldf.Add(key, subValue);
                    }
                }
            }
            else
            {
                // Convert the object.
                var newValue = value;
                if (value is GameObject gameObject)
                {
                    newValue = (long)gameObject.Id;
                }

                // Store the object.
                if (this.GameObject.TryGetComponent <LuaScriptComponent>(out var component))
                {
                    component.Data ??= new LegoDataDictionary();
                    component.Data.Add(name, newValue);
                }
                ldf.Add(name, newValue);
            }
        }
コード例 #22
0
        /// <summary>
        /// Performs and operations between setting the
        /// boot.cfg and launching the client. This will
        /// yield launching the client.
        /// </summary>
        public void OnClientRequestLaunch()
        {
            // Determine the host to check.
            var bootConfig = LegoDataDictionary.FromString(File.ReadAllText(Path.Combine(this.systemInfo.ClientLocation, "boot.cfg").Replace("\n", "")).Trim(), ',');
            var host       = (string)bootConfig["AUTHSERVERIP"];

            Console.WriteLine("Check for TCP/UDP for: " + host);

            // Assume TCP/UDP if any port is specified.
            // Even if 1001, the stock client will not connect correctly.
            if (host.Contains(":"))
            {
                var portString = host.Remove(0, host.IndexOf(":", StringComparison.Ordinal) + 1).Trim();
                if (int.TryParse(portString, out var port))
                {
                    Console.WriteLine("Custom port " + port + " specified. Assuming TCP/UDP.");
                    this.Enable();
                    return;
                }
            }

            // Try to connect and disconnect from port 21836 (default TCP/UDP port).
            // Port 1001 is more likely to be used by other applications like games.
            try
            {
                // Enable TCP/UDP after a successful connect and close.
                var client = new TcpClient(host, 21836);
                client.Close();
                Console.WriteLine("Connection to default TCP/UDP port 21836 successful. Assuming TCP/UDP.");
                this.Enable();
            }
            catch (Exception)
            {
                // Disable TCP/UDP (assume RakNet).
                Console.WriteLine("Connection to default TCP/UDP port 21836 failed. Assuming not TCP/UDP.");
                this.Disable();
            }
        }
コード例 #23
0
        public async Task AddItemAsync(int lot, uint count, InventoryType inventoryType, LegoDataDictionary extraInfo = default)
        {
            var itemCount = count;

            Detach(() =>
            {
                OnLotAdded.Invoke(lot, itemCount);
            });

            var inventory = _inventories[inventoryType];

            // The math here cannot be executed in parallel

            await using var cdClient = new CdClientContext();

            var componentId = cdClient.ComponentsRegistryTable.FirstOrDefault(
                r => r.Id == lot && r.Componenttype == (int)ComponentId.ItemComponent
                );

            if (componentId == default)
            {
                Logger.Error($"{lot} does not have a Item component");
                return;
            }

            var component = cdClient.ItemComponentTable.FirstOrDefault(
                i => i.Id == componentId.Componentid
                );

            if (component == default)
            {
                Logger.Error(
                    $"{lot} has a corrupted component registry. There is no Item component of Id: {componentId.Componentid}"
                    );
                return;
            }

            As <Player>().SendChatMessage($"Calculating for {lot} x {count} [{inventoryType}]", PlayerChatChannel.Normal);

            var stackSize = component.StackSize ?? 1;

            // Bricks and alike does not have a stack limit.
            if (stackSize == default)
            {
                stackSize = int.MaxValue;
            }

            //
            // Update quest tasks
            //

            var questInventory = GameObject.GetComponent <MissionInventoryComponent>();

            for (var i = 0; i < count; i++)
            {
                await questInventory.ObtainItemAsync(lot);
            }

            //
            // Fill stacks
            //

            lock (_lock)
            {
                foreach (var item in inventory.Items.Where(i => i.Lot == lot))
                {
                    if (item.Count == stackSize)
                    {
                        continue;
                    }

                    var toAdd = (uint)Min(stackSize, (int)count, (int)(stackSize - item.Count));

                    item.Count += toAdd;

                    count -= toAdd;

                    if (count <= 0)
                    {
                        return;
                    }
                }

                //
                // Create new stacks
                //

                var toCreate = count;

                while (toCreate != default)
                {
                    var toAdd = (uint)Min(stackSize, (int)toCreate);

                    var item = Item.Instantiate(lot, inventory, toAdd, extraInfo);

                    Start(item);

                    toCreate -= toAdd;
                }
            }
        }
コード例 #24
0
ファイル: MatchHandler.cs プロジェクト: UchuServer/Uchu
        public void RequestActivitySummaryLeaderboardDataMessageHandler(RequestActivitySummaryLeaderboardDataMessage message, Player player)
        {
            using var ctx = new UchuContext();
            // Get current year and week number according to ISO 8601
            var yearAndWeek = ISOWeek.GetYear(DateTime.Now) * 100 + ISOWeek.GetWeekOfYear(DateTime.Now);

            // Find leaderboard entries for this activity
            // If weekly leaderboard is requested, only return results from current week
            var leaderboardQueryable = ctx.ActivityScores
                                       .Where(score => score.Activity == message.GameId &&
                                              (message.Weekly ? score.Week == yearAndWeek : score.Week == 0));

            // Find leaderboard type
            var activity        = ClientCache.Find <Activities>(message.GameId);
            var leaderboardType = (LeaderboardType)(activity?.LeaderboardType ?? -1);

            // For some reason, whoever made this in 2011 gave the the NS and NT footraces the
            // same activity ID. So for footraces, we filter by zone ID to ensure we don't mix
            // the leaderboards. But this check shouldn't be done for other leaderboards, as
            // Survival minigames have their leaderboards accessible from multiple zones.
            if (leaderboardType == LeaderboardType.Footrace)
            {
                leaderboardQueryable = leaderboardQueryable.Where(score => score.Zone == (int)player.Zone.ZoneId);
            }

            // Order either by time ascending or time descending depending on which kind of activity it is
            if (leaderboardType == LeaderboardType.Footrace ||
                leaderboardType == LeaderboardType.AvantGardensSurvival ||
                leaderboardType == LeaderboardType.BattleOfNimbusStation)
            {
                leaderboardQueryable = leaderboardQueryable.OrderByDescending(score => score.Time);
            }
            else
            {
                leaderboardQueryable = leaderboardQueryable.OrderBy(score => score.Time);
            }

            var leaderboard = leaderboardQueryable.ToList();

            // Dictionary <rank, score>
            // Rank is what the client will show as position on the leaderboard
            var toSend = new Dictionary <int, ActivityScore>();

            switch (message.QueryType)
            {
            case QueryType.TopSocial:
                // TODO: Friends.
                break;

            case QueryType.TopAll:
                // Top 10.
                for (var i = message.ResultsStart; i < message.ResultsEnd && i < leaderboard.Count; i++)
                {
                    toSend.Add(i + 1, leaderboard[i]);
                }
                break;

            case QueryType.TopCharacter:
                // Leaderboard around this player's rank.
                var playerIndex = leaderboard.FindIndex(score => score.CharacterId == player.Id);

                // If player is not in leaderboard, return (client will show a friendly message telling the player
                // to first complete the activity)
                if (playerIndex == -1)
                {
                    break;
                }

                var availableBefore = playerIndex;
                var availableAfter  = leaderboard.Count - playerIndex;

                // By default we show 5 scores before this player's, and 4 after (last index isn't included).
                var includeBefore = 5;
                var includeAfter  = 5;

                // For every step we can't go before, add one to after
                includeAfter += Math.Max(0, 5 - availableBefore);

                // For every step we can't go after, add one to before
                includeBefore += Math.Max(0, 5 - availableAfter);

                // Ensure we don't go outside the leaderboard limits
                var startIndex = Math.Max(0, playerIndex - includeBefore);
                var stopIndex  = Math.Min(leaderboard.Count, playerIndex + includeAfter);

                for (var i = startIndex; i < stopIndex; i++)
                {
                    toSend.Add(i + 1, leaderboard[i]);
                }
                break;
            }

            // "Properly" implementing this odd nested-dictionaries-and-arrays-inside-LDF didn't seem
            // particularly fun and/or useful; this implementation just does everything needed for leaderboards.
            var data = new LegoDataDictionary
            {
                { "ADO.Result", true },
                { "Result.Count", 1 },
                { "Result[0].Index", "RowNumber" },
                { "Result[0].RowCount", toSend.Count },
            };

            var index = 0;

            foreach (var(rank, activityScore) in toSend)
            {
                var characterName = ctx.Characters.FirstOrDefault(c => c.Id == activityScore.CharacterId)?.Name
                                    ?? "Deleted Character";
                data.Add($"Result[0].Row[{index}].CharacterID", activityScore.CharacterId);
                data.Add($"Result[0].Row[{index}].LastPlayed", activityScore.LastPlayed);
                data.Add($"Result[0].Row[{index}].NumPlayed", activityScore.NumPlayed);
                data.Add($"Result[0].Row[{index}].RowNumber", rank);
                data.Add($"Result[0].Row[{index}].Time", activityScore.Time);
                data.Add($"Result[0].Row[{index}].Points", activityScore.Points);
                data.Add($"Result[0].Row[{index}].name", characterName);
                // TODO: ".Relationship" variable (int).
                // (AGS client script: if not 0, FoundFriendGuild set to true. Teams?)
                // data.Add($"Result[0].Row[{index}].Relationship", 0);
                index++;
            }

            player.Message(new SendActivitySummaryLeaderboardDataMessage
            {
                Associate       = player,
                GameId          = message.GameId,
                InfoType        = (int)message.QueryType,
                LeaderboardData = data,
                Throttled       = false,
                Weekly          = message.Weekly,
            });
        }
コード例 #25
0
        /// <summary>
        /// Instantiates an item using static information.
        /// </summary>
        /// <param name="owner">The owner of this item</param>
        /// <param name="lot">The lot of this item</param>
        /// <param name="inventory">The inventory to add the item to, if left empty, this item will be left unmanaged</param>
        /// <param name="count">The count of the item to add</param>
        /// <param name="slot">The slot to add the item to</param>
        /// <param name="extraInfo">Optional LDD to set on the item</param>
        /// <param name="objectId">Explicit object Id for this item, generally only used for player instance items</param>
        /// <param name="rootItem">The root item this item is based on</param>
        /// <param name="isEquipped">Whether the game object has this item equipped or not</param>
        /// <param name="isBound">Whether the game object has bound this item or not</param>
        /// <param name="lootType">Where this item came from</param>
        /// <remarks>Note that <c>Start</c> still needs to be called on the item to be registered properly in the world.</remarks>
        /// <returns>The instantiated item or <c>null</c> if no slot could be acquired or if the item couldn't be added to the inventory</returns>
        public static async Task <Item> Instantiate(GameObject owner, Lot lot,
                                                    Inventory inventory, uint count, uint slot = default, LegoDataDictionary extraInfo = default,
                                                    ObjectId objectId = default, Item rootItem = default, bool isEquipped = false, bool isBound = false, LootType lootType = LootType.None)
        {
            // Try to find the slot at which this item should be inserted if no explicit slot is provided
            if (inventory != default && slot == default)
            {
                try
                {
                    slot = inventory.ClaimSlot();
                }
                catch (InventoryFullException)
                {
                    return(null);
                }
            }

            var itemTemplate      = (await ClientCache.FindAsync <Core.Client.Objects>(lot));
            var itemRegistryEntry = (await ClientCache.FindAllAsync <ComponentsRegistry>(lot)).FirstOrDefault(
                r => r.Componenttype == (int)ComponentId.ItemComponent
                );

            if (itemRegistryEntry == default)
            {
                return(default);
コード例 #26
0
ファイル: Item.cs プロジェクト: kulaj/Uchu
        public static Item Instantiate(Lot lot, Inventory inventory, uint count, uint slot, LegoDataDictionary extraInfo = default)
        {
            using var cdClient = new CdClientContext();
            using var ctx      = new UchuContext();

            var cdClientObject = cdClient.ObjectsTable.FirstOrDefault(
                o => o.Id == lot
                );

            var itemRegistryEntry = cdClient.ComponentsRegistryTable.FirstOrDefault(
                r => r.Id == lot && r.Componenttype == 11
                );

            if (cdClientObject == default || itemRegistryEntry == default)
            {
                Logger.Error($"<new item> [{lot}] is not a valid item");
                return(null);
            }

            var instance = Instantiate <Item>
                           (
                inventory.ManagerComponent.Zone, cdClientObject.Name, objectId: ObjectId.Standalone, lot: lot
                           );

            instance.Settings = extraInfo ?? new LegoDataDictionary();

            var itemComponent = cdClient.ItemComponentTable.First(
                i => i.Id == itemRegistryEntry.Componentid
                );

            instance.Inventory = inventory;
            instance.Player    = inventory.ManagerComponent.GameObject as Player;

            var playerCharacter = ctx.Characters.Include(c => c.Items).First(
                c => c.Id == inventory.ManagerComponent.GameObject.Id
                );

            var inventoryItem = new InventoryItem
            {
                Count         = count,
                InventoryType = (int)inventory.InventoryType,
                Id            = instance.Id,
                IsBound       = itemComponent.IsBOP ?? false,
                Slot          = (int)slot,
                Lot           = lot,
                ExtraInfo     = extraInfo?.ToString()
            };

            playerCharacter.Items.Add(inventoryItem);

            ctx.SaveChanges();

            var message = new AddItemToInventoryMessage
            {
                Associate       = inventory.ManagerComponent.GameObject,
                InventoryType   = (int)inventory.InventoryType,
                Delta           = count,
                TotalItems      = count,
                Slot            = (int)slot,
                ItemLot         = lot,
                IsBoundOnEquip  = itemComponent.IsBOE ?? false,
                IsBoundOnPickup = itemComponent.IsBOP ?? false,
                IsBound         = inventoryItem.IsBound,
                Item            = instance,
                ExtraInfo       = extraInfo
            };

            (inventory.ManagerComponent.GameObject as Player)?.Message(message);

            inventory.ManageItem(instance);

            return(instance);
        }