Home/Game Development/msw-defaultplayer
M

msw-defaultplayer

by @msw-gitv
4.4(120)

This skill specializes in the detailed management of the MSW DefaultPlayer character model. It empowers developers to easily inspect and patch DefaultPlayer.model and Player.model files using the ModelBuilder tool, enabling flexible addition and removal of components. Developers can effortlessly configure character movement speed, jump force, HP, camera behavior, and map-mode-specific movement components. This Skill significantly simplifies the customization of player character attributes and behaviors, bypassing tedious manual file editing. Consequently, it boosts game development efficiency and the precision of character configurations, ensuring a smooth and consistent player experience.

game-developmentcharacter-configplayer-modelgame-designcomponent-managementGitHub
Installation
npx skills add https://github.com/msw-git/msw-ai-coding-plugins-official --skill msw-defaultplayer
compare_arrows

Before / After Comparison

1
Before

Before this skill, developers had to manually delve into complex model files to locate and modify various player character attributes (e.g., movement speed, HP). This was not only time-consuming but also highly prone to syntax or dependency errors, leading to game crashes or abnormal behavior, with high debugging costs.

After

This skill provides a structured ModelBuilder interface, allowing developers to quickly configure all player character attributes and components declaratively. This greatly simplifies the operational process, reduces manual errors, and significantly boosts the efficiency and accuracy of character customization, ensuring smooth game development.

SKILL.md

MSW DefaultPlayer

Use the msw-general ModelBuilder to inspect/patch the DefaultPlayer model file, manage components, and configure movement / physics / HP / camera.

For costume / avatar equipment, see the msw-avatar skill. Costumes apply not only to DefaultPlayer but to any entity, so they live in a separate skill.


DefaultPlayer overview

What is DefaultPlayer?

The player character model provided by default in the MapleStory Worlds Maker workspace.

  • When any user enters a world, a player entity is created based on this model.
  • The model ID to use is specified by the PlayerUri property of DefaultUserEnterLeaveLogic.

File location and structure

DefaultPlayer is made up of two .model files:

FilePathRole
Player.model./Global/Player.modelBase model. Defines the Components list and Properties links
DefaultPlayer.model./Global/DefaultPlayer.modelInherits Player (BaseModelId: "player"). Overrides Values

Important: both files are located in ./Global/. Custom script files are created under ./RootDesk/MyDesk/.

DefaultPlayer is patched through ModelBuilder

DefaultPlayer is managed through the sibling msw-general/scripts/model/msw_model_builder.cjs, not raw JSON edits.

  • Change a property value: ModelBuilder.read("./Global/DefaultPlayer.model").value(...)
  • Add/remove a component: component() / removeComponent()
  • Check the base component list: ModelBuilder.snapshot("./Global/Player.model")

File structure detail

Player.model (base)

Path: ./Global/Player.model
EntryKey: model://player
  • Components: the full list of default components on the player (MOD.Core.* native components)
  • Properties: model property → component property link definitions (properties editable from the inspector)
  • Values: empty (defaults are provided by the engine)

DefaultPlayer.model (override)

Path: ./Global/DefaultPlayer.model
EntryKey: model://defaultplayer
BaseModelId: "player"
  • Components: only the components added on DefaultPlayer (e.g. script.PlayerHit, script.PlayerAttack)
  • Values: the array of overridden setting values

DefaultPlayer default component list

Native components inherited from Player.model:

