LPC 语言基础教程:5.5 游戏最常用的外部函数

本文节选自《LPC语言基础教程:从零学习游戏开发》,版权归@mudren,欢迎转载,但必须注明来源(mud.ren)。

在本章第一节 《LPC语言的函数和方法》 中说明有一类函数叫模拟外部函数(simulated external function),但我们一直没有使用到。为方便后续章节学习,我们先实现几个模拟外部函数,当然,在要教程配套的 mudlib 中,已经写好。

我们打开 /system/kernel/simul_efun.c 文件看看代码:

#include <ansi.h>

...

void debug(mixed arg)
{
    string *color = ({HIB, HIC, HIG, HIM, HIR, HIW, HIY});

    write(element_of(color) + arg + NOR "\n");
}

// 数字字符串转数字
int atoi(string str)
{
    int v;

    if (!stringp(str) || !sscanf(str, "%d", v))
        return 0;

    return v;
}

// 数组打印
varargs void print_r(mixed *arr, int step)
{
    int i, j;
    if (sizeof(arr))
    {
        write(YEL "({\n" NOR);

        for (i = 0; i < sizeof(arr); i++)
        {
            if (arrayp(arr[i]))
            {
                step++;
                for (j = 0; j < step; j++)
                {
                    write("    ");
                }
                write(i + " => ");
                print_r(arr[i], step);
                step--;
            }
            else
            {
                for (j = 0; j <= step; j++)
                {
                    write("    ");
                }
                write(i + " => " + arr[i] + "\n");
            }
        }

        for (j = 0; j < step; j++)
        {
            write("    ");
        }
        write(YEL "})\n" NOR);
    }
    else
    {
        write(YEL "({ })\n" NOR);
    }
}

...

这里实现了部分 sefun,其中 debug()、atoi() 和 print_r()的作用简单说明:debug() 的作用就是 write() 自动换行并随机配色,这样不用每次调试代码时都要用 "\n" 换行;atoi() 主要用来把指令中的参数中的字符串型数字转为整型;print_r() 则是自己实现的一个打印数组函数,方便测试数组输出(比 printf() 等方式更简单更美观)。以后的学习中我们会使用这些模拟外部函数,请注意和外部函数区分。

sefun 除了实现全局可用的自定义函数,还可以保护重要的外部函数,这种情况下需要实现一个和外部函数同名的模拟外部函数,实现自己的功能,而需要使用原始的外部函数时需要使用 efun:: 前缀。比如对关闭游戏的外部函数 shutdown(),为了安全需要记录是谁关闭的,或者限制谁才有权限使用这个指令,可以定义类似下以的模拟外部函数:

void shutdown(int how)
{
    // 用户权限判断功能实现
    // 关闭日志记录功能实现

    // 调用外部函数
    efun::shutdown(how);
}

需要注意的是,如果使用了 efun:: 就会触发 apply 方法 valid_override(),这个方法在对象 /system/kernel/master 中。这个方法的用法如下:

名称

valid_override - 控制 `efun::` 前缀的使用

语法

int valid_override( string file, string efun_name , string main_file );

描述

在主控对象中增加 valid_override() 方法以控制 `efun::` 前缀的使用。每当驱动程序试图编译一个以 `efun::` 为前缀调用外部函数的文件时都会呼叫主控对象中的 valid_override() 方法。如果 valid_override() 返回 0 ,编译会失败。因此 valid_override() 提供了一种方式保证修改过功能的外部函数(同名模拟外部函数)无法使用 efun:: 绕过。

参数 `file` 是实际使用 efun:: 的文件,参数 `efun_name` 是通过 efun:: 调用的外部函数名称,参数 `main_file` 是准备编译的文件(包含扩展名 `.c`,而且通过使用 #include,`file` 和 `main_file` 可以不同)。

这里是一个通过 valid_override 限制重写外部函数的示例:

    int valid_override(string file, string name, string main_file)
    {
        if (file == "/system/kernel/simul_efun")
        {
            return 1;
        }
        if (name == "destruct")
            return 0;
        if (name == "shutdown")
            return 0;
        if (name == "snoop")
            return 0;
        if (name == "exec")
            return 0;
        return 1;
    }

在本教程代码中,默认所有 efun:: 调用都返回 1。

京ICP备13031296号-4