Survivalcraft API 1.8.2.3 v1.8.2.3
Survivalcraft 2.4
载入中...
搜索中...
未找到
CraftingRecipesManager.cs
浏览该文件的文档.
1using System.Globalization;
2using System.Xml.Linq;
3using Engine;
4using XmlUtilities;
5
6namespace Game {
7 public static class CraftingRecipesManager {
8 public static List<CraftingRecipe> m_recipes = [];
9 public static List<CraftingRecipe> Recipes => m_recipes;
10 public static string fName = "CraftingRecipesManager";
11
16 public static bool EnableLevelRestrictions = true;
17
18 public static void Initialize() {
19 m_recipes.Clear();
20 XElement source = null;
21 foreach (ModEntity modEntity in ModsManager.ModList) {
22 modEntity.LoadCr(ref source);
23 }
24 LoadData(source);
25 Block[] blocks = BlocksManager.Blocks;
26 foreach (Block block in blocks) {
28 }
29 bool sort = true;
31 "CraftingRecipesManagerInitialize",
32 loader => {
33 loader.CraftingRecipesManagerInitialize(m_recipes, ref sort);
34 return false;
35 }
36 );
37 if (sort) {
38 m_recipes.Sort(
39 delegate(CraftingRecipe r1, CraftingRecipe r2) {
40 int result = Comparer<int>.Default.Compare(r1.DisplayOrder, r2.DisplayOrder);
41 if (result == 0) {
42 int y = r1.Ingredients.Count(s => !string.IsNullOrEmpty(s));
43 int x = r2.Ingredients.Count(s => !string.IsNullOrEmpty(s));
44 return Comparer<int>.Default.Compare(x, y);
45 }
46 return result;
47 }
48 );
49 }
51 "CraftingRecipesManagerInitialized",
52 loader => {
53 loader.CraftingRecipesManagerInitialized();
54 return false;
55 }
56 );
57 }
58
59 public static void LoadData(XElement item) {
60 try {
61 if (item.Attribute("Result") != null) {
62 foreach (XElement xElement in item.Elements()) {
63 LoadData(xElement);
64 }
65 return;
66 }
67 bool flag = false;
69 "OnCraftingRecipeDecode",
70 modLoader => {
71 modLoader.OnCraftingRecipeDecode(m_recipes, item, out flag);
72 return flag;
73 }
74 );
75 if (!flag) {
76 CraftingRecipe craftingRecipe = DecodeElementToCraftingRecipe(item);
77 m_recipes.Add(craftingRecipe);
78 }
79 }
80 catch (Exception e) {
81 Log.Error(e);
82 }
83 }
84
85 public static CraftingRecipe DecodeElementToCraftingRecipe(XElement item, int horizontalLen = 3) {
86 CraftingRecipe craftingRecipe = new();
87 string attributeValue = XmlUtils.GetAttributeValue<string>(item, "Result");
88 string desc = XmlUtils.GetAttributeValue<string>(item, "Description");
89 if (desc.StartsWith('[')
90 && desc.EndsWith(']')
91 && LanguageControl.TryGetBlock(attributeValue, $"CRDescription:{desc.Substring(1, desc.Length - 2)}", out string r)) {
92 desc = r;
93 }
94 craftingRecipe.ResultValue = DecodeResult(attributeValue);
95 craftingRecipe.ResultCount = XmlUtils.GetAttributeValue<int>(item, "ResultCount");
96 string attributeValue2 = XmlUtils.GetAttributeValue(item, "Remains", string.Empty);
97 if (!string.IsNullOrEmpty(attributeValue2)) {
98 craftingRecipe.RemainsValue = DecodeResult(attributeValue2);
99 craftingRecipe.RemainsCount = XmlUtils.GetAttributeValue<int>(item, "RemainsCount");
100 }
101 craftingRecipe.RequiredHeatLevel = XmlUtils.GetAttributeValue<float>(item, "RequiredHeatLevel");
102 craftingRecipe.RequiredPlayerLevel = XmlUtils.GetAttributeValue(item, "RequiredPlayerLevel", 1f);
103 craftingRecipe.Description = desc;
104 craftingRecipe.Message = XmlUtils.GetAttributeValue<string>(item, "Message", null);
105 craftingRecipe.DisplayOrder = XmlUtils.GetAttributeValue(item, "DisplayOrder", 0);
106 Dictionary<char, string> dictionary = new();
107 foreach (XAttribute item2 in from a in item.Attributes()
108 where a.Name.LocalName.Length == 1 && char.IsLower(a.Name.LocalName[0])
109 select a) {
110 DecodeIngredient(item2.Value, out string craftingId, out int? data);
111 if (BlocksManager.FindBlocksByCraftingId(craftingId).Length == 0) {
112 throw new InvalidOperationException($"Block with craftingId \"{item2.Value}\" not found.");
113 }
114 if (data.HasValue
115 && (data.Value < 0 || data.Value > 262143)) {
116 throw new InvalidOperationException($"Data in recipe ingredient \"{item2.Value}\" must be between 0 and 0x3FFFF.");
117 }
118 dictionary.Add(item2.Name.LocalName[0], item2.Value);
119 }
120 string[] array = item.Value.Trim().Split(["\n"], StringSplitOptions.None);
121 for (int i = 0; i < array.Length; i++) {
122 int num = array[i].IndexOf('"');
123 int num2 = array[i].LastIndexOf('"');
124 if (num < 0
125 || num2 < 0
126 || num2 <= num) {
127 throw new InvalidOperationException("Invalid recipe line.");
128 }
129 string text = array[i].Substring(num + 1, num2 - num - 1);
130 for (int j = 0; j < text.Length; j++) {
131 char c = text[j];
132 if (char.IsLower(c)) {
133 string text2 = dictionary[c];
134 craftingRecipe.Ingredients[j + i * horizontalLen] = text2;
135 }
136 }
137 }
138 return craftingRecipe;
139 }
140
141 public static CraftingRecipe FindMatchingRecipe(SubsystemTerrain terrain, string[] ingredients, float heatLevel, float playerLevel) {
142 if (ingredients.All(string.IsNullOrEmpty)) {
143 return null;
144 }
145 CraftingRecipe craftingRecipe = null;
146 Block[] blocks = BlocksManager.Blocks;
147 for (int i = 0; i < blocks.Length; i++) {
148 CraftingRecipe adHocCraftingRecipe = blocks[i].GetAdHocCraftingRecipe(terrain, ingredients, heatLevel, playerLevel);
149 if (adHocCraftingRecipe != null
150 && MatchRecipe(adHocCraftingRecipe.Ingredients, ingredients)) {
151 craftingRecipe = adHocCraftingRecipe;
152 break;
153 }
154 }
155 if (craftingRecipe == null) {
156 foreach (CraftingRecipe recipe in Recipes) {
157 if (MatchRecipe(recipe.Ingredients, ingredients)) {
158 craftingRecipe = recipe;
159 break;
160 }
161 }
162 }
163 if (craftingRecipe != null) {
164 if (heatLevel < craftingRecipe.RequiredHeatLevel) {
165 craftingRecipe = !(heatLevel > 0f)
166 ? new CraftingRecipe { Message = LanguageControl.Get(fName, 0) }
167 : new CraftingRecipe { Message = LanguageControl.Get(fName, 1) };
168 }
169 else if (playerLevel < craftingRecipe.RequiredPlayerLevel && EnableLevelRestrictions) {
170 craftingRecipe = !(craftingRecipe.RequiredHeatLevel > 0f)
171 ? new CraftingRecipe { Message = string.Format(LanguageControl.Get(fName, 2), craftingRecipe.RequiredPlayerLevel) }
172 : new CraftingRecipe { Message = string.Format(LanguageControl.Get(fName, 3), craftingRecipe.RequiredPlayerLevel) };
173 }
174 }
175 return craftingRecipe;
176 }
177
178 public static int DecodeResult(string result) {
179 bool flag2 = false;
180 int result2 = 0;
182 "DecodeResult",
183 modLoader => {
184 result2 = modLoader.DecodeResult(result, out flag2);
185 return flag2;
186 }
187 );
188 if (flag2) {
189 return result2;
190 }
191 if (!string.IsNullOrEmpty(result)) {
192 string[] array = result.Split([':'], StringSplitOptions.None);
193 int blockIndex = BlocksManager.GetBlockIndex(array[0], true);
194 return Terrain.MakeBlockValue(blockIndex, 0, array.Length == 2 ? int.Parse(array[1], CultureInfo.InvariantCulture) : 0);
195 }
196 return 0;
197 }
198
199 public static void DecodeIngredient(string ingredient, out string craftingId, out int? data) {
200 bool flag2 = false;
201 string craftingId_R = string.Empty;
202 int? data_R = null;
204 "DecodeIngredient",
205 modLoader => {
206 modLoader.DecodeIngredient(ingredient, out craftingId_R, out data_R, out flag2);
207 return flag2;
208 }
209 );
210 if (flag2) {
211 craftingId = craftingId_R;
212 data = data_R;
213 return;
214 }
215 string[] array = ingredient.Split([':'], StringSplitOptions.None);
216 craftingId = array[0];
217 data = array.Length >= 2 ? new int?(int.Parse(array[1], CultureInfo.InvariantCulture)) : null;
218 }
219
220 public static bool MatchRecipe(string[] requiredIngredients, string[] actualIngredients) {
221 bool flag2 = false;
222 bool result = false;
224 "MatchRecipe",
225 modLoader => {
226 result = modLoader.MatchRecipe(requiredIngredients, actualIngredients, out flag2);
227 return flag2;
228 }
229 );
230 if (flag2) {
231 return result;
232 }
233 if (actualIngredients.Length > 9) {
234 return false;
235 }
236 string[] array = new string[9];
237 for (int i = 0; i < 2; i++) {
238 bool flip = i != 0;
239 for (int j = -4; j <= 2; j++) {
240 for (int k = -4; k <= 2; k++) {
241 if (!TransformRecipe(array, requiredIngredients, k, j, flip)) {
242 continue;
243 }
244 bool flag = true;
245 for (int l = 0; l < 9; l++) {
246 if (l == actualIngredients.Length
247 || !CompareIngredients(array[l], actualIngredients[l])) {
248 flag = false;
249 break;
250 }
251 }
252 if (flag) {
253 return true;
254 }
255 }
256 }
257 }
258 return false;
259 }
260
261 public static bool TransformRecipe(string[] transformedIngredients, string[] ingredients, int shiftX, int shiftY, bool flip) {
262 for (int i = 0; i < 9; i++) {
263 transformedIngredients[i] = null;
264 }
265 for (int j = 0; j < 3; j++) {
266 for (int k = 0; k < 3; k++) {
267 int num = (flip ? 3 - k - 1 : k) + shiftX;
268 int num2 = j + shiftY;
269 string text = ingredients[k + j * 3];
270 if (num >= 0
271 && num2 >= 0
272 && num < 3
273 && num2 < 3) {
274 transformedIngredients[num + num2 * 3] = text;
275 }
276 else if (!string.IsNullOrEmpty(text)) {
277 return false;
278 }
279 }
280 }
281 return true;
282 }
283
284 public static bool CompareIngredients(string requiredIngredient, string actualIngredient) {
285 if (requiredIngredient == null) {
286 return actualIngredient == null;
287 }
288 if (actualIngredient == null) {
289 //return requiredIngredient == null;
290 return false;
291 }
292 DecodeIngredient(requiredIngredient, out string craftingId, out int? data);
293 DecodeIngredient(actualIngredient, out string craftingId2, out int? data2);
294 if (!data2.HasValue) {
295 throw new InvalidOperationException("Actual ingredient data not specified.");
296 }
297 if (craftingId == craftingId2) {
298 if (!data.HasValue) {
299 return true;
300 }
301 return data.Value == data2.Value;
302 }
303 return false;
304 }
305 }
306}
static void Error(object message)
定义 Log.cs:80
virtual IEnumerable< CraftingRecipe > GetProceduralCraftingRecipes()
virtual CraftingRecipe GetAdHocCraftingRecipe(SubsystemTerrain subsystemTerrain, string[] ingredients, float heatLevel, float playerLevel)
static int GetBlockIndex(string BlockName, bool throwIfNotFound=false)
通过方块名称来获取方块的Index
static Block[] FindBlocksByCraftingId(string craftingId)
int DisplayOrder
在配方表中的显示顺序,DisplayOrder越小,配方越靠前
static void DecodeIngredient(string ingredient, out string craftingId, out int? data)
static CraftingRecipe DecodeElementToCraftingRecipe(XElement item, int horizontalLen=3)
static CraftingRecipe FindMatchingRecipe(SubsystemTerrain terrain, string[] ingredients, float heatLevel, float playerLevel)
static bool CompareIngredients(string requiredIngredient, string actualIngredient)
static List< CraftingRecipe > m_recipes
static List< CraftingRecipe > Recipes
static bool EnableLevelRestrictions
启用等级限制 Mod在初始化时,设置为false可以让物品合成不受玩家等级限制
static bool TransformRecipe(string[] transformedIngredients, string[] ingredients, int shiftX, int shiftY, bool flip)
static bool MatchRecipe(string[] requiredIngredients, string[] actualIngredients)
static bool TryGetBlock(string blockName, string prop, out string result)
static string Get(string className, int key)
获取在当前语言类名键对应的字符串
virtual void LoadCr(ref XElement xElement)
初始化CraftingRecipe
static int MakeBlockValue(int contents)
static void HookAction(string HookName, Func< ModLoader, bool > action)
执行Hook
static List< ModEntity > ModList
所有已启用的模组
static object GetAttributeValue(XElement node, string attributeName, Type type)