ComponentRole
TransformComponentPosition, rotation, scale
MovementComponentMovement speed and jump force control
RigidbodyComponentPhysics (gravity, footholds), MapleStory-style movement
KinematicbodyComponentUp/down/left/right movement on a RectTileMap
SideviewbodyComponentSide-scrolling movement on a SideViewRectTileMap
StateComponentState machine (Walk, Jump, Dead, etc.)
AvatarRendererComponentAvatar rendering, color, emotion
AvatarStateAnimationComponentState → avatar animation mapping
CostumeManagerComponentEquipment / costume management → see the msw-avatar skill for details
CameraComponentCamera tracking settings
PlayerControllerComponentInput-to-action mapping, condition handling
PlayerComponentHP, death/revive, PVP, map travel
ChatBalloonComponentChat balloon
NameTagComponentName tag
DamageSkinSettingComponentDamage skin
DamageSkinSpawnerComponentDamage skin spawn
HitEffectSpawnerComponentHit effect spawn
TriggerComponentCollision detection
InventoryComponentInventory

Script components added in DefaultPlayer.model:

ComponentRole
script.PlayerHitPlayer hit-handling logic
script.PlayerAttackPlayer attack logic

Quick reference — key components

ComponentRoleKey properties / methods
PlayerComponentHP, death/revive, PVP, map travelHp, MaxHp, PVPMode, RespawnDuration, RespawnPosition, UserId, IsDead(), ProcessDead(), ProcessRevive(), MoveToMapPosition()
PlayerControllerComponentInput → action mapping, conditional controlSetActionKey(key, actionName), ActionAttack(), ActionJump(), LookDirectionX
MovementComponentHigh-level movement speed / jump interfaceInputSpeed (default 1.0), JumpForce (default 1), Jump(), Stop()
RigidbodyComponentMaple side-view physics (gravity / footholds)Gravity, WalkAcceleration, WalkSpeed, AddForce(), IsOnGround()
KinematicbodyComponentTop-view up/down/left/right movement on RectTile(RectTile map-mode only)
SideviewbodyComponentSide-view on SideViewRectTile(SideViewRectTile map-mode only)
AvatarRendererComponentAvatar rendering / color / emotionSetColor(), SetAlpha(), PlayEmotion(), PlayRate
StateComponentState machine (Walk/Jump/Dead)CurrentStateName, ChangeState(), DeadEvent/ReviveEvent
NameTagComponentName tagName, FontSize, FontColor, NameTagRUID
ChatBalloonComponentChat balloonMessage, ChatModeEnabled, ShowDuration
CameraComponentCamera trackingDeadZone, SoftZone, Damping, ScreenOffset
TriggerComponentCollision detectionBoxSize, Offset, CollisionGroup

DefaultPlayer Values structure

Format of each entry in the Values array of DefaultPlayer.model:

{
  "TargetType": "<component name> or null",
  "Name": "<property name>",
  "ValueType": {
    "$type": "MODNativeType",
    "type": "<type info>"
  },
  "Value": <value>
}

TargetType rules

  • null: a model property defined in Player.model's Properties (linked through Properties to the actual component property)
  • "MOD.Core.<ComponentName>": directly override a property on a specific native component
  • "script.<ScriptName>": a property of a custom script component

Model properties (TargetType: null)

Mapped to actual component properties through the links defined in Player.model's Properties.

Model property nameSource component.propertyDescriptionDefault
speedMovementComponent.InputSpeedMovement speed1.0
jumpForceMovementComponent.JumpForceJump height1.0
walkAccelerationRigidbodyComponent.WalkAccelerationAcceleration / deceleration1.0
gravityRigidbodyComponent.GravityGravity1.0
cameraDeadZoneCameraComponent.DeadZoneCamera dead zone{x: 0.052, y: 0.08}
cameraSoftZoneCameraComponent.SoftZoneCamera soft zone{x: 0.268, y: 0.7}
cameraDampingCameraComponent.DampingCamera smooth-follow{x: 2.5, y: 3.9}
cameraScreenCameraComponent.ScreenOffsetDead-zone center point{x: 0.5, y: 0.655}
cameraDutchCameraComponent.DutchAngleCamera rotation0.0
cameraOffsetCameraComponent.CameraOffsetCamera position offset{x: 0.0, y: 0.0}
messageChatBalloonComponent.MessageChat balloon message""
chatModeEnabledChatBalloonComponent.ChatModeEnabledWhether chat is processed (e.g. balloon shown)true
nameTagNameTagComponent.NameName tag""
damageSkinIdDamageSkinSettingComponent.DamageSkinIdDamage skin typeDataRef
damageDelayPerAttackDamageSkinSettingComponent.DelayPerAttackDamage delay0.05
triggerBodyBoxSizeTriggerComponent.BoxSizeCollision detection area size{x: 0.66, y: 0.7}
triggerBodyBoxOffsetTriggerComponent.BoxOffsetCollision detection area offset{x: 0.0, y: 0.35}
triggerBodyColliderOffsetTriggerComponent.ColliderOffsetCollider offset{x: 0.0, y: 0.35}
maxHpPlayerComponent.MaxHpMax HP1000

