Skip to content

Events

82 are written with override; 43 are recognized by name and argument type. Types are written with their fully qualified names. Add a using to write short names.

Forms written by overriding a base declaration

Section titled “Forms written by overriding a base declaration”

The base class holds the declaration, so you write these with public override.

SyntaxName calledVariable that receives the argument
void InputDrop(bool value, VRC.Udon.Common.UdonInputEventArgs args)_inputDropinputDropBoolValue inputDropArgs
void InputGrab(bool value, VRC.Udon.Common.UdonInputEventArgs args)_inputGrabinputGrabBoolValue inputGrabArgs
void InputJump(bool value, VRC.Udon.Common.UdonInputEventArgs args)_inputJumpinputJumpBoolValue inputJumpArgs
void InputLookHorizontal(float value, VRC.Udon.Common.UdonInputEventArgs args)_inputLookHorizontalinputLookHorizontalFloatValue inputLookHorizontalArgs
void InputLookVertical(float value, VRC.Udon.Common.UdonInputEventArgs args)_inputLookVerticalinputLookVerticalFloatValue inputLookVerticalArgs
void InputMoveHorizontal(float value, VRC.Udon.Common.UdonInputEventArgs args)_inputMoveHorizontalinputMoveHorizontalFloatValue inputMoveHorizontalArgs
void InputMoveVertical(float value, VRC.Udon.Common.UdonInputEventArgs args)_inputMoveVerticalinputMoveVerticalFloatValue inputMoveVerticalArgs
void InputUse(bool value, VRC.Udon.Common.UdonInputEventArgs args)_inputUseinputUseBoolValue inputUseArgs
void Interact()_interact
void MidiControlChange(int channel, int number, int value)_midiControlChangemidiControlChangeChannel midiControlChangeNumber midiControlChangeValue
void MidiNoteOff(int channel, int number, int velocity)_midiNoteOffmidiNoteOffChannel midiNoteOffNumber midiNoteOffVelocity
void MidiNoteOn(int channel, int number, int velocity)_midiNoteOnmidiNoteOnChannel midiNoteOnNumber midiNoteOnVelocity
void OnAsyncGpuReadbackComplete(VRC.SDK3.Rendering.VRCAsyncGPUReadbackRequest request)_onAsyncGpuReadbackCompleteonAsyncGpuReadbackCompleteRequest
void OnAvatarChanged(VRC.SDKBase.VRCPlayerApi player)_onAvatarChangedonAvatarChangedPlayer
void OnAvatarEyeHeightChanged(VRC.SDKBase.VRCPlayerApi player, float prevEyeHeightAsMeters)_onAvatarEyeHeightChangedonAvatarEyeHeightChangedPlayer onAvatarEyeHeightChangedPrevEyeHeightAsMeters
void OnContactEnter(VRC.Dynamics.ContactEnterInfo contactInfo)_onContactEnteronContactEnterContactInfo
void OnContactExit(VRC.Dynamics.ContactExitInfo contactInfo)_onContactExitonContactExitContactInfo
void OnControllerColliderHitPlayer(VRC.SDK3.ControllerColliderPlayerHit hit)_onControllerColliderHitPlayeronControllerColliderHitPlayerHit
void OnDeserialization(VRC.Udon.Common.DeserializationResult result)_onDeserializationonDeserializationResult
void OnDroneTriggerEnter(VRC.SDKBase.VRCDroneApi drone)_onDroneTriggerEnteronDroneTriggerEnterDrone
void OnDroneTriggerExit(VRC.SDKBase.VRCDroneApi drone)_onDroneTriggerExitonDroneTriggerExitDrone
void OnDroneTriggerStay(VRC.SDKBase.VRCDroneApi drone)_onDroneTriggerStayonDroneTriggerStayDrone
void OnDrop()_onDrop
void OnImageLoadError(VRC.SDK3.Image.IVRCImageDownload result)_onImageLoadErroronImageLoadErrorIVRCImageDownload
void OnImageLoadSuccess(VRC.SDK3.Image.IVRCImageDownload result)_onImageLoadSuccessonImageLoadSuccessIVRCImageDownload
void OnInputMethodChanged(VRC.SDKBase.VRCInputMethod inputMethod)_onInputMethodChangedonInputMethodChangedInputMethod
void OnLanguageChanged(string language)_onLanguageChangedonLanguageChangedLanguage
void OnListAvailableProducts(VRC.Economy.IProduct[] products)_onListAvailableProductsonListAvailableProductsResult
void OnListProductOwners(VRC.Economy.IProduct product, string[] owners)_onListProductOwnersonListProductOwnersResult onListProductOwnersOwners
void OnListPurchases(VRC.Economy.IProduct[] products, VRC.SDKBase.VRCPlayerApi player)_onListPurchasesonListPurchasesResult onListPurchasesPlayer
void OnMasterTransferred(VRC.SDKBase.VRCPlayerApi newMaster)_onMasterTransferredonMasterTransferredNewMaster
bool OnOwnershipRequest(VRC.SDKBase.VRCPlayerApi requestingPlayer, VRC.SDKBase.VRCPlayerApi requestedOwner)_onOwnershipRequestonOwnershipRequestRequester onOwnershipRequestNewOwner
void OnOwnershipTransferred(VRC.SDKBase.VRCPlayerApi player)_onOwnershipTransferredonOwnershipTransferredPlayer
void OnPersistenceUsageUpdated()_onPersistenceUsageUpdated
void OnPhysBoneGrabbed(VRC.Dynamics.PhysBoneGrabbedInfo physBoneInfo)_onPhysBoneGrabbedonPhysBoneGrabbedPhysBoneInfo
void OnPhysBonePosed(VRC.Dynamics.PhysBonePosedInfo physBoneInfo)_onPhysBonePosedonPhysBonePosedPhysBoneInfo
void OnPhysBoneReleased(VRC.Dynamics.PhysBoneReleasedInfo physBoneInfo)_onPhysBoneReleasedonPhysBoneReleasedPhysBoneInfo
void OnPhysBoneUnPosed(VRC.Dynamics.PhysBoneUnPosedInfo physBoneInfo)_onPhysBoneUnPosedonPhysBoneUnPosedPhysBoneInfo
void OnPickup()_onPickup
void OnPickupUseDown()_onPickupUseDown
void OnPickupUseUp()_onPickupUseUp
void OnPlayerCollisionEnter(VRC.SDKBase.VRCPlayerApi player)_onPlayerCollisionEnteronPlayerCollisionEnterPlayer
void OnPlayerCollisionExit(VRC.SDKBase.VRCPlayerApi player)_onPlayerCollisionExitonPlayerCollisionExitPlayer
void OnPlayerCollisionStay(VRC.SDKBase.VRCPlayerApi player)_onPlayerCollisionStayonPlayerCollisionStayPlayer
void OnPlayerDataStorageExceeded(VRC.SDKBase.VRCPlayerApi player)_onPlayerDataStorageExceededonPlayerDataStorageExceededPlayer
void OnPlayerDataStorageWarning(VRC.SDKBase.VRCPlayerApi player)_onPlayerDataStorageWarningonPlayerDataStorageWarningPlayer
void OnPlayerDataUpdated(VRC.SDKBase.VRCPlayerApi player, VRC.SDK3.Persistence.PlayerData.Info[] infos)_onPlayerDataUpdatedonPlayerDataUpdatedPlayer onPlayerDataUpdatedInfos
void OnPlayerJoined(VRC.SDKBase.VRCPlayerApi player)_onPlayerJoinedonPlayerJoinedPlayer
void OnPlayerLeft(VRC.SDKBase.VRCPlayerApi player)_onPlayerLeftonPlayerLeftPlayer
void OnPlayerObjectStorageExceeded(VRC.SDKBase.VRCPlayerApi player)_onPlayerObjectStorageExceededonPlayerObjectStorageExceededPlayer
void OnPlayerObjectStorageWarning(VRC.SDKBase.VRCPlayerApi player)_onPlayerObjectStorageWarningonPlayerObjectStorageWarningPlayer
void OnPlayerParticleCollision(VRC.SDKBase.VRCPlayerApi player)_onPlayerParticleCollisiononPlayerParticleCollisionPlayer
void OnPlayerRespawn(VRC.SDKBase.VRCPlayerApi player)_onPlayerRespawnonPlayerRespawnPlayer
void OnPlayerRestored(VRC.SDKBase.VRCPlayerApi player)_onPlayerRestoredonPlayerRestoredPlayer
void OnPlayerSuspendChanged(VRC.SDKBase.VRCPlayerApi player)_onPlayerSuspendChangedonPlayerSuspendChangedPlayer
void OnPlayerTriggerEnter(VRC.SDKBase.VRCPlayerApi player)_onPlayerTriggerEnteronPlayerTriggerEnterPlayer
void OnPlayerTriggerExit(VRC.SDKBase.VRCPlayerApi player)_onPlayerTriggerExitonPlayerTriggerExitPlayer
void OnPlayerTriggerStay(VRC.SDKBase.VRCPlayerApi player)_onPlayerTriggerStayonPlayerTriggerStayPlayer
void OnPostSerialization(VRC.Udon.Common.SerializationResult result)_onPostSerializationonPostSerializationResult
void OnPreSerialization()_onPreSerialization
void OnProductEvent(VRC.Economy.IProduct product, VRC.SDKBase.VRCPlayerApi player)_onProductEventonProductEventResult onProductEventPlayer
void OnPurchaseConfirmed(VRC.Economy.IProduct product, VRC.SDKBase.VRCPlayerApi player, bool purchasedNow)_onPurchaseConfirmedonPurchaseConfirmedResult onPurchaseConfirmedPlayer onPurchaseConfirmedPurchasedNow
void OnPurchaseConfirmedMultiple(VRC.Economy.IProduct product, VRC.SDKBase.VRCPlayerApi player, bool purchasedNow, int quantity)_onPurchaseConfirmedMultipleonPurchaseConfirmedMultipleResult onPurchaseConfirmedMultiplePlayer onPurchaseConfirmedMultiplePurchasedNow onPurchaseConfirmedMultipleQuantity
void OnPurchaseExpired(VRC.Economy.IProduct product, VRC.SDKBase.VRCPlayerApi player)_onPurchaseExpiredonPurchaseExpiredResult onPurchaseExpiredPlayer
void OnPurchasesLoaded(VRC.Economy.IProduct[] products, VRC.SDKBase.VRCPlayerApi player)_onPurchasesLoadedonPurchasesLoadedResult onPurchasesLoadedPlayer
void OnScreenUpdate(VRC.SDK3.Platform.ScreenUpdateData data)_onScreenUpdateonScreenUpdateData
void OnSpawn()_onSpawn
void OnStationEntered(VRC.SDKBase.VRCPlayerApi player)_onStationEnteredonStationEnteredPlayer
void OnStationExited(VRC.SDKBase.VRCPlayerApi player)_onStationExitedonStationExitedPlayer
void OnStringLoadError(VRC.SDK3.StringLoading.IVRCStringDownload result)_onStringLoadErroronStringLoadErrorIVRCStringDownload
void OnStringLoadSuccess(VRC.SDK3.StringLoading.IVRCStringDownload result)_onStringLoadSuccessonStringLoadSuccessIVRCStringDownload
void OnVRCCameraSettingsChanged(VRC.SDK3.Rendering.VRCCameraSettings cameraSettings)_onVRCCameraSettingsChangedonVRCCameraSettingsChangedCamera
void OnVRCPlusMassGift(VRC.SDKBase.VRCPlayerApi gifter, int numGifts)_onVRCPlusMassGiftonVRCPlusMassGiftGifter onVRCPlusMassGiftNumGifts
void OnVRCQualitySettingsChanged()_onVRCQualitySettingsChanged
void OnVideoEnd()_onVideoEnd
void OnVideoError(VRC.SDK3.Components.Video.VideoError videoError)_onVideoErroronVideoErrorVideoError
void OnVideoLoop()_onVideoLoop
void OnVideoPause()_onVideoPause
void OnVideoPlay()_onVideoPlay
void OnVideoReady()_onVideoReady
void OnVideoStart()_onVideoStart
void PostLateUpdate()_postLateUpdate

