CK2源码分析一

CK2源码分析一

当我们玩十字军之王的时候,常常为游戏角色不能做出符合我们心里预期的而苦恼。遂萌生了自己编写mod的想法,但ck2的
的mod开发难度宛如回到数十年前用文本编辑器写代码的时代。我们常常只能自己化身人肉编译器,检查代码中的bug。难度
与手写代码无异。
所以我就萌生了自己开发一款适合ck编辑mod的想法,今天把首款源码露出,欢迎大家一起讨论。

CK2的代码都是文本该怎么办?

查看CK2的源码的时候我们都能发现,CK2的代码都是由一个个txt组成的,都是字符串。其内容架构与其说是代码,更类似一
个配置文件,其中再夹杂着一些逻辑判断。P社官方可能有自己的代码生成器,可以很轻易生成这些配置文件,以及检查报错
。但P社并没有把生成器放出来,所以我们只能自己通过官方源码逆向的去制作生成器了。

按字符解析文本

工欲善其事必先利其器,如果我们没办法知道每个单词的含义以及它后面所可以跟着值,那自然是没办法制作生成器的。
所以制作生成器的第一步解锁解析整个文本,将它们拆成一个个单词。先将它们做一个简单的分类:
    public enum TokenType
    {
        STRING = 1,         // 字符串
        EQUIP = 2,          //  =
        LEFT_BRACKET = 4,   // {
        RIGHT_BRACKET = 8,  // }
        NUMBER = 16,        // number
        POUND = 32,         // #
        NULL = 64,          // 空
        END = 128,          // 结束
    }
我们要做的第一步,是将每个单词分出来。但带有注释的单词都不要,所以拆分了#和字符串两个。接下来是解析:
public class ReaderChar
    {
        private const int BUFFER_SIZE = 2;
        private StreamReader reader;
        private char[] buffer;
        private int index;
        private int size;

        public ReaderChar(StreamReader reader)
        {
            this.reader = reader;
            fillBuffer();
        }
        
        // 返回下标位置
        public char peek()
        {
            if (index - 1 >= size)
                return '\0';
            return buffer[Math.Max(0, index - 1)];
        }
        
        // 返回下一位
        public char next()
        {
            if (!hasMore())
                fillBuffer();

            if(!hasMore())
                return '\0';

            return buffer[index++];
        }
        
        // 判断流是否结束
        public bool hasMore()
        {
            if(index >= size)
                fillBuffer();
            
            return index < size;
        }
        
        // 填充buffer流
        private void fillBuffer()
        {
            buffer = new char[BUFFER_SIZE];
            int n = reader.Read(buffer, 0, BUFFER_SIZE);
            if (n == -1)
                return;

            index = 0;
            size = n;
        }
    }
通过以上的代码就能将一个文本字符串转为一个个的字符供我们解析使用。接下来是重头戏:将它们解析成一个个的单词
public class CK2ParseToken
    {
        private ReaderChar reader;
        private TokenList tokenList = new TokenList();

        public void getTokenStream(ReaderChar reader)
        {
            this.reader = reader;
            tokenizer();
        }

        private void tokenizer()
        {
            Token token;
            do
            {
                token = parse();
                if(token.TokenType != TokenType.NULL)
                    tokenList.Add(token);
            } while (token.TokenType != TokenType.END);
        }
        
        private Token parse()
        {
            char ch = '\0';
            
            
            while (reader.hasMore())
            {
                ch = reader.next();
                if(isWhiteSpace(ch))
                    return new Token(TokenType.NULL, "NULL");
                else
                    break;
            }

            switch (ch)
            {
                case '=':
                    return new Token(TokenType.EQUIP, ch.ToString());
                case '{':
                    return new Token(TokenType.LEFT_BRACKET, ch.ToString());
                case '}':
                    return new Token(TokenType.RIGHT_BRACKET, ch.ToString());
                case '\0':
                    return new Token(TokenType.END, "END");
                default:
                    return read(ch);
            }
        }

        private Token read(char start)
        {
            if (start == '#')
            {
                string result = start.ToString();
                while (reader.hasMore())
                {
                    var ch = reader.next();
                    if (isOtherLine(ch))
                        break;
                    else
                        result += ch;
                }

                return new Token(TokenType.POUND, result);
            }
            else
            {
                string result = start.ToString();
                while (reader.hasMore())
                {
                    var ch = reader.next();
                    if (isWhiteSpace(ch))
                        break;
                    else
                        result += ch;
                }

                if (CK2Tool.isNumber(result))
                    return new Token(TokenType.NUMBER, result);
                else
                    return new Token(TokenType.STRING, result);
            }
        }

        private bool isWhiteSpace(char ch)
        {
            return ch == ' ' || ch == '\n' || ch == '\t' || ch == '\r';
        }

        private bool isOtherLine(char ch)
        {
            return ch == '\n' || ch == '\t' || ch == '\r';
        }
    }
}
至此,所以的CK2的单词都被我们解析,接下来就是通过对{},=,换行符等关键符号重构整个代码
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值