Table of Contents

Interface IPlayerCharacter

Namespace
FishMMO.Shared.Core
Assembly
FishMMO.Shared.dll

Interface for player-controlled character entities, extending ICharacter with player-specific properties and methods. Includes networking, instance, race, chat, hotkey, and teleportation features.

public interface IPlayerCharacter : ICharacter
Inherited Members
Extension Methods

Fields

OnReadPayload

Event triggered when a payload is read for this player character.

public static Action<IPlayerCharacter> OnReadPayload

Field Value

Action<IPlayerCharacter>

Remarks

Memory leak risk: Static events hold strong references to all subscribers. Callers MUST unsubscribe via -= when no longer needed (e.g., OnDestroy, OnStopClient) or the subscriber and its entire closure chain will never be garbage collected.

OnStartLocalClient

Event triggered when the local client starts for this player character.

public static Action<IPlayerCharacter> OnStartLocalClient

Field Value

Action<IPlayerCharacter>

Remarks

Memory leak risk: Static events hold strong references to all subscribers. Callers MUST unsubscribe via -= when no longer needed (e.g., OnDestroy, OnStopClient) or the subscriber and its entire closure chain will never be garbage collected.

OnStopLocalClient

Event triggered when the local client stops for this player character.

public static Action<IPlayerCharacter> OnStopLocalClient

Field Value

Action<IPlayerCharacter>

Remarks

Memory leak risk: Static events hold strong references to all subscribers. Callers MUST unsubscribe via -= when no longer needed (e.g., OnDestroy, OnStopClient) or the subscriber and its entire closure chain will never be garbage collected.

OnTeleport

Event triggered when this player character teleports.

public static Action<IPlayerCharacter> OnTeleport

Field Value

Action<IPlayerCharacter>

Remarks

Memory leak risk: Static events hold strong references to all subscribers. Callers MUST unsubscribe via -= when no longer needed (e.g., OnDestroy, OnStopClient) or the subscriber and its entire closure chain will never be garbage collected.

Properties

AccessLevel

The access level of the player (e.g., admin, moderator, player).

AccessLevel AccessLevel { get; set; }

Property Value

AccessLevel

Account

The account name associated with this character.

string Account { get; set; }

Property Value

string

BindPosition

The position in the bind scene where the character will respawn.

Vector3 BindPosition { get; set; }

Property Value

Vector3

BindScene

The name of the scene where the character is bound (e.g., respawn location).

string BindScene { get; set; }

Property Value

string

CharacterController

The controller for kinematic character movement.

KCCController CharacterController { get; }

Property Value

KCCController

CharacterName

The display name of the character.

string CharacterName { get; set; }

Property Value

string

CharacterNameLower

Lowercase version of the character's name for case-insensitive comparisons.

string CharacterNameLower { get; set; }

Property Value

string

ChatTokenLastRefillTicks

UTC ticks of the last token bucket refill. Used to calculate how many tokens to add based on elapsed time. Stored as ticks to avoid per-message DateTime allocation.

long ChatTokenLastRefillTicks { get; set; }

Property Value

long

ChatTokens

Current number of chat tokens available in the token bucket (double for precision on long-uptime servers). Consumed on each sent message; refilled at a configurable rate. Server-side anti-spam: when below 1.0 the message is silently dropped.

double ChatTokens { get; set; }

Property Value

double

EquipmentViewCamera

The camera used for equipment view (e.g., inspecting gear).

Camera EquipmentViewCamera { get; set; }

Property Value

Camera

Hotkeys

The list of hotkey data for this character.

List<HotkeyData> Hotkeys { get; set; }

Property Value

List<HotkeyData>

InstanceID

Unique identifier for the instance the character is in.

long InstanceID { get; set; }

Property Value

long

InstancePosition

The position in the instance scene.

Vector3 InstancePosition { get; set; }

Property Value

Vector3

InstanceRotation

The rotation in the instance scene.

Quaternion InstanceRotation { get; set; }

Property Value

Quaternion

InstanceSceneHandle

Identity of the instance scene the character is inside — the scenes.id of its row. See SceneHandle.

long InstanceSceneHandle { get; set; }

Property Value

long

InstanceSceneName

The name of the instance scene.

string InstanceSceneName { get; set; }

Property Value

string

IsChatTokensFull

Indicates whether ChatTokens is in its initial "filled to capacity" state (i.e. no token refill has been applied since construction/reset). When true, the first token refill should fill to bucket capacity instead of incrementing from a stale starting value. Replaces the previous sentinel of double.MaxValue which overflowed to Infinity on the first add operation.

bool IsChatTokensFull { get; set; }

Property Value

bool

KCCPlayer

The player controller for kinematic character movement.

KCCPlayer KCCPlayer { get; }

Property Value

KCCPlayer

LastChatMessage

The last chat message sent by the character.

string LastChatMessage { get; set; }

Property Value

string

LastWorldPosition

Where the character stood in the open world before entering an instance, and where it is put back when it leaves one.

