VScript 基本原理
本页面内容由Dazai Nerau译自英文版页面. 欢迎任何人补充新内容或者修改其中的错误.
这篇文章旨在阐述有关VScript脚本的基本概念以及使用方法.
表和脚本域
脚本环境由关联数组或者 表 构成 , 彼此之间互相嵌套.
脚本被加载时, 它就会被放置在一个被称为它的脚本域的表中, 然后脚本中的任何代码都能够被执行. 执行完代码后,所有的变量、函数以及类都会被保存在脚本域中.
脚本句柄
与游戏中的实体进行交互是经由 脚本句柄 得以实现的, 脚本句柄是一种用于引用特定实体的对象. 脚本句柄包含了访问器(accessor)和修改器(mutator)方法以读取和修改实体的属性. 方法的可用性取决于游戏和实体的类型. 请阅读各种游戏的脚本的API参考以了解详情。
所有正处于游戏中的服务器端的实体都可以通过CEntities
类的对象Entities
来搜寻或者迭代。
实体脚本
详阅文章Entity Scripts
常见的VScript用法是使用实体脚本来扩充实体的功能.
添加一个脚本到一个服务器端实体的vscripts
(实体脚本)键值将使得该脚本作为实体脚本被加载. 该脚本将在实体产生后被自动执行, 并加载到一个脚本域内,该脚本域由唯一标识符+实体名称或种类名组成; _<unique ID>_<entity name>
, 并被放在根表中. 如果一个实体没有任何脚本被执行, 可以通过 CBaseEntity::ValidateScriptScope()
方法来手动创建一个脚本域.

可以通过在vscripts
键值中指定多个脚本来加载其他脚本, 或者使用 RunScriptFile
输入. 在同一实体上运行的所有脚本将加载到相同的脚本范围, 覆盖任何相同的变量和函数.
Think函数可以被设置于thinkfunction
键值中或者由 AddThinkToEnt()
函数来添加, 被指定的函数会以0.1秒一次的频率被调用. 函数也可以通过I/O系统的 RunScriptCode function_name(argument, ...)
和RunScriptFunction function_name
这两个输入来手动调用。
实体脚本有 self
(起源1) 或者 thisEntity
(起源2)这两个能够引用它自身实体的脚本句柄.
预定义的钩子
实体能够从C++端调用其脚本域中的函数. 公共实体类被写入了一些预定义的函数调用(predefined function calls),以在特定事件中发生时允许脚本执行代码. 例如, 在一个实体脚本中创建一个名为 Precache()
的函数将在实体生成后立即调用该函数, 以允许脚本预缓存自定义的资源. 这些钩子函数不需要注册,并且只要名字没写错的话就会在合适的时候被调用. 请参阅游戏的API文档以了解每个类可用的钩子函数.
To do: Does Source 2 implement this?
I/O系统交互
触发输出
如果游戏的API支持的话, 脚本可以通过EntFire()
和 DoEntFire()
来对地图上的实体触发输出. 可能还有更多类似的函数, 取决于游戏. (译者注:例如CSGO还有EntFireByHandle()
这一函数)
如果函数支持activator
和 caller
的参数, 就可以使用"!self" 或者 "!activator" 关键字将输出发送给实体,而不必知道其名词,前提是句柄有效.
使用RunScriptCode
输入可以通过I/O系统执行任何VScript代码. 代码将在被调用实体的脚本域中运行.

RunScriptCode
被传递.
示范代码:
// 将拥有脚本域的实体的生命值设置成500
DoEntFire( "!self", "SetHealth", "500", 0, self, self )
关联输出
通过CBaseEntity::ConnectOutput(string output, string function)
方法, 实体输出可以关联到实体的脚本域中的函数.
在函数被调用期间, 变量 activator
和 caller
会被设置为I/O链中激活实体与调用实体的句柄, 从而可以轻松地找到是哪个玩家触发了某些内容.
示范代码:
// 当玩家使用时,点燃道具
function IgniteSelf()
{
DoEntFire( "!self", "Ignite", "", 0, self, self )
}
// 关联OnPlayerUse输出与脚本函数.
self.ConnectOutput( "OnPlayerUse", "IgniteSelf" )
输入钩子
When an entity receives an input, the game code will attempt to call a script function of the format Input<Name of Input>()
in the receiving Entity Script. If the function returns false
, the input is prevented from firing.

As with connected output functions, the variables activator
and caller
are set to the handles of the activating and calling entities.
Example Squirrel code:
// The script of a door or button. Intercepts the Unlock input,
// and doesn't allow the door/button to unlock until 5 inputs have been received.
UnlockCounter <- 5 // Counter local to the entity script scope.
// Called when the Unlock input is received.
function InputUnlock()
{
UnlockCounter--
if( UnlockCounter <= 0 )
{
return true // Allows the unlock
}
return false // Discards the input
}
术语表
- Entity handle
- An opaque entity reference passing a C++ EHANDLE. Can only be compared with other handles or passed to API functions expecting them. Only used rarely.
- Script handle
- An entity instance with accessors and mutators to the C++ entity object. Represented as a HSCRIPT typedef in C++ code.
- Script scope
- Execution context of a script. A table where the variables, functions and classes of a VScript are placed.
API参考
List of Portal 2 Script Functions
List of CS:GO Script Functions
List of Contagion Script Functions