Direct component override (TargetType: specific component)

Values that directly override a component property rather than going through a model-property link:

TargetTypeNameDescriptionDefault
MOD.Core.CameraComponentZoomRatioMaxCamera max zoom ratio500.0
MOD.Core.MovementComponentJumpForceJump force (direct override)1.0
MOD.Core.MovementComponentInputSpeedMovement speed (direct override)1.0
script.PlayerHitCollisionGroupHit collision groupCollisionGroup ID
script.PlayerHitBoxSizeHit collision area size{x: 0.45, y: 0.7}
script.PlayerHitColliderOffsetHit collision offset{x: 0.0, y: 0.35}

Movement components per map mode

See msw-general/references/platform.md §4 for the TileMapMode↔Body mapping table. Depending on the map mode, one of RigidbodyComponent / KinematicbodyComponent / SideviewbodyComponent is active.


Identifying a player (for script reference)

  • entity.PlayerComponent ~= nil → whether the entity is a player
  • _UserService.LocalPlayer → my player entity (client-only)
  • _UserService:GetUserEntityByUserId(userId) → player entity for a specific user

Player entity runtime structure (root vs children)

A spawned player is not a single flat entity. At runtime the engine builds a small hierarchy under the player root, and avatar action selectors live on grandchild entities — not on the root. This affects how you look up components and how you trigger avatar poses.

Component → entity mapping

ComponentWhere it livesLookup
PlayerComponentRootplayer:GetComponent("PlayerComponent") (or player.PlayerComponent)
StateComponentRootplayer:GetComponent("StateComponent")
MovementComponentRootplayer:GetComponent("MovementComponent")
AvatarRendererComponentRootplayer.AvatarRendererComponent
AvatarStateAnimationComponentRootplayer:GetComponent("AvatarStateAnimationComponent")
PlayerControllerComponentRootplayer.PlayerControllerComponent
AvatarBodyActionSelectorComponentBody grandchild of root (under the avatar root)not reachable via player:GetComponent(...) — see below
AvatarFaceActionSelectorComponentFace grandchild of rootnot reachable via player:GetComponent(...) — see below

player:GetComponent("AvatarBodyActionSelectorComponent") returns nil and the LSP does not warn (the signature is Component, not nilable). The failure is only visible at runtime.

How to reach the selectors

-- ClientOnly context (recommended — the direct API)
local body  = self.Entity.AvatarRendererComponent:GetBodyEntity()
local face  = self.Entity.AvatarRendererComponent:GetFaceEntity()
local bodySelector = body and body:GetComponent("AvatarBodyActionSelectorComponent")
local faceSelector = face and face:GetComponent("AvatarFaceActionSelectorComponent")

-- Server or "either side" context (GetBodyEntity / GetFaceEntity are ClientOnly)
local bodySelector = self.Entity:GetFirstChildComponentByTypeName(
    "AvatarBodyActionSelectorComponent", true)

AvatarRendererComponent:GetBodyEntity() and GetFaceEntity() are declared @ExecSpace("ClientOnly") — calling them from a server-side method returns nil. Use GetFirstChildComponentByTypeName(name, recursive=true) as the cross-side fallback.


Triggering avatar poses — use StateComponent, never write the selector directly

A live player has a state machine running every tick: PlayerControllerComponent evaluates input/movement → StateComponent transitions (IDLE / MOVE / etc.) → AvatarStateAnimationComponent.ReceiveStateChangeEvent translates that into BodyActionStateChangeEvent → the selector's ActionState is rewritten.

This means writing AvatarBodyActionSelectorComponent.ActionState directly is a silent overwrite: the value applies for one frame, then the next state-machine tick maps the current StateComponent state back onto the selector and your write is gone. Logs print ActionState=Attack immediately after the assignment, but in play mode the pose flickers for one frame and disappears.

Correct entry point

local state = self.Entity:GetComponent("StateComponent")
state:ChangeState("ATTACK")   -- ActionSheet keys are UPPERCASE

State keys come from the player's ActionSheet. The DefaultPlayer ships with 11 UPPERCASE keys, each mapped to a default animation:

StateComponent:ChangeState(...) keyDefault animation
"IDLE"stand
"MOVE"walk
"ATTACK"attack
"HIT"hit
"CROUCH"crouch
"FALL"fall
"JUMP"fall
"CLIMB"rope
"LADDER"ladder
"DEAD"dead
"SIT"sit

The state machine auto-returns to IDLE once the action finishes — no manual restore timer needed.

Casing pitfall: the string key passed to ChangeState is UPPERCASE ("ATTACK"). The enum value written to selector.ActionState directly (NPC path — see below) is MapleAvatarBodyActionState.AttackPascalCase, separate API surface, same underlying state. Wrong casing on the string side ("attack" / "Attack") misses the ActionSheet mapping silently — no warning.

When can you write the selector directly?

Only on entities without a running PlayerControllerComponent + StateComponent + AvatarStateAnimationComponent stack — e.g. NPCs / monsters that use the avatar renderer for visuals but have no input controller driving a state machine. On those, selector.ActionState = MapleAvatarBodyActionState.<Pose> sticks. On DefaultPlayer-shaped entities, route through StateComponent:ChangeState(...) instead.

Key services at a glance (for script reference)

ServiceRoleKey API
_UserServiceUser management, enter/leaveLocalPlayer, UserEntities, GetUserEntityByUserId(), UserEnterEvent/UserLeaveEvent
_TeleportServiceTeleport / map travelTeleportToEntity(), TeleportToMapPosition(), WarpUserToWorldAsync()
_CameraServiceCamera controlSwitchCameraTo(), ZoomTo(), ZoomReset()
DefaultUserEnterLeaveLogicUser enter/leave logicPlayerUri (player model ID), StartPoint (starting map)

How to modify DefaultPlayer

Changing property values (Values)

Load ./Global/DefaultPlayer.model with ModelBuilder.read(), then update values with value().

Example: set movement speed to 2.0

const { ModelBuilder } = require("../msw-general/scripts/model/msw_model_builder.cjs");

const b = ModelBuilder.read("./Global/DefaultPlayer.model");

b.value(null, "speed", 2.0, "float")
  .value("MovementComponent", "InputSpeed", 2.0, "float")
  .write("./Global/DefaultPlayer.model");

Note: both the model property (TargetType: null, Name: "speed") and the direct component override (`TargetType: "MOD.Core.MovementCompon

...

User Reviews (0)

Write a Review

Effect
Usability
Docs
Compatibility

No reviews yet

Statistics

Installs2.8K
Rating4.4 / 5.0
Version
Updated2026年7月10日
Comparisons1

User Rating

4.4(120)
5
37%
4
43%
3
13%
2
5%
1
2%

Rate this Skill

0.0

Compatible Platforms

🤖claude-code

Timeline

Created2026年6月21日
Last Updated2026年7月10日
🎁 Agent Knowledge Cards
Survey