Survivalcraft API 1.8.2.3 v1.8.2.3
Survivalcraft 2.4
载入中...
搜索中...
未找到
ModEntity.cs
浏览该文件的文档.
1using System.Reflection;
2using System.Xml.Linq;
3using Engine;
5using NuGet.Versioning;
6
7namespace Game {
8 public class ModEntity {
12 public Dictionary<string, ZipArchiveEntry> ModFiles = [];
13 public List<Type> BlockTypes = [];
14 public string ModFilePath;
15 public bool IsDisabled;
17 public long Size;
19 public static HashSet<string> InvalidDllNames = ["Survivalcraft.dll", "Engine.dll", "EntitySystem.dll"];
20 public const string fName = "ModEntity";
21
23 get => ModLoader_;
24 set => ModLoader_ = value;
25 }
26
28
29 public ModEntity() { }
30
31 public ModEntity(ZipArchive zipArchive) {
33 ModArchive = zipArchive;
35 }
36
37 public ModEntity(string FileName, ZipArchive zipArchive) {
38 ModFilePath = FileName;
39 Size = Storage.GetFileSize(FileName);
40 ModArchive = zipArchive;
42 }
43
44 public virtual void LoadIcon(Stream stream) {
45 Icon = Texture2D.Load(stream);
46 stream.Close();
47 }
48
54 public virtual void GetFiles(string extension, Action<string, Stream> action) {
55 //将每个zip里面的文件读进内存中
56 bool skip = false;
57 Loader?.GetModFiles(extension, action, out skip);
58 if (skip) {
59 return;
60 }
61 foreach (ZipArchiveEntry zipArchiveEntry in ModArchive.ReadCentralDir()) {
62 if (Storage.GetExtension(zipArchiveEntry.FilenameInZip) == extension) {
63 MemoryStream stream = new();
64 ModArchive.ExtractFile(zipArchiveEntry, stream);
65 stream.Position = 0L;
66 try {
67 action.Invoke(zipArchiveEntry.FilenameInZip, stream);
68 }
69 catch (Exception e) {
70 Log.Error($"Get file [{zipArchiveEntry.FilenameInZip}] failed: {e}");
71 }
72 finally {
73 stream.Dispose();
74 }
75 }
76 }
77 }
78
82 public virtual bool GetFilesAndExist(string extension, Action<string, Stream> action) {
83 if (ModArchive.ReadCentralDir().Count != 0) {
84 GetFiles(extension, action);
85 return false;
86 }
87 return true;
88 }
89
96 public virtual bool GetFile(string filename, Action<Stream> stream) {
97 bool skip = false;
98 bool loaderReturns = false;
99 Loader?.GetModFile(filename, stream, out skip, out loaderReturns);
100 if (skip) {
101 return loaderReturns;
102 }
103 if (ModFiles.TryGetValue(filename, out ZipArchiveEntry entry)) {
104 using MemoryStream ms = new();
105 ModArchive.ExtractFile(entry, ms);
106 ms.Position = 0L;
107 try {
108 stream?.Invoke(ms);
109 }
110 catch (Exception e) {
111 LoadingScreen.Error($"[{modInfo.Name}] Get file [{filename}] failed: {e}");
112 }
113 return false;
114 }
115 return true;
116 }
117
118 public virtual bool GetAssetsFile(string filename, Action<Stream> stream) => GetFile($"Assets/{filename}", stream);
119
123 public virtual void LoadLauguage() {
125 "Lang/en-US.json",
126 stream => {
127 LoadingScreen.Info($"[{modInfo.Name}] Loading English Language file");
129 }
130 );
131 string language = ModsManager.Configs["Language"];
132 if (language == "en-US") {
133 return;
134 }
136 $"Lang/{language}.json",
137 stream => {
138 LoadingScreen.Info($"[{modInfo.Name}] Loading Current Language file");
140 }
141 );
142 }
143
147 public virtual void ModInitialize() {
148 LoadingScreen.Info($"[{modInfo.Name}] Executing __ModInitialize mission");
149 ModLoader_?.__ModInitialize();
150 }
151
155 public virtual void InitResources() {
156 ModFiles.Clear();
157 if (ModArchive == null) {
158 return;
159 }
160 List<ZipArchiveEntry> entries = ModArchive.ReadCentralDir();
161 foreach (ZipArchiveEntry zipArchiveEntry in entries) {
162 if (zipArchiveEntry.FileSize > 0) {
163 ModFiles.Add(zipArchiveEntry.FilenameInZip, zipArchiveEntry);
164 }
165 }
166 if (GetFile("icon.webp", LoadIcon)) {
167 GetFile("icon.png", LoadIcon);
168 }
169 GetFile("modinfo.json",
170 stream => {
171 try {
173 }
174 catch (Exception e) {
175 Log.Error($"Deserialize modinfo.json from [{Storage.GetFileName(ModFilePath)}] failed: {e}");
176 }
177 });
178 if (modInfo == null) {
179 IsDisabled = true;
181 return;
182 }
183 if (string.IsNullOrEmpty(modInfo.PackageName)
184 || (ModsManager.ModListAll.Count >= 2 && (modInfo.PackageName == "survivalcraft" || modInfo.PackageName == "fastdebug"))
185 || modInfo.PackageName.Contains(';')
186 || modInfo.PackageName.Contains('\n')) {
187 IsDisabled = true;
188 DisableReason = ModDisableReason.InvalidPackageName;
189 return;
190 }
191 if (ModsManager.DisabledMods.TryGetValue(modInfo.PackageName, out HashSet<string> disabledVersions)
192 && disabledVersions.Contains(modInfo.Version)) {
193 IsDisabled = true;
195 return;
196 }
197 foreach (KeyValuePair<string, ZipArchiveEntry> c in ModFiles) {
198 ZipArchiveEntry zipArchiveEntry = c.Value;
199 string filename = zipArchiveEntry.FilenameInZip;
200 if (!zipArchiveEntry.IsFilenameUtf8) {
202 new Exception(
203 $"[{modInfo.Name}] The file name [{zipArchiveEntry.FilenameInZip}] is not encoded in UTF-8, need to be corrected."
204 )
205 );
206 }
207 if (filename.StartsWith("Assets/")) {
208 MemoryStream memoryStream = new();
209 ContentInfo contentInfo = new(filename.Substring(7));
210 ModArchive.ExtractFile(zipArchiveEntry, memoryStream);
211 contentInfo.SetContentStream(memoryStream);
212 ContentManager.Add(contentInfo);
213 }
214 }
215 LoadingScreen.Info($"[{modInfo.Name}] Loaded {ModFiles.Count} resource files.");
216 }
217
221 public virtual void LoadBlocksData() {
222 bool flag = true;
223 GetFiles(
224 ".csv",
225 (_, stream) => {
226 if (flag) {
227 LoadingScreen.Info($"[{modInfo.Name}] {LanguageControl.Get(fName, "1")}");
228 flag = false;
229 }
231 }
232 );
233 }
234
239 public virtual void LoadXdb(ref XElement xElement) {
240 bool flag = true;
241 XElement element = xElement;
242 GetFiles(
243 ".xdb",
244 (_, stream) => {
245 if (flag) {
246 LoadingScreen.Info($"[{modInfo.Name}] {LanguageControl.Get(fName, "2")}");
247 flag = false;
248 }
249 ModsManager.CombineDataBase(element, stream, modInfo.PackageName);
250 }
251 );
252 Loader?.OnXdbLoad(xElement);
253 }
254
260 // ReSharper disable UnusedParameter.Global
261 public virtual void LoadClo(ClothingBlock block, ref XElement xElement)
262 // ReSharper restore UnusedParameter.Global
263 {
264 bool flag = true;
265 XElement element = xElement;
266 GetFiles(
267 ".clo",
268 (_, stream) => {
269 if (flag) {
270 LoadingScreen.Info($"[{modInfo.Name}] {LanguageControl.Get(fName, "3")}");
271 flag = false;
272 }
273 ModsManager.CombineClo(element, stream);
274 }
275 );
276 }
277
282 public virtual void LoadCr(ref XElement xElement) {
283 bool flag = true;
284 XElement element = xElement;
285 GetFiles(
286 ".cr",
287 (_, stream) => {
288 if (flag) {
289 LoadingScreen.Info($"[{modInfo.Name}] {LanguageControl.Get(fName, "4")}");
290 flag = false;
291 }
292 ModsManager.CombineCr(element, stream);
293 }
294 );
295 }
296
300 public virtual Assembly[] GetAssemblies() {
301 bool flag = true;
302 List<Assembly> assemblies = new();
303 GetFiles(
304 ".dll",
305 (filename, stream) => {
306 if (flag) {
307 LoadingScreen.Info($"[{modInfo.Name}] Loading .dll assembly files.");
308 flag = false;
309 }
310 if (!filename.StartsWith("Assets/")) {
311 string fileNameWithoutDirectory = Storage.GetFileName(filename);
312 if (!InvalidDllNames.Contains(fileNameWithoutDirectory)) {
313#pragma warning disable IL2026
314 assemblies.Add(Assembly.Load(ModsManager.StreamToBytes(stream)));
315#pragma warning restore IL2026
316 }
317 }
318 }
319 ); //获取mod文件内的dll文件(不包括Assets目录内的dll)
320 return [.. assemblies];
321 }
322
323 public virtual void HandleAssembly(Assembly assembly) {
324 List<Type> blockTypes = new();
325#pragma warning disable IL2026
326 Type[] types = assembly.GetTypes();
327#pragma warning restore IL2026
328 for (int i = 0; i < types.Length; i++) {
329 Type type = types[i];
330 if (type.IsSubclassOf(typeof(ModLoader))
331 && !type.IsAbstract) {
332#pragma warning disable IL2062
333 if (Activator.CreateInstance(types[i]) is ModLoader modLoader) {
334#pragma warning disable IL2062
335 modLoader.Entity = this;
336 Loader = modLoader;
337 modLoader.__ModInitialize();
338 ModsManager.ModLoaders.Add(modLoader);
339 }
340 }
341 if (type.IsSubclassOf(typeof(IContentReader.IContentReader))
342 && !type.IsAbstract
343#pragma warning disable IL2062
344 && Activator.CreateInstance(type) is IContentReader.IContentReader reader) {
345#pragma warning restore IL2062
346 ContentManager.ReaderList.TryAdd(reader.Type, reader);
347 }
348 if (type.IsSubclassOf(typeof(Block))
349 && !type.IsAbstract) {
350 blockTypes.Add(type);
351 }
352 /*if (type.Namespace == "Game")
353 {
354 Log.Warning("\"Game\" is not recommended as a namespace for mod class. It is only for Survivalcraft itself. " + type.AssemblyQualifiedName);
355 }*/
356 }
357 BlockTypes.AddRange(blockTypes);
358 }
359
360 public virtual void LoadJs() {
361#if !IOS && !BROWSER
362 bool flag = true;
363 GetFiles(
364 ".js",
365 (_, stream) => {
366 if (flag) {
367 LoadingScreen.Info($"[{modInfo.Name}] {LanguageControl.Get(fName, "5")}");
368 flag = false;
369 }
370 JsInterface.Execute(new StreamReader(stream).ReadToEnd());
371 }
372 );
373#endif
374 }
375
379 public virtual void CheckDependencies(List<ModEntity> modEntities = null) {
380 if (IsDisabled || modInfo == null) {
381 return;
382 }
383 modEntities ??= ModsManager.ModList;
384 if (modInfo.DependencyRanges.Count == 0) {
385 IsDependencyChecked = true;
386 modEntities.Add(this);
387 ModsManager.PackageNameToModEntity.TryAdd(modInfo.PackageName, this);
388 return;
389 }
390 LoadingScreen.Info($"[{modInfo.Name}] Checking dependencies.");
391 foreach ((string name, VersionRange range) in modInfo.DependencyRanges) {
392 ModEntity entity = ModsManager.ModListAll.Find(px => !px.IsDisabled
393 && px.modInfo != null
394 && px.modInfo.PackageName == name
395 && ((px.modInfo.NuGetVersion != null && range.Satisfies(px.modInfo.NuGetVersion)) || range.Equals(VersionRange.All) || px.modInfo.Version == range.OriginalString)
396 );
397 if (entity != null) {
398 if (!entity.IsDependencyChecked) {
399 if (entity.modInfo.DependencyRanges.ContainsKey(modInfo.PackageName)) {
400 throw new Exception($"[{modInfo.Name}] Dependency {name} is dependent on {modInfo.Name}, which is not allowed.");
401 }
402 entity.CheckDependencies(modEntities);
403 }
404 }
405 else {
406 IsDisabled = true;
407 DisableReason = ModDisableReason.DependencyError;
408 throw new Exception($"[{modInfo.Name}] Failed to find dependency {name}");
409 }
410 }
411 IsDependencyChecked = true;
412 modEntities.Add(this);
413 ModsManager.PackageNameToModEntity.TryAdd(modInfo.PackageName, this);
414 }
415
420 public virtual void SaveSettings(XElement xElement) {
421 Loader?.SaveSettings(xElement);
422 }
423
428 public virtual void LoadSettings(XElement xElement) {
429 Loader?.LoadSettings(xElement);
430 }
431
435 // <param name="categories"></param>
436 public virtual void OnBlocksInitalized() {
437 Loader?.BlocksInitalized();
438 }
439
440 //释放资源
441 public virtual void Dispose() {
442 try {
443 Loader?.ModDispose();
444 }
445 catch {
446 // ignored
447 }
448 ModArchive?.ZipFileStream.Close();
449 }
450
451 public override bool Equals(object obj) {
452 if (obj is ModEntity px) {
453 return px.modInfo.PackageName == modInfo.PackageName && px.modInfo.NuGetVersion.Equals(modInfo.NuGetVersion);
454 }
455 return false;
456 }
457
458 public override int GetHashCode() =>
459 // ReSharper disable NonReadonlyMemberInGetHashCode
460 modInfo.GetHashCode();
461 // ReSharper restore NonReadonlyMemberInGetHashCode
462 }
463}
static Texture2D Load(LegacyImage image, int mipLevelsCount=1)
static void Error(object message)
定义 Log.cs:80
static string GetExtension(string path)
static string GetFileName(string path)
static long GetFileSize(string path)
static void LoadBlocksData(string blocksDataString)
void SetContentStream(Stream stream)
static void Add(ContentInfo contentInfo)
static Dictionary< string, IContentReader.IContentReader > ReaderList
static void Execute(string str)
static void loadJson(Stream stream)
static void LoadEnglishJson(Stream stream)
static void Info(string mesg)
static void Error(string mesg)
ModEntity(string FileName, ZipArchive zipArchive)
ModEntity(ZipArchive zipArchive)
List< Type > BlockTypes
virtual void ModInitialize()
Mod初始化
virtual bool GetFile(string filename, Action< Stream > stream)
获取指定文件
virtual bool GetFilesAndExist(string extension, Action< string, Stream > action)
virtual void Dispose()
virtual void InitResources()
初始化Content资源
virtual bool GetAssetsFile(string filename, Action< Stream > stream)
const string fName
ModLoader ModLoader_
virtual void CheckDependencies(List< ModEntity > modEntities=null)
检查依赖项
ModDisableReason DisableReason
virtual void LoadBlocksData()
初始化BlocksData资源
virtual void LoadSettings(XElement xElement)
加载设置
virtual Assembly[] GetAssemblies()
加载mod程序集
virtual void LoadXdb(ref XElement xElement)
初始化Database数据
static HashSet< string > InvalidDllNames
virtual void HandleAssembly(Assembly assembly)
virtual void SaveSettings(XElement xElement)
保存设置
virtual void LoadClo(ClothingBlock block, ref XElement xElement)
初始化Clothing数据
virtual void GetFiles(string extension, Action< string, Stream > action)
获取模组的文件时调用。
virtual void OnBlocksInitalized()
BlocksManager初始化完毕
override int GetHashCode()
virtual void LoadJs()
Dictionary< string, ZipArchiveEntry > ModFiles
virtual void LoadIcon(Stream stream)
ZipArchive ModArchive
virtual void LoadCr(ref XElement xElement)
初始化CraftingRecipe
override bool Equals(object obj)
virtual void LoadLauguage()
初始化语言包
Dictionary< string, VersionRange > DependencyRanges
bool IsFilenameUtf8
string FilenameInZip
uint FileSize
static List< ModLoader > ModLoaders
static ModInfo DeserializeJson(string json)
static byte[] StreamToBytes(Stream stream)
将 Stream 转成 byte[]
static void AddException(Exception e, bool AllowContinue_=false)
static Dictionary< string, ModEntity > PackageNameToModEntity
含所有已启用的模组
static void CombineClo(XElement clothesRoot, Stream toCombineStream)
static string ModsPath
static void CombineCr(XElement xElement, Stream cloorcr)
static List< ModEntity > ModList
所有已启用的模组
static Dictionary< string, HashSet< string > > DisabledMods
static void CombineDataBase(XElement databaseRoot, Stream toCombineStream)
static Dictionary< string, string > Configs
static List< ModEntity > ModListAll
所有模组,含禁用的
static string StreamToString(Stream stream)