Vector3 LastWorldPosition { get; set; }

Property Value

Vector3

Remarks

The character row carries two positions — the open-world one and the instance one — but a spawned character has only one transform, so while it is inside an instance the transform describes the instance and something has to remember the other. Without this, every save taken inside a dungeon overwrote the open-world position with dungeon coordinates, and a character released from a dead instance was placed at those coordinates in the open world: through terrain, or outside the playable bounds entirely, until the out-of-bounds sweep noticed and relocated them.

LastWorldRotation

Rotation to restore alongside LastWorldPosition.

Quaternion LastWorldRotation { get; set; }

Property Value

Quaternion

ModelIndex

The model index for the character's race appearance.

int ModelIndex { get; set; }

Property Value

int

Motor

The motor for kinematic character movement.

KinematicCharacterMotor Motor { get; }

Property Value

KinematicCharacterMotor

NextChatMessageTicks

The next time the character is allowed to send a chat message, stored as UTC ticks. Avoids DateTime allocation on every message comparison.

long NextChatMessageTicks { get; set; }

Property Value

long

NextInteractTime

The next time the character is allowed to interact with objects.

DateTime NextInteractTime { get; set; }

Property Value

DateTime

RaceID

The race ID of the character.

int RaceID { get; set; }

Property Value

int

RaceName

The character's race name, for display.

string RaceName { get; }

Property Value

string

Remarks

Derived from RaceTemplate, and null when that cannot be resolved. This was once a string field of its own, assigned in ReadPayload — except nothing in the tree ever assigned it on the way out, so the wire value was always null and every reader got an empty race. It is derived rather than stored because a name is not identity: RaceID is, and a name travelling separately from the id it describes is a name that can disagree with it.

RaceTemplate

The character's race, resolved from RaceID.

RaceTemplate RaceTemplate { get; }

Property Value

RaceTemplate

Remarks

A character stores its race as an ID, not as a template reference, and that is the right way round: the ID is what persists, what the spawn payload carries, and what survives a template being reimported. The template is a cache entry that ID names, so this resolves rather than holds — there is no second copy to fall out of step with RaceID.

Not to be confused with IFactionController.RaceTemplate. That is a SEPARATE holding with its own id, deliberately overridable per spawn (NPCSpawnableSettings.FactionOverride → SetRaceTemplateOnSpawn) so one NPC prefab can answer for several factions. For a player the two agree, but the faction controller's copy answers a different question and must not be read as "what race is this character".

Null when RaceID is 0 (a character whose race was never assigned) or when no template with that ID is cached on this peer. Callers that display the answer decide what an unknown race reads as; this invents no placeholder.

SceneHandle

Identity of the scene instance the character belongs to: the scenes.id of the row describing it.

long SceneHandle { get; set; }

Property Value

long

Remarks

This used to hold the hosting scene server's local scene-manager handle, which is only meaningful inside that one process. Two scene servers running the same build routinely allocate identical handles, so the value could not tell one server's instance from another's: the world server's routing map collided between them, and a scene server accepted a character routed to a different server's instance whenever the handle and scene name happened to match. The row ID is unique by construction.

SceneName

The name of the current scene the character is in.

string SceneName { get; set; }

Property Value

string

TeleporterName

The name of the teleporter used for the last teleport action.

string TeleporterName { get; set; }

Property Value

string

TimeCreated

The date and time when this character was created.

DateTime TimeCreated { get; set; }

Property Value

DateTime

Version

The current Version of the character data, used for optimistic concurrency control.

long Version { get; set; }

Property Value

long

WorldServerID

Unique identifier for the world server this character belongs to.

long WorldServerID { get; set; }

Property Value

long

Methods

CurrentSceneName()

The name of the scene the character is physically standing in.

string CurrentSceneName()

Returns

string

Remarks

Not the same thing as SceneName. While a character is inside an instance, SceneName keeps naming the open-world scene it will return to — that is what makes the return trip possible — and the scene it is actually in is InstanceSceneName. Reading SceneName where this was meant has been the same bug several times over: teleporters inside a dungeon could never fire because the wrong scene's teleporter list was consulted, and every interactable handler's "is this a known scene?" check was answered about a scene the character had left.

This names a scene, so it still cannot distinguish one instance of a scene from another — scene stacking means several share a name. Anything that needs instance identity within this process must compare GameObject.scene.handle, and anything that needs it across processes must use the scene row id. See SceneHandle.

IsInInstance()

Returns true if the character is currently inside an instance.

bool IsInInstance()

Returns

bool

IsLoaded()

Returns true if the character is currently loaded in the scene and active.

bool IsLoaded()

Returns

bool

ResetHotkeys()

Resets all hotkeys to their default state.

void ResetHotkeys()

SetGuildName(string)

Sets the guild name for this character.

void SetGuildName(string guildName)

Parameters

guildName string

The name of the guild to set.

Teleport(string)

Teleports the character using the specified teleporter name.

void Teleport(string teleporterName)

Parameters

teleporterName string

The name of the teleporter to use.