@@ -1920,3 +1920,137 @@ def get_block_by_color(self, color: str) -> Block:
19201920 self .client .send_call (self .uuid , "blockColor" , [color ])
19211921 block = Block (** json .loads (self .client .result ))
19221922 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
0 commit comments