【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)、アイテムの個数。
チェスト内のアイテムを書きかえる
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 にて。
散らばっていたチェスト内のアイテムを自動でまとめてくれるプログラム。 pic.twitter.com/DjCNiTCTEe
— たくのろじぃ / takunology (@takunology_net) February 8, 2021
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自動化に追加する予定。