py2hackCraft2 1.1.41__tar.gz → 1.1.43__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: py2hackCraft2
3
- Version: 1.1.41
3
+ Version: 1.1.43
4
4
  Summary: Python client library for hackCraft2
5
5
  Home-page: https://github.com/0x48lab/hackCraft2-python
6
6
  Author: masafumi_t
@@ -1920,3 +1920,349 @@ class Entity:
1920
1920
  self.client.send_call(self.uuid, "blockColor", [color])
1921
1921
  block = Block(** json.loads(self.client.result))
1922
1922
  return block
1923
+
1924
+ def _convert_recipe_pattern(self, recipe):
1925
+ """
1926
+ Convert recipe pattern to comma-separated string format.
1927
+
1928
+ Handles two input formats:
1929
+ 1. String: "1,1,1,,2,,,2" -> returns as-is
1930
+ 2. List: [1,1,1,None,2,None,None,2] -> "1,1,1,,2,,,2"
1931
+
1932
+ Args:
1933
+ recipe: Recipe pattern as string or list
1934
+
1935
+ Returns:
1936
+ str: Comma-separated string pattern
1937
+
1938
+ Raises:
1939
+ ValueError: If pattern is invalid
1940
+ """
1941
+ # If already a string, validate and return
1942
+ if isinstance(recipe, str):
1943
+ if not recipe.strip():
1944
+ raise ValueError("Pattern cannot be empty")
1945
+
1946
+ elements = recipe.split(",")
1947
+ if len(elements) > 9:
1948
+ raise ValueError(f"Pattern exceeds 3x3 grid size (max 9 elements, got {len(elements)})")
1949
+
1950
+ # Validate each non-empty element is a valid number or 'X'
1951
+ for i, element in enumerate(elements):
1952
+ trimmed = element.strip()
1953
+ if trimmed:
1954
+ # Allow 'X' or 'x' as AIR placeholder
1955
+ if trimmed.upper() == 'X':
1956
+ continue
1957
+ try:
1958
+ int(trimmed)
1959
+ # Allow any integer (negative values are treated as AIR on server)
1960
+ except ValueError as e:
1961
+ if "invalid literal" in str(e):
1962
+ raise ValueError(f"Invalid slot number at position {i}: '{element}' (use number or 'X' for empty)")
1963
+ raise
1964
+
1965
+ return recipe
1966
+
1967
+ # List format
1968
+ if isinstance(recipe, list):
1969
+ if len(recipe) == 0:
1970
+ raise ValueError("Pattern list cannot be empty")
1971
+
1972
+ if len(recipe) > 9:
1973
+ raise ValueError(f"Pattern exceeds 3x3 grid size (max 9 elements, got {len(recipe)})")
1974
+
1975
+ # Validate and convert to string
1976
+ result = []
1977
+ for i, slot in enumerate(recipe):
1978
+ if slot is None or slot == "":
1979
+ result.append("")
1980
+ elif isinstance(slot, str):
1981
+ # Allow 'X' or 'x' as AIR placeholder, convert to -1
1982
+ if slot.strip().upper() == 'X':
1983
+ result.append("-1")
1984
+ else:
1985
+ raise ValueError(f"Invalid slot value at position {i}: '{slot}' (use number, None, or 'X')")
1986
+ elif isinstance(slot, int):
1987
+ # Allow any integer (negative values are treated as AIR on server)
1988
+ result.append(str(slot))
1989
+ else:
1990
+ raise ValueError(f"Invalid slot value at position {i}: {slot}")
1991
+
1992
+ return ",".join(result)
1993
+
1994
+ raise ValueError("Recipe pattern must be a string or list")
1995
+
1996
+ def craft(self, recipe, qty=1, slot=None):
1997
+ """
1998
+ ペットのインベントリにある材料を使ってアイテムをクラフトする。
1999
+
2000
+ 引数:
2001
+ recipe: レシピパターン(文字列またはリスト形式)
2002
+ - 文字列形式: "1,1,1,X,2,X,X,2,X" (カンマ区切りのスロット番号、空は X または空文字)
2003
+ - リスト形式: [1,1,1,"X",2,"X","X",2,"X"] または [1,1,1,None,2,None,None,2,None]
2004
+ - スロット番号は0から始まる(0=スロット1)
2005
+ - 負の数(-1など)も空気として扱われる
2006
+ qty: クラフトする個数(デフォルト: 1)
2007
+ slot: 結果を配置するスロット番号(デフォルト: None = 自動配置)
2008
+
2009
+ 戻り値:
2010
+ dict: クラフト結果(以下の構造)
2011
+ {
2012
+ "success": bool, # 成功したか
2013
+ "result_item": str | None, # 作成されたアイテム名
2014
+ "result_quantity": int | None,# 作成された個数
2015
+ "requested_quantity": int, # リクエストした個数
2016
+ "result_slot": int | None, # 配置されたスロット
2017
+ "materials_consumed": dict, # 消費された材料
2018
+ "game_mode": str, # ゲームモード
2019
+ "error": dict | None # エラー情報
2020
+ }
2021
+
2022
+ 使用例:
2023
+ >>> # パンをクラフト(スロット0に小麦3つ)
2024
+ >>> result = entity.craft("0,0,0")
2025
+ >>> if result["success"]:
2026
+ >>> print(f"{result['result_item']}を{result['result_quantity']}個作ったよ!")
2027
+
2028
+ >>> # リスト形式でつるはしをクラフト
2029
+ >>> result = entity.craft([3,3,3,"X",4,"X","X",4,"X"])
2030
+
2031
+ >>> # 複数個クラフトして、スロット10に配置
2032
+ >>> result = entity.craft("0,0,0", qty=5, slot=10)
2033
+
2034
+ >>> # エラー処理
2035
+ >>> result = entity.craft("0,0,0")
2036
+ >>> if not result["success"]:
2037
+ >>> error = result["error"]
2038
+ >>> print(f"エラー: {error['message']}")
2039
+ >>> if error["code"] == "INSUFFICIENT_MATERIALS":
2040
+ >>> print("材料が足りないよ")
2041
+ """
2042
+ # Convert recipe to string format
2043
+ pattern = self._convert_recipe_pattern(recipe)
2044
+
2045
+ # Prepare arguments
2046
+ args = [pattern, qty]
2047
+ if slot is not None:
2048
+ args.append(slot)
2049
+
2050
+ # Send craft request
2051
+ self.client.send_call(self.uuid, "craft", args)
2052
+
2053
+ # Parse response
2054
+ result = json.loads(self.client.result)
2055
+
2056
+ return result
2057
+
2058
+ # ===== Livestock Methods =====
2059
+
2060
+ def livestock_count_nearby(self, animal_type: str = "ALL", radius: float = 50.0) -> int:
2061
+ """
2062
+ 近くの動物を数える
2063
+
2064
+ Args:
2065
+ animal_type (str): 動物種別(COW, PIG, SHEEP, CHICKEN, RABBIT, HORSE, ALL)
2066
+ radius (float): 検索半径(ブロック数)
2067
+
2068
+ Returns:
2069
+ int: 動物の数
2070
+
2071
+ Example:
2072
+ >>> count = entity.livestock_count_nearby("COW", 50)
2073
+ >>> print(f"Found {count} cows")
2074
+ """
2075
+ self.client.send_call(self.uuid, "livestockCountNearby", [animal_type, radius])
2076
+ result = json.loads(self.client.result)
2077
+ if not result.get('success', False):
2078
+ raise Exception(f"Livestock operation failed: {result.get('message', 'Unknown error')}")
2079
+ return result.get('data', {}).get('count', 0)
2080
+
2081
+ def livestock_get_nearest_uuid(self, animal_type: str = "ALL", radius: float = 50.0) -> Optional[str]:
2082
+ """
2083
+ 最も近い動物のUUIDを取得
2084
+
2085
+ Args:
2086
+ animal_type (str): 動物種別(COW, PIG, SHEEP, CHICKEN, RABBIT, HORSE, ALL)
2087
+ radius (float): 検索半径(ブロック数)
2088
+
2089
+ Returns:
2090
+ Optional[str]: 動物のUUID(見つからない場合はNone)
2091
+
2092
+ Example:
2093
+ >>> cow_uuid = entity.livestock_get_nearest_uuid("COW", 50)
2094
+ >>> if cow_uuid:
2095
+ >>> print(f"Found cow: {cow_uuid}")
2096
+ """
2097
+ self.client.send_call(self.uuid, "livestockGetNearestUuid", [animal_type, radius])
2098
+ result = json.loads(self.client.result)
2099
+ if not result.get('success', False):
2100
+ raise Exception(f"Livestock operation failed: {result.get('message', 'Unknown error')}")
2101
+ uuid = result.get('data', {}).get('uuid')
2102
+ return uuid if uuid else None
2103
+
2104
+ def livestock_find_nearby(self, animal_type: str = "ALL", radius: float = 50.0) -> list:
2105
+ """
2106
+ 近くの動物を詳細情報付きで検索
2107
+
2108
+ Args:
2109
+ animal_type (str): 動物種別(COW, PIG, SHEEP, CHICKEN, RABBIT, HORSE, ALL)
2110
+ radius (float): 検索半径(ブロック数)
2111
+
2112
+ Returns:
2113
+ list: 動物情報の辞書リスト
2114
+
2115
+ Example:
2116
+ >>> animals = entity.livestock_find_nearby("SHEEP", 30)
2117
+ >>> for animal in animals:
2118
+ >>> print(f"{animal['animalType']} at distance {animal['distance']}")
2119
+ """
2120
+ self.client.send_call(self.uuid, "livestockFindNearby", [animal_type, radius])
2121
+ result = json.loads(self.client.result)
2122
+ if not result.get('success', False):
2123
+ raise Exception(f"Livestock operation failed: {result.get('message', 'Unknown error')}")
2124
+ return result.get('data', {}).get('entities', [])
2125
+
2126
+ def livestock_herd(self, animal_uuid: str, x: float, y: float, z: float, cord: str = "^", speed: float = 1.0) -> None:
2127
+ """
2128
+ 動物を指定座標に誘導
2129
+
2130
+ Args:
2131
+ animal_uuid (str): 動物のUUID
2132
+ x (float): 目標X座標
2133
+ y (float): 目標Y座標
2134
+ z (float): 目標Z座標
2135
+ cord (str): 座標系("": 絶対座標, "~": 相対座標, "^": ローカル座標、デフォルト: "^")
2136
+ speed (float): 移動速度(0.5-2.0、デフォルト1.0)
2137
+
2138
+ Example:
2139
+ >>> entity.livestock_herd(cow_uuid, 100, 64, 200, "^", 1.0)
2140
+ """
2141
+ self.client.send_call(animal_uuid, "livestockHerd", [x, y, z, cord, speed])
2142
+ result = json.loads(self.client.result)
2143
+ if not result.get('success', False):
2144
+ raise Exception(f"Herd operation failed: {result.get('message', 'Unknown error')}")
2145
+
2146
+ def livestock_herd_all_nearby(
2147
+ self,
2148
+ animal_type: str,
2149
+ radius: float,
2150
+ x: float,
2151
+ y: float,
2152
+ z: float,
2153
+ cord: str = "^",
2154
+ speed: float = 1.0
2155
+ ) -> int:
2156
+ """
2157
+ 近くの動物すべてを指定座標に誘導
2158
+
2159
+ Args:
2160
+ animal_type (str): 動物種別(COW, PIG, SHEEP, CHICKEN, RABBIT, HORSE, ALL)
2161
+ radius (float): 検索半径(ブロック数)
2162
+ x (float): 目標X座標
2163
+ y (float): 目標Y座標
2164
+ z (float): 目標Z座標
2165
+ cord (str): 座標系("": 絶対座標, "~": 相対座標, "^": ローカル座標、デフォルト: "^")
2166
+ speed (float): 移動速度(0.5-2.0、デフォルト1.0)
2167
+
2168
+ Returns:
2169
+ int: 誘導した動物の数
2170
+
2171
+ Example:
2172
+ >>> count = entity.livestock_herd_all_nearby("COW", 50, 100, 64, 200)
2173
+ >>> print(f"Herded {count} cows")
2174
+ """
2175
+ self.client.send_call(self.uuid, "livestockHerdAllNearby", [animal_type, radius, x, y, z, cord, speed])
2176
+ result = json.loads(self.client.result)
2177
+ if not result.get('success', False):
2178
+ raise Exception(f"Herd all operation failed: {result.get('message', 'Unknown error')}")
2179
+ return result.get('data', {}).get('count', 0)
2180
+
2181
+ def livestock_shear(self, sheep_uuid: str) -> dict:
2182
+ """
2183
+ 羊の毛を刈る
2184
+
2185
+ Args:
2186
+ sheep_uuid (str): 羊のUUID
2187
+
2188
+ Returns:
2189
+ dict: 羊毛情報 {wool, color, amount}
2190
+
2191
+ Raises:
2192
+ Exception: 羊毛が生えていない、または羊以外の動物の場合
2193
+
2194
+ Example:
2195
+ >>> try:
2196
+ >>> result = entity.livestock_shear(sheep_uuid)
2197
+ >>> print(f"Got {result['amount']} {result['color']} wool")
2198
+ >>> except Exception as e:
2199
+ >>> print(f"Cannot shear: {e}")
2200
+ """
2201
+ self.client.send_call(sheep_uuid, "livestockShear", [])
2202
+ result = json.loads(self.client.result)
2203
+ if not result.get('success', False):
2204
+ raise Exception(f"Shear operation failed: {result.get('message', 'Unknown error')}")
2205
+ return result.get('data', {})
2206
+
2207
+ def livestock_milk(self, cow_uuid: str) -> dict:
2208
+ """
2209
+ 牛のミルクを搾る
2210
+
2211
+ Args:
2212
+ cow_uuid (str): 牛のUUID
2213
+
2214
+ Returns:
2215
+ dict: ミルク情報 {milk, amount}
2216
+
2217
+ Raises:
2218
+ Exception: 牛以外の動物の場合
2219
+
2220
+ Example:
2221
+ >>> try:
2222
+ >>> result = entity.livestock_milk(cow_uuid)
2223
+ >>> print(f"Got {result['amount']} milk bucket")
2224
+ >>> except Exception as e:
2225
+ >>> print(f"Cannot milk: {e}")
2226
+ """
2227
+ self.client.send_call(cow_uuid, "livestockMilk", [])
2228
+ result = json.loads(self.client.result)
2229
+ if not result.get('success', False):
2230
+ raise Exception(f"Milk operation failed: {result.get('message', 'Unknown error')}")
2231
+ return result.get('data', {})
2232
+
2233
+ def livestock_feed(self, animal_uuid: str, food_type: str = "wheat") -> None:
2234
+ """
2235
+ 動物に餌をやる
2236
+
2237
+ Args:
2238
+ animal_uuid (str): 動物のUUID
2239
+ food_type (str): 餌種別(wheat, carrot, seeds, beetroot)
2240
+
2241
+ Example:
2242
+ >>> entity.livestock_feed(cow_uuid, "wheat")
2243
+ """
2244
+ self.client.send_call(animal_uuid, "livestockFeed", [food_type])
2245
+ result = json.loads(self.client.result)
2246
+ if not result.get('success', False):
2247
+ raise Exception(f"Feed operation failed: {result.get('message', 'Unknown error')}")
2248
+
2249
+ def livestock_get_info(self, animal_uuid: str) -> dict:
2250
+ """
2251
+ 動物の詳細情報を取得
2252
+
2253
+ Args:
2254
+ animal_uuid (str): 動物のUUID
2255
+
2256
+ Returns:
2257
+ dict: 動物の詳細情報
2258
+
2259
+ Example:
2260
+ >>> info = entity.livestock_get_info(cow_uuid)
2261
+ >>> print(f"Health: {info['health']}/{info['maxHealth']}")
2262
+ >>> print(f"Can breed: {info['canBreed']}")
2263
+ """
2264
+ self.client.send_call(animal_uuid, "livestockInfo", [])
2265
+ result = json.loads(self.client.result)
2266
+ if not result.get('success', False):
2267
+ raise Exception(f"Get info operation failed: {result.get('message', 'Unknown error')}")
2268
+ return result.get('data', {}).get('entityInfo', {})
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: py2hackCraft2
3
- Version: 1.1.41
3
+ Version: 1.1.43
4
4
  Summary: Python client library for hackCraft2
5
5
  Home-page: https://github.com/0x48lab/hackCraft2-python
6
6
  Author: masafumi_t
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
2
2
 
3
3
  setup(
4
4
  name="py2hackCraft2",
5
- version="1.1.41",
5
+ version="1.1.43",
6
6
  packages=find_packages(),
7
7
  install_requires=[
8
8
  "websocket-client>=1.6.0",
File without changes
File without changes