Forms recognized by name and argument type

Section titled “Forms recognized by name and argument type”

There’s no declaration in a base class, so you write the declaration yourself. The return type is void.

SyntaxName calledVariable that receives the argument
void FixedUpdate()_fixedUpdate
void LateUpdate()_lateUpdate
void OnAnimatorIK(int layerIndex)_onAnimatorIKonAnimatorIKLayerIndex
void OnAnimatorMove()_onAnimatorMove
void OnBecameInvisible()_onBecameInvisible
void OnBecameVisible()_onBecameVisible
void OnCollisionEnter(UnityEngine.Collision other)_onCollisionEnteronCollisionEnterOther
void OnCollisionEnter2D(UnityEngine.Collision2D other)_onCollisionEnter2DonCollisionEnter2DOther
void OnCollisionExit(UnityEngine.Collision other)_onCollisionExitonCollisionExitOther
void OnCollisionExit2D(UnityEngine.Collision2D other)_onCollisionExit2DonCollisionExit2DOther
void OnCollisionStay(UnityEngine.Collision other)_onCollisionStayonCollisionStayOther
void OnCollisionStay2D(UnityEngine.Collision2D other)_onCollisionStay2DonCollisionStay2DOther
void OnControllerColliderHit(UnityEngine.ControllerColliderHit hit)_onControllerColliderHitonControllerColliderHitHit
void OnDestroy()_onDestroy
void OnDisable()_onDisable
void OnEnable()_onEnable
void OnJointBreak(float breakForce)_onJointBreakonJointBreakBreakForce
void OnJointBreak2D(UnityEngine.Joint2D brokenJoint)_onJointBreak2DonJointBreak2DBrokenJoint
void OnMouseDown()_onMouseDown
void OnMouseDrag()_onMouseDrag
void OnMouseEnter()_onMouseEnter
void OnMouseExit()_onMouseExit
void OnMouseOver()_onMouseOver
void OnMouseUp()_onMouseUp
void OnMouseUpAsButton()_onMouseUpAsButton
void OnParticleCollision(UnityEngine.GameObject other)_onParticleCollisiononParticleCollisionOther
void OnParticleTrigger()_onParticleTrigger
void OnPostRender()_onPostRender
void OnPreCull()_onPreCull
void OnPreRender()_onPreRender
void OnRenderImage(UnityEngine.RenderTexture src, UnityEngine.RenderTexture dest)_onRenderImageonRenderImageSrc onRenderImageDest
void OnRenderObject()_onRenderObject
void OnTransformChildrenChanged()_onTransformChildrenChanged
void OnTransformParentChanged()_onTransformParentChanged
void OnTriggerEnter(UnityEngine.Collider other)_onTriggerEnteronTriggerEnterOther
void OnTriggerEnter2D(UnityEngine.Collider2D other)_onTriggerEnter2DonTriggerEnter2DOther
void OnTriggerExit(UnityEngine.Collider other)_onTriggerExitonTriggerExitOther
void OnTriggerExit2D(UnityEngine.Collider2D other)_onTriggerExit2DonTriggerExit2DOther
void OnTriggerStay(UnityEngine.Collider other)_onTriggerStayonTriggerStayOther
void OnTriggerStay2D(UnityEngine.Collider2D other)_onTriggerStay2DonTriggerStay2DOther
void OnWillRenderObject()_onWillRenderObject
void Start()_start
void Update()_update
SyntaxDescriptionErrorReasonInstead
public void _start() と void Start()Give a method the name the runtime usesTUKI0001runtimeChange the method’s name

