Difference between revisions of "Vscript Fundamentals:zh-cn"

From Valve Developer Community
Jump to: navigation, search
(预定义的钩子函数)
 
(23 intermediate revisions by the same user not shown)
Line 11: Line 11:
  
 
== 表和脚本域 ==
 
== 表和脚本域 ==
The scripting environment consists of [https://en.wikipedia.org/wiki/Associative_array associative arrays], or ''tables'', nested inside each other.
+
脚本环境由[https://en.wikipedia.org/wiki/Associative_array 关联数组]或者'' ''构成 , 彼此之间互相嵌套.  
 
 
When a script is loaded, it is placed inside a table called its ''script scope'', and any code inside the script is executed. All variables, functions and classes in the script persist in the script scope after the code has finished executing.  
 
  
 +
脚本被加载时, 它就会被放置在一个被称为它的''脚本域''的表中, 然后脚本中的任何代码都能够被执行. 执行完代码后,所有的变量、函数以及类都会被保存在脚本域中.
  
 
== 脚本句柄 ==
 
== 脚本句柄 ==
Interaction with in-game entities is done through ''script handles'', which are objects that reference a specific entity. The script handles contain accessor and and mutator methods to read and modify the entity properties. What methods are available depend on the game and entity type. See the scripting API reference for each game for more information.
+
与游戏中的实体进行交互是经由 ''脚本句柄'' 得以实现的, 脚本句柄是一种用于引用特定实体的对象. 脚本句柄包含了访问器(accessor)和修改器(mutator)方法以读取和修改实体的属性. 方法的可用性取决于游戏和实体的类型. 请阅读各种游戏的脚本的API参考以了解详情。
 
 
All server-side entities currently in play can be searched and iterated through with the <code>CEntities</code> class object, <code>Entities</code>.
 
  
 +
所有正处于游戏中的服务器端的实体都可以通过<code>CEntities</code>类的对象<code>Entities</code>来搜寻或者迭代。
  
 
== 实体脚本 ==
 
== 实体脚本 ==
''Main article [[Entity Scripts]]''
+
''详阅文章[[Entity Scripts]]''
  
  
A common VScript feature is to augment the features of entities using Entity Scripts.  
+
常见的VScript用法是使用实体脚本来扩充实体的功能.
  
Adding a script to the <code>vscripts</code> (Entity Scripts) KeyValue of a server-side entity loads the script as an Entity Script. The script is executed when the entity spawns, and loads into a script scope made up of an unique identifier followed by the entity name or class name; <code>_<unique ID>_<entity name></code>, placed in the root table. If no script has been run on the entity, a script scope can be manually created by using the <code>CBaseEntity::ValidateScriptScope()</code> method.
+
添加一个脚本到一个服务器端实体的<code>vscripts</code> (实体脚本)键值将使得该脚本作为实体脚本被加载. 该脚本将在实体产生后被自动执行, 并加载到一个脚本域内,该脚本域由唯一标识符+实体名称或种类名组成; <code>_<unique ID>_<entity name></code>, 并被放在根表中. 如果一个实体没有任何脚本被执行, 可以通过 <code>CBaseEntity::ValidateScriptScope()</code> 方法来手动创建一个脚本域.
  
{{note|Source 2 has both public and private script scopes. Entity Scripts get loaded into the private script scope.}}
+
{{注意|起源2 有公共脚本域和私有脚本域之分. 实体脚本会被加载到私有脚本域之中.}}
  
Additional scripts can be loaded by specifying multiple scripts in the <code>vscripts</code> keyvalue, or using the <code>RunScriptFile</code> Input. All scripts that are run on the same entity will load into the same script scope, overwriting any identical variables and functions.
+
可以通过在<code>vscripts</code> 键值中指定多个脚本来加载其他脚本, 或者使用 <code>RunScriptFile</code> 输入. 在同一实体上运行的所有脚本将加载到相同的脚本域, 覆盖任何相同的变量和函数.
  
A think function can be set with the <code>thinkfunction</code> [[Keyvalue|KeyValue]] or by the <code>AddThinkToEnt()</code> function, the specified script function every 0.1 seconds. While it has the potential to become expensive, a programmer is able to limit the amount of code executed. Functions can also be manually called through the I/O system with the inputs <code>RunScriptCode ''function_name(argument, ...)''</code> or <code>RunScriptFunction ''function_name''</code>.
+
Think函数可以被设置于<code>thinkfunction</code> [[Keyvalue|键值]]中或者由 <code>AddThinkToEnt()</code> 函数来添加, 被指定的函数会以0.1秒一次的频率被调用. 函数也可以通过I/O系统的 <code>RunScriptCode ''function_name(argument, ...)''</code><code>RunScriptFunction ''function_name''</code>这两个输入来手动调用。
  
An Entity Script has a <code>self</code> (Source 1) or <code>thisEntity</code> (Source 2) reference to the script handle of the entity owning it, allowing the script easy access to control the entity through its class methods.
+
实体脚本有 <code>self</code> (起源1) 或者 <code>thisEntity</code> (起源2)这两个能够引用它自身实体的脚本句柄.
  
=== 预定义的钩子 ===
+
=== 预定义的钩子函数 ===
Entities have the ability to call functions in their script scope from the C++ side. Common entity classes have predefined function calls programmed into them to occur at certain events, allowing scripts to execute code. For example, creating a function called <code>Precache()</code> in an entity script will call that function right after the entity spawns, allowing the script to precache any custom assets. These functions do not need to be registered, and are always called if if one with the right name exist. Please see the API documentation for your game to find out what hook functions are available for each class.
+
实体能够从C++端(游戏的底层代码)中调用其脚本域的函数, 我们称之为钩子函数(Hook Functions), 简称钩子.公共实体类被写入了一些预定义的函数调用(predefined function calls),以在特定事件发生时允许脚本执行代码. 例如, 在一个实体脚本中创建一个名为 <code>Precache()</code> 的函数将在实体生成后立即调用该函数, 以允许脚本预缓存自定义的资源. 这些钩子函数不需要注册,并且只要名字没写错的话就会在合适的时候被调用. 请参阅游戏的API文档以了解每个类可用的钩子函数.
  
 
{{todo|Does Source 2 implement this?}}
 
{{todo|Does Source 2 implement this?}}
Line 46: Line 44:
  
 
=== 触发输出 ===
 
=== 触发输出 ===
If available in the game API, scripts can use the <code>EntFire()</code> and <code>DoEntFire()</code> functions to fire outputs to map entities. More functions may be available depending on game.
+
如果游戏的API支持的话, 脚本可以通过<code>EntFire()</code> <code>DoEntFire()</code> 来对地图上的实体触发输出. 可能还有更多类似的函数, 取决于游戏. (译者注:例如CSGO还有<code>EntFireByHandle()</code>这一函数)
  
If arguments for ''<code>activator</code>'' and ''<code>caller</code>'' are available in the functions, they take a script handle and can be used to fire an output to an entity using the "!self" or "!activator" keyword, even without having to know its name, as long as the handle is available.
+
如果函数支持''<code>activator</code>'' ''<code>caller</code>'' 的参数, 就可以使用"!self" 或者 "!activator" 关键字将输出发送给实体,而不必知道其targetname,前提是句柄有效.
  
Arbitrary VScript code can be run from the I/O system, using the <code>RunScriptCode</code> input available in all entities. The code will run in the calling entities script scope.
+
使用<code>RunScriptCode</code> 输入可以通过I/O系统执行任何VScript代码. 代码将在被调用实体的脚本域中运行.
{{warning|Never use double-quotation marks in any Hammer Output, since it will corrupt the map file. This means that strings cannot be passed with <code>RunScriptCode</code>.}}
+
{{警告|在Hammer的输出中绝对不要使用双引号, 因为这样做会破坏地图文件. 这意味着字符串无法通过 <code>RunScriptCode</code> 被传递.}}
  
  
Example Squirrel code:
+
示范代码:
 
<source lang=cpp>
 
<source lang=cpp>
// Sets the health of the entity owning the script scope to 500.
+
// 将拥有脚本域的实体的生命值设置成500
 
DoEntFire( "!self", "SetHealth", "500", 0, self, self )
 
DoEntFire( "!self", "SetHealth", "500", 0, self, self )
 
</source>
 
</source>
 
  
 
=== 关联输出 ===
 
=== 关联输出 ===
  
Using the <code>CBaseEntity::ConnectOutput(string ''output'', string ''function'')</code> method, an entity Output can be connected to a function in the script scope of the entity.  
+
通过<code>CBaseEntity::ConnectOutput(string ''output'', string ''function'')</code>方法, 实体输出可以关联到实体的脚本域中的函数.
  
For the duration of the function call, the variables <code>activator</code> and <code>caller</code> are set to the handles of the activating and calling entities, allowing for example for an easy way to find which player triggered something.
+
在函数被调用期间, 变量 <code>activator</code> <code>caller</code> 会被设置为I/O链中激活实体与调用实体的句柄, 从而可以轻松地找到是哪个玩家触发了某些内容.
{{bug|In {{l4d2}}, these variables are not set correctly.}}
+
{{Bug|{{l4d2}}中, 这些变量并没有被正确地设置.(译者注:在实践中, 译者并未发现该Bug的存在, 这意味着也许该Bug已经被修复了.)}}
  
  
Example Squirrel code:
+
示范代码:
 
<source lang=cpp>
 
<source lang=cpp>
// Lights a prop on fire when it's used by the player.
+
// 当玩家使用时,点燃道具
 
function IgniteSelf()
 
function IgniteSelf()
 
{
 
{
Line 77: Line 74:
 
}
 
}
  
// Connects the OnPlayerUse output to the above function.
+
// 关联OnPlayerUse输出与脚本函数.
 
self.ConnectOutput( "OnPlayerUse", "IgniteSelf" )
 
self.ConnectOutput( "OnPlayerUse", "IgniteSelf" )
 
</source>
 
</source>
 
  
 
=== 输入钩子 ===
 
=== 输入钩子 ===
  
When an entity receives an input, the game code will attempt to call a script function of the format <code>Input<Name of Input>()</code> in the receiving Entity Script. If the function returns <code>false</code>, the input is prevented from firing.  
+
当实体接收到了输入, 游戏代码会尝试在接收实体的实体脚本中调用格式为 <code>Input<Name of Input>()</code> 的脚本函数. 如果该函数返回 <code>false</code>, 输入就不会被触发.(译者注:这意味着输入可以被打断)
  
{{note|The input name is case sensitive, and uses the CamelCase format.}}
+
{{注意|输入名称区分大小写, 并使用骆驼拼写法格式.}}
  
As with connected output functions, the variables <code>activator</code> and <code>caller</code> are set to the handles of the activating and calling entities.
+
与关联实体输出的函数一样, <code>activator</code> <code>caller</code> 这两个变量会被设置为激活实体和调用实体.
{{note|Unlike for output functions, these are set correctly in {{l4d2}}.}}
+
{{note|不同于输出函数的Bug, 它们在{{l4d2}}中的设置是正确的.}}
  
  
Example Squirrel code:
+
示范代码:
 
<source lang=cpp>
 
<source lang=cpp>
// The script of a door or button. Intercepts the Unlock input,  
+
// 一个门或者按钮的脚本, 监听Unlock输入
// and doesn't allow the door/button to unlock until 5 inputs have been received.
+
// 禁止门被打开, 除非尝试开门5次(进行了5次unlock输入).
  
UnlockCounter <- 5 // Counter local to the entity script scope.
+
UnlockCounter <- 5 // 实体脚本域的本地计数器
  
// Called when the Unlock input is received.
+
// 接收到Unlock输入时调用
 
function InputUnlock()
 
function InputUnlock()
 
{
 
{
Line 106: Line 102:
 
if( UnlockCounter <= 0 )
 
if( UnlockCounter <= 0 )
 
{
 
{
return true // Allows the unlock
+
return true // 允许解锁
 
}
 
}
 
 
return false // Discards the input
+
return false // 打断输入
 
}
 
}
 
</source>
 
</source>
 
  
 
== 术语表 ==
 
== 术语表 ==
;Entity handle
+
;Entity handle(实体句柄,也称为EHANDLE)
:An opaque entity reference passing a C++ [[CHandle#EHANDLE|EHANDLE]]. Can only be compared with other handles or passed to API functions expecting them. Only used rarely.  
+
:一个能够传递C++ [[CHandle#EHANDLE|EHANDLE]]的不透明的实体引用(类似于指针). 只能与其他句柄进行比较或传递给期望需要用到它们的API函数, 很少被使用到.
;Script handle
+
;Script handle(脚本句柄)
:An entity instance with accessors and mutators to the C++ entity object. Represented as a HSCRIPT typedef in C++ code.
+
:具有C++实体对象的访问器和修改器的实体实例. 在C++代码中表示为HSCRIPT typedef.
;Script scope
+
;Script scope(脚本域)
:Execution context of a script. A table where the variables, functions and classes of a VScript are placed.
+
:脚本的执行上下文(Execution context).它是一个包含了VScript的变量,函数和类的表.
 
 
  
 
== API参考 ==
 
== API参考 ==
  
[[List of L4D2 Script Functions]]
+
[[List of L4D2 Script Functions|L4D2脚本函数列表]]
 
 
[[List of Portal 2 Script Functions]]
 
  
[[List_of_Counter-Strike:_Global_Offensive_Script_Functions| List of CS:GO Script Functions]]
+
[[List of Portal 2 Script Functions|Portal2脚本函数列表]]
  
[[List of Contagion Script Functions]]
+
[[List_of_Counter-Strike:_Global_Offensive_Script_Functions|CSGO脚本函数列表]]
  
[[Dota_2_Workshop_Tools/Scripting/API| Dota 2 Scripting API]]
+
[[List of Contagion Script Functions|Contagion脚本函数列表]]
  
 +
[[Dota_2_Workshop_Tools/Scripting/API|Dota2脚本API]]
  
 
== 推荐阅读 ==
 
== 推荐阅读 ==
 
* [[VScript]]
 
* [[VScript]]
 
* [[Squirrel]]
 
* [[Squirrel]]
* [[L4D2_Vscripts| Left 4 Dead 2 Scripting]]
+
* [[Dota_2_Workshop_Tools/Scripting| Dota2 脚本]]
* [[Dota_2_Workshop_Tools/Scripting| Dota 2 Scripting]]
+
* [[L4D2_Vscripts:zh-cn|求生之路2脚本]]
 +
* [[L4D2_Director_Scripts:zh-cn|求生之路2导演脚本]]
  
 
[[Category:Scripting]]
 
[[Category:Scripting]]

Latest revision as of 09:54, 30 July 2019

English

本页面内容由Dazai Nerau译自英文版页面. 欢迎任何人补充新内容或者修改其中的错误.


这篇文章旨在阐述有关VScript脚本的基本概念以及使用方法.

表和脚本域

脚本环境由关联数组或者构成 , 彼此之间互相嵌套.

脚本被加载时, 它就会被放置在一个被称为它的脚本域的表中, 然后脚本中的任何代码都能够被执行. 执行完代码后,所有的变量、函数以及类都会被保存在脚本域中.

脚本句柄

与游戏中的实体进行交互是经由 脚本句柄 得以实现的, 脚本句柄是一种用于引用特定实体的对象. 脚本句柄包含了访问器(accessor)和修改器(mutator)方法以读取和修改实体的属性. 方法的可用性取决于游戏和实体的类型. 请阅读各种游戏的脚本的API参考以了解详情。

所有正处于游戏中的服务器端的实体都可以通过CEntities类的对象Entities来搜寻或者迭代。

实体脚本

详阅文章Entity Scripts


常见的VScript用法是使用实体脚本来扩充实体的功能.

添加一个脚本到一个服务器端实体的vscripts (实体脚本)键值将使得该脚本作为实体脚本被加载. 该脚本将在实体产生后被自动执行, 并加载到一个脚本域内,该脚本域由唯一标识符+实体名称或种类名组成; _<unique ID>_<entity name>, 并被放在根表中. 如果一个实体没有任何脚本被执行, 可以通过 CBaseEntity::ValidateScriptScope() 方法来手动创建一个脚本域.

注意:起源2 有公共脚本域和私有脚本域之分. 实体脚本会被加载到私有脚本域之中.

可以通过在vscripts 键值中指定多个脚本来加载其他脚本, 或者使用 RunScriptFile 输入. 在同一实体上运行的所有脚本将加载到相同的脚本域, 覆盖任何相同的变量和函数.

Think函数可以被设置于thinkfunction 键值中或者由 AddThinkToEnt() 函数来添加, 被指定的函数会以0.1秒一次的频率被调用. 函数也可以通过I/O系统的 RunScriptCode function_name(argument, ...)RunScriptFunction function_name这两个输入来手动调用。

实体脚本有 self (起源1) 或者 thisEntity (起源2)这两个能够引用它自身实体的脚本句柄.

预定义的钩子函数

实体能够从C++端(游戏的底层代码)中调用其脚本域的函数, 我们称之为钩子函数(Hook Functions), 简称钩子.公共实体类被写入了一些预定义的函数调用(predefined function calls),以在特定事件发生时允许脚本执行代码. 例如, 在一个实体脚本中创建一个名为 Precache() 的函数将在实体生成后立即调用该函数, 以允许脚本预缓存自定义的资源. 这些钩子函数不需要注册,并且只要名字没写错的话就会在合适的时候被调用. 请参阅游戏的API文档以了解每个类可用的钩子函数.

To do: Does Source 2 implement this?

I/O系统交互

触发输出

如果游戏的API支持的话, 脚本可以通过EntFire()DoEntFire() 来对地图上的实体触发输出. 可能还有更多类似的函数, 取决于游戏. (译者注:例如CSGO还有EntFireByHandle()这一函数)

如果函数支持activatorcaller 的参数, 就可以使用"!self" 或者 "!activator" 关键字将输出发送给实体,而不必知道其targetname,前提是句柄有效.

使用RunScriptCode 输入可以通过I/O系统执行任何VScript代码. 代码将在被调用实体的脚本域中运行.

警告:在Hammer的输出中绝对不要使用双引号, 因为这样做会破坏地图文件. 这意味着字符串无法通过 RunScriptCode 被传递.


示范代码:

// 将拥有脚本域的实体的生命值设置成500
DoEntFire( "!self", "SetHealth", "500", 0, self, self )

关联输出

通过CBaseEntity::ConnectOutput(string output, string function)方法, 实体输出可以关联到实体的脚本域中的函数.

在函数被调用期间, 变量 activatorcaller 会被设置为I/O链中激活实体与调用实体的句柄, 从而可以轻松地找到是哪个玩家触发了某些内容.

Bug: <Left 4 Dead 2>中, 这些变量并没有被正确地设置.(译者注:在实践中, 译者并未发现该Bug的存在, 这意味着也许该Bug已经被修复了.)


示范代码:

// 当玩家使用时,点燃道具
function IgniteSelf()
{
	DoEntFire( "!self", "Ignite", "", 0, self, self )
}

// 关联OnPlayerUse输出与脚本函数.
self.ConnectOutput( "OnPlayerUse", "IgniteSelf" )

输入钩子

当实体接收到了输入, 游戏代码会尝试在接收实体的实体脚本中调用格式为 Input<Name of Input>() 的脚本函数. 如果该函数返回 false, 输入就不会被触发.(译者注:这意味着输入可以被打断)

注意:输入名称区分大小写, 并使用骆驼拼写法格式.

与关联实体输出的函数一样, activatorcaller 这两个变量会被设置为激活实体和调用实体.

Note:不同于输出函数的Bug, 它们在<Left 4 Dead 2>中的设置是正确的.


示范代码:

// 一个门或者按钮的脚本, 监听Unlock输入
// 禁止门被打开, 除非尝试开门5次(进行了5次unlock输入).

UnlockCounter <- 5 // 实体脚本域的本地计数器

// 接收到Unlock输入时调用
function InputUnlock()
{
	UnlockCounter--
	
	if( UnlockCounter <= 0 )
	{
		return true // 允许解锁
	}
	
	return false // 打断输入
}

术语表

Entity handle(实体句柄,也称为EHANDLE)
一个能够传递C++ 的EHANDLE的不透明的实体引用(类似于指针). 只能与其他句柄进行比较或传递给期望需要用到它们的API函数, 很少被使用到.
Script handle(脚本句柄)
具有C++实体对象的访问器和修改器的实体实例. 在C++代码中表示为HSCRIPT typedef.
Script scope(脚本域)
脚本的执行上下文(Execution context).它是一个包含了VScript的变量,函数和类的表.

API参考

L4D2脚本函数列表

Portal2脚本函数列表

CSGO脚本函数列表

Contagion脚本函数列表

Dota2脚本API

推荐阅读