<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.steeveeo.com/index.php?action=history&amp;feed=atom&amp;title=Creating_Custom_VTI_Drivers</id>
	<title>Creating Custom VTI Drivers - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.steeveeo.com/index.php?action=history&amp;feed=atom&amp;title=Creating_Custom_VTI_Drivers"/>
	<link rel="alternate" type="text/html" href="https://wiki.steeveeo.com/index.php?title=Creating_Custom_VTI_Drivers&amp;action=history"/>
	<updated>2026-05-04T06:42:32Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.41.0</generator>
	<entry>
		<id>https://wiki.steeveeo.com/index.php?title=Creating_Custom_VTI_Drivers&amp;diff=51&amp;oldid=prev</id>
		<title>Steeveeo: Added &quot;Next Steps&quot; section and some minor cleanup and code highlighting to previous commits.</title>
		<link rel="alternate" type="text/html" href="https://wiki.steeveeo.com/index.php?title=Creating_Custom_VTI_Drivers&amp;diff=51&amp;oldid=prev"/>
		<updated>2024-02-14T01:06:48Z</updated>

		<summary type="html">&lt;p&gt;Added &amp;quot;Next Steps&amp;quot; section and some minor cleanup and code highlighting to previous commits.&lt;/p&gt;
&lt;a href=&quot;https://wiki.steeveeo.com/index.php?title=Creating_Custom_VTI_Drivers&amp;amp;diff=51&amp;amp;oldid=50&quot;&gt;Show changes&lt;/a&gt;</summary>
		<author><name>Steeveeo</name></author>
	</entry>
	<entry>
		<id>https://wiki.steeveeo.com/index.php?title=Creating_Custom_VTI_Drivers&amp;diff=50&amp;oldid=prev</id>
		<title>Steeveeo: Initial tutorial writeup.</title>
		<link rel="alternate" type="text/html" href="https://wiki.steeveeo.com/index.php?title=Creating_Custom_VTI_Drivers&amp;diff=50&amp;oldid=prev"/>
		<updated>2024-02-13T08:39:40Z</updated>

		<summary type="html">&lt;p&gt;Initial tutorial writeup.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;[[Category:VTI]]&lt;br /&gt;