A misspelled name stops compilation only for events written with override. For the ones recognized by name, this net doesn’t exist.

SyntaxIf you misspell the nameIf you get the argument types wrong
Written with override (82)Stops with CS0115Stops with CS0115
Written by name and argument type (43)Compiles. Never calledCompiles. Never called

There are two forms because events come from two sources. The 82 written with override are VRChat events; the base class holds the declaration. The 43 recognized by name are Unity messages; there’s no declaration anywhere, even tracing back through MonoBehaviour. Unity itself has called them by name since long ago.

The calling mechanism is the same for both. The compiler matches methods against a fixed list of names and argument types, and emits an entry point name like _start for the ones that match. The runtime calls that name. C#‘s virtual call isn’t used here. The override declaration exists so the C# compiler can check the name — that’s what it’s there for.

∴ Who checks the form you wrote differs between the two. For override, the C# compiler checks it. For the ones recognized by name, no one checks it. The table in the previous section is exactly this difference.

For the ones recognized by name, you write the declaration yourself. The shortest form is Start.

using UnityEngine;
using Tsukimi;
public class EventsStart : TsukimiBehaviour
{
void Start()
{
Debug.Log(1); // => 1
}
}

For the ones written with override, you match the declaration the base class holds.

using UnityEngine;
using Tsukimi;
public class EventsInteract : TsukimiBehaviour
{
public override void Interact()
{
Debug.Log(2);
}
void Start()
{
Debug.Log(1);
}
}
// Output
// 1

