),压缩的时候a、b两个是同时存在的
作者:
Maxwell 时间: 2004-12-2 22:38
原帖由van于2004-12-02, 22:24:01发表
字典是直接对原文做频率统计后得出的。
字典可以求逆(把a=t改成b[t]=a),压缩的时候a、b两个是同时存在的
我觉得对完整原文统计不如对lz过还保持不变的那些原文进行统计压缩率高。
作者:
逐鹿苍狼 时间: 2004-12-3 00:40
有个问题憋在心里很久了,问吧,你们又看不起我,不问把,我良心上有过不去。
这个帖子到底说明了什么东西???
作者:
gameplore 时间: 2004-12-3 04:17
看题目。
说的就是ls11压缩文件格式的解码方法。什么是ls11压缩文件?看看前面的帖子。比如san9中m_msg.s9、m_rtdn.s9就是用这种算法压缩的
作者:
东方无翼 时间: 2004-12-3 08:07
原帖由Maxwell于2004-12-02, 22:38:30发表
我觉得对完整原文统计不如对lz过还保持不变的那些原文进行统计压缩率高。
同意这一点。
不过这个算法不注重压缩效率。属于压着玩的
作者:
东方无翼 时间: 2004-12-3 08:22
刚才我试了van解出来的M_Msg.s9 怎么也出错进不了游戏?不是我的san9有问题吧。
并且van能不能解释一下压缩后长度和原文长度后面那8个字节的意义?
其中前四字节,Msg文件都是0000 0120,图像文件有0000 0103和0000 0102(是吧,Maxwell来看看对不对)。
后四个字节在van的M_Msg.s9里是CCCC CCCC。是怎么算出来的?
作者:
Maxwell 时间: 2004-12-3 10:57
原帖由东方无翼于2004-12-03, 8:07:07发表
同意这一点。
不过这个算法不注重压缩效率。属于压着玩的
这个算法压缩率还是挺高的,我记得以前估算了一下好像有的文件压缩率有0.6左右,是个不错的算法了。
作者:
Maxwell 时间: 2004-12-3 10:58
原帖由东方无翼于2004-12-03, 8:22:24发表
刚才我试了van解出来的M_Msg.s9 怎么也出错进不了游戏?不是我的san9有问题吧。
并且van能不能解释一下压缩后长度和原文长度后面那8个字节的意义?
其中前四字节,Msg文件都是0000 0120,图像文件有0000 0103和0000 0102(是吧,Maxwell来看看对不对)。
后四个字节在van的M_Msg.s9里是CCCC CCCC。是怎么算出来的?
对,是这样的,而且好像是0102的没有调色板吧,记不清了,原来的资料遗失了
作者:
van 时间: 2004-12-3 13:05
那个0x120是偏移。
至于后面的CCCCCCCC是不对的,应该改成00000000,这样那个m_msg应该就能能用了
作者:
Maxwell 时间: 2004-12-3 13:09
头像里的0103 0102是什么van可知道?这个东西随便改个数值会有些奇怪的变化。
作者:
gameplore 时间: 2004-12-3 13:58
原帖由东方无翼于2004-12-03, 8:22:24发表
刚才我试了van解出来的M_Msg.s9 怎么也出错进不了游戏?不是我的san9有问题吧。
并且van能不能解释一下压缩后长度和原文长度后面那8个字节的意义?
其中前四字节,Msg文件都是0000 0120,图像文件有0000 0103和0000 0102(是吧,Maxwell来看看对不对)。
后四个字节在van的M_Msg.s9里是CCCC CCCC。是怎么算出来的?
我试了也不行;另外试了我自己解出来的也不行,都会出错。
似乎游戏程序认定M_msg.s9就是压缩过的,而并没有去比较哪两个长度,所以一读进来就立刻解压,殊不知本来就解压过了。
作者:
Maxwell 时间: 2004-12-3 14:02
后面的CCCCCCCC是不对的,应该改成00000000,这样那个m_msg应该就能能用了
van说了这么句话,你试试看。
作者:
gameplore 时间: 2004-12-3 14:12
原帖由Maxwell于2004-12-03, 14:02:48发表
后面的CCCCCCCC是不对的,应该改成00000000,这样那个m_msg应该就能能用了
van说了这么句话,你试试看。
我解压出来的,后面就是0,其余跟van的一样。
另,我还试过改原m_msg.s9中的压缩长度47EEF和为压缩长度9DE3A,发现只有改9DE3A才有影响,说明程序根本没有理会前面那个压缩后长度47EEF,而是直接用文件长度-0x120来计算压缩后长度。感觉san9.exe就是认定那个文件是压缩过的。
作者:
Maxwell 时间: 2004-12-3 14:14
原帖由
gameplore于2004-12-03, 14:12:16发表
原帖由Maxwell于2004-12-03, 14:02:48发表
后面的CCCCCCCC是不对的,应该改成00000000,这样那个m_msg应该就能能用了
van说了这么句话,你试试看。
我解压出来的,后面就是0,其余跟van的一样。
另,我还试过改原m_msg.s9中的压缩长度47EEF和为压缩长度9DE3A,发现只有改9DE3A才有影响,说明程序根本没有理会前面那个压缩后长度47EEF,而是直接用文件长度-0x120来计算压缩后长度。感觉san9.exe就是认定那个文件是压缩过的。
那你调整一下0120这个数值行不行?让它计算出来的压缩长度等于未压缩长度。
作者:
gameplore 时间: 2004-12-3 14:15
尝试了一下压回去,却不能还原
可能编码方法不太正确
作者:
Maxwell 时间: 2004-12-3 14:20
原帖由gameplore于2004-12-03, 14:15:37发表
尝试了一下压回去,却不能还原
可能编码方法不太正确
压缩算法可能有问题吧,我一直没有仔细研究lz系列算法,只是大致明白原理,从来没有写过代码。lz是个贪心算法吧?不一定能够达到最大压缩率是吗?
作者:
gameplore 时间: 2004-12-3 14:20
原帖由
Maxwell于2004-12-03, 14:14:20发表
原帖由gameplore于2004-12-03, 14:12:16发表
[quote]原帖由Maxwell于2004-12-03, 14:02:48发表
后面的CCCCCCCC是不对的,应该改成00000000,这样那个m_msg应该就能能用了
van说了这么句话,你试试看。
我解压出来的,后面就是0,其余跟van的一样。
另,我还试过改原m_msg.s9中的压缩长度47EEF和为压缩长度9DE3A,发现只有改9DE3A才有影响,说明程序根本没有理会前面那个压缩后长度47EEF,而是直接用文件长度-0x120来计算压缩后长度。感觉san9.exe就是认定那个文件是压缩过的。
那你调整一下0120这个数值行不行?让它计算出来的压缩长度等于未压缩长度。 [/quote]
改那个数的确有影响,如果改成0,进入游戏后什么文字都没有了。
0x120的含义应该是:压缩文本起始地址偏移。
据猜测san9.exe处理m_msg的过程:
1)读入m_msg.s9;
2)读取为压缩长度,0x9DE3A,并分配这么长的buffer;
3)获取文件长度_get_file_length,用文件长度-偏移;
4)从偏移处开始解压,共解压文件长度-偏移这么长。
作者:
gameplore 时间: 2004-12-3 14:24
原帖由
Maxwell于2004-12-03, 14:20:01发表
原帖由gameplore于2004-12-03, 14:15:37发表
尝试了一下压回去,却不能还原
可能编码方法不太正确
压缩算法可能有问题吧,我一直没有仔细研究lz系列算法,只是大致明白原理,从来没有写过代码。lz是个贪心算法吧?不一定能够达到最大压缩率是吗?
我用的是lz77的方法,压回去后比原m_msg.s9稍小。但是由于寻找重复串时全文本比较,因此非常非常地慢。估计原来的压缩方法并没有这么慢。
作者:
Maxwell 时间: 2004-12-3 14:27
那你的字典压缩压缩了没有?更新了字典了没有?
作者:
gameplore 时间: 2004-12-3 14:43
// Msg_Codec.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <crtdbg.h>
#ifndef BYTE
typedef unsigned char BYTE;
#endif
static const int DICT_LEN = 0x100;
static const int ACTUAL_LEN = 0x9DE3A;
class CLS11
{
// Operations
public:
//---------------------------------------------------------------------------
// Inputs: pDict -- Pointer to the dictionary.
// pSrc -- Pointer to source data buffer.
// pDest -- Pointer to destination data buffer.
// nLenActual -- Length of valid source data.
// nLenSrc -- Length of source data buffer.
// nLenDest -- Length of destination data buffer.
// bCompress -- true if LZ compression needs to be taken.
// Returns: The length of encoded data.
// Summary: Call this method to encode specified data with LS11.
//--------------------------------------------------------------------------
int Encode( BYTE *pDict, const BYTE *pSrc, BYTE *pDest, int nLenActual, int nLenSrc, int nLenDest, bool bCompress = false );
//--------------------------------------------------------------------------
// Inputs: pDict -- Pointer to the dictionary.
// pSrc -- Pointer to source data buffer.
// pDest -- Pointer to destination data buffer.
// nLenSrc -- Length of source data buffer.
// nLenDest -- Length of destination data buffer.
// nLenActual -- Length of original data.
// Returns: The length of decoded data.
// Summary: Call this method to decode LS11-encoded data. This procedure is
// based on the code written by Maxwell & van.
//--------------------------------------------------------------------------
int Decode( BYTE *pDict, const BYTE *pSrc, BYTE *pDest, int nLenActual, int nLenSrc, int nLenDest );
// Properties
protected:
int m_srcpos;
int m_destpos;
int m_bitpos;
BYTE *m_pDest;
const BYTE *m_pSrc;
// Implementations
protected:
void SetCode( unsigned int code );
unsigned int GetCode( );
void ReorderDict( BYTE const *pDictSrc, BYTE *pDictDest, int nLenDict );
} ;
int CLS11::Encode( BYTE *pDict, const BYTE *pSrc, BYTE *pDest, int nLenActual, int nLenSrc, int nLenDest, bool bCompress )
{
int off, len, lenmax, offmax;
BYTE *pNewDict = new BYTE[DICT_LEN];
m_pDest = pDest;
m_pSrc = pSrc;
m_srcpos = 0;
m_destpos = 0;
m_bitpos = 0;
_ASSERT( nLenActual <= nLenSrc && pNewDict );
memset( m_pDest, 0, nLenDest );
ReorderDict( pDict, pNewDict, DICT_LEN );
// If no compress needs to be taken, use dictionary only.
if( !bCompress )
{
while( m_srcpos < nLenActual && m_destpos < nLenDest )
{
SetCode( pNewDict[m_pSrc[m_srcpos++]] );
}
}
else
{
while( m_srcpos < nLenActual && m_destpos < nLenDest )
{
// Scan whole text
for( off = 1, lenmax = 0, offmax = 1; off <= m_srcpos; off++ )
{
for( len = 0; len + m_srcpos < nLenSrc && m_pSrc[m_srcpos - off + len] == m_pSrc[m_srcpos + len]; len++ );
if( len > lenmax )
{
lenmax = len;
offmax = off;
}
}
// Replace the duplicated string with two number: offmax + 256 and lenmax - 3
if( lenmax >= 3 )
{
SetCode( offmax + 256 );
SetCode( lenmax - 3 );
m_srcpos += lenmax;
}
else
{
SetCode( pNewDict[m_pSrc[m_srcpos++]] );
}
}
}
while( m_bitpos )
{
m_pDest[m_destpos] <<= 1;
m_bitpos++;
if( m_bitpos > 7 )
{
m_bitpos = 0;
m_destpos++;
break;
}
}
delete [] pNewDict;
return m_destpos;
}
int CLS11:ecode( BYTE *pDict, const BYTE *pSrc, BYTE *pDest, int nLenActual, int nLenSrc, int nLenDest )
{
unsigned int code, off, len;
m_pSrc = pSrc;
m_destpos = 0;
m_srcpos = 0;
m_bitpos = 7;
_ASSERT( nLenActual <= nLenDest );
while( m_srcpos < nLenSrc && m_destpos < nLenActual )
{
code = GetCode( );
if( code < 256 )
{
pDest[m_destpos++] = pDict[code];
}
else
{
off = code - 256;
len = GetCode( ) + 3;
for( unsigned int i = 0; i < len && m_destpos < nLenDest; i++ )
{
pDest[m_destpos] = pDest[m_destpos - off];
m_destpos++;
}
}
}
// Padding
while( m_destpos < nLenActual )
{
pDest[m_destpos++] = pDict[0];
}
return m_destpos;
}
void CLS11::SetCode( unsigned int code )
{
unsigned int temp, code1, code2;
int len, i;
temp = code;
len = 0;
code1 = 0;
// How many valid bits are contained in variable code
while( temp > 1)
{
temp >>= 1;
code1 = (code1 << 1) | 0x01;
len++;
}
if( (code1 << 1) <= code )
{
len++;
code1 = code & (~1);
}
else
code1--;
code2 = code - code1;
// Output bits of code1
for( i = len - 1; i >= 0; i-- )
{
m_pDest[m_destpos] = (m_pDest[m_destpos] << 1) | (code1 >> i);
m_bitpos++;
if( m_bitpos > 7)
{
m_bitpos = 0;
m_destpos++;
}
}
// Output bits of code2
for( i = len - 1; i >= 0; i-- )
{
m_pDest[m_destpos] = (m_pDest[m_destpos] << 1) | (code2 >> i);
m_bitpos++;
if( m_bitpos > 7)
{
m_bitpos = 0;
m_destpos++;
}
}
}
unsigned int CLS11::GetCode( )
{
unsigned int code1 = 0, code2 = 0;
int len = 0, bit;
do
{
bit = (m_pSrc[m_srcpos] >> m_bitpos) & 0x01;
code1 = (code1 << 1) | bit;
len++;
m_bitpos--;
if( m_bitpos < 0 )
{
m_bitpos = 7;
m_srcpos++;
}
} while( bit );
for( int i = 0; i < len; i++ )
{
bit = (m_pSrc[m_srcpos] >> m_bitpos) & 0x01;
code2 = (code2 << 1) | bit;
m_bitpos--;
if( m_bitpos < 0 )
{
m_bitpos = 7;
m_srcpos++;
}
}
return (code1 + code2);
}
void CLS11::ReorderDict( const BYTE *pDictSrc, BYTE *pDictDest, int nLenDict )
{
for( int i = 0; i < nLenDict; i++ )
{
for( int j = 0; j < nLenDict; j++ )
{
if( pDictSrc[j] == i )
{
pDictDest = j;
break;
}
}
}
}
// Big-endian to Little-endian or reverse
int Convert( int x )
{
int ret = 0;
BYTE *p = (BYTE *)(&x);
ret = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
return ret;
}
void TestEncode()
{
CLS11 ls11;
BYTE *pDict, *pSrc, *pDest;
int l1, l2, off, zero = 0;// Big-endian values
pDict = new BYTE[DICT_LEN];
FILE *fin = fopen("C:/code/m_msg_dec.s9", "rb");
FILE *fout = fopen("C:/code/m_msg_enc1.s9", "wb");
FILE *fout2 = fopen("C:/code/m_msg_enc2.s9", "wb");
_ASSERT( fin && fout && fout2 && pDict );
fread( pDict, 0x10, 1, fin );
fwrite( pDict, 0x10, 1, fout );
fwrite( pDict, 0x10, 1, fout2 );
fread( pDict, 0x100, 1, fin );
fwrite( pDict, 0x100, 1, fout );
fwrite( pDict, 0x100, 1, fout2 );
fread( &l1, 4, 1, fin );
pSrc = new BYTE[Convert(l1)];
fread( &l2, 4, 1, fin );
pDest = new BYTE[Convert(l2)];
fread( &off, 4, 1, fin );
_ASSERT( pSrc && pDest );
fseek( fin, Convert(off), SEEK_SET );
fseek( fout, Convert(off), SEEK_SET );
fread( pSrc, Convert(l1), 1, fin );
int nLen = ls11.Encode( pDict, pSrc, pDest, ACTUAL_LEN, Convert(l1), Convert(l2), false );
fwrite( pDest, nLen, 1, fout );
fseek( fout, 0x110, SEEK_SET );
l1 = Convert( nLen );
fwrite( &l1, 4, 1, fout );
fwrite( &l2, 4, 1, fout );
fwrite( &off, 4, 1, fout );
fwrite( &zero, 4, 1, fout );
nLen = ls11.Encode( pDict, pSrc, pDest, ACTUAL_LEN, Convert(l2), Convert(l2), true );
fseek( fout2, Convert(off), SEEK_SET );
fwrite( pDest, nLen, 1, fout2 );
fseek( fout2, 0x110, SEEK_SET );
l1 = Convert( nLen );
fwrite( &l1, 4, 1, fout2 );
fwrite( &l2, 4, 1, fout2 );
fwrite( &off, 4, 1, fout2 );
fwrite( &zero, 4, 1, fout2 );
fclose( fin );
fclose( fout );
fclose( fout2 );
delete [] pDict;
delete [] pSrc;
delete [] pDest;
}
void TestDecode()
{
CLS11 ls11;
BYTE *pDict, *pSrc, *pDest;
int l1, l2, off, zero = 0;
pDict = new BYTE[DICT_LEN];
FILE *fin = fopen("I:/San9pk/m_msg.s9", "rb");
FILE *fout = fopen("C:/code/m_msg_dec.s9", "wb");
_ASSERT( fin && fout && pDict );
fread( pDict, 0x10, 1, fin );
fwrite( pDict, 0x10, 1, fout );
fread( pDict, 0x100, 1, fin );
fwrite( pDict, 0x100, 1, fout );
fread( &l1, 4, 1, fin );
l1 = Convert( l1 );
pSrc = new BYTE[l1];
fread( &l2, 4, 1, fin );
l2 = Convert( l2 );
pDest = new BYTE[12];
fread( &off, 4, 1, fin );
off = Convert( off );
_ASSERT( pSrc && pDest );
fseek( fin, off, SEEK_SET );
fseek( fout, off, SEEK_SET );
fread( pSrc, 0x47EEF, 1, fin );
int nLen = ls11.Decode( pDict, pSrc, pDest, ACTUAL_LEN, l1, l2 );
fwrite( pDest, nLen, 1, fout );
fseek( fout, 0x110, SEEK_SET );
l1 = l2 = Convert( nLen );
fwrite( &l1, 4, 1, fout );
fwrite( &l2, 4, 1, fout );
off = Convert( off );
fwrite( &off, 4, 1, fout );
fwrite( &zero, 4, 1, fout );
fclose( fin );
fclose( fout );
delete [] pDict;
delete [] pSrc;
delete [] pDest;
}
int _tmain(int argc, _TCHAR* argv[])
{
//TestDecode();
TestEncode();
return 0;
}
作者:
gameplore 时间: 2004-12-3 14:51
根据解码时的描述:
向回偏移a个位置后复制b个字节
所以猜测编码时采用的是类似于lz77的那种方法,不过原来的编码可能没有全文本扫描匹配,而只在前后一定长度范围内扫描。。。
作者:
Maxwell 时间: 2004-12-3 15:09
原帖由gameplore于2004-12-03, 14:51:32发表
根据解码时的描述:
向回偏移a个位置后复制b个字节
所以猜测编码时采用的是类似于lz77的那种方法,不过原来的编码可能没有全文本扫描匹配,而只在前后一定长度范围内扫描。。。
其实分块大小和窗口大小只影响压缩速度和压缩率,并不影响解压缩。
作者:
gameplore 时间: 2004-12-4 00:50
前面的压缩编码方法有点小bug,调试后已经修正。解码出来的文件再压缩回去之后,san9.exe都能够正确识别。
附件:
m_msg_dec.s9: 从原来的m_msg.s9中解压出来的,并改了两个人的名字:
曹操==>嬴政;吕布==>项羽
m_msg_enc1.s9:采用最低压缩率(没有用lz扫描,而只用了字典)对m_msg_dec.s9重新压缩后的文件;
m_msg_end2.s9:采用最高压缩率(全文本lz扫描,对于lz来说应该是最高了)对m_msg_dec.s9重新压缩后的文件。
把m_msg_enc1.s9和m_msg_enc2.s9改名为m_msg.s9后放回去,游戏程序都能正确解压,而且进入游戏发现曹操和吕布的名字变成嬴政和项羽了
很早之前,我就一直在考虑怎么改历史武将的姓名,无奈自己水平有限,很长时间以来都不知道怎么改。幸好得到van,maxwell等的帮助,今日才得以实现。
另外还有一个问题,虽然名字是改了,可是旗子怎么还是没变呢?新武将的话,旗子应该是和姓有关系的,怎么历史武将的旗子不是根据姓名来确定的么?
附件装不下,分3个帖子
附件:
m_msg_dec.rar (2004-12-4 00:50, 173.47 K) / 该附件被下载次数 424
http://xycq.org.cn/forum/attachment.php?aid=144
作者:
gameplore 时间: 2004-12-4 00:52
m_msg_enc2.s9
附件:
m_msg_enc2.rar (2004-12-4 00:52, 239.26 K) / 该附件被下载次数 361
http://xycq.org.cn/forum/attachment.php?aid=45
作者:
gameplore 时间: 2004-12-4 00:56
m_msg_enc1_part1.s9
附件:
m_msg_enc1.part1.rar (2004-12-4 00:56, 200 K) / 该附件被下载次数 288
http://xycq.org.cn/forum/attachment.php?aid=124
作者:
gameplore 时间: 2004-12-4 00:58
m_msg_enc1 part2
附件:
m_msg_enc1.part2.rar (2004-12-4 00:58, 123.7 K) / 该附件被下载次数 287
http://xycq.org.cn/forum/attachment.php?aid=125
作者:
东方无翼 时间: 2004-12-4 09:29
真的要压缩回去
作者:
Maxwell 时间: 2004-12-4 11:07
原来gameplore是用vc的高手呀,以后这个版上有人请教vc的问题你可要出手呀。
作者:
van 时间: 2004-12-4 12:18
另外还有一个问题,虽然名字是改了,可是旗子怎么还是没变呢?新武将的话,旗子应该是和姓有关系的,怎么历史武将的旗子不是根据姓名来确定的么?
类似于三十,游戏里只支持一部分姓,所以对于历史武将,旗帜编号应该存在于剧本中
作者:
gameplore 时间: 2004-12-4 15:28
原帖由Maxwell于2004-12-04, 11:07:38发表
原来gameplore是用vc的高手呀,以后这个版上有人请教vc的问题你可要出手呀。
高手不敢当,不过欢迎讨论
作者:
gameplore 时间: 2004-12-4 15:35
原帖由van于2004-12-04, 12:18:19发表
类似于三十,游戏里只支持一部分姓,所以对于历史武将,旗帜编号应该存在于剧本中
这就试一下
作者:
爱喝绿茶 时间: 2005-1-16 16:20
编译无法通过,有完整的cpp文件或程序吗?
作者:
Maxwell 时间: 2005-1-16 19:26
原帖由爱喝绿茶于2005-01-16, 16:20:20发表
编译无法通过,有完整的cpp文件或程序吗?
给出的应该都是完整的代码,自己加上调用部分就可以了。
作者:
爱喝绿茶 时间: 2005-1-20 11:13
大哥知道是怎么回事吗?
作者:
Maxwell 时间: 2005-1-20 11:27
应该是你复制代码的时候出了问题,重新从论坛上复制一遍就可以了。
作者:
van 时间: 2005-1-20 12:09
网页上复制的是全角空格,在VC里将全角空格(0xa10xa1)全部替换为空格(0x32)就可以了
作者:
爱喝绿茶 时间: 2005-1-20 16:19
替换后发现少了个引用文件 stdio.h
作者:
爱喝绿茶 时间: 2005-1-21 11:18
可能吧,搞不好改好了_tchar 的某个地方就出来了。
金圭子解决了这些问题了吗?
指点一下啊!!!
作者:
东方无翼 时间: 2005-1-22 20:02
原帖由van于2005-01-20, 12:09:59发表
网页上复制的是全角空格,在VC里将全角空格(0xa10xa1)全部替换为空格(0x32)就可以了
真是不好意思,我为了对齐把两个半角的空格合并成一个全角的了。看来还造成了不少麻烦。
作者:
金圭子 时间: 2005-1-24 09:15
原帖由爱喝绿茶于2005-01-21, 11:18:13发表
可能吧,搞不好改好了_tchar 的某个地方就出来了。
金圭子解决了这些问题了吗?
指点一下啊!!!
这个…………可惜我也是没解决………………直接放弃了。
作者:
三国在飞 时间: 2005-4-1 18:52
好人做到底,把三九的也做出来吧!
作个能修改三九的MSG来,不能让三十专美于前啊!
代码有啦,怎么没有人帮忙做个出来呢???
作者:
gameplore 时间: 2005-4-1 19:31
原帖由三国在飞于2005-04-01, 18:52:34发表
好人做到底,把三九的也做出来吧!
作个能修改三九的MSG来,不能让三十专美于前啊!
代码有啦,怎么没有人帮忙做个出来呢???
三九的msg好像不是很有规律
直接用ultraedit改改就可以啦
作者:
三国在飞 时间: 2005-4-1 22:15
原帖由
gameplore于2005-04-01, 19:31:14发表
原帖由三国在飞于2005-04-01, 18:52:34发表
好人做到底,把三九的也做出来吧!
作个能修改三九的MSG来,不能让三十专美于前啊!
代码有啦,怎么没有人帮忙做个出来呢???
三九的msg好像不是很有规律
直接用ultraedit改改就可以啦
不行,全是看不懂的乱码,怎么改,另外,乱改后游戏都进不去啊!
作者:
gameplore 时间: 2005-4-5 18:03
原帖由三国在飞于2005-04-01, 22:15:56发表
不行,全是看不懂的乱码,怎么改,另外,乱改后游戏都进不去啊!
可以改的
乱码是因为解压缩之后还是BIG5,要用AppLocale启动UE32,选择繁体中文语言(BIG5),然后再打开文件解压缩后的文件,就可以看见文字了。
至于输入,随便哪一个能输入BIG5码的输入法都可以
作者:
三国在飞 时间: 2005-4-5 18:13
原帖由gameplore于2005-04-05, 18:03:46发表
可以改的
乱码是因为解压缩之后还是BIG5,要用AppLocale启动UE32,选择繁体中文语言(BIG5),然后再打开文件解压缩后的文件,就可以看见文字了。
至于输入,随便哪一个能输入BIG5码的输入法都可以
我做不出来的,不会解压啊,更不要说解压更改后再压缩回去!你能不能帮忙做个出来呢(修改器)
作者:
Maxwell 时间: 2005-4-6 12:35
修改器应该不是很难做,只要有解压,压缩,GB<->BIG5几个就可以了。
作者:
gameplore 时间: 2005-4-14 23:52
原帖由
三国在飞于2005-04-05, 18:13:18发表
原帖由gameplore于2005-04-05, 18:03:46发表
可以改的
乱码是因为解压缩之后还是BIG5,要用AppLocale启动UE32,选择繁体中文语言(BIG5),然后再打开文件解压缩后的文件,就可以看见文字了。
至于输入,随便哪一个能输入BIG5码的输入法都可以
我做不出来的,不会解压啊,更不要说解压更改后再压缩回去!你能不能帮忙做个出来呢(修改器)
原来是不会解压缩啊,其实前面的代码已经给出了。这里附上了一个简单的压缩/解压缩程序
我没有测试过,只在以前试过修改人名是可以的。完整的源代码也附上,想做完整的msg修改器的朋友可以以此为基础
程序仅仅提供压缩、解压缩功能,没有提供BIG5/GBK转码及修改功能。
使用方法:
1. 将m_msg.s9解压缩,假设解压后为m_msg_dec.s9;
2.用applocale开ultraedit32打开m_msg_dec.s9进行修改;
3.将m_msg_dec.s9压缩,假设压缩后为m_msg_enc.s9;
4.备份原来的m_msg.s9,将m_msg_enc.s9重命名为m_msg.s9,修改生效。
附件:
s9msg.rar (2005-4-14 23:52, 284.77 K) / 该附件被下载次数 416
http://xycq.org.cn/forum/attachment.php?aid=7872
作者:
三国在飞 时间: 2005-4-15 11:51
原帖由
gameplore于2005-04-14, 23:52:21发表
原帖由三国在飞于2005-04-05, 18:13:18发表
[quote]原帖由gameplore于2005-04-05, 18:03:46发表
可以改的
乱码是因为解压缩之后还是BIG5,要用AppLocale启动UE32,选择繁体中文语言(BIG5),然后再打开文件解压缩后的文件,就可以看见文字了。
至于输入,随便哪一个能输入BIG5码的输入法都可以
我做不出来的,不会解压啊,更不要说解压更改后再压缩回去!你能不能帮忙做个出来呢(修改器)
原来是不会解压缩啊,其实前面的代码已经给出了。这里附上了一个简单的压缩/解压缩程序
我没有测试过,只在以前试过修改人名是可以的。完整的源代码也附上,想做完整的msg修改器的朋友可以以此为基础
程序仅仅提供压缩、解压缩功能,没有提供BIG5/GBK转码及修改功能。
使用方法:
1. 将m_msg.s9解压缩,假设解压后为m_msg_dec.s9;
2.用applocale开ultraedit32打开m_msg_dec.s9进行修改;
3.将m_msg_dec.s9压缩,假设压缩后为m_msg_enc.s9;
4.备份原来的m_msg.s9,将m_msg_enc.s9重命名为m_msg.s9,修改生效。 [/quote]
谢谢。转码的可以到别处。
我试过,只能改对应的字(两个的改两个,三个的改三个)加多个都不行,会有乱码。
比如我们自制的剧本都要加些关之类的,如果把且兰加多个关字,进入游戏后很多字看不到且乱码。
作者:
boylinming 时间: 2005-4-16 08:52
我是新人,前两天才知道有这个论坛,看了LS的解压缩,不知道你们如何测试出来的,我觉得GetCode函数应该改进,昨晚测到0点30分,应该快了不少,方法是利用查表代替测试Bit位。(为了能够让大家看明白意思,我没有做进一步的优化)
m_bitPos初始化为0,不是7了。
struct CompressValue
{
union
{
int nValue;
BYTE byValue[4];
};
};
int g_CodeLen[] =
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 5
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 7
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 10
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 11
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 12
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 13
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 14
4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 7, 8, // 15
};
int g_nValue[] =
{
0, 2, 6, 14, 30, 62, 126, 254
};
int g_nMask[] =
{
1, 3, 7, 15, 31, 63, 127, 255, 511
};
unsigned int GetCode()
{
// 得到3个字节的数据, 反序
CompressValue data;
data.byValue[3] = m_pSrc[m_srcPos];
data.byValue[2] = m_pSrc[m_srcPos+1];
data.byValue[1] = m_pSrc[m_srcPos+2];
// 移位, 使得最高位是有效数据
data.nValue <<= m_bitPos;
// 查表得到有效数据里面Bit==1的个数
int nSetBitsNum = g_CodeLen[data.byValue[3]];
// 查表得到uCode1
unsigned int uCode1 = g_nValue[nSetBitsNum];
// 数据移位, 消去uCode1使用部分
// 同时使得data.byValue[3]的Bit0就是uCode2的Bit0
// x <<= y, 当 y < 0 时有问题, 如果直接用汇编写, 就可能不需要分之判断
// (我的8086的汇编忘光了, 但一些DSP芯片支持这样的指令的)
int nShiftNum = (2*(nSetBitsNum+1) - 8);
if (nShiftNum > 0)
{
data.nValue <<= nShiftNum;
}
else
{
data.nValue >>= abs(nShiftNum);
}
// 通过掩码计算, 得到uCode2
unsigned int uCode2 = (data.byValue[3] & g_nMask[nSetBitsNum+1]);
// 计算bitPos和srcPos的改变, 并改变之
m_srcPos += ((2*(nSetBitsNum+1)+m_bitPos) >> 3);
m_bitPos += 2*(nSetBitsNum+1);
m_bitPos &= 7;
return uCode1 + uCode2;
}
作者:
van 时间: 2005-4-16 19:13
论坛里面的代码是直接反汇编得到的,所以只是和光荣的实际算法保持一致,而没有考虑效率的问题做进一步的优化。
欢迎提改进意见!
作者:
van 时间: 2005-4-16 20:19
你的算法有些问题
int nSetBitsNum = g_CodeLen[data.byValue[3]];
unsigned int uCode1 = g_nValue[nSetBitsNum];
在你的算法中nSetBitsNum可以等于8(data.byValue[3]=255),这时g_nValue就缓冲区溢出了。另外LS算法并没有限制在0~255之间,也可以是11111111110之类的
作者:
boylinming 时间: 2005-4-18 12:36
我开始领会错了,是会溢出。
我修改下,生成的曹操传data.e5文件和网上下载的一样。但里面有几个if语句很不爽,谁优化下,尽量不要清空计算机的流水线。修改后的程序连续的1的个数也不能太多,12个以后也可能会出问题(曹操传data文件里面包含了几部分,不知道是否也是这个原因)。那个大表格不用动,其它改动如下:
struct CompressValue
{
union
{
unsigned int nValue;
unsigned short sValue[2];
BYTE byValue[4];
};
};
int g_nValue[] =
{
0, 2, 6, 14, 30, 62, 126, 254, 510, 1022, 2046, 4094, 8190, 16382
};
int g_nMask[] =
{
1, 3, 7, 15, 31, 63, 127, 255, 511, 1023
};
unsigned int LSCompress::GetCode()
{
// 得到4个字节的数据, 反序
CompressValue data;
data.byValue[3] = m_pSrc[m_srcPos];
data.byValue[2] = m_pSrc[m_srcPos+1];
data.byValue[1] = m_pSrc[m_srcPos+2];
data.byValue[0] = m_pSrc[m_srcPos+3];
data.nValue <<= m_bitPos;
int nSetBitsNum = g_CodeLen[data.byValue[3]];
int nSetBitsNum1 = g_CodeLen[data.byValue[2]];
unsigned int uCode1;
unsigned int uCode2;
if (nSetBitsNum >= 8)
{
uCode1 = g_nValue[nSetBitsNum+nSetBitsNum1];
int nRealShiftNum = nSetBitsNum + nSetBitsNum1 + 1;
data.nValue <<= nRealShiftNum;
data.nValue >>= (16-nRealShiftNum);
uCode2 = data.sValue[1];
m_srcPos += ((2*nRealShiftNum+m_bitPos) >> 3);
m_bitPos += 2*(nRealShiftNum);
m_bitPos &= 7;
}
else
{
uCode1 = g_nValue[nSetBitsNum];
int nShiftNum = (2*(nSetBitsNum+1) - 8);
if (nShiftNum > 0)
{
data.nValue <<= nShiftNum;
}
else
{
data.nValue >>= abs(nShiftNum);
}
uCode2 = (data.byValue[3] & g_nMask[nSetBitsNum+1]);
m_srcPos += ((2*(nSetBitsNum+1)+m_bitPos) >> 3);
m_bitPos += 2*(nSetBitsNum+1);
m_bitPos &= 7;
}
return uCode1 + uCode2;
}
作者:
Maxwell 时间: 2005-4-19 08:35
我考虑过表格的问题,不过后来测试了一下速度完全可以满足需要,因此保留了那种比较直观的算法。
作者:
gameplore 时间: 2005-4-22 20:54
原帖由三国在飞于2005-04-15, 11:51:44发表
我试过,只能改对应的字(两个的改两个,三个的改三个)加多个都不行,会有乱码。
比如我们自制的剧本都要加些关之类的,如果把且兰加多个关字,进入游戏后很多字看不到且乱码。
可能是压缩的代码处理长度时有点问题,我现在没有san9游戏。
以前写那个程序就是为了该名字的,其他的没改过。可以修改一下压缩的代码
作者:
三国在飞 时间: 2005-4-22 22:31
原帖由
gameplore于2005-04-22, 20:54:21发表
原帖由三国在飞于2005-04-15, 11:51:44发表
我试过,只能改对应的字(两个的改两个,三个的改三个)加多个都不行,会有乱码。
比如我们自制的剧本都要加些关之类的,如果把且兰加多个关字,进入游戏后很多字看不到且乱码。
可能是压缩的代码处理长度时有点问题,我现在没有san9游戏。
以前写那个程序就是为了该名字的,其他的没改过。可以修改一下压缩的代码
只是改名字,但不能乱改,比如曹操改成三个字的人名就不行(会出错),还有就是旗子也不对(还是原来的那个)
作者:
elvis1000 时间: 2005-6-5 16:11
有没有人会 C & Delphi的,可不可以把上面的C翻译成DELPHI,我只会DELPHI,实在看不懂!
boylinming写的好像和gameplore的不一样!
如果一次读取一个 integer (4 bytes),是不是前两个BYTE的值可以直接当作读取字典的值?还是应该要全换成二进位来分析呢?
作者:
叶落秋寒 时间: 2005-6-5 16:42
原帖由elvis1000于2005-06-05, 16:11:37发表
有没有人会 C & Delphi的,可不可以把上面的C翻译成DELPHI,我只会DELPHI,实在看不懂!
boylinming写的好像和gameplore的不一样!
如果一次读取一个 integer (4 bytes),是不是前两个BYTE的值可以直接当作读取字典的值?还是应该要全换成二进位来分析呢?
你先别看他们的代码
先把分解和还原原理看懂了(必须!)
再自已动手试着写写看。
LS文件的结构
0-15 文件头16个字节
16-271 字典256个字节
N组 12字节为一组控制信息(压缩后长度,原文长度,压缩数据起始地址)
数据段
作者:
elvis1000 时间: 2005-6-5 18:49
三十的240x240图片的压缩档(RGBquad+Bits)也有档头吗?还是直接把资料用lz11的原理压的?
作者:
ALCLA 时间: 2005-12-11 02:22
问一下,如何反汇编直接反汇编得到光荣的算法?而且压缩算法无论是LZ77,LZ78,LZW如果不确定具体如何操做,感觉很难解压,不知道如何得到准确的算法,我好象就不敢下手修改了,这个帖子不错,但是我想知道到底如何得到算法的?
作者:
Maxwell 时间: 2005-12-11 22:28
这个算法是van反汇编得到的。这个算法的可靠性是有保障的,不必非要搞清楚算法的名字,由于这个算法的一些特点,很难而且也不需要搞清楚压缩算法的细节。根据解压算法很容易构造一个压缩算法,即使这个算法跟光荣的算法不一致也能让解压算法正常工作。
作者:
ALCLA 时间: 2005-12-12 09:25
谢谢,van反汇编得到?我觉得算法的实现,和解开都不是难点,这个我都做过,字典在2的19还是多少次方以内都没什么问题,只是再大我电脑内存有问题不够,关键是我不知道van太守如何反汇编得到算法?恩,我去看看怎么反汇编,毕竟总不能老是=着人家把算法讲出来嘛
作者:
神源拓也 时间: 2007-9-25 18:12
虽然有点复杂,但还是能学习的
作者:
隋唐英雄传 时间: 2008-8-27 11:22
好东西
欢迎光临 轩辕春秋文化论坛 (http://xycq.org.cn/forum/) |
Powered by Discuz! 5.0.0 |