[[Category:VTI Tutorials]]&lt;br /&gt;
&lt;br /&gt;
The [[VTI World Kit]] is designed to be easily extensible by both world designers and programmers alike. To this end, custom Drivers are highly recommended and are built to be fairly simple to create. This article serves as a tutorial on how to create a custom Driver. It will assume basic knowledge of UdonSharp.&lt;br /&gt;
&lt;br /&gt;
In this tutorial, we will be replicating the [[VTIObjectToggle]] Driver as it demonstrates all the core tenets of how [[VTI Drivers]] function.&lt;br /&gt;
&lt;br /&gt;
== Create the Script ==&lt;br /&gt;
Create a new U# script and open it in your IDE of choice. Change the inherited class from UdonSharpBehaviour to VTIDriverBase.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
public class CustomDriver : VTIDriverBase&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next, we need our control variables so the script can function. As we are turning a GameObject on for a period of time, and then off after it, add a public property for a GameObject a float for the time it will take to reset. For sanity&amp;#039;s sake, also add a call in the Start() method to turn the Target off, to make sure it won&amp;#039;t fire when the level loads.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
public class CustomDriver : VTIDriverBase&lt;br /&gt;
{&lt;br /&gt;
	public GameObject Target;&lt;br /&gt;
	public float ResetTime = 5.0f;&lt;br /&gt;
&lt;br /&gt;
	void Start()&lt;br /&gt;
	{&lt;br /&gt;
		Target.SetActive(false);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Add Core Functionality ==&lt;br /&gt;
The simplest possible [[VTI Drivers|Driver]] only needs to implement the &amp;lt;syntaxhighlight lang=&amp;quot;csharp&amp;quot; inline&amp;gt;VTIEventPlay()&amp;lt;/syntaxhighlight&amp;gt; method. This is what is called when an [[VTI Events|Event]] is received, all checks have passed, and [[VRChat Twitch Integration|VTI]] is attempting to Fire this Driver&amp;#039;s [[VTI Targets|Target]].&lt;br /&gt;
&lt;br /&gt;
Add a public override void method called VTIEventPlay(). Clear out the &amp;lt;syntaxhighlight lang=&amp;quot;csharp&amp;quot; inline&amp;gt;base.VTIEventPlay();&amp;lt;/syntaxhighlight&amp;gt; line if your IDE added it automatically.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
	public override void VTIEventPlay()&lt;br /&gt;
	{&lt;br /&gt;
		&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next, we need to make the Driver actually do the thing we want it to do, which is to turn on a GameObject, wait, and then turn it off. The first thing we&amp;#039;ll need is to call &amp;lt;syntaxhighlight lang=&amp;quot;csharp&amp;quot; inline&amp;gt;Target.SetActive(true)&amp;lt;/syntaxhighlight&amp;gt; in our new method. Then, create another method that will do the exact opposite and call &amp;lt;syntaxhighlight lang=&amp;quot;csharp&amp;quot; inline&amp;gt;Target.SetActive(false)&amp;lt;/syntaxhighlight&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
	public override void VTIEventPlay()&lt;br /&gt;
	{&lt;br /&gt;
		Target.SetActive(true);&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	public void ResetTarget()&lt;br /&gt;
	{&lt;br /&gt;
		Target.SetActive(false);&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the core of our functionality, we only need to do one more thing: make &amp;lt;syntaxhighlight lang=&amp;quot;csharp&amp;quot; inline&amp;gt;VTIEventPlay()&amp;lt;/syntaxhighlight&amp;gt; call &amp;lt;syntaxhighlight lang=&amp;quot;csharp&amp;quot; inline&amp;gt;ResetTarget()&amp;lt;/syntaxhighlight&amp;gt; after a delay. We can do this simply by utilizing the built-in &amp;lt;syntaxhighlight lang=&amp;quot;csharp&amp;quot; inline&amp;gt;SendCustomEventDelayedSeconds()&amp;lt;/syntaxhighlight&amp;gt; method. Add that into &amp;lt;syntaxhighlight lang=&amp;quot;csharp&amp;quot; inline&amp;gt;VTIEventPlay()&amp;lt;/syntaxhighlight&amp;gt; and have it wait for &amp;lt;syntaxhighlight lang=&amp;quot;csharp&amp;quot; inline&amp;gt;ResetTime&amp;lt;/syntaxhighlight&amp;gt; seconds.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
SendCustomEventDelayedSeconds(nameof(ResetTarget), ResetTime);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As an aside, note the usage of &amp;lt;syntaxhighlight lang=&amp;quot;csharp&amp;quot; inline&amp;gt;nameof&amp;lt;/syntaxhighlight&amp;gt; instead of just putting &amp;lt;syntaxhighlight lang=&amp;quot;csharp&amp;quot; inline&amp;gt;&amp;quot;ResetTarget&amp;quot;&amp;lt;/syntaxhighlight&amp;gt; in the first argument. This allows for a measure of safety when maintaining projects later on, as if you need to rename &amp;lt;syntaxhighlight lang=&amp;quot;csharp&amp;quot; inline&amp;gt;ResetTarget()&amp;lt;/syntaxhighlight&amp;gt; for whatever reason, you can utilize something like Visual Studio&amp;#039;s Rename function and not have to worry about manually typing the name change into all the Custom Event calls.&lt;br /&gt;
&lt;br /&gt;
At this end of this section, this is how our script looks:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
using UnityEngine;&lt;br /&gt;
&lt;br /&gt;
public class CustomDriver : VTIDriverBase&lt;br /&gt;
{&lt;br /&gt;
	public GameObject Target;&lt;br /&gt;
	public float ResetTime = 5.0f;&lt;br /&gt;
&lt;br /&gt;
	void Start()&lt;br /&gt;
	{&lt;br /&gt;
		Target.SetActive(false);&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	public override void VTIEventPlay()&lt;br /&gt;
	{&lt;br /&gt;
		Target.SetActive(true);&lt;br /&gt;
		SendCustomEventDelayedSeconds(nameof(ResetTarget), ResetTime);&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	public void ResetTarget()&lt;br /&gt;
	{&lt;br /&gt;
		Target.SetActive(false);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Dealing With Readiness ==&lt;br /&gt;
For the most basic of Drivers, the Cooldown timer is automatically handled by [[VTI Targets|VTITarget]]. However, in this case, we&amp;#039;re turning an object on and telling VRChat to turn it back off after an arbitrary delay. In some circumstances, you may want your Drivers to be able to overlap themselves when triggered multiple times. But in this case, we have a Custom Event running on a timer, which can cause some level of havoc if we don&amp;#039;t tell the parent [[VTI Targets|VTITarget]] that we&amp;#039;re not ready to Fire again.&lt;br /&gt;
&lt;br /&gt;
There are two ways to do this: The &amp;lt;syntaxhighlight lang=&amp;quot;csharp&amp;quot; inline&amp;gt;IsReady&amp;lt;/syntaxhighlight&amp;gt; variable, and adding in a custom &amp;lt;syntaxhighlight lang=&amp;quot;csharp&amp;quot; inline&amp;gt;VTICheckReady()&amp;lt;/syntaxhighlight&amp;gt; method. The former method is exceptionally simple, and all we really need for this tutorial, so we&amp;#039;ll cover that first.&lt;br /&gt;
&lt;br /&gt;
==== The IsReady Boolean ====&lt;br /&gt;
The &amp;lt;syntaxhighlight lang=&amp;quot;csharp&amp;quot; inline&amp;gt;IsReady&amp;lt;/syntaxhighlight&amp;gt; boolean serves as a bit of a &amp;quot;Green Light&amp;quot; to signal the [[VTI World Kit]] that this [[VTI Drivers|Driver]] is ready to go or not. Right now, we need to turn that light &amp;quot;red&amp;quot; while we wait for the Custom Event timer to elapse, and then turn it back to &amp;quot;green&amp;quot; when we&amp;#039;re done. To do this, simply set &amp;lt;syntaxhighlight lang=&amp;quot;csharp&amp;quot; inline&amp;gt;IsReady = false;&amp;lt;/syntaxhighlight&amp;gt; in &amp;lt;syntaxhighlight lang=&amp;quot;csharp&amp;quot; inline&amp;gt;VTIEventPlay()&amp;lt;/syntaxhighlight&amp;gt;, and set it back to &amp;lt;syntaxhighlight lang=&amp;quot;csharp&amp;quot; inline&amp;gt;true&amp;lt;/syntaxhighlight&amp;gt; in &amp;lt;syntaxhighlight lang=&amp;quot;csharp&amp;quot; inline&amp;gt;ResetTarget()&amp;lt;/syntaxhighlight&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
	public override void VTIEventPlay()&lt;br /&gt;
	{&lt;br /&gt;
		IsReady = false;&lt;br /&gt;
&lt;br /&gt;
		Target.SetActive(true);&lt;br /&gt;
		SendCustomEventDelayedSeconds(nameof(ResetTarget), ResetTime);&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	public void ResetTarget()&lt;br /&gt;
	{&lt;br /&gt;
		IsReady = true;&lt;br /&gt;
&lt;br /&gt;
		Target.SetActive(false);&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And that&amp;#039;s it! By default, &amp;lt;syntaxhighlight lang=&amp;quot;csharp&amp;quot; inline&amp;gt;VTICheckReady()&amp;lt;/syntaxhighlight&amp;gt; will simply return the value of &amp;lt;syntaxhighlight lang=&amp;quot;csharp&amp;quot; inline&amp;gt;IsReady&amp;lt;/syntaxhighlight&amp;gt; unless overridden, so for the purposes of this script, we don&amp;#039;t even need to do anything more than this!&lt;br /&gt;
&lt;br /&gt;
==== VTICheckReady() ====&lt;br /&gt;
However, what if we need to be more complex in our checks to see if we can Fire again or not? In this case, a simple boolean may not be enough. For the purposes of this tutorial, this step is optional, and will only serve as an example of how this can be done in another way.&lt;br /&gt;
&lt;br /&gt;
There&amp;#039;s not really much we need to check in a Driver as simple as this, so let&amp;#039;s just be super paranoid about the state of the Target GameObject and ensure that it got turned off before allowing [[VRChat Twitch Integration|VTI]] to Fire this again. To do this, first add in an override for &amp;lt;syntaxhighlight lang=&amp;quot;csharp&amp;quot; inline&amp;gt;VTICheckReady()&amp;lt;/syntaxhighlight&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Next, replace the auto-generated &amp;quot;base&amp;quot; call (if your IDE made one) with a simple expression to return &amp;lt;syntaxhighlight lang=&amp;quot;csharp&amp;quot; inline&amp;gt;true&amp;lt;/syntaxhighlight&amp;gt; if both &amp;lt;syntaxhighlight lang=&amp;quot;csharp&amp;quot; inline&amp;gt;IsReady&amp;lt;/syntaxhighlight&amp;gt; is &amp;lt;syntaxhighlight lang=&amp;quot;csharp&amp;quot; inline&amp;gt;true&amp;lt;/syntaxhighlight&amp;gt; and Target is not currently active. This can look like the below:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
	public override bool VTICheckReady()&lt;br /&gt;
	{&lt;br /&gt;
		return IsReady &amp;amp;&amp;amp; !Target.activeSelf;&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Closing ==&lt;br /&gt;
And that&amp;#039;s basically it! This Driver can now be attached to a [[VTI Targets|VTITarget]] like any of the base Drivers that came with the [[VTI World Kit]]. At a very rough estimate, there are about seven times more words in this tutorial than there are in all of the base Drivers in the Kit combined. Our simple Driver code should now look like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
using UnityEngine;&lt;br /&gt;
&lt;br /&gt;
public class CustomDriver : VTIDriverBase&lt;br /&gt;
{&lt;br /&gt;
	public GameObject Target;&lt;br /&gt;
	public float ResetTime = 5.0f;&lt;br /&gt;
&lt;br /&gt;
	void Start()&lt;br /&gt;
	{&lt;br /&gt;
		Target.SetActive(false);&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	public override void VTIEventPlay()&lt;br /&gt;
	{&lt;br /&gt;
		IsReady = false;&lt;br /&gt;
&lt;br /&gt;
		Target.SetActive(true);&lt;br /&gt;
		SendCustomEventDelayedSeconds(nameof(ResetTarget), ResetTime);&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	public void ResetTarget()&lt;br /&gt;
	{&lt;br /&gt;
		IsReady = true;&lt;br /&gt;
&lt;br /&gt;
		Target.SetActive(false);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Next Steps ==&lt;br /&gt;
This is not all that can be done with a Driver. To continue on, read the next tutorial: [[User Messaging On Custom VTI Drivers]].&lt;/div&gt;</summary>
		<author><name>Steeveeo</name></author>
	</entry>
</feed>