C# checks both the spelling and the argument types, so a mistake stops compilation right there.

using UnityEngine;
using Tsukimi;
using VRC.SDKBase;
public class R_events_override_typo : TsukimiBehaviour
{
public override void OnPlayerJoind(VRCPlayerApi player)
{
Debug.Log(player.playerId);
}
}

The ones recognized by name have no such safety. Only methods whose name and argument types match the table become events; anything else is treated as an ordinary method. The following Update takes one argument, so it isn’t an event. Nothing calls it, so no instruction is generated either.

using UnityEngine;
using Tsukimi;
public class EventsNameMatchMiss : TsukimiBehaviour
{
private void Update(float delta)
{
Debug.Log(2);
}
void Start()
{
Debug.Log(1);
}
}
// Output
// 1

Visibility doesn’t matter. A method marked private still becomes an event.

using UnityEngine;
using Tsukimi;
public class EventsPrivateEvent : TsukimiBehaviour
{
private void LateUpdate()
{
Debug.Log(2);
}
void Start()
{
Debug.Log(1);
}
}
// Output
// 1

The runtime calls the program using the event name with its first letter lowercased and a _ prefix. For Start, that’s _start. The middle column of the table above holds this name.

This name is registered separately from the method’s own name. If you write a method with the same spelling, the registration collides, so that form is rejected with TUKI0001.

