Beta Modding
SDK and docs are unfinished.
Go to discord mod development channel for live support. ( https://discord.gg/UNwnxRzRen )
DOWNSHOT Build: 1.4
Unreal Engine Version: 5.5
SDK: 1.4
Unreal Engine Version: 5.5
SDK: 1.4
(Mod SDK will update a few days before major game update. In that short period, mod builds will only work in beta)
Basic Info:
Coming Soon to SDK
Grab location components. (allows for grabing handels, grips, ect.). Will also have input events such as trigger and button, allowing for things like guns that can be shot.
More API functions that allow mod developers to make calls to the main DOWNSHOT interface, along with gaining acsess to important data.
Ability to spawn items, NPCs, and more.
Template project so to help get mod developers started.
Much more...
Common Issues
Translucent and additive materials don't always render corectly in DOWNSHOT 1.4. Try creating a new material and copying over nodes to possibly fix the issue.
Masked materials don't render in the far right eye. No know fix at the moment. While it causes a performance hit, you can replace masked materials with additive materials to fix the issue.
Menu componets in the world stop updating. Change tick to pre-physics and disable Update When Not Rendered.
Somtimes a mod is compiled with no or little assets. Please reach out to the developer if this happens to you. This issue should be fixed as of v1.4.
Error 101 indicates an error with cooked assets.
Any assets outside of the content folder for your mod are not compiled. This is not a bug. Ensure the only assets you refrence are: In your mod content folder (Content/{YourModName}/, not Content/ ), engine assets, sdk assets. Some default plugin assets will work, this is not always the case.
Getting Started
Using a windows PC, install the Unreal Engine version required for your mod build target version (see above).
Download the SDK version required for your mod build target version (see above)
Create a new unreal project, it can be blank or include starter content. Name the project whatever you like.
In your project directory (standard directory is Documents\Unreal Projects\[YourProject]), create a new folder named "Plugins".
Extract the SDK into your new plugins folder.
See plugin setup for more info on configuring the plugin.
Optional: See "quick development" below for faster development iteration.
Plugin Setup
To launch the SDK tools window, in the unreal editor's level editor, at the top toolbar click DOWNSHOT SDK -> Launch SDK Tools Window.
Open XR, XR Base, and other XR plugins should be disabled or may cause issues. Please confirm this in plugin settings.
Enter a name, can NOT be changed, that will be used as your mod name.
Hit "configure", then restart.
Quick Development
The "install to game" and "install to HMD" buttons in the SDK tool allow you to directly install your mod to DOWNSHOT.
Install to game will always work as long as DOWNSHOT is downloaded to your PC via the rift store.
Install to HMD is a bit more dificult. You must have ABD settup for your meta quest device, (many tutorials online), then set the "AbdPath" setting in your project's DefaultEngine.ini file. Inside the file, find "[/Script/DOWNSHOT_SDK.Settings]" and type in the location of your adb.exe install, no quotations. If you have sidequest installed, it would most likley be ...\AppData\Roaming\SideQuest\platform-tools\adb.exe. Install to HMD is not fully functional yet, it currently will only work with one mod project at a time. Your engine will manualy need to be restarted after setting the AbdPath setting. A working example in your DefaultEngine.int file would be:
[/Script/DOWNSHOT_SDK.Settings]
ModName=test
SDK_Version=0.11
AdbPath=C:\Users\username\AppData\Roaming\SideQuest\platform-tools\adb.exe
Mod Creation
Put all assets in the content folder with the same name as your mod.
Put maps in the map folder or subfolders.
Put spawnables in the spawnables folder or subfolders.
Hit compile to compile the mod to a platform. The first compile will take a while, but all other compiles will be quick because shaders are saved.
Mods are saved in archive folder.
Hit the "create template map" button to create a template map in your mod folder. Use the world settings and light source settings from this map in your other maps. Make sure to rename it!
Mod Distribution
Zip the mod archive folder for each platform, (same name as your mod), then upload to modio.
Enusre that you lable your mod with the game version it was compiled for. If you do not do this, players will not be able to download your mod.
Tips:
Most Important Info:
Follow all rules for making mods that both mod developers and users agree to upon downloading the SDK or downloading mods.
Be mindfull of performance. Disable tick on actors that don't use it. Keep the scene component count to a minimum. Setup LODs for meshes. Limit use of translucent materials and other complex shaders. Disable overlap and hit events on physics actors that don't need them. Use walls to limit how many actors are in view at once. Use fog to limit how far the user can see. Keep drawl calls as low as possible. Use the built in debug options in DOWNSHOT to test your mod's performance. In general, the better your mod performs the more fun it will be to players.
Keep in mind that in multiplayer, there is not just one instance of an object, but instead it exist on all machines. Blueprint has replicated events, however, inexperienced developers should stick to only making calls to the local player. (Players have ownership over grabbed items, RPCs to server from actors will only work when grabbed).
The host machine has absolute athority, use the "IsServer" pure function in your scripts to run specific logic only on host machine.
Creating Levels:
Template Level
Instead of creating a level from scratch, it is recomended to use the template level as a starting point. Hit the "Create Template Map" button in the SDK Tools window to add the map to your map folder. Rename it, then delete anything that you do not need. The lights, fog, and other objects in this map are configured to be optimal. If you expand the level, ensure you also expand the nav mesh and precompute visiblity volume.
Configuring a Level
Create a level within the Maps directory of your mod folder, add a directional light and sky light. Make sure both are set to "stationary" or "static", "stationary" is recomended.
Feel free to configure CMS shadows the be used on quest 3 and other high power mobile devices.
Walls are great for performance because they limit what is in view.
Precomputed visibility volumes help with performance with static objects.
To cull moveable objects behind walls, see "Dynamic Culling" in the API docs below.
Add Nav meshes to enable NPCs to move around.
Use the "grab" tag and "NoGrabAlert" tag on static level objects that you want the player to be able to climb.
For moving floors, see below in Items.
(more info coming soon)
Creating Spawnables:
Configuring an Item
Create an actor within the Spawnables directory of your mod. Use underscores instead of spaces and the game will display spaces at runtime.
The "grab", "pull", and "stab" tags allow for simple interaction and are self explanatory. You can use these as actor tags or for individual mesh components. (It is not recommended to use the "grab" tag on spawnables, it does not allow for multiplayer replicated ownership. Use it on static world objects, like climbing walls).
Use the "NoGrabAlert" tag to ensure no replication logic runs. Add to anything in the world that is grabable but not moveable or controllable.
For moving floors or meshes that are intended to be walked on, you can add the "RelativeGround" tag to bind the player rig rotation and velocity to it. For example, a merry-go-round that the player can walk on. This is make the player rotation and velocity relative to that component. In the case of a non moving component that moves the player by a constant amount, (like the walkway), add the tag "VelocityOverride" and below that tag add a vector, for example, "0,2,-99", this will be the velocity that the player velocity is made relatative to.
To adjust the spawn offset when spawned via the item spawner, use the "SpawnVisualizerOffset" actor tag with another tag containing the vector of the offset, for example, "4,0,-100", directly after in the array. Use the actor tag "SpawnBoxExtentOverride" with a vector after in the array to use a custom overlap check box when spawning. Use the tag "HFV" in any components you do not want to be displayed in the spawn visualizer.
Item Interaction
For any spawnable actor, add the ItemManager component to it. This component will set up the spawnable for multiplayer assuming "Replicate" and "ReplicateMovement" are both set to true.
For complex interaction, use the StaticMeshInteraction component for any areas on actors you want to be interactable. It allows for input events and snapping the hand to a position. (For example, use one for the handle of a gun, one for the foregrip, and one for the slider. Use the trigger input event from the handle interaction to fire the gun). Each StaticMeshInteraction should have an attached GrabLocation component. (See the template map items for an example, see below for more info). You can configure physical grab settings and grab permissions via the StaticMeshInteraction. To enable or disable the ability to grab at runtime, call the SetGrabAllowed function and do not set the GrabAllowed variable directly. To know what hand is grabbing, save the IsRight value sent in the grab event. Use the input and button event for interaction. (While it is unrelated to this component, the PlayHapticRumble function in the API is intended to be used alongside interaction components). Set the "IndexFingerFreeMovement" variable to true if you want the index finger to not be locked in a grab position. (Use for guns with triggers).
The GrabLocation componet must always be a child of a StaticMeshInteraction component. This will be the location and rotation of the grab. Because the hands use smart finger positioning, you do not have to alter the finger curl value. If you want to force a specifc grip animation, the figer curl values act as clamps on each finger. (Setting the value of the ring curl to 1 will for the ring finger to close all the way, setting it to 0.5 will force the ring finger to close between 0.5 and 1 depending on what the finger solver calculates).
Use the CollisionEffects component to add collision sound and/or collision damage effects to an actor. Will only work with meshes that have hit events.
Use the Inventory component to allow an item to be stored in the player inventory. The relative offsets can be configured here.
Configuring a NPC.
(more info coming soon)
Configuring a Vehicle.
(more info coming soon)
API Docs:
About the API
Use the SDK API to read and write data to the core game instance. For ease of use and stablility, it is written in the blueprint scripting language. You can make funciton calls in any blueprint object, commonly used ones include Actors, Scene Components, Level Blueprints, and so on.
The SDK function library will expand with time, functions will be documented here.
API Functions
AddDamageToActor - Use this to add damage to any replicated shell, local player, or enemies.
AddPlayerDamage - Damages the local player. World impulse is not needed.
AddPlayerVelocity - Adds to the local player's velocity in world space.
GetActorNetOwnership - Tries to get the owning pawn of an actor. When an actor is held by a player, that player owns the actor and has authority over its transform and can make RPCs.
GetCameraTransform - Gets the camera transform in world space.
GetGrabbedActor - Attempts to get the actor that a hand is grabbing.
GetHandTransform - Gets the hand transforms in world space.
GetPlayerActors - Useful for checking if something collided with the player. Body is the core player rig. Left and right hands are the separate hand actors. Replicated shell is the version of the player seen on all other clients.
GetDirectionalValues - This is the internal velocity values of the player. The same values are used in animation and are affected by relative ground objects. They are rotated relative to player orientation.
GetLocomotionSphere - Gets the sphere that rolls around on the ground for player movement. Could be used to move the player around. This is not the root component.
GetPlayerWorldLocation - Gets the location of the local player, at the player's feet center.
GetPlayerWorldVelocity - Gets the player's world space velocity.
GrabActor - Tries to grab an actor with a hand.
Log - Record a string of text to the log, readable via the debug menu.
Open Level - Opens a level, using screen fade transition and replicated travel.
Game path ex: Game/{YourModName}/map1
Absolute path ex: c:/user/projects/unreal/mymod/Content/{YourModName}/map1.umap
Must be called from server.
PlayHapticRumble - Plays a haptic effect for a hand.
ReleaseHand - Tries to release anything a hand is grabbing.
SetActorPlayerCollision - Enables/disables the collision of all meshes in an actor with the player's body. Hand collision will not be affected.
SetGrabAllowed - Enables/disables grabbing for an SMInteraction.
SetHardwareOcclusion - DO NOT USE UNLESS YOU KNOW WHAT YOU ARE DOING. When enabled, casues meshes blocked from view to not be rendered. It has a large hit on performance and should almost never be used. The only DOWNSHOT map to use this is prop hunt, where many non-static meshes need to be culled. Reset to false every time a level is opened.
SetPlayerScale - Sets the scale of the local player.
SetReverbLevel - Values between 0-3 inclusive are valid. 0 is none, 3 is the most. Reset to default when new level loaded.
TeleportPlayer - Teleports the player. Collision will not occur with objects between teleportation.