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

From Valve Developer Community
Jump to: navigation, search
(触发输出)
(预定义的钩子函数)
 
(17 intermediate revisions by the same user not shown)
Line 30: Line 30:
 
{{注意|起源2 有公共脚本域和私有脚本域之分. 实体脚本会被加载到私有脚本域之中.}}
 
{{注意|起源2 有公共脚本域和私有脚本域之分. 实体脚本会被加载到私有脚本域之中.}}
  
可以通过在<code>vscripts</code> 键值中指定多个脚本来加载其他脚本, 或者使用 <code>RunScriptFile</code> 输入. 在同一实体上运行的所有脚本将加载到相同的脚本范围, 覆盖任何相同的变量和函数.
+
可以通过在<code>vscripts</code> 键值中指定多个脚本来加载其他脚本, 或者使用 <code>RunScriptFile</code> 输入. 在同一实体上运行的所有脚本将加载到相同的脚本域, 覆盖任何相同的变量和函数.
  
 
Think函数可以被设置于<code>thinkfunction</code> [[Keyvalue|键值]]中或者由 <code>AddThinkToEnt()</code> 函数来添加, 被指定的函数会以0.1秒一次的频率被调用. 函数也可以通过I/O系统的 <code>RunScriptCode ''function_name(argument, ...)''</code>和<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>这两个输入来手动调用。
Line 36: Line 36:
 
实体脚本有 <code>self</code> (起源1) 或者 <code>thisEntity</code> (起源2)这两个能够引用它自身实体的脚本句柄.
 
实体脚本有 <code>self</code> (起源1) 或者 <code>thisEntity</code> (起源2)这两个能够引用它自身实体的脚本句柄.
  
=== 预定义的钩子 ===
+
=== 预定义的钩子函数 ===
实体能够从C++端调用其脚本域中的函数. 公共实体类被写入了一些预定义的函数调用(predefined function calls),以在特定事件中发生时允许脚本执行代码. 例如, 在一个实体脚本中创建一个名为 <code>Precache()</code> 的函数将在实体生成后立即调用该函数, 以允许脚本预缓存自定义的资源. 这些钩子函数不需要注册,并且只要名字没写错的话就会在合适的时候被调用. 请参阅游戏的API文档以了解每个类可用的钩子函数.
+
实体能够从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 46:
 
如果游戏的API支持的话, 脚本可以通过<code>EntFire()</code> 和 <code>DoEntFire()</code> 来对地图上的实体触发输出. 可能还有更多类似的函数, 取决于游戏. (译者注:例如CSGO还有<code>EntFireByHandle()</code>这一函数)
 
如果游戏的API支持的话, 脚本可以通过<code>EntFire()</code> 和 <code>DoEntFire()</code> 来对地图上的实体触发输出. 可能还有更多类似的函数, 取决于游戏. (译者注:例如CSGO还有<code>EntFireByHandle()</code>这一函数)
  
如果函数支持''<code>activator</code>'' 和 ''<code>caller</code>'' 的参数, 就可以使用"!self" 或者 "!activator" 关键字将输出发送给实体,而不必知道其名词,前提是句柄有效.
+
如果函数支持''<code>activator</code>'' 和 ''<code>caller</code>'' 的参数, 就可以使用"!self" 或者 "!activator" 关键字将输出发送给实体,而不必知道其targetname,前提是句柄有效.
  
 
使用<code>RunScriptCode</code> 输入可以通过I/O系统执行任何VScript代码. 代码将在被调用实体的脚本域中运行.
 
使用<code>RunScriptCode</code> 输入可以通过I/O系统执行任何VScript代码. 代码将在被调用实体的脚本域中运行.
Line 52: Line 52:
  
  
实例Squirrel代码:
+
示范代码:
 
<source lang=cpp>
 
<source lang=cpp>
 
// 将拥有脚本域的实体的生命值设置成500
 
// 将拥有脚本域的实体的生命值设置成500
Line 60: Line 60:
 
=== 关联输出 ===
 
=== 关联输出 ===
  
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 74: 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 103: 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

推荐阅读