Skip to content

Latest commit

 

History

History
188 lines (179 loc) · 7.51 KB

build.md

File metadata and controls

188 lines (179 loc) · 7.51 KB

API制作方法

Engine(2.2请忽略下列内容,只需删除Engine.Properties命名空间下的类即可)

  • Engine.Content.ContentStream构造函数第一个参数类型改为Stream,参数名改为stream并删掉m_path的赋值,再把m_stream的赋值改为stream,同时将Engine.Content.ContentCache.AddPackage第一个参数类型改为Stream,参数名改为stream
  • (Windows版)Engine.Serialization.TypeCache.LoadedAssemblies的get方法改为和安卓版的一样。 如果想加载所有子文件夹里的程序集文件及其引用就改为
lock (m_typesByName)
{
	if (m_rescanAssemblies)
	{
		HashSet<Assembly> hashSet = new HashSet<Assembly>(AppDomain.CurrentDomain.GetAssemblies());
		hashSet.Add(typeof(int).GetTypeInfo().Assembly);
		hashSet.Add(typeof(Uri).GetTypeInfo().Assembly);
		hashSet.Add(typeof(Enumerable).GetTypeInfo().Assembly);
		var enumerator = Directory.EnumerateFiles(Environment.CurrentDirectory, "*.*", SearchOption.AllDirectories).GetEnumerator();
		while (enumerator.MoveNext())
		{
			string current = enumerator.Current;
			string extension = Path.GetExtension(current);
			if (string.Equals(extension, ".dll", StringComparison.OrdinalIgnoreCase) || string.Equals(extension, ".exe", StringComparison.OrdinalIgnoreCase))
				try
				{
					hashSet.Add(Assembly.LoadFrom(current, null));
				}
				catch (Exception ex)
				{
					Log.Warning("Failed to load assembly \"{0}\". Reason: {1}", new object[2]
					{
						current,
						ex.Message
					});
				}
		}
		m_loadedAssemblies = new List<Assembly>(hashSet);
		m_rescanAssemblies = false;
	}
	return new ReadOnlyList<Assembly>(m_loadedAssemblies);
}
```(可能会影响性能TypeCache添加一个新方法:
``` c#
public static void AssemblyLoad(object obj, AssemblyLoadEventArgs a)
{
	lock (m_typesByName)
	{
		m_rescanAssemblies = true;
	}
}

并在静态构造函数末尾添加

AppDomain.CurrentDomain.AssemblyLoad += AssemblyLoad;

Storage.OpenFile改为

	if (openFileMode < 0 || openFileMode > OpenFileMode.CreateOrOpen)
		throw new ArgumentException("openFileMode");
	FileMode mode;
	switch (openFileMode)
	{
	case OpenFileMode.Create:
		mode = FileMode.Create;
		break;
	case OpenFileMode.CreateOrOpen:
		mode = FileMode.OpenOrCreate;
		break;
	default:
		mode = FileMode.Open;
		break;
	}
	return File.Open(ProcessPath(path, openFileMode != OpenFileMode.Read, false), mode, (openFileMode == OpenFileMode.Read) ? FileAccess.Read : FileAccess.ReadWrite, FileShare.Read);

(Bugs)Storage.ProcessPath里的if (!path.StartsWith("data:"))下一行改为

return path;

EntitySystem(如果有的话)

