Starcraft Campaign Editor 是什么呢?其实就是一个能让您自己作出星际争霸地图的程序。 并把地图以SCM格式保存,或者保存为SCX文件。 可是这些个SCM/SCXs文件 和Warcraft 2是一样的原始文件? 假如您用hex editor 看过这些文件,那么您会得到一个否定的答案。 实际上SCM/SCXs就是MPQ文件!! 那么你也许认为很简单,那你就错了,StarEdit使用了一套难以捉摸的MPQ编写套路。 不过在您仔细阅读下面的内容,您将会得到答案。 Using StarEdit - The MPQ API Library 使用编辑器- The MPQ API Library 注意:这章是针对WINDOWS平台的,适用于THE MPQ API LIBRARY 2.0或更高! 在这里我们并不能很快的编译,因为编辑器有的功能我们并不能直接使用。 不像STROM之类的shared libraries ,StarEdit拥有复杂的操作系统保护机智,而不只是对于文件的保护。就算您是一位很好的程序员,您一样无法直接修改它。对于这种高难度的熟练的对运行系统的改写,还没有人能完成过。 就在这个时候Andrey Lelikov (简称Lelik)横空出世。 Lelik是一位熟悉系统内部工作机制的俄罗斯程序员。他设计了一个能够使用 StarEdit MPQ 的方法。 他把自己写的详细功能放进了MPQ API Library 。 就像STROM,MPQ API Library(又名LMPQAPI),它包含了共享库(可惜的是,像STROM接口库,现在在MAC机上还没有)。LMPQAPI不仅包括了StarEdit的MPQ编写功能,而且提供接口读写STROM。 如果您想同时使用STROM和StarEdit,您不需要同时使用LMPQAPI和STROM接口库。 一个LMPQAPI足已。 好吧。我提醒您一件事,您想在使用LMPQAPI的时候区分是用STROM还是StarEdit么? STROM功能有就像使用STROM接口库时一样有一个前缀'SFile',在使用StarEdit时,前缀是'Mpq'。 这是很重要的,因为这说明了STROM和StarEdit的功能不兼容。 这意味着您无法用SFileOpenArchive获得的MPQ HANDLE去在StarEdit('Mpq'前缀的函数)里调用,反之亦然。 如果您还是调用的话,调用会失败,程序会崩溃。记住这点。 ¿Sé Habla Español? 让人讲西班牙语? 因为75%以上的星际争霸或暗黑的玩家是以英语为母语,所以大多数MPQ开发测试都基于这些游戏的英文版。对于使用英文版游戏的玩家,MPQ会运行良好。但事实上,98%的标准MPQ文件使用的是language-neutral (比如图象文件等等)。甚至有人用全非英语的MPQ玩游戏也没有问题。 不过,很明显这里是有问题的,只是还要等些时间才有人能发现吧。 做为上面两章的解释,MPQ格式具有强大的多国语言功能。 但是,您完全没必要做多语言的SCM/SCXs。 这就是说,您完全不必要让StarEdit支持多语言功能,就连暴雪的程序员都懒的做。 但是我们都有兴趣研究MPQ,除非没必要,其中的许多语言功能还是有用的。 在技术方面说,所有的StarEdit功能都只运行有语言代码为0或language-neutral代码的文件。 也就是说,MpqAddFileToArchive和MpqAddWAVToArchive只增加language- neutral files, MpqDeleteFile只删除language-neutral files, MpqRenameFile 只会重命名language-neutral files. 这种设计决定了,执行结果并不明显。在前一章也提到过,假如在打开有相同名称不同语言的文件时,STROM使用了SFileSetLocale做为语言过滤器,用来决定到底打开哪个文件。 假设在StarEdit使用一个MPQ文件代替patch_rt.mpq ,而且在那个MPQ文件里有英语/language-neutral解析度文件rez\gluAll.tbl (这文件内有多个语言版本),但是不能有葡萄牙语版本(选定任意语言)。 当您运行这个游戏的葡萄牙语版时,程序会查询在您MPQ文件中的该语言版。结果就是失败,而且默认又为英语版本的,对不对? 好吧,不是这样的。STROM允许您同时打开几个MPQ文件,并且STROM会搜索已经加载的MPQ,然后自动加载最新的MPQ到文件里。但是在这个过程中,STROM在系统为language-neutral以前,会检查已经打开的所有特殊语言的MPQ。 这意味着,前面STROM从broodat.mpq 载入葡萄牙语版本,而不是您自己的language-neutral 版本。 很不幸,现在还没有解决的办法,希望新版本的LMPQAPI能被解决吧。 Initializing the MPQ API Library - MpqInitialize 初始化MPQ API Library函数- MpqInitialize BOOL WINAPI MpqInitialize(); 不像STROM,LMPQAPI在控制StarEdit时有巨大的复杂的任务要做。 因此,无法在启动LMPQAPI时做完一切。你必须告诉LMPQAPI什么时候运行。所幸,这很简单。 你要做的就是在您启动程序前调用MpqInitialize,LMPQAPI会自动做完剩下的。 请确定在调用LMPQAPI其他函数前,您调用了MpqInitialize。此外,即使您对STROM接口库什么都不做,也必须在任何STROM函数调用前被调用。 一次调用会同时初始化STROM和STAREIDT。 1.Starcraft/Brood War 1.07 必须已经安装,Storm.dll和StarEdit.exe必须在程序目录中 2.StarEdit不能和LMPQAPI一起运行. 为了调用MpqInitialize初始化上面的两个要求必须满足。尽管还有其他原因,上面两个却是最常见的。 不管什么原因,MpqInitialize调用失败后,都会返回FLASH,您可以检索GetLastError设置一个错误值。 如果LMPQAPI无法在游戏目录或在您程序的目录里无法找到StarEdit.exe ,那么GetLastError会返回MPQ_ERROR_NO_STAREDIT; 如果StarEdit.exe的版本不匹配,GetLastError会返回MPQ_ERROR_BAD_STAREDIT; 如果StarEdit已经运行GetLastError会返回MPQ_ERROR_STAREDIT_RUNNING; 如果是因为其他原因GetLastError通常会返回MPQ_ERROR_INIT_FAILED。 但是,无论为什么GetLastError调用失败,返回了什么,您要做的就是尽快的关闭程序。 不要调用任何LMPQAPI功能(STROM或者StarEdit的功能),当然也不要在调用MpqInitialize了。 Opening an MPQ for Editing - MpqOpenArchiveForUpdate 打开MPQ- MpqOpenArchiveForUpdate HANDLE WINAPI MpqOpenArchiveForUpdate(LPCSTR lpFileName, DWORD dwCreationDisposition, DWORD dwHashTableSize); Parameter What it is lpFileName [in] A pointer to NULL-terminated string that holds the path of the MPQ to open. MpqOpenArchiveForUpdate will fail if this is NULL. dwCreationDisposition [in] Specifies what MpqOpenArchiveForUpdate should do with the archive if it does/doesn't exist. Must be one of the following values defined in lmpqapi.h: MOAU_CREATE_NEW MpqOpenArchiveForUpdate will create a brand new archive. If lpFileName already exists, MpqOpenArchiveForUpdate will fail. MOAU_CREATE_ALWAYS MpqOpenArchiveForUpdate will create a new archive if lpFileName doesn't exist. If lpFileName does exist, it will be deleted and overwritten. MOAU_OPEN_EXISTING MpqOpenArchiveForUpdate will open the archive lpFileName. MpqOpenArchiveForUpdate will fail if lpFileName does not exist. MOAU_OPEN_ALWAYS If lpFileName exists, MpqOpenArchiveForUpdate will open it. If it doesn't, MpqOpenArchiveForUpdate will create a new archive. MOAU_MAINTAIN_LISTFILE This flag specifies that as MpqOpenArchiveForUpdate uses the archive lpFileName, it should update the internal listfile, if one exists. This is a flag, and must be ORed (with the | operator) with one of the other options for dwCreationDisposition dwHashTableSize [in] Whenever MpqOpenArchiveForUpdate creates a new archive (see the dwCreationDisposition for details on when this occurs), dwHashTableSize specifies how large the hash table for the new archive will be, with a minimum size of 16, and a maximum size of 262,144 (if dwHashTableSize is not within these values,MpqOpenArchiveForUpdate will change it). This parameter does not affect archives that already exist. 与STROM一样,您在使用前必须先打开它. MpqOpenArchiveForUpdate 打开(或创建)一个存档,这是为了您使用其他StarEdit功能的,并返回存档的HANDLE. 但是不像SFileOpenArchive,MpqOpenArchiveForUpdate需要您在时间上做出选择. 第一选择是dwcreationdisposition参数。它告诉mpqopenarchiveforupdate是否应该创建一个新的存档还是打开一个现有的,或两者之间。其他的决定性参数是dwhashtablesize 。 dwhashtablesize告诉mpqopenarchiveforupdate创建什么大小存档的哈希表(这也是该文件限制),在 mpqopenarchiveforupdate事件中必须创建要一个新的存档。 做为一个存档的哈希表大小差不多是1000,除非你知道存档一定会超过1000个文件。 但同时请记住,每个哈希表项和存档文件将新增16个字节,(见第2章的哈希表,或第5章关于mpq哈希表的更多信息) 。 在上面的进程中MpqOpenArchiveForUpdate可能调用失败. MpqOpenArchiveForUpdate将返回INVALID_HANDLE_VALUE或者NULL. 我们根据调用GetLastError通常可以获取有用的信息,但不是绝对. 如果lpfilename参数为空, getlasterror将返回error_invalid_parameter 。 如果dwcreationdisposition返回moau_open_existing或者lpfilename不存在, getlasterror将返回error_file_not_found 。反过来说,如果dwcreationdisposition返回moau_create_new和档案lpfilename已经存在, getlasterror将返回error_already_exists 。 最后,如果mpq存档存在,但是是无效或损坏的, getlasterror将返回mpq_error_mpq_invalid 。 在一些罕见的情况下, getlasterror将返回其他一些错误代码。 Closing a Modified Archive - MpqCloseUpdatedArchive 关闭修改过的存档- MpqCloseUpdatedArchive BOOL WINAPI MpqCloseUpdatedArchive(HANDLE hMPQ, DWORD dwUnknown); Parameter What it is hMPQ [in] The HANDLE of the MPQ to close, which was acquired earlier with MpqOpenArchiveForUpdate. MpqCloseUpdatedArchive will fail (or worse) if this is NULL or aHANDLE not obtained with MpqOpenArchiveForUpdate. dwUnknown Unknown. Should always be NULL. 这里和在STROM中一样,您在哪用SFileOpenArchive打开MPQ,那么就在修改它的地方用SFileCloseArchive 关闭. 那么MPQ存档打开时用MpqOpenArchiveForUpdate,关闭时用MpqCloseUpdatedArchive. 然而在这时候有一点区别.STROM不会修改实际MPQ,所以关闭MPQ HANDLE时没有什么特别需要做的. 但是StarEdit 确实修改了MPQ.而且MPQ的散列值和文件表是在没有调用MpqCloseUpdatedArchive关闭MPQ HANDLE前不能写在MPQ分区的. 这意味着要快速关闭StarEdit MPQ HANDLEs,要不然您有可能再次程序崩溃,而无法保存修改的MPQ. Adding a File - MpqAddFileToArchive 添加文件函数- MpqAddFileToArchive BOOL WINAPI MpqAddFileToArchive(HANDLE hMPQ, LPCSTR lpSourceFileName, LPCSTR lpDestFileName, DWORD dwFlags); Parameter What it is hMPQ [in] The HANDLE of the MPQ to add the file to, which was acquired earlier with MpqOpenArchiveForUpdate. MpqAddFileToArchive will fail if this is NULL or aHANDLE not obtained with MpqOpenArchiveForUpdate. lpSourceFileName [in] A pointer to a NULL-terminated string containing the path of the file on disk to add. MpqAddFileToArchive will crash if this is NULL. lpDestFileName [in] A pointer to a NULL-terminated string containing the name that the file will be given in the MPQ. MpqAddFileToArchive will crash if this is NULL. dwFlags [in] Flags specifying properties that MpqAddFileToArchive will apply to the file inside the MPQ. Must be a combination of the following flags specified in lmpqapi.h: MAFA_ENCRYPT The file will be encrypted. MAFA_COMPRESS The file will be compressed. MAFA_REPLACE_EXISTING If the file lpDestFileName already exists in the MPQ, it will be replaced with the new file to be added 往往大约 95%的时候会在使用 StarEdit MPQ功能时候添加文件. 对于这个任务, 您会用到的函数有MpqAddFileToArchive和它的姊妹功能MpqAddWAVToArchive (稍后讨论). MpqAddFileToArchive在MPQ hMPQ分区添加文件lpSourceFileName 使用名称lpDestFileName, 并在这个过程中压缩 或/和 加密它. 由于一些设计上的疏漏,在您并没有完全明白前,MpqAddFileToArchive会是个大麻烦. 1.MpqAddFileToArchive并不检查lpSourceFileName和lpDestFileName是否为空. 就是说假如任一参数为空,您会再次看到程序崩溃. 2.覆盖MPQ中已有文件时MpqAddFileToArchive的运行机制. 当您调用MpqAddFileToArchive去添加的文件已经存在MPQ中(在这种情况下,你就不得不指定dwflags为mafa_replace_existing ),MpqAddFileToArchive会在不确定文件lpSourceFileName是否存在前就不分青红皂白地删除存在的文件lpDestFileName. 解决的办法很简单:确保lpsourcefilename和lpdestfilename是有效的(非空) ,以及确保lpsourcefilename存在之前,调用mpqaddfiletoarchive 。 |