using UnityEngine;
using Tsukimi;
public class R_events_entry_collision : TsukimiBehaviour
{
public void _start()
{
Debug.Log(2);
}
void Start()
{
Debug.Log(1);
}
}

Udon has no mechanism for passing arguments. The runtime writes the value into a named variable first, then calls the event.

The variable’s name joins the event name with its first letter lowercased and the runtime’s argument name with its first letter uppercased — that’s how it’s built. The right column of the table above holds this name.

If the name differs by even one character, the write goes nowhere. The event is still called, and the argument runs at its initial value. No error and no runtime failure occurs. The compiler holds this mapping, checked against the event definitions the runtime holds.

using UnityEngine;
using Tsukimi;
using VRC.SDKBase;
public class EventsPlayerJoined : TsukimiBehaviour
{
public override void OnPlayerJoined(VRCPlayerApi player)
{
Debug.Log(player.playerId);
}
void Start()
{
Debug.Log(1);
}
}
// Output
// 1

The runtime’s own argument name decides the variable’s name, not the argument name you wrote. You can name your argument anything.

using UnityEngine;
using Tsukimi;
using VRC.SDKBase;
public class EventsParameterName : TsukimiBehaviour
{
public override void OnPlayerLeft(VRCPlayerApi who)
{
Debug.Log(who.playerId);
}
void Start()
{
Debug.Log(1);
}
}
// Output
// 1

Events recognized by name receive arguments under the same rule.

using UnityEngine;
using Tsukimi;
public class EventsTriggerEnter : TsukimiBehaviour
{
void OnTriggerEnter(Collider other)
{
Debug.Log(other.gameObject.activeSelf);
}
void Start()
{
Debug.Log(1);
}
}
// Output
// 1

There are events where the argument name in the base declaration differs from the name of the variable the runtime writes the value into — 22 of them. The argument name you wrote is never used, so behaviour doesn’t change.