(可选)在 Database::AddDatabaseObject 中从后往前找callvirt instance void class [mscorlib]System.Collections.Generic.Dictionary`2<valuetype [mscorlib]System.Guid,class TemplatesDatabase.DatabaseObject>::Add改为set_Item;在 DatabaseObject::set_NestingParent 中找 callvirt instance void TemplatesDatabase.Database::AddDatabaseObject第二个参数改为false(即前面的ldc.i4.1改为ldc.i4.0

修改主程序

  1. 编译要注入的dll并反编译成il
  2. LabelWidget类中新建类型为Dictionary<string, string>的字段Strings并将LabelWidget.Text的set方法修改为
if (Strings.TryGetValue(value, out string text))
	value = text;
if (value != m_text)
{
	m_text = value;
	m_linesSize = null;
}
  1. 添加ModInfo, PluginLoaderAttribute, FileEntry, ModsManager四个类
  2. LoadingScreen.Update中把ldstr "Loading error. Reason: "call void [Engine]Engine.Log::Error(string)之前的指令修改为
ldloc.2
call       string [mscorlib]System.String::Concat(object, object)
  1. (Bugs&RuthlessConquest)ModsManager类中添加个类型为stringPath字段并将ModsManager那段illdsfld string Game.ContentManager::Path替换成ldsfld string Game.ModsManager::PathProgram.Initialize末尾添加ModsManager.Initialize();在ModsManager.Initialize()前添加
call       class [Mono.Android]Java.IO.File [Mono.Android]Android.OS.Environment::get_ExternalStorageDirectory()
callvirt   instance string [Mono.Android]Java.IO.File::get_AbsolutePath()
ldstr      "[游戏名]/Mods"
call       string Game.ModsManager::Combine(string, string)

(安卓版)

ldstr      "Mods"
stsfld     string Game.ContentManager::Path

(Windows版)
6. (Survivalcraft)替换BlocksManager, ContentManager, CraftingRecipesManager, HelpScreen, StringsManager整个类并替换ClothingBlock.Initialize, DatabaseManager.Initialize, WorldsManager.Initialize整个方法,如果SettingsGraphicsScreen和原版的不一样就替换成原版的(保证安卓版与电脑版mod的通用性),删除Game.Properties命名空间下带[CompilerGenerated]的类(如果有的话); ComponentGui.DisplayLargeMessage改为

	m_message = new Message
	{
		LargeText = largeText ?? string.Empty,
		SmallText = smallText,
		Duration = duration,
		StartTime = Time.RealTime + (double)delay
	};

(安卓版)AndroidSdCardExternalContentProvider.InitializeFilesystemAccess改为

m_rootDirectory = "/sdcard/Survivalcraft/"
  1. (Bugs&RuthlessConquest)GameLogSink的构造函数改为
try
{
	if (m_stream != null)
		throw new InvalidOperationException("GameLogSink already created.");
	Directory.CreateDirectory("/sdcard/Bugs");
	string path = "/sdcard/Bugs/Game.log";
	m_stream = File.Open(path, FileMode.OpenOrCreate);
	if (m_stream.Length > 10485760)
	{
		m_stream.Dispose();
		m_stream = File.Open(path, FileMode.Create);
	}
	m_stream.Position = m_stream.Length;
	m_writer = new StreamWriter(m_stream);
}
catch (Exception ex)
{
	Engine.Log.Error("Error creating GameLogSink. Reason: {0}", ex.Message);
}
  1. (Bugs)GameData的构造函数偏移82位置后插入
ldstr ".pat"
call class [mscorlib]System.Collections.Generic.List`1<class Game.FileEntry> Game.ModsManager::GetEntries(string)
ldstr "Name"
ldstr "Type"
ldnull
call class [System.Xml.Linq]System.Xml.Linq.XElement Game.ContentManager::CombineXml(class [System.Xml.Linq]System.Xml.Linq.XElement, class [mscorlib]System.Collections.Generic.IEnumerable`1<class Game.FileEntry>, string, string, string)

将以上exe/dll文件拖入Injector

替换图标

  • 做几个不同分辨率的png格式的图标(分辨率跟原图标相同)
  • (可选)打开limitPNG最新版,压缩等级选择极限,无损压缩png图标
  • (Windows版)将png制作成图标组,并替换exe里的资源(推荐用 PNGtoICO 制作图标组)
  • (安卓版)替换所有drawable开头的文件夹里的androidicon.png;并压缩所有png(可选)

(可选)优化

  • 将其余无强名称的dll文件拖入Injector
  • 将Content.pak拖入PAKOptimizer,安卓版在当前文件夹新建个assets文件夹并把输出的pak移到该文件夹下,Windows版直接用输出的pak替换掉
  • (安卓版)解压lib文件夹到当前文件夹,打开命令行输入:
7z a -mx=9 -tzip "SCPluginAPI.apk" "lib\*" -r -mfb=258
7z a -mx=9 -tzip "SCPluginAPI.apk" "assets\Content.pak" -mfb=258

打包 & 发布

  • (安卓版)用制作好的dll替换assemblies文件夹里的dll文件,压缩等级选存储,然后签名apk
  • (Windows版)推荐用7zip压缩,右键文件夹点添加到压缩包,格式选7z,算法选LZMA2,压缩等级选极限,单词大小选最大