.agents/skills/amxx-modding-kit/api/player-music/SKILL.md
Helps with Player Music API usage for MP3 music playback with automatic duration detection, pause/resume, and activity detection.
npx skillsauth add hedgefog/amxx-modding-kit amxx-modding-kit-api-player-musicInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
api_player_music)The Player Music API provides sophisticated MP3 music management with automatic duration detection, pause/resume functionality, activity detection, and event forwarding.
Reference: See README.md for complete documentation and examples.
This API allows you to:
All tracks MUST be loaded during plugin_precache:
new PlayerMusic_Track:g_track;
public plugin_precache() {
g_track = PlayerMusic_LoadTrack("media/Half-Life01.mp3");
}
new const g_rgszMusicList[][] = {
"media/ambient01.mp3",
"media/ambient02.mp3",
"media/ambient03.mp3"
};
new PlayerMusic_Track:g_rgTracks[sizeof(g_rgszMusicList)];
public plugin_precache() {
for (new i = 0; i < sizeof(g_rgszMusicList); ++i) {
g_rgTracks[i] = PlayerMusic_LoadTrack(g_rgszMusicList[i]);
}
}
// Play immediately
PlayerMusic_Player_PlayTrack(pPlayer, g_track);
// Play with delay
PlayerMusic_Player_PlayTrack(pPlayer, g_track, 5.0); // 5 second delay
// Play looped
PlayerMusic_Player_PlayTrack(pPlayer, g_track, 0.0, true);
// Stop current track
PlayerMusic_Player_StopTrack(pPlayer);
// Pause current track
PlayerMusic_Player_PauseTrack(pPlayer);
// Resume paused track
PlayerMusic_Player_ResumeTrack(pPlayer);
// Check if track is paused
if (PlayerMusic_Player_IsTrackPaused(pPlayer)) {
// Handle paused state
}
// Check if track is looped
if (PlayerMusic_Player_IsTrackLooped(pPlayer)) {
// Handle looped state
}
// Check if track has started playing
if (PlayerMusic_Player_IsTrackStarted(pPlayer)) {
// Track is actively playing
}
// Get remaining time
new Float:flTimeLeft = PlayerMusic_Player_GetTrackTimeLeft(pPlayer);
new PlayerMusic_Track:track = PlayerMusic_Player_GetTrack(pPlayer);
if (track == PlayerMusic_Track_Invalid) {
// No track playing
}
new szTitle[64]; PlayerMusic_GetTrackTitle(track, szTitle, charsmax(szTitle));
new szArtist[64]; PlayerMusic_GetTrackArtist(track, szArtist, charsmax(szArtist));
new szAlbum[64]; PlayerMusic_GetTrackAlbum(track, szAlbum, charsmax(szAlbum));
new iYear = PlayerMusic_GetTrackYear(track);
Hook into playback events:
// Called when track is scheduled
public PlayerMusic_OnTrackScheduled(pPlayer, PlayerMusic_Track:track, bool:bLoop, Float:flStartTime) {
// Track scheduled for playback
}
// Called when track starts playing
public PlayerMusic_OnTrackStart(pPlayer, PlayerMusic_Track:track) {
// Track playback started
}
// Called when track ends
public PlayerMusic_OnTrackEnd(pPlayer, PlayerMusic_Track:track, bool:bStopped) {
// bStopped = true if manually stopped, false if ended naturally
if (!bStopped) {
// Play next track in queue
PlayNextTrack(pPlayer);
}
}
// Called when track is paused
public PlayerMusic_OnTrackPause(pPlayer, PlayerMusic_Track:track) {
// Handle pause
}
// Called when track is resumed
public PlayerMusic_OnTrackResume(pPlayer, PlayerMusic_Track:track) {
// Handle resume
}
// Called when looped track restarts
public PlayerMusic_OnTrackLoop(pPlayer, PlayerMusic_Track:track) {
// Track looped to beginning
}
public client_putinserver(pPlayer) {
// Schedule random track with delay
new iTrackIndex = random(sizeof(g_rgTracks));
PlayerMusic_Player_PlayTrack(pPlayer, g_rgTracks[iTrackIndex], 5.0);
}
public PlayerMusic_OnTrackEnd(pPlayer, PlayerMusic_Track:track, bool:bStopped) {
if (bStopped) return;
// Play next random track
new iNext = random(sizeof(g_rgTracks));
PlayerMusic_Player_PlayTrack(pPlayer, g_rgTracks[iNext], 2.0);
}
public Round_OnStart() {
for (new pPlayer = 1; pPlayer <= MaxClients; ++pPlayer) {
if (!is_user_connected(pPlayer)) continue;
PlayerMusic_Player_PlayTrack(pPlayer, g_trackRoundStart);
}
}
public Round_OnEnd(iTeam) {
new PlayerMusic_Track:track = (iTeam == TEAM_WIN) ? g_trackVictory : g_trackDefeat;
for (new pPlayer = 1; pPlayer <= MaxClients; ++pPlayer) {
if (!is_user_connected(pPlayer)) continue;
PlayerMusic_Player_StopTrack(pPlayer);
PlayerMusic_Player_PlayTrack(pPlayer, track);
}
}
new g_pHudObj;
public plugin_init() {
g_pHudObj = CreateHudSyncObj();
set_task(1.0, "Task_ShowTrackInfo", 0, _, _, "b");
}
public Task_ShowTrackInfo() {
for (new pPlayer = 1; pPlayer <= MaxClients; ++pPlayer) {
if (!is_user_connected(pPlayer)) continue;
new PlayerMusic_Track:track = PlayerMusic_Player_GetTrack(pPlayer);
if (track == PlayerMusic_Track_Invalid) continue;
static szTitle[64]; PlayerMusic_GetTrackTitle(track, szTitle, charsmax(szTitle));
static Float:flTimeLeft; flTimeLeft = PlayerMusic_Player_GetTrackTimeLeft(pPlayer);
set_hudmessage(255, 255, 255, 0.02, 0.9, 0, 0.0, 1.1, 0.0, 0.0);
ShowSyncHudMsg(pPlayer, g_pHudObj, "Now Playing: %s (%.0fs)", szTitle, flTimeLeft);
}
}
The API automatically handles:
plugin_precachePlayerMusic_OnTrackEnd for playlistsPlayerMusic_Track_Invalid when getting current tracktools
Best practices for organizing large AMX Mod X projects with multiple plugins sharing entities, weapons, events, and other definitions. Use when creating mod-scale projects that need consistent namespace patterns and shared constants.
development
Guide for Waypoint Markers API creating 3D waypoint sprites visible through walls with per-player visibility.
development
Guide for States API usage implementing state machines with transitions, guards, and lifecycle hooks.
development
Guide for Shops API usage creating in-game shops with items, custom balance systems, and access control.