【MinecraftConnection】ライブラリメモ #5

自作ライブラリのメモその5。ChestItems クラスを追加。

チェストアイテムに対して操作ができるクラスで、現在はアイテムの取得、更新、ソートが行える。

名前空間MinecraftConnection.Data

コンストラクタ:RCON

  • GetChestItems(int x, int y, int z) : チェスト内のアイテムを取得する。
  • SetChestItems(int x, int y, int z, List<Item> ItemList) : チェスト内のアイテムを ItemList で上書きする。
  • SortByItemCount(List<Item> ItemList) : アイテムをソートする。

x, y, z はチェストの座標

チェスト内のアイテムを取得する

返り値は List<Item> で、Itemクラスにはプロパティが3つある。これを返すメソッドが次の通り。

  • GetItemSlot() : アイテムスロットを取得する
  • GetItemID() : アイテム名(ID)を取得する
  • GetItemCount() : アイテム数を取得する

使い方

using CoreRCON;
using MinecraftConnection.Data;
//名前空間
class Program
{
    private static IPAddress IP = IPAddress.Parse("127.0.0.1");
    private static ushort Port = 25575;
    private static string Password = "minecraft";
    private static RCON rcon = new RCON(IP, Port, Password);

    static void Main(string[] args)
    {
        ChestItems chestItems = new ChestItems(rcon);
        var getItems = chestItems.GetChestItems(<チェストの座標(x, y, z)>);
        foreach (var item in getItems)
        {
            Console.WriteLine($"{item.GetItemSlot()} {item.GetItemID()} {item.GetItemCount()}");
        }
    }
}

実行結果

コンソール出力にて、左から順にアイテムスロット、アイテム名(ID)、アイテムの個数。

f:id:takunology:20210208174303p:plain

チェスト内のアイテムを書きかえる

List<Item> を作って、そこにアイテムを Add() メソッドで追加する。作ったアイテムリストを引数に入れて実行。

Item のコンストラクタの引数はそれぞれ Item(srting ItemID, int ItemCount, int ItemSlot) となっている。現在はこの状態だが、後にスロット、ID、アイテム数の順に変更する予定。

使い方

class Program
{
    private static IPAddress IP = IPAddress.Parse("127.0.0.1");
    private static ushort Port = 25575;
    private static string Password = "minecraft";
    private static RCON rcon = new RCON(IP, Port, Password);

    static void Main(string[] args)
    {
        var items = new List<Item>();
        items.Add(new Item("minecraft:diamond", 4, 0));
        items.Add(new Item("minecraft:chest", 2, 5));
        items.Add(new Item("minecraft:oak_planks", 8, 1)); 
        items.Add(new Item("minecraft:oak_planks", 16, 8));
        items.Add(new Item("minecraft:stone", 9, 3));
        items.Add(new Item("minecraft:stone", 46, 10));
        items.Add(new Item("minecraft:torch", 42, 11));
        items.Add(new Item("minecraft:stone", 55, 12));
        items.Add(new Item("minecraft:torch", 23, 16));
        items.Add(new Item("minecraft:stone", 1, 7));
        
        ChestItems chestItems = new ChestItems(rcon);
        chestItems.SetChestItems(<チェストの座標(x, y, z)>, items);
    }
}

チェスト内のアイテムをソートする

正確には「アイテムリストをなるべく1スタックにまとめて並べる」が正しい。なので、チェスト内のアイテムに限らず、アイテムリストであればソートはできる。(正直、 ChestItems クラスに作るのではなく、別のクラスに作ったほうがよかったかもしれない。)

使い方

取得したチェスト内のアイテムをリスト化し、それをソートして再度上書きする例。

class Program
{
    private static IPAddress IP = IPAddress.Parse("127.0.0.1");
    private static ushort Port = 25575;
    private static string Password = "minecraft";
    private static RCON rcon = new RCON(IP, Port, Password);

    static void Main(string[] args)
    {
        ChestItems chestItems = new ChestItems(rcon);
        var getItems = chestItems.GetChestItems(<チェストの座標(x, y, z)>);        
        var sortedItems = chestItems.SortByItemCount(getItems);
        chestItems.SetChestItems(<チェストの座標(x, y, z)>, items);
    }
}

実行結果

実行結果は twitter にて。

LINQ がめっちゃ便利だった件

Item クラスでは3つの値を持っているので、データベースのような操作ができる。今回はキーをアイテム名にして並べ替えて、重複を削除しつつ、その重複しているアイテムの個数をなるべく1つにまとめた。ただ、Minecraft の仕様上、アイテム1つにつき 64 個が最大数なので 64 で割り切れれば1スタックとし、リストを追加していった。この並べ替えが LINQ を使うとすごい便利で、いちいち配列に分けてスワップしなくても良い。C# 最高。

とりあえずソート部分だけ。もっと短くできそうだけど知識がないので今はこれが限界。

private List<Item> SortByItemCountList = new List<Item>();

public List<Item> SortByItemCount(List<Item> ItemList)
{
    //名前順に並べ替え
    var queryItems = ItemList
        .OrderBy(x => x.GetItemID())
        .ThenBy(x => x.GetItemCount())
        .ThenBy(x => x.GetItemSlot())
        .ToList();

    //重複アイテムの抽出
    var distinctes = queryItems.Select(x => x.GetItemID()).Distinct();

    //重複したアイテムを全て合計して一つの要素にまとめる
    Dictionary<string, int> ItemsSum = new Dictionary<string, int>();
    //Dictionary初期化
    foreach (var item in distinctes)
    {
        ItemsSum.Add(item, 0);
    }

    for (int i = 0; i < ItemList.Count; i++)
    {
        foreach (var element in distinctes)
        {
            if (element == ItemList[i].GetItemID())
            {
                ItemsSum[element] += ItemList[i].GetItemCount();
            }
        }
    }

    //アイテムスロットのID
    int SlotIndex = 0;

    foreach (var item in ItemsSum)
    {
        if (item.Value <= 64)
        {
            SortByItemCountList.Add(new Item(item.Key, item.Value, SlotIndex));
            SlotIndex++;
        }
        else if (item.Value > 64)
        {
            int stack = item.Value / 64;
            int over = item.Value % 64;

            for (int i = 0; i < stack; i++)
            {
                SortByItemCountList.Add(new Item(item.Key, 64, SlotIndex));
                SlotIndex++;
            }
            SortByItemCountList.Add(new Item(item.Key, over, SlotIndex));
            SlotIndex++;
        }
    }

    return SortByItemCountList;
}

プロジェクトが大きくなってきたので、名前空間やクラスを色々整理したいなぁと思った。あと、これを Minecraft with Code Project の Minecraft自動化に追加する予定。