EventsArgument name in the base declarationVariable that receives the argument
InputDropvalueinputDropBoolValue
InputGrabvalueinputGrabBoolValue
InputJumpvalueinputJumpBoolValue
InputLookHorizontalvalueinputLookHorizontalFloatValue
InputLookVerticalvalueinputLookVerticalFloatValue
InputMoveHorizontalvalueinputMoveHorizontalFloatValue
InputMoveVerticalvalueinputMoveVerticalFloatValue
InputUsevalueinputUseBoolValue
OnImageLoadErrorresultonImageLoadErrorIVRCImageDownload
OnImageLoadSuccessresultonImageLoadSuccessIVRCImageDownload
OnListAvailableProductsproductsonListAvailableProductsResult
OnListProductOwnersproductonListProductOwnersResult
OnListPurchasesproductsonListPurchasesResult
OnOwnershipRequestrequestingPlayer requestedOwneronOwnershipRequestRequester onOwnershipRequestNewOwner
OnProductEventproductonProductEventResult
OnPurchaseConfirmedproductonPurchaseConfirmedResult
OnPurchaseConfirmedMultipleproductonPurchaseConfirmedMultipleResult
OnPurchaseExpiredproductonPurchaseExpiredResult
OnPurchasesLoadedproductsonPurchasesLoadedResult
OnStringLoadErrorresultonStringLoadErrorIVRCStringDownload
OnStringLoadSuccessresultonStringLoadSuccessIVRCStringDownload
OnVRCCameraSettingsChangedcameraSettingsonVRCCameraSettingsChangedCamera
using UnityEngine;
using Tsukimi;
using VRC.Udon.Common;
public class EventsInputJump : TsukimiBehaviour
{
public override void InputJump(bool value, UdonInputEventArgs args)
{
Debug.Log(value);
}
void Start()
{
Debug.Log(1);
}
}
// Output
// 1

4 events also have a declaration with no arguments. If you don’t need the argument, you can write it this way.

EventsAnother way to write it
OnDeserializationvoid OnDeserialization()
OnOwnershipTransferredvoid OnOwnershipTransferred()
OnStationEnteredvoid OnStationEntered()
OnStationExitedvoid OnStationExited()
using UnityEngine;
using Tsukimi;
public class EventsNoArgumentOverload : TsukimiBehaviour
{
public override void OnStationEntered()
{
Debug.Log(2);
}
void Start()
{
Debug.Log(1);
}
}
// Output
// 1

Ones called without writing any calling code

Section titled “Ones called without writing any calling code”

Every event in the tables above is called without a call written anywhere. For Interact, that’s when a player uses that object (see the example in How they’re recognized).

Separately from events, there’s a form that calls a method by name. A method marked public is registered by name and becomes a destination for SendCustomEvent. The way to write it and the forms that get rejected are covered in Collaboration between components.

Registration happens even if there isn’t a single call inside that program. The caller may be in a different program, or on the runtime’s side, invisible at compile time.

OnDeserialization OnPreSerialization OnPostSerialization OnOwnershipRequest and OnOwnershipTransferred are called along with value sync and ownership. The conditions for being called are covered in Sync.

In the base classes of the distributed package, the following 6 are wrapped in conditional compilation. If the project hasn’t enabled that feature, the declaration doesn’t exist, so you can’t write it with override.

EventsCondition
OnPersistenceUsageUpdated`VRC_ENABLE_PLAYER_PERSISTENCE \
OnPlayerDataStorageExceededVRC_ENABLE_PLAYER_PERSISTENCE
OnPlayerDataStorageWarningVRC_ENABLE_PLAYER_PERSISTENCE
OnPlayerDataUpdatedVRC_ENABLE_PLAYER_PERSISTENCE
OnPlayerObjectStorageExceededVRC_ENABLE_PLAYER_PERSISTENCE
OnPlayerObjectStorageWarningVRC_ENABLE_PLAYER_PERSISTENCE

The following 2 compile, but they aren’t in the event definitions the runtime holds. Existing code that overrides existing code that override this name keeps compiling.

Events
OnVideoPause
OnVideoPlay

There’s 1 event that exists on the runtime’s side but not in this language. OnVariableChange is called under a different name per variable, so it can’t be placed as a single event.

using UnityEngine;
using Tsukimi;
public class R_events_on_variable_change : TsukimiBehaviour
{
public override void OnVariableChange()
{
Debug.Log(1);
}
}