Overview
Your expressions won’t work with OPE without some adjustments! Everything you need to know about setting them up can be found here.
The Gist
In case you’re here out of curiosity, Online Party Expressions (OPE) is a mod I made which synchronizes expressions across Online Party as best as it can. Since it looks at the expression currently equipped on the local player(s), OPE doesn’t need to know anything about the mod itself, which makes supporting OPE a straightforward process!
Expression components from the base game do not work when applied to online players. This is due to the GetOwnerMesh function of Hat_ExpressionComponent not being able to identify the mesh of online players.
Depending on what kind of expression component your mod is using, you will need to do a different process to get your expression component to work on online players. Online Party Plus (OPP) may also complicate the process.
Supported Base Game Expressions
If your expression component is one from the base game, e.g., not a custom one made by you, you might not have to do anything. The following expression components are already supported by OPE:
- Hat Kid Hat_ExpressionComponent_HatKid
- Bow Kid Hat_ExpressionComponent_BowKid
- Shadow Puppet Hat_ExpressionComponent_ShadowPuppet
However, please note that there are special considerations for each of these if the expression component is applied to a different mesh than expected for an online player. Do note that these considerations may be bypassed using the replacement system (see respective section).
- Hat Kid: For online players only:
- For most cases, the mesh must use index 5 for the face and index 6 for the eyes.
- If your mesh is a head mesh for OPP’s custom data system, then it must use index 0 for the face and index 4 for the eyes.
- Bow Kid: For online players only:
- For most cases, the mesh must use index 2 for the face and index 1 for the eyes.
- If your mesh is a head mesh for OPP’s custom data system, then it must use index 1 for the face and index 0 for the eyes.
- Shadow Puppet: For online players only, the mesh must use index 0 for the face and index 4 for the eyes.
As a side note, Wireframe (Hat Kid) Hat_Wireframe_ExpressionComponent_HatKid and Wireframe (Bow Kid) Hat_Wireframe_ExpressionComponent_BowKid are also technically supported, but because Wireframe normally does not sync, OPE translates each to its respective regular expression component (Hat_ExpressionComponent_HatKid or Hat_ExpressionCompoennt_BowKid). Because of this, I would highly recommend treating it as unsupported and reading the below section
Unsupported Base Game Expressions
All other base game expression components are not recognized by OPE. Due to this, they will not work on online players. If your mod uses such an expression component, then you will need to make a custom expression component.
This expression component can be as simple as extending the expression component you want to use, which will let it effectively be exactly the same expression component, but with any changes you want to make. That last part is important, because it needs to be made compatible with online players. Continue reading the below section to see what else needs to be done.
Custom Expressions
A custom expression component has the most liberty when it comes to supporting OPE. However, there are two things which must happen in order for it to correctly support OPE.
- The mesh for online players must have the same indices for the face and eyes as the one used for local players. OPE cannot tell the expression component to use different indices for online players.
If this is impossible (such as if the mesh cannot be controlled), then you will need to use the replacement system. This may also be used to bypass this need even if the mesh can be controlled. See the below section.
- The expression component needs the issue with the GetOwnerMesh function fixed. Here, I have an override that should work for nearly anything!
function MeshComponent GetOwnerMesh() { return Hat_GhostPartyPlayer(Owner) != None ? Hat_GhostPartyPlayer(Owner).SkeletalMeshComponent : Super.GetOwnerMesh(); }
The Replacement System
When using a custom expression component, there is no way for my mod to adjust the set indices for a different mesh. This is a problem because online players use different meshes for Hat Kid and Bow Kid.
To combat this, OPE has a special but more complicated system to allow mod creators to tell my mod to use a replacement expression component. This system supports being specified in custom expression components, skins, and playable characters, with minor differences in each implementation. Expression Components have priority over skins, which have priority over custom characters. You do not need to use all three methods.
The key method which is shared across all methods is telling OPE’s data collector (Ysm_Ope_CustomDataCollector) where your data is so that my mod can parse it.
You will need to create a new class for each class that needs to use the system. This class may be named anything, but it must extend SeqVar_String. This class will eventually contain your custom data.
Because this is extending the class for a Kismet variable, it’ll try to show it as a valid Kismet variable in the A Hat in Time editor’s level Kismet editor. We can easily prevent this by overriding the following function as such.
Additionally, each custom data class will have a defaultproperties block that sets the StrValue property.
The custom data is a string (meaning it’s surrounded by double quotation marks) split into three sections.
- ExprForSingle: The replacement expression component will be applied only when the online player is using a single-type mesh.
- ExprForSingle: The replacement expression component will be applied only when the online player is using a split-type mesh (as per OPP’s definition).
- ExprForBoth: The replacement expression component will be always be applied, regardless of mesh type.
Any section that isn’t needed can be omitted. Each section’s data is separated from other sections with a space. The information in each section is different depending on the method.
For each custom data class, you will want to have the following name prepared for it:
Replace <Class Name>, including the less than and greater than signs, with the name of the custom data class. Do not format it as class'<Class>’. Only include the name!
The data collector uses the GetOwnerMesh function of the expression component. The first thing the method should do before anything else is check if it’s attached to OPE’s custom data collector, and then set its Tag property to the string you’ve prepared.
In the custom data class, you’ll set the StrValue for each section. The syntax for each section is as follows. Anything surrounded in less than and greater than signs should be replaced, including the signs.
Section name is the name of the section (such as ExprForSingle). <Replacement Class> is the name of the replacement expression component’s class. Do not format it as class'<Class>’. Only include the name!
The value should look similar to this:
The data collector uses the Apply function of the expression component. The first thing the method should do before anything else is check if OPE’s custom data collector was passed as the argument (usually named a), and then set its Tag property to the string you’ve prepared.
In the custom data class, you’ll set the StrValue for each section. The syntax for each section is as follows. Anything surrounded in less than and greater than signs should be replaced, including the signs.
Section name is the name of the section (such as ExprForSingle). <Local Class> is the class of the expression component applied to the local player of the online player. <Replacement Class> is the replacement expression component’s class. Do not format either class as class'<Class>’. Only include the name!
The value should look similar to this:
The data collector uses the ConvertGhostPartyPlayer function of the expression component. The first thing the method should do before anything else is check if OPE’s custom data collector was passed as the argument (usually named gp), and then set its Tag property to the string you’ve prepared.
In the custom data class, you’ll set the StrValue for each section. The syntax for each section is as follows. Anything surrounded in less than and greater than signs should be replaced, including the signs.
Section name is the name of the section (such as ExprForSingle). <Local Class> is the class of the expression component applied to the local player of the online player. <Replacement Class> is the replacement expression component’s class. Do not format either class as class'<Class>’. Only include the name!
The value should look similar to this:
Closing Words
While the above information should be everything needed to support OPE, if anything is still confusing, you may ask about it in the comments below, and I’ll try to clarify. If there’s anything that isn’t discussed that’s important for your expression component specifically, you may also ask about that.
Finally, if you’re concerned about if your changes are correct, OPE is set up in a way that allows local testing for many things! Assuming the expression component class is the same, you can run a cooked version of your mod without pushing an update, and the expression component should work if it’s been set up correctly. I highly encourage doing this to ensure that things are in order before pushing an update!