add SMJSONAPI
This commit is contained in:
parent
ab4e9de4a4
commit
2262559464
927
SMJSONAPI/configs/Events.cstrike.cfg
Normal file
927
SMJSONAPI/configs/Events.cstrike.cfg
Normal file
@ -0,0 +1,927 @@
|
||||
//=========== (C) Copyright 1999 Valve, L.L.C. All rights reserved. ===========
|
||||
//
|
||||
// The copyright to the contents herein is the property of Valve, L.L.C.
|
||||
// The contents may be used and/or copied only with the written permission of
|
||||
// Valve, L.L.C., or in accordance with the terms and conditions stipulated in
|
||||
// the agreement/contract under which the contents have been supplied.
|
||||
//=============================================================================
|
||||
|
||||
// No spaces in event names, max length 32
|
||||
// All strings are case sensitive
|
||||
// total game event byte length must be < 1024
|
||||
//
|
||||
// valid data key types are:
|
||||
// none : value is not networked
|
||||
// string : a zero terminated string
|
||||
// bool : unsigned int, 1 bit
|
||||
// byte : unsigned int, 8 bit
|
||||
// short : signed int, 16 bit
|
||||
// long : signed int, 32 bit
|
||||
// float : float, 32 bit
|
||||
|
||||
|
||||
// gameevents + hltvevents + replayevents + engineevents
|
||||
"allevents"
|
||||
{
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Game events
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
"team_info" // info about team
|
||||
{
|
||||
"teamid" "byte" // unique team id
|
||||
"teamname" "string" // team name eg "Team Blue"
|
||||
}
|
||||
|
||||
"team_score" // team score changed
|
||||
{
|
||||
"teamid" "byte" // team id
|
||||
"score" "short" // total team score
|
||||
}
|
||||
|
||||
"teamplay_broadcast_audio" // emits a sound to everyone on a team
|
||||
{
|
||||
"team" "byte" // unique team id
|
||||
"sound" "string" // name of the sound to emit
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Player events
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
// "player_team" // player change his team
|
||||
// {
|
||||
// "userid" "short" // user ID on server
|
||||
// "team" "byte" // team id
|
||||
// "oldteam" "byte" // old team id
|
||||
// "disconnect" "bool" // team change because player disconnects
|
||||
// "autoteam" "bool" // true if the player was auto assigned to the team
|
||||
// "silent" "bool" // if true wont print the team join messages
|
||||
// "name" "string" // player's name
|
||||
// }
|
||||
|
||||
"player_class" // a player changed his class
|
||||
{
|
||||
"userid" "short" // user ID on server
|
||||
"class" "string" // new player class / model
|
||||
}
|
||||
|
||||
// "player_death" // a game event, name may be 32 charaters long
|
||||
// {
|
||||
// "userid" "short" // user ID who died
|
||||
// "attacker" "short" // user ID who killed
|
||||
// }
|
||||
|
||||
// "player_hurt"
|
||||
// {
|
||||
// "userid" "short" // player index who was hurt
|
||||
// "attacker" "short" // player index who attacked
|
||||
// "health" "byte" // remaining health points
|
||||
// }
|
||||
|
||||
"player_chat" // a public player chat
|
||||
{
|
||||
"teamonly" "bool" // true if team only chat
|
||||
"userid" "short" // chatting player
|
||||
"text" "string" // chat text
|
||||
}
|
||||
|
||||
"player_score" // players scores changed
|
||||
{
|
||||
"userid" "short" // user ID on server
|
||||
"kills" "short" // # of kills
|
||||
"deaths" "short" // # of deaths
|
||||
"score" "short" // total game score
|
||||
}
|
||||
|
||||
"player_spawn" // player spawned in game
|
||||
{
|
||||
"userid" "short" // user ID on server
|
||||
}
|
||||
|
||||
"player_shoot" // player shoot his weapon
|
||||
{
|
||||
"userid" "short" // user ID on server
|
||||
"weapon" "byte" // weapon ID
|
||||
"mode" "byte" // weapon mode
|
||||
}
|
||||
|
||||
"player_use"
|
||||
{
|
||||
"userid" "short" // user ID on server
|
||||
"entity" "short" // entity used by player
|
||||
}
|
||||
|
||||
"player_changename"
|
||||
{
|
||||
"userid" "short" // user ID on server
|
||||
"oldname" "string" // players old (current) name
|
||||
"newname" "string" // players new name
|
||||
}
|
||||
|
||||
"player_hintmessage"
|
||||
{
|
||||
"hintmessage" "string" // localizable string of a hint
|
||||
}
|
||||
|
||||
"base_player_teleported"
|
||||
{
|
||||
"entindex" "short"
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Game events
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
"game_init" // sent when a new game is started
|
||||
{
|
||||
}
|
||||
|
||||
"game_newmap" // send when new map is completely loaded
|
||||
{
|
||||
"mapname" "string" // map name
|
||||
}
|
||||
|
||||
"game_start" // a new game starts
|
||||
{
|
||||
"roundslimit" "long" // max round
|
||||
"timelimit" "long" // time limit
|
||||
"fraglimit" "long" // frag limit
|
||||
"objective" "string" // round objective
|
||||
}
|
||||
|
||||
"game_end" // a game ended
|
||||
{
|
||||
"winner" "byte" // winner team/user id
|
||||
}
|
||||
|
||||
"round_start"
|
||||
{
|
||||
"timelimit" "long" // round time limit in seconds
|
||||
"fraglimit" "long" // frag limit in seconds
|
||||
"objective" "string" // round objective
|
||||
}
|
||||
|
||||
"round_end"
|
||||
{
|
||||
"winner" "byte" // winner team/user i
|
||||
"reason" "byte" // reson why team won
|
||||
"message" "string" // end round message
|
||||
}
|
||||
|
||||
"game_message" // a message send by game logic to everyone
|
||||
{
|
||||
"target" "byte" // 0 = console, 1 = HUD
|
||||
"text" "string" // the message text
|
||||
}
|
||||
|
||||
"break_breakable"
|
||||
{
|
||||
"entindex" "long"
|
||||
"userid" "short"
|
||||
"material" "byte" // BREAK_GLASS, BREAK_WOOD, etc
|
||||
}
|
||||
|
||||
"break_prop"
|
||||
{
|
||||
"entindex" "long"
|
||||
"userid" "short"
|
||||
}
|
||||
|
||||
"entity_killed"
|
||||
{
|
||||
"entindex_killed" "long"
|
||||
"entindex_attacker" "long"
|
||||
"entindex_inflictor" "long"
|
||||
"damagebits" "long"
|
||||
}
|
||||
|
||||
"bonus_updated"
|
||||
{
|
||||
"numadvanced" "short"
|
||||
"numbronze" "short"
|
||||
"numsilver" "short"
|
||||
"numgold" "short"
|
||||
}
|
||||
|
||||
"achievement_event"
|
||||
{
|
||||
"achievement_name" "string" // non-localized name of achievement
|
||||
"cur_val" "short" // # of steps toward achievement
|
||||
"max_val" "short" // total # of steps in achievement
|
||||
}
|
||||
|
||||
// sent whenever an achievement that's tracked on the HUD increases
|
||||
"achievement_increment"
|
||||
{
|
||||
"achievement_id" "long" // ID of achievement that went up
|
||||
"cur_val" "short" // # of steps toward achievement
|
||||
"max_val" "short" // total # of steps in achievement
|
||||
}
|
||||
|
||||
"physgun_pickup"
|
||||
{
|
||||
"entindex" "long" // entity picked up
|
||||
}
|
||||
|
||||
"flare_ignite_npc"
|
||||
{
|
||||
"entindex" "long" // entity ignited
|
||||
}
|
||||
|
||||
"helicopter_grenade_punt_miss"
|
||||
{
|
||||
}
|
||||
|
||||
"user_data_downloaded" // fired when achievements/stats are downloaded from Steam or XBox Live
|
||||
{
|
||||
}
|
||||
|
||||
"ragdoll_dissolved"
|
||||
{
|
||||
"entindex" "long"
|
||||
}
|
||||
|
||||
"hltv_changed_mode"
|
||||
{
|
||||
"oldmode" "short"
|
||||
"newmode" "short"
|
||||
"obs_target" "short"
|
||||
}
|
||||
"hltv_changed_target"
|
||||
{
|
||||
"mode" "short"
|
||||
"old_target" "short"
|
||||
"obs_target" "short"
|
||||
}
|
||||
|
||||
// Client side VoteController talking to HUD
|
||||
"vote_ended"
|
||||
{
|
||||
}
|
||||
"vote_started"
|
||||
{
|
||||
"issue" "string"
|
||||
"param1" "string"
|
||||
"team" "byte"
|
||||
"initiator" "long" // entity id of the player who initiated the vote
|
||||
}
|
||||
"vote_changed"
|
||||
{
|
||||
"vote_option1" "byte"
|
||||
"vote_option2" "byte"
|
||||
"vote_option3" "byte"
|
||||
"vote_option4" "byte"
|
||||
"vote_option5" "byte"
|
||||
"potentialVotes" "byte"
|
||||
}
|
||||
"vote_passed"
|
||||
{
|
||||
"details" "string"
|
||||
"param1" "string"
|
||||
"team" "byte"
|
||||
}
|
||||
"vote_failed"
|
||||
{
|
||||
"team" "byte"
|
||||
}
|
||||
"vote_cast"
|
||||
{
|
||||
"vote_option" "byte" // which option the player voted on
|
||||
"team" "short"
|
||||
"entityid" "long" // entity id of the voter
|
||||
}
|
||||
"vote_options"
|
||||
{
|
||||
"count" "byte" // Number of options - up to MAX_VOTE_OPTIONS
|
||||
"option1" "string"
|
||||
"option2" "string"
|
||||
"option3" "string"
|
||||
"option4" "string"
|
||||
"option5" "string"
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Replay events
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
"replay_saved"
|
||||
{
|
||||
}
|
||||
|
||||
"entered_performance_mode"
|
||||
{
|
||||
}
|
||||
|
||||
"browse_replays"
|
||||
{
|
||||
}
|
||||
|
||||
"replay_youtube_stats"
|
||||
{
|
||||
"views" "long"
|
||||
"likes" "long"
|
||||
"favorited" "long"
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Economy events
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
"inventory_updated"
|
||||
{
|
||||
}
|
||||
"cart_updated"
|
||||
{
|
||||
}
|
||||
"store_pricesheet_updated"
|
||||
{
|
||||
}
|
||||
"gc_connected"
|
||||
{
|
||||
}
|
||||
"item_schema_initialized"
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// HLTV specific events
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
"hltv_status" // general HLTV status
|
||||
{
|
||||
"clients" "long" // number of HLTV spectators
|
||||
"slots" "long" // number of HLTV slots
|
||||
"proxies" "short" // number of HLTV proxies
|
||||
"master" "string" // disptach master IP:port
|
||||
}
|
||||
|
||||
"hltv_cameraman" // a spectator/player is a cameraman
|
||||
{
|
||||
"index" "short" // camera man entity index
|
||||
}
|
||||
|
||||
"hltv_rank_camera" // a camera ranking
|
||||
{
|
||||
"index" "byte" // fixed camera index
|
||||
"rank" "float" // ranking, how interesting is this camera view
|
||||
"target" "short" // best/closest target entity
|
||||
}
|
||||
|
||||
"hltv_rank_entity" // an entity ranking
|
||||
{
|
||||
"index" "short" // entity index
|
||||
"rank" "float" // ranking, how interesting is this entity to view
|
||||
"target" "short" // best/closest target entity
|
||||
}
|
||||
|
||||
"hltv_fixed" // show from fixed view
|
||||
{
|
||||
"posx" "long" // camera position in world
|
||||
"posy" "long"
|
||||
"posz" "long"
|
||||
"theta" "short" // camera angles
|
||||
"phi" "short"
|
||||
"offset" "short"
|
||||
"fov" "float"
|
||||
"target" "short" // follow this entity or 0
|
||||
}
|
||||
|
||||
"hltv_chase" // shot of a single entity
|
||||
{
|
||||
"target1" "short" // primary traget index
|
||||
"target2" "short" // secondary traget index or 0
|
||||
"distance" "short" // camera distance
|
||||
"theta" "short" // view angle horizontal
|
||||
"phi" "short" // view angle vertical
|
||||
"inertia" "byte" // camera inertia
|
||||
"ineye" "byte" // diretcor suggests to show ineye
|
||||
}
|
||||
|
||||
"hltv_message" // a HLTV message send by moderators
|
||||
{
|
||||
"text" "string"
|
||||
}
|
||||
|
||||
"hltv_title"
|
||||
{
|
||||
"text" "string"
|
||||
}
|
||||
|
||||
"hltv_chat" // a HLTV chat msg send by spectators
|
||||
{
|
||||
"text" "string"
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// replay specific events
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
"replay_startrecord" // Sent when the server begins recording - only used to display UI
|
||||
{
|
||||
}
|
||||
|
||||
"replay_sessioninfo" // Sent when the server begins recording, or when a client first connects - only sent once per recording session
|
||||
{
|
||||
"sn" "string" // session name
|
||||
"di" "byte" // dump interval
|
||||
"cb" "long" // current block
|
||||
"st" "long" // session start tick
|
||||
}
|
||||
|
||||
"replay_endrecord"
|
||||
{
|
||||
}
|
||||
|
||||
"replay_replaysavailable"
|
||||
{
|
||||
}
|
||||
|
||||
"replay_servererror"
|
||||
{
|
||||
"error" "string"
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Server events
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
"server_spawn" // send once a server starts
|
||||
{
|
||||
"hostname" "string" // public host name
|
||||
"address" "string" // hostame, IP or DNS name
|
||||
"ip" "long"
|
||||
"port" "short" // server port
|
||||
"game" "string" // game dir
|
||||
"mapname" "string" // map name
|
||||
"maxplayers" "long" // max players
|
||||
"os" "string" // WIN32, LINUX
|
||||
"dedicated" "bool" // true if dedicated server
|
||||
"password" "bool" // true if password protected
|
||||
}
|
||||
|
||||
"server_changelevel_failed"
|
||||
{
|
||||
"levelname" "string" // The level name that failed changelevel
|
||||
}
|
||||
|
||||
"server_shutdown" // server shut down
|
||||
{
|
||||
"reason" "string" // reason why server was shut down
|
||||
}
|
||||
|
||||
"server_cvar" // a server console var has changed
|
||||
{
|
||||
"cvarname" "string" // cvar name, eg "mp_roundtime"
|
||||
"cvarvalue" "string" // new cvar value
|
||||
}
|
||||
|
||||
"server_message" // a generic server message
|
||||
{
|
||||
"text" "string" // the message text
|
||||
}
|
||||
|
||||
"server_addban"
|
||||
{
|
||||
"name" "string" // player name
|
||||
"userid" "short" // user ID on server
|
||||
"networkid" "string" // player network (i.e steam) id
|
||||
"ip" "string" // IP address
|
||||
"duration" "string" // length of the ban
|
||||
"by" "string" // banned by...
|
||||
"kicked" "bool" // whether the player was also kicked
|
||||
}
|
||||
|
||||
"server_removeban"
|
||||
{
|
||||
"networkid" "string" // player network (i.e steam) id
|
||||
"ip" "string" // IP address
|
||||
"by" "string" // removed by...
|
||||
}
|
||||
|
||||
"player_connect" // a new client connected - we should only really have server listeners for this, due to the IP being exposed
|
||||
{
|
||||
"name" "string" // player name
|
||||
"index" "byte" // player slot (entity index-1)
|
||||
"userid" "short" // user ID on server (unique on server)
|
||||
"networkid" "string" // player network (i.e steam) id
|
||||
"address" "string" // ip:port
|
||||
"bot" "short" // is a bot
|
||||
}
|
||||
|
||||
"player_connect_client" // a new client connected
|
||||
{
|
||||
"name" "string" // player name
|
||||
"index" "byte" // player slot (entity index-1)
|
||||
"userid" "short" // user ID on server (unique on server)
|
||||
"networkid" "string" // player network (i.e steam) id
|
||||
"bot" "short" // is a bot
|
||||
}
|
||||
|
||||
"player_info" // a player changed his name
|
||||
{
|
||||
"name" "string" // player name
|
||||
"index" "byte" // player slot (entity index-1)
|
||||
"userid" "short" // user ID on server (unique on server)
|
||||
"networkid" "string" // player network (i.e steam) id
|
||||
"bot" "bool" // true if player is a AI bot
|
||||
}
|
||||
|
||||
"player_disconnect" // a client was disconnected
|
||||
{
|
||||
"userid" "short" // user ID on server
|
||||
"reason" "string" // "self", "kick", "ban", "cheat", "error"
|
||||
"name" "string" // player name
|
||||
"networkid" "string" // player network (i.e steam) id
|
||||
"bot" "short" // is a bot
|
||||
}
|
||||
|
||||
"player_activate"
|
||||
{
|
||||
"userid" "short" // user ID on server
|
||||
}
|
||||
|
||||
"player_say"
|
||||
{
|
||||
"userid" "short" // user ID on server
|
||||
"text" "string" // the say text
|
||||
}
|
||||
|
||||
"client_disconnect" // client side disconnect message
|
||||
{
|
||||
"message" "string" // Why are we disconnecting? This could be a localization token or an English-language string
|
||||
}
|
||||
|
||||
"client_beginconnect" // client tries to connect to server
|
||||
{
|
||||
"address" "string" // Name we used to connect to the server
|
||||
"ip" "long"
|
||||
"port" "short" // server port
|
||||
"source" "string" // what caused us to attempt this connection? (blank for general command line, "serverbrowser", "quickplay", etc)
|
||||
}
|
||||
|
||||
"client_connected" // client has completed the challenge / handshake process and is in SIGNONSTATE_CONNECTED
|
||||
{
|
||||
"address" "string" // Name we used to connect to the server
|
||||
"ip" "long"
|
||||
"port" "short" // server port
|
||||
}
|
||||
|
||||
"client_fullconnect"
|
||||
{
|
||||
"address" "string" // Name we used to connect to the server
|
||||
"ip" "long"
|
||||
"port" "short" // server port
|
||||
}
|
||||
|
||||
"host_quit"
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// CStrike events
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
"player_death" // a game event, name may be 32 characters long
|
||||
{
|
||||
// this extents the original player_death by a new fields
|
||||
"userid" "short" // user ID who died
|
||||
"attacker" "short" // user ID who killed
|
||||
"weapon" "string" // weapon name killer used
|
||||
"headshot" "bool" // singals a headshot
|
||||
"dominated" "short" // did killer dominate victim with this kill
|
||||
"revenge" "short" // did killer get revenge on victim with this kill
|
||||
}
|
||||
|
||||
"player_hurt"
|
||||
{
|
||||
"userid" "short" // player index who was hurt
|
||||
"attacker" "short" // player index who attacked
|
||||
"health" "byte" // remaining health points
|
||||
"armor" "byte" // remaining armor points
|
||||
"weapon" "string" // weapon name attacker used, if not the world
|
||||
"dmg_health" "byte" // damage done to health
|
||||
"dmg_armor" "byte" // damage done to armor
|
||||
"hitgroup" "byte" // hitgroup that was damaged
|
||||
}
|
||||
|
||||
"bomb_beginplant"
|
||||
{
|
||||
"userid" "short" // player who is planting the bomb
|
||||
"site" "short" // bombsite index
|
||||
}
|
||||
|
||||
"bomb_abortplant"
|
||||
{
|
||||
"userid" "short" // player who is planting the bomb
|
||||
"site" "short" // bombsite index
|
||||
}
|
||||
|
||||
"bomb_planted"
|
||||
{
|
||||
"userid" "short" // player who planted the bomb
|
||||
"site" "short" // bombsite index
|
||||
"posx" "short" // position x
|
||||
"posy" "short" // position y
|
||||
}
|
||||
|
||||
"bomb_defused"
|
||||
{
|
||||
"userid" "short" // player who defused the bomb
|
||||
"site" "short" // bombsite index
|
||||
}
|
||||
|
||||
"bomb_exploded"
|
||||
{
|
||||
"userid" "short" // player who planted the bomb
|
||||
"site" "short" // bombsite index
|
||||
}
|
||||
|
||||
"bomb_dropped"
|
||||
{
|
||||
"userid" "short" // player who dropped the bomb
|
||||
}
|
||||
|
||||
"bomb_pickup"
|
||||
{
|
||||
"userid" "short" // player who picked up the bomb
|
||||
}
|
||||
|
||||
"bomb_begindefuse"
|
||||
{
|
||||
"userid" "short" // player who is defusing
|
||||
"haskit" "bool"
|
||||
}
|
||||
|
||||
"bomb_abortdefuse"
|
||||
{
|
||||
"userid" "short" // player who was defusing
|
||||
}
|
||||
|
||||
"hostage_follows"
|
||||
{
|
||||
"userid" "short" // player who touched the hostage
|
||||
"hostage" "short" // hostage entity index
|
||||
}
|
||||
|
||||
"hostage_hurt"
|
||||
{
|
||||
"userid" "short" // player who hurt the hostage
|
||||
"hostage" "short" // hostage entity index
|
||||
}
|
||||
|
||||
"hostage_killed"
|
||||
{
|
||||
"userid" "short" // player who killed the hostage
|
||||
"hostage" "short" // hostage entity index
|
||||
}
|
||||
|
||||
"hostage_rescued"
|
||||
{
|
||||
"userid" "short" // player who rescued the hostage
|
||||
"hostage" "short" // hostage entity index
|
||||
"site" "short" // rescue site index
|
||||
}
|
||||
|
||||
"hostage_stops_following"
|
||||
{
|
||||
"userid" "short" // player who rescued the hostage
|
||||
"hostage" "short" // hostage entity index
|
||||
}
|
||||
|
||||
"hostage_rescued_all"
|
||||
{
|
||||
}
|
||||
|
||||
"hostage_call_for_help"
|
||||
{
|
||||
"hostage" "short" // hostage entity index
|
||||
}
|
||||
|
||||
"vip_escaped"
|
||||
{
|
||||
"userid" "short" // player who was the VIP
|
||||
}
|
||||
|
||||
"vip_killed"
|
||||
{
|
||||
"userid" "short" // player who was the VIP
|
||||
"attacker" "short" // user ID who killed the VIP
|
||||
}
|
||||
|
||||
"player_radio"
|
||||
{
|
||||
"userid" "short"
|
||||
"slot" "short"
|
||||
}
|
||||
|
||||
"bomb_beep"
|
||||
{
|
||||
"entindex" "long" // c4 entity
|
||||
}
|
||||
|
||||
"weapon_fire"
|
||||
{
|
||||
"userid" "short"
|
||||
"weapon" "string" // weapon name used
|
||||
}
|
||||
|
||||
"weapon_fire_on_empty"
|
||||
{
|
||||
"userid" "short"
|
||||
"weapon" "string" // weapon name used
|
||||
}
|
||||
|
||||
"weapon_reload"
|
||||
{
|
||||
"userid" "short"
|
||||
}
|
||||
|
||||
"weapon_zoom"
|
||||
{
|
||||
"userid" "short"
|
||||
}
|
||||
|
||||
"item_pickup"
|
||||
{
|
||||
"userid" "short"
|
||||
"item" "string" // either a weapon such as 'tmp' or 'hegrenade', or an item such as 'nvgs'
|
||||
}
|
||||
|
||||
"grenade_bounce"
|
||||
{
|
||||
"userid" "short"
|
||||
}
|
||||
|
||||
"hegrenade_detonate"
|
||||
{
|
||||
"userid" "short"
|
||||
"x" "float"
|
||||
"y" "float"
|
||||
"z" "float"
|
||||
}
|
||||
|
||||
"flashbang_detonate"
|
||||
{
|
||||
"userid" "short"
|
||||
"x" "float"
|
||||
"y" "float"
|
||||
"z" "float"
|
||||
}
|
||||
|
||||
"smokegrenade_detonate"
|
||||
{
|
||||
"userid" "short"
|
||||
"x" "float"
|
||||
"y" "float"
|
||||
"z" "float"
|
||||
}
|
||||
|
||||
"bullet_impact"
|
||||
{
|
||||
"userid" "short"
|
||||
"x" "float"
|
||||
"y" "float"
|
||||
"z" "float"
|
||||
}
|
||||
|
||||
"player_footstep"
|
||||
{
|
||||
"userid" "short"
|
||||
}
|
||||
|
||||
"player_jump"
|
||||
{
|
||||
"userid" "short"
|
||||
}
|
||||
|
||||
"player_blind"
|
||||
{
|
||||
"userid" "short"
|
||||
}
|
||||
|
||||
"player_falldamage"
|
||||
{
|
||||
"userid" "short"
|
||||
"damage" "float"
|
||||
}
|
||||
|
||||
"door_moving"
|
||||
{
|
||||
"entindex" "long"
|
||||
"userid" "short"
|
||||
}
|
||||
|
||||
"round_freeze_end"
|
||||
{
|
||||
}
|
||||
|
||||
"nav_blocked"
|
||||
{
|
||||
"area" "long"
|
||||
"blocked" "bool"
|
||||
}
|
||||
|
||||
"nav_generate"
|
||||
{
|
||||
}
|
||||
|
||||
"player_stats_updated"
|
||||
{
|
||||
"forceupload" "bool"
|
||||
}
|
||||
|
||||
"spec_target_updated"
|
||||
{
|
||||
}
|
||||
|
||||
"cs_win_panel_round"
|
||||
{
|
||||
"show_timer_defend" "bool"
|
||||
"show_timer_attack" "bool"
|
||||
"timer_time" "short"
|
||||
|
||||
"final_event" "byte" //define in cs_gamerules.h
|
||||
|
||||
"funfact_token" "string"
|
||||
"funfact_player" "short"
|
||||
"funfact_data1" "long"
|
||||
"funfact_data2" "long"
|
||||
"funfact_data3" "long"
|
||||
}
|
||||
|
||||
"cs_win_panel_match"
|
||||
{
|
||||
"t_score" "short"
|
||||
"ct_score" "short"
|
||||
"t_kd" "float"
|
||||
"ct_kd" "float"
|
||||
"t_objectives_done" "short"
|
||||
"ct_objectives_done" "short"
|
||||
"t_money_earned" "long"
|
||||
"ct_money_earned" "long"
|
||||
}
|
||||
|
||||
"show_freezepanel"
|
||||
{
|
||||
"killer" "short" // entindex of the killer entity
|
||||
}
|
||||
|
||||
"hide_freezepanel"
|
||||
{
|
||||
}
|
||||
|
||||
"freezecam_started"
|
||||
{
|
||||
}
|
||||
|
||||
"player_avenged_teammate"
|
||||
{
|
||||
"avenger_id" "short"
|
||||
"avenged_player_id" "short"
|
||||
}
|
||||
|
||||
"achievement_earned"
|
||||
{
|
||||
"player" "byte" // entindex of the player
|
||||
"achievement" "short" // achievement ID
|
||||
}
|
||||
|
||||
"achievement_earned_local"
|
||||
{
|
||||
"achievement" "short" // achievement ID
|
||||
}
|
||||
|
||||
"match_end_conditions"
|
||||
{
|
||||
"frags" "long"
|
||||
"max_rounds" "long"
|
||||
"win_rounds" "long"
|
||||
"time" "long"
|
||||
}
|
||||
|
||||
"round_mvp"
|
||||
{
|
||||
"userid" "short"
|
||||
"reason" "short"
|
||||
}
|
||||
|
||||
"player_decal"
|
||||
{
|
||||
"userid" "short"
|
||||
}
|
||||
|
||||
"teamplay_round_start" // round restart
|
||||
{
|
||||
"full_reset" "bool" // is this a full reset of the map
|
||||
}
|
||||
|
||||
"christmas_gift_grab"
|
||||
{
|
||||
"userid" "short"
|
||||
}
|
||||
}
|
127
SMJSONAPI/example.txt
Normal file
127
SMJSONAPI/example.txt
Normal file
@ -0,0 +1,127 @@
|
||||
request:
|
||||
{
|
||||
"method": "subscribe",
|
||||
"module": "gameevents",
|
||||
"events": [
|
||||
"player_connect",
|
||||
"player_disconnect",
|
||||
"player_say",
|
||||
"invalid"
|
||||
]
|
||||
}
|
||||
|
||||
response:
|
||||
{
|
||||
"method": "subscribe",
|
||||
"module": "gameevents",
|
||||
"error": 0,
|
||||
"events": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
-3
|
||||
]
|
||||
}
|
||||
|
||||
-----
|
||||
|
||||
events:
|
||||
{
|
||||
"method": "publish",
|
||||
"module": "gameevents",
|
||||
"event": {
|
||||
"name": "player_connect",
|
||||
"data": {
|
||||
"name": "BotoX",
|
||||
"index": 0,
|
||||
"userid": 4,
|
||||
"networkid": "[U:1:51174697]",
|
||||
"address": "192.168.1.4:27006",
|
||||
"bot": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
"method": "publish",
|
||||
"module": "gameevents",
|
||||
"event": {
|
||||
"name": "player_say",
|
||||
"data": {
|
||||
"text": "hello",
|
||||
"userid": 4
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
"method": "publish",
|
||||
"module": "gameevents",
|
||||
"event": {
|
||||
"name": "player_disconnect",
|
||||
"data": {
|
||||
"userid": 4,
|
||||
"reason": "Disconnect by user.",
|
||||
"name": "BotoX",
|
||||
"networkid": "[U:1:51174697]",
|
||||
"bot": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-----
|
||||
|
||||
request:
|
||||
{
|
||||
"method": "unsubscribe",
|
||||
"module": "gameevents",
|
||||
"events": [
|
||||
"player_connect",
|
||||
"player_disconnect",
|
||||
"player_say",
|
||||
"invalid"
|
||||
]
|
||||
}
|
||||
|
||||
response:
|
||||
{
|
||||
"method": "unsubscribe",
|
||||
"module": "gameevents",
|
||||
"error": 0,
|
||||
"events": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
}
|
||||
|
||||
-----
|
||||
|
||||
request:
|
||||
{
|
||||
"method": "function",
|
||||
"function": "KickClient",
|
||||
"parameters": [
|
||||
1,
|
||||
"%d hello %s",
|
||||
1337,
|
||||
"cat"
|
||||
]
|
||||
}
|
||||
|
||||
Other examples:
|
||||
|
||||
{ "method": "function", "function": "PrintToServer", "parameters": ["1: %s, 2: %d, 3: %s, 4: %d", "1test1", [2222], "3test3", [4444]] }
|
||||
|
||||
{ "method": "function", "function": "TeleportEntity", "parameters": [1, [206.472443, 2418.516357, -62.058395], [26.994024, -14.119852, 0.000000], [["NULL_VECTOR"]] ] }
|
||||
|
||||
{ "method": "function", "function": "GetClientName", "parameters": [ 1, "", 1024 ] }
|
||||
|
||||
{ "method": "function", "function": "GetClientAbsOrigin", "parameters": [ 1, [0.0,0,0] ] }
|
||||
|
||||
{ "method": "function", "function": "ServerCommandEx", "parameters": [ "", 1024, "echo hello mates %d %f %s", [123], [123.456], "test" ] }
|
||||
|
||||
{ "method": "subscribe", "module": "gameevents", "events": [ "player_say" ] }
|
||||
|
||||
{ "method": "function", "function": "GetUserFlagBits", "args": [ 9 ] }
|
49
SMJSONAPI/scripting/API.inc
Normal file
49
SMJSONAPI/scripting/API.inc
Normal file
@ -0,0 +1,49 @@
|
||||
public void API_PrintToChatAll(const char[] format, any ...)
|
||||
{
|
||||
char buffer[254];
|
||||
|
||||
for (int i = 1; i <= MaxClients; i++)
|
||||
{
|
||||
if (IsClientInGame(i))
|
||||
{
|
||||
SetGlobalTransTarget(i);
|
||||
VFormat(buffer, sizeof(buffer), format, 2);
|
||||
PrintToChat(i, "%s", buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void API_PrintCenterTextAll(const char[] format, any ...)
|
||||
{
|
||||
char buffer[254];
|
||||
|
||||
for (int i = 1; i <= MaxClients; i++)
|
||||
{
|
||||
if (IsClientInGame(i))
|
||||
{
|
||||
SetGlobalTransTarget(i);
|
||||
VFormat(buffer, sizeof(buffer), format, 2);
|
||||
PrintCenterText(i, "%s", buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void API_PrintHintTextToAll(const char[] format, any ...)
|
||||
{
|
||||
char buffer[254];
|
||||
|
||||
for (int i = 1; i <= MaxClients; i++)
|
||||
{
|
||||
if (IsClientInGame(i))
|
||||
{
|
||||
SetGlobalTransTarget(i);
|
||||
VFormat(buffer, sizeof(buffer), format, 2);
|
||||
PrintHintText(i, "%s", buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int API_GetMaxClients()
|
||||
{
|
||||
return MaxClients;
|
||||
}
|
158
SMJSONAPI/scripting/GameEvents.inc
Normal file
158
SMJSONAPI/scripting/GameEvents.inc
Normal file
@ -0,0 +1,158 @@
|
||||
static KeyValues g_Config;
|
||||
|
||||
bool GameEvents_Init()
|
||||
{
|
||||
char sGame[32];
|
||||
GetGameFolderName(sGame, sizeof(sGame));
|
||||
|
||||
char sConfigFile[PLATFORM_MAX_PATH];
|
||||
BuildPath(Path_SM, sConfigFile, sizeof(sConfigFile), "configs/Events.%s.cfg", sGame);
|
||||
if(!FileExists(sConfigFile))
|
||||
{
|
||||
SetFailState("Could not find config: \"%s\"", sConfigFile);
|
||||
}
|
||||
|
||||
g_Config = new KeyValues("allevents");
|
||||
if(!g_Config.ImportFromFile(sConfigFile))
|
||||
{
|
||||
delete g_Config;
|
||||
SetFailState("ImportFromFile() failed!");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void GameEvents_OnHook(Event event, const char[] name, bool dontBroadcast)
|
||||
{
|
||||
static char sEventName[32];
|
||||
event.GetName(sEventName, sizeof(sEventName));
|
||||
|
||||
g_Config.JumpToKey(sEventName);
|
||||
|
||||
JSONObject jEvent = new JSONObject();
|
||||
jEvent.SetString("name", sEventName);
|
||||
|
||||
JSONObject jEventData = new JSONObject();
|
||||
|
||||
if(g_Config.GotoFirstSubKey(false))
|
||||
{
|
||||
do
|
||||
{
|
||||
static char sKey[32];
|
||||
static char sType[8];
|
||||
|
||||
g_Config.GetSectionName(sKey, sizeof(sKey));
|
||||
g_Config.GetString(NULL_STRING, sType, sizeof(sType));
|
||||
|
||||
if(StrEqual(sKey, "_hooked"))
|
||||
continue;
|
||||
|
||||
if(StrEqual(sType, "short") || StrEqual(sType, "long") || StrEqual(sType, "byte"))
|
||||
{
|
||||
int iValue = event.GetInt(sKey);
|
||||
jEventData.SetInt(sKey, iValue);
|
||||
}
|
||||
else if(StrEqual(sType, "float"))
|
||||
{
|
||||
float fValue = event.GetFloat(sKey);
|
||||
jEventData.SetFloat(sKey, fValue);
|
||||
}
|
||||
else if(StrEqual(sType, "bool"))
|
||||
{
|
||||
bool bValue = event.GetBool(sKey);
|
||||
jEventData.SetBool(sKey, bValue);
|
||||
}
|
||||
else if(StrEqual(sType, "string"))
|
||||
{
|
||||
static char sValue[1024];
|
||||
event.GetString(sKey, sValue, sizeof(sValue));
|
||||
jEventData.SetString(sKey, sValue);
|
||||
}
|
||||
} while(g_Config.GotoNextKey(false));
|
||||
g_Config.Rewind();
|
||||
}
|
||||
|
||||
jEvent.Set("data", jEventData);
|
||||
|
||||
Subscribe_GameEvents_Publish(sEventName, jEvent);
|
||||
}
|
||||
|
||||
int GameEvents_Hook(const char[] sEventName)
|
||||
{
|
||||
if(!g_Config.JumpToKey(sEventName))
|
||||
return -1;
|
||||
|
||||
int Hooked = g_Config.GetNum("_hooked", 0);
|
||||
if(Hooked)
|
||||
{
|
||||
g_Config.SetNum("_hooked", Hooked + 1);
|
||||
return Hooked + 1;
|
||||
}
|
||||
|
||||
Hooked = HookEventEx(sEventName, GameEvents_OnHook, EventHookMode_Post);
|
||||
if(Hooked)
|
||||
g_Config.SetNum("_hooked", 1);
|
||||
|
||||
g_Config.Rewind();
|
||||
return Hooked ? 1 : -1;
|
||||
}
|
||||
|
||||
int GameEvents_Unhook(const char[] sEventName)
|
||||
{
|
||||
if(!g_Config.JumpToKey(sEventName))
|
||||
return -1;
|
||||
|
||||
int Hooked = g_Config.GetNum("_hooked", 0);
|
||||
if(!Hooked)
|
||||
return 0;
|
||||
|
||||
if(Hooked == 1)
|
||||
UnhookEvent(sEventName, GameEvents_OnHook, EventHookMode_Post);
|
||||
|
||||
g_Config.SetNum("_hooked", Hooked - 1);
|
||||
|
||||
g_Config.Rewind();
|
||||
return Hooked - 1;
|
||||
}
|
||||
|
||||
stock void GameEvents_HookAll()
|
||||
{
|
||||
g_Config.GotoFirstSubKey(false);
|
||||
|
||||
do
|
||||
{
|
||||
static char sKey[32];
|
||||
g_Config.GetSectionName(sKey, sizeof(sKey));
|
||||
|
||||
int Hooked = g_Config.GetNum("_hooked", 0);
|
||||
if(!Hooked)
|
||||
{
|
||||
if(HookEventEx(sKey, GameEvents_OnHook, EventHookMode_Post))
|
||||
g_Config.SetNum("_hooked", 1);
|
||||
}
|
||||
else
|
||||
g_Config.SetNum("_hooked", Hooked + 1);
|
||||
} while(g_Config.GotoNextKey(true));
|
||||
|
||||
g_Config.Rewind();
|
||||
}
|
||||
|
||||
stock void GameEvents_UnhookAll()
|
||||
{
|
||||
g_Config.GotoFirstSubKey(false);
|
||||
|
||||
do
|
||||
{
|
||||
static char sKey[32];
|
||||
g_Config.GetSectionName(sKey, sizeof(sKey));
|
||||
|
||||
int Hooked = g_Config.GetNum("_hooked", 0);
|
||||
if(Hooked)
|
||||
{
|
||||
UnhookEvent(sKey, GameEvents_OnHook, EventHookMode_Post);
|
||||
g_Config.SetNum("_hooked", 0);
|
||||
}
|
||||
} while(g_Config.GotoNextKey(true));
|
||||
|
||||
g_Config.Rewind();
|
||||
}
|
472
SMJSONAPI/scripting/SMJSONAPI.sp
Normal file
472
SMJSONAPI/scripting/SMJSONAPI.sp
Normal file
@ -0,0 +1,472 @@
|
||||
#pragma semicolon 1
|
||||
#pragma newdecls required
|
||||
#pragma dynamic 65535
|
||||
|
||||
#include <sourcemod>
|
||||
#include <AsyncSocket>
|
||||
#include <smjansson>
|
||||
|
||||
#define MAX_CLIENTS 16
|
||||
|
||||
#include "API.inc"
|
||||
#include "Subscribe.inc"
|
||||
|
||||
static AsyncSocket g_ServerSocket;
|
||||
|
||||
static AsyncSocket g_Client_Socket[MAX_CLIENTS] = { null, ... };
|
||||
static int g_Client_Subscriber[MAX_CLIENTS] = { -1, ... };
|
||||
|
||||
ConVar g_ListenAddr;
|
||||
ConVar g_ListenPort;
|
||||
|
||||
public Plugin myinfo =
|
||||
{
|
||||
name = "SM JSON API",
|
||||
author = "SourceMod TCP JSON API",
|
||||
description = "",
|
||||
version = "1.0",
|
||||
url = ""
|
||||
}
|
||||
|
||||
public void OnPluginStart()
|
||||
{
|
||||
Subscribe_OnPluginStart();
|
||||
|
||||
g_ListenAddr = CreateConVar("sm_jsonapi_addr", "127.0.0.1", "SM JSON API listen ip address", FCVAR_PROTECTED);
|
||||
g_ListenPort = CreateConVar("sm_jsonapi_port", "27021", "SM JSON API listen ip address", FCVAR_PROTECTED, true, 1025.0, true, 65535.0);
|
||||
|
||||
AutoExecConfig(true, "plugin.SMJSONAPI");
|
||||
}
|
||||
|
||||
public void OnConfigsExecuted()
|
||||
{
|
||||
if(g_ServerSocket)
|
||||
return;
|
||||
|
||||
g_ServerSocket = new AsyncSocket();
|
||||
|
||||
g_ServerSocket.SetConnectCallback(OnAsyncConnect);
|
||||
g_ServerSocket.SetErrorCallback(OnAsyncServerError);
|
||||
|
||||
char sAddr[32];
|
||||
g_ListenAddr.GetString(sAddr, sizeof(sAddr));
|
||||
int Port = g_ListenPort.IntValue;
|
||||
|
||||
g_ServerSocket.Listen(sAddr, Port);
|
||||
LogMessage("Listening on %s:%d", sAddr, Port);
|
||||
}
|
||||
|
||||
static void OnAsyncConnect(AsyncSocket socket)
|
||||
{
|
||||
int Client = GetFreeClientIndex();
|
||||
LogMessage("OnAsyncConnect(Client=%d)", Client);
|
||||
|
||||
if(Client == -1)
|
||||
{
|
||||
delete socket;
|
||||
return;
|
||||
}
|
||||
|
||||
g_Client_Socket[Client] = socket;
|
||||
socket.SetErrorCallback(OnAsyncClientError);
|
||||
socket.SetDataCallback(OnAsyncData);
|
||||
}
|
||||
|
||||
static void OnAsyncServerError(AsyncSocket socket, int error, const char[] errorName)
|
||||
{
|
||||
SetFailState("OnAsyncServerError(): %d, \"%s\"", error, errorName);
|
||||
}
|
||||
|
||||
static void OnAsyncClientError(AsyncSocket socket, int error, const char[] errorName)
|
||||
{
|
||||
int Client = ClientFromSocket(socket);
|
||||
LogMessage("OnAsyncClientError(Client=%d): %d, \"%s\"", Client, error, errorName);
|
||||
|
||||
if(Client == -1)
|
||||
{
|
||||
delete socket;
|
||||
return;
|
||||
}
|
||||
|
||||
if(g_Client_Subscriber[Client] != -1)
|
||||
{
|
||||
Subscriber_Destroy(g_Client_Subscriber[Client]);
|
||||
g_Client_Subscriber[Client] = -1;
|
||||
}
|
||||
|
||||
g_Client_Socket[Client] = null;
|
||||
delete socket;
|
||||
}
|
||||
|
||||
static void OnAsyncData(AsyncSocket socket, const char[] data, const int size)
|
||||
{
|
||||
int Client = ClientFromSocket(socket);
|
||||
|
||||
int iLine;
|
||||
int iColumn;
|
||||
static char sError[256];
|
||||
JSONValue jRequest = json_load_ex(data, sError, sizeof(sError), iLine, iColumn);
|
||||
|
||||
if(jRequest == null)
|
||||
{
|
||||
JSONObject jResponse = new JSONObject();
|
||||
|
||||
JSONObject jError = new JSONObject();
|
||||
jError.SetString("type", "json");
|
||||
jError.SetString("error", sError);
|
||||
jError.SetInt("line", iLine);
|
||||
jError.SetInt("column", iColumn);
|
||||
|
||||
jResponse.Set("error", jError);
|
||||
|
||||
jResponse.ToString(sError, sizeof(sError));
|
||||
socket.WriteNull(sError);
|
||||
|
||||
delete jResponse;
|
||||
return;
|
||||
}
|
||||
|
||||
if(jRequest.IsObject)
|
||||
{
|
||||
//view_as<JSONObject>(jRequest).DumpToServer();
|
||||
JSONObject jResponse = new JSONObject();
|
||||
// Negative values and objects indicate errors
|
||||
// 0 and positive integers indicate success
|
||||
jResponse.SetInt("error", 0);
|
||||
|
||||
HandleRequest(Client, view_as<JSONObject>(jRequest), jResponse);
|
||||
|
||||
static char sResponse[4096];
|
||||
jResponse.ToString(sResponse, sizeof(sResponse));
|
||||
socket.WriteNull(sResponse);
|
||||
delete jResponse;
|
||||
}
|
||||
|
||||
delete jRequest;
|
||||
}
|
||||
|
||||
static int HandleRequest(int Client, JSONObject jRequest, JSONObject jResponse)
|
||||
{
|
||||
static char sMethod[32];
|
||||
if(jRequest.GetString("method", sMethod, sizeof(sMethod)) < 0)
|
||||
{
|
||||
JSONObject jError = new JSONObject();
|
||||
jError.SetString("error", "Request has no 'method' string-value.");
|
||||
jResponse.Set("error", jError);
|
||||
return -1;
|
||||
}
|
||||
jResponse.SetString("method", sMethod);
|
||||
|
||||
if(StrEqual(sMethod, "subscribe") || StrEqual(sMethod, "unsubscribe") || StrEqual(sMethod, "replay"))
|
||||
{
|
||||
int Subscriber = g_Client_Subscriber[Client];
|
||||
if(Subscriber == -1)
|
||||
{
|
||||
Subscriber = Subscriber_Create(Client);
|
||||
if(Subscriber < 0)
|
||||
{
|
||||
JSONObject jError = new JSONObject();
|
||||
jError.SetString("type", "subscribe");
|
||||
jError.SetString("error", "Could not allocate a subscriber.");
|
||||
jError.SetInt("code", Subscriber);
|
||||
jResponse.Set("error", jError);
|
||||
return -1;
|
||||
}
|
||||
g_Client_Subscriber[Client] = Subscriber;
|
||||
}
|
||||
|
||||
return Subscriber_HandleRequest(Subscriber, jRequest, jResponse);
|
||||
}
|
||||
else if(StrEqual(sMethod, "function"))
|
||||
{
|
||||
static char sFunction[64];
|
||||
if(jRequest.GetString("function", sFunction, sizeof(sFunction)) < 0)
|
||||
{
|
||||
JSONObject jError = new JSONObject();
|
||||
jError.SetString("error", "Request has no 'function' string-value.");
|
||||
jResponse.Set("error", jError);
|
||||
return -1;
|
||||
}
|
||||
jResponse.SetString("function", sFunction);
|
||||
|
||||
static char sAPIFunction[64];
|
||||
Format(sAPIFunction, sizeof(sAPIFunction), "API_%s", sFunction);
|
||||
|
||||
Function Fun = GetFunctionByName(INVALID_HANDLE, sAPIFunction);
|
||||
if(Fun == INVALID_FUNCTION)
|
||||
{
|
||||
int Res = Call_StartNative(sFunction);
|
||||
if(!Res)
|
||||
{
|
||||
JSONObject jError = new JSONObject();
|
||||
jError.SetString("error", "Invalid function specified.");
|
||||
jError.SetInt("code", Res);
|
||||
jResponse.Set("error", jError);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
Call_StartFunction(INVALID_HANDLE, Fun);
|
||||
|
||||
JSONArray jArgsArray = view_as<JSONArray>(jRequest.Get("args"));
|
||||
if(jArgsArray == null || !jArgsArray.IsArray)
|
||||
{
|
||||
delete jArgsArray;
|
||||
Call_Cancel();
|
||||
JSONObject jError = new JSONObject();
|
||||
jError.SetString("error", "Request has no 'args' array-value.");
|
||||
jResponse.Set("error", jError);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int aiValues[32];
|
||||
int iValues = 0;
|
||||
|
||||
float afValues[32];
|
||||
int fValues = 0;
|
||||
|
||||
static char asValues[16][1024];
|
||||
int sValues = 0;
|
||||
|
||||
for(int i = 0; i < jArgsArray.Length; i++)
|
||||
{
|
||||
bool Fail = false;
|
||||
JSONValue jValue;
|
||||
jValue = jArgsArray.Get(i);
|
||||
|
||||
char sType1[32];
|
||||
jValue.TypeToString(sType1, sizeof(sType1));
|
||||
|
||||
if(jValue.IsArray)
|
||||
{
|
||||
JSONArray jValueArray = view_as<JSONArray>(jValue);
|
||||
JSONValue jArrayValue = jValueArray.Get(0);
|
||||
|
||||
char sType2[32];
|
||||
jArrayValue.TypeToString(sType2, sizeof(sType2));
|
||||
|
||||
if(jArrayValue.IsInteger || jArrayValue.IsBoolean)
|
||||
{
|
||||
int iValues_ = iValues;
|
||||
for(int j = 0; j < jValueArray.Length; j++)
|
||||
{
|
||||
JSONInteger jInteger = view_as<JSONInteger>(jValueArray.Get(j));
|
||||
aiValues[iValues_++] = jInteger.Value;
|
||||
delete jInteger;
|
||||
}
|
||||
|
||||
Call_PushArrayEx(aiValues[iValues], jValueArray.Length, SM_PARAM_COPYBACK);
|
||||
iValues += jValueArray.Length;
|
||||
}
|
||||
else if(jArrayValue.IsFloat)
|
||||
{
|
||||
int fValues_ = fValues;
|
||||
for(int j = 0; j < jValueArray.Length; j++)
|
||||
{
|
||||
JSONFloat jFloat = view_as<JSONFloat>(jValueArray.Get(j));
|
||||
afValues[fValues_++] = jFloat.Value;
|
||||
delete jFloat;
|
||||
}
|
||||
|
||||
Call_PushArrayEx(afValues[fValues], jValueArray.Length, SM_PARAM_COPYBACK);
|
||||
fValues += jValueArray.Length;
|
||||
}
|
||||
/*else if(jArrayValue.IsString)
|
||||
{
|
||||
int sValues_ = sValues;
|
||||
for(int j = 0; j < jValueArray.Length; j++)
|
||||
{
|
||||
JSONString jString = view_as<JSONString>(jValueArray.Get(j));
|
||||
jString.GetString(asValues[sValues_++], sizeof(asValues[]));
|
||||
delete jString;
|
||||
}
|
||||
|
||||
Call_PushArrayEx(view_as<int>(asValues[sValues]), jValueArray.Length, SM_PARAM_COPYBACK);
|
||||
sValues += jValueArray.Length;
|
||||
}*/
|
||||
else if(jArrayValue.IsArray) // Special
|
||||
{
|
||||
static char sSpecial[32];
|
||||
view_as<JSONArray>(jArrayValue).GetString(0, sSpecial, sizeof(sSpecial));
|
||||
|
||||
if(StrEqual(sSpecial, "NULL_VECTOR"))
|
||||
Call_PushArrayEx(NULL_VECTOR, 3, 0);
|
||||
else if(StrEqual(sSpecial, "NULL_STRING"))
|
||||
Call_PushString(NULL_STRING);
|
||||
else
|
||||
Fail = true;
|
||||
}
|
||||
else
|
||||
Fail = true;
|
||||
|
||||
if(Fail)
|
||||
{
|
||||
Call_Cancel();
|
||||
delete jArrayValue;
|
||||
delete jValue;
|
||||
delete jArgsArray;
|
||||
|
||||
static char sType[16];
|
||||
jValue.TypeToString(sType, sizeof(sType));
|
||||
|
||||
char sError[128];
|
||||
FormatEx(sError, sizeof(sError), "Unsupported parameter in list %d of type '%s'", i, sType);
|
||||
|
||||
JSONObject jError = new JSONObject();
|
||||
jError.SetString("error", sError);
|
||||
jResponse.Set("error", jError);
|
||||
return -1;
|
||||
}
|
||||
delete jArrayValue;
|
||||
}
|
||||
else if(jValue.IsInteger || jValue.IsBoolean)
|
||||
{
|
||||
aiValues[iValues] = view_as<JSONInteger>(jValue).Value;
|
||||
Call_PushCell(aiValues[iValues++]);
|
||||
}
|
||||
else if(jValue.IsFloat)
|
||||
{
|
||||
afValues[fValues] = view_as<JSONFloat>(jValue).Value;
|
||||
Call_PushFloat(afValues[fValues++]);
|
||||
}
|
||||
else if(jValue.IsString)
|
||||
{
|
||||
// Broken: view_as<JSONString>(jValue).GetString(asValues[sValues], sizeof(asValues[]));
|
||||
JSONString jString = view_as<JSONString>(jValue);
|
||||
jString.GetString(asValues[sValues], sizeof(asValues[]));
|
||||
Call_PushStringEx(asValues[sValues++], sizeof(asValues[]), SM_PARAM_STRING_COPY, SM_PARAM_COPYBACK);
|
||||
}
|
||||
else
|
||||
{
|
||||
Call_Cancel();
|
||||
delete jValue;
|
||||
delete jArgsArray;
|
||||
|
||||
static char sType[16];
|
||||
jValue.TypeToString(sType, sizeof(sType));
|
||||
|
||||
char sError[128];
|
||||
FormatEx(sError, sizeof(sError), "Unsupported parameter %d of type '%s'", i, sType);
|
||||
|
||||
JSONObject jError = new JSONObject();
|
||||
jError.SetString("error", sError);
|
||||
jResponse.Set("error", jError);
|
||||
return -1;
|
||||
}
|
||||
delete jValue;
|
||||
}
|
||||
|
||||
int Result;
|
||||
static char sException[1024];
|
||||
int Error = Call_FinishEx(Result, sException, sizeof(sException));
|
||||
|
||||
if(Error != SP_ERROR_NONE)
|
||||
{
|
||||
delete jArgsArray;
|
||||
JSONObject jError = new JSONObject();
|
||||
jError.SetInt("error", Error);
|
||||
jError.SetString("exception", sException);
|
||||
jResponse.Set("error", jError);
|
||||
return -1;
|
||||
}
|
||||
|
||||
jResponse.SetInt("result", Result);
|
||||
|
||||
JSONArray jArgsResponse = new JSONArray();
|
||||
iValues = 0;
|
||||
fValues = 0;
|
||||
sValues = 0;
|
||||
|
||||
for(int i = 0; i < jArgsArray.Length; i++)
|
||||
{
|
||||
JSONValue jValue;
|
||||
jValue = jArgsArray.Get(i);
|
||||
|
||||
if(jValue.IsArray)
|
||||
{
|
||||
JSONArray jArrayResponse = new JSONArray();
|
||||
JSONArray jValueArray = view_as<JSONArray>(jValue);
|
||||
JSONValue jArrayValue = jValueArray.Get(0);
|
||||
|
||||
if(jArrayValue.IsInteger || jArrayValue.IsBoolean)
|
||||
{
|
||||
for(int j = 0; j < jValueArray.Length; j++)
|
||||
jArrayResponse.AppendInt(aiValues[iValues++]);
|
||||
}
|
||||
else if(jArrayValue.IsFloat)
|
||||
{
|
||||
for(int j = 0; j < jValueArray.Length; j++)
|
||||
jArrayResponse.AppendFloat(afValues[fValues++]);
|
||||
}
|
||||
else if(jArrayValue.IsString)
|
||||
{
|
||||
for(int j = 0; j < jValueArray.Length; j++)
|
||||
jArrayResponse.AppendString(asValues[sValues++]);
|
||||
}
|
||||
else if(jArrayValue.IsArray) // Special
|
||||
{
|
||||
static char sSpecial[32];
|
||||
view_as<JSONArray>(jArrayValue).GetString(0, sSpecial, sizeof(sSpecial));
|
||||
jArrayResponse.AppendString(sSpecial);
|
||||
}
|
||||
delete jArrayValue;
|
||||
jArgsResponse.Append(jArrayResponse);
|
||||
}
|
||||
else if(jValue.IsInteger || jValue.IsBoolean)
|
||||
{
|
||||
jArgsResponse.AppendInt(aiValues[iValues++]);
|
||||
}
|
||||
else if(jValue.IsFloat)
|
||||
{
|
||||
jArgsResponse.AppendFloat(afValues[fValues++]);
|
||||
}
|
||||
else if(jValue.IsString)
|
||||
{
|
||||
jArgsResponse.AppendString(asValues[sValues++]);
|
||||
}
|
||||
delete jValue;
|
||||
}
|
||||
|
||||
jResponse.Set("args", jArgsResponse);
|
||||
|
||||
delete jArgsArray;
|
||||
return 0;
|
||||
}
|
||||
|
||||
JSONObject jError = new JSONObject();
|
||||
jError.SetString("error", "No handler found for requested method.");
|
||||
jResponse.Set("error", jError);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int PublishEvent(int Client, JSONObject Object)
|
||||
{
|
||||
if(Client < 0 || Client > MAX_CLIENTS || g_Client_Socket[Client] == null)
|
||||
return -1;
|
||||
|
||||
static char sEvent[4096];
|
||||
Object.ToString(sEvent, sizeof(sEvent));
|
||||
g_Client_Socket[Client].WriteNull(sEvent);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int GetFreeClientIndex()
|
||||
{
|
||||
for(int i = 0; i < MAX_CLIENTS; i++)
|
||||
{
|
||||
if(!g_Client_Socket[i])
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int ClientFromSocket(AsyncSocket socket)
|
||||
{
|
||||
for(int i = 0; i < MAX_CLIENTS; i++)
|
||||
{
|
||||
if(g_Client_Socket[i] == socket)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
279
SMJSONAPI/scripting/Subscribe.inc
Normal file
279
SMJSONAPI/scripting/Subscribe.inc
Normal file
@ -0,0 +1,279 @@
|
||||
#include "GameEvents.inc"
|
||||
|
||||
#define MAX_SUBSCRIBERS MAX_CLIENTS
|
||||
|
||||
enum
|
||||
{
|
||||
eSubscribeError_OutOfRange = -1,
|
||||
eSubscribeError_Inactive = -2,
|
||||
eSubscribeError_GameEvent = -3,
|
||||
}
|
||||
|
||||
static bool g_Subscriber_Active[MAX_SUBSCRIBERS] = { false, ... };
|
||||
static int g_Subscriber_Client[MAX_SUBSCRIBERS] = { -1, ... };
|
||||
|
||||
static ArrayList g_Subscriber_GameEvents[MAX_SUBSCRIBERS];
|
||||
|
||||
bool Subscribe_OnPluginStart()
|
||||
{
|
||||
GameEvents_Init();
|
||||
}
|
||||
|
||||
int Subscriber_Create(int Client)
|
||||
{
|
||||
int Index = Client;
|
||||
if(Index < 0 || Index >= MAX_SUBSCRIBERS || g_Subscriber_Active[Index])
|
||||
{
|
||||
Index = GetFreeSubscriberIndex();
|
||||
if(Index == eSubscribeError_OutOfRange)
|
||||
return eSubscribeError_OutOfRange;
|
||||
}
|
||||
|
||||
g_Subscriber_Active[Index] = true;
|
||||
g_Subscriber_Client[Index] = Client;
|
||||
|
||||
g_Subscriber_GameEvents[Index] = new ArrayList(ByteCountToCells(32));
|
||||
|
||||
return Index;
|
||||
}
|
||||
|
||||
int Subscriber_Destroy(int Index)
|
||||
{
|
||||
if(Index < 0 || Index >= MAX_SUBSCRIBERS)
|
||||
return eSubscribeError_OutOfRange;
|
||||
|
||||
if(!g_Subscriber_Active[Index])
|
||||
return eSubscribeError_Inactive;
|
||||
|
||||
for(int i = 0; i < g_Subscriber_GameEvents[Index].Length; i++)
|
||||
{
|
||||
static char sEventName[32];
|
||||
g_Subscriber_GameEvents[Index].GetString(i, sEventName, sizeof(sEventName));
|
||||
GameEvents_Unhook(sEventName);
|
||||
}
|
||||
|
||||
delete g_Subscriber_GameEvents[Index];
|
||||
|
||||
g_Subscriber_Active[Index] = false;
|
||||
g_Subscriber_Client[Index] = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Subscriber_HandleRequest(int Index, JSONObject Request, JSONObject Response)
|
||||
{
|
||||
static char sMethod[32];
|
||||
Request.GetString("method", sMethod, sizeof(sMethod));
|
||||
|
||||
static char sModule[32];
|
||||
if(Request.GetString("module", sModule, sizeof(sModule)) < 0)
|
||||
{
|
||||
JSONObject jError = new JSONObject();
|
||||
jError.SetString("error", "Request has no 'module' string-value.");
|
||||
Response.Set("error", jError);
|
||||
return -1;
|
||||
}
|
||||
Response.SetString("module", sModule);
|
||||
|
||||
if(StrEqual(sModule, "gameevents"))
|
||||
{
|
||||
JSONArray EventArray = view_as<JSONArray>(Request.Get("events"));
|
||||
if(EventArray == null || !EventArray.IsArray)
|
||||
{
|
||||
delete EventArray;
|
||||
JSONObject jError = new JSONObject();
|
||||
jError.SetString("error", "Request has no 'events' array-value.");
|
||||
Response.Set("error", jError);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int Method = 0;
|
||||
if(StrEqual(sMethod, "subscribe"))
|
||||
Method = 1;
|
||||
else if(StrEqual(sMethod, "unsubscribe"))
|
||||
Method = 2;
|
||||
else if(StrEqual(sMethod, "replay"))
|
||||
Method = 3;
|
||||
|
||||
JSONArray EventArrayResponse = new JSONArray();
|
||||
|
||||
for(int i = 0; i < EventArray.Length; i++)
|
||||
{
|
||||
static char sEventName[32];
|
||||
if(EventArray.GetString(i, sEventName, sizeof(sEventName)) < 0)
|
||||
{
|
||||
JSONObject jError = new JSONObject();
|
||||
jError.SetString("error", "not a string-value");
|
||||
EventArrayResponse.Append(jError);
|
||||
continue;
|
||||
}
|
||||
|
||||
int Res;
|
||||
if(Method == 1)
|
||||
Res = Subscribe_GameEvents_Subscribe(Index, sEventName);
|
||||
else if(Method == 2)
|
||||
Res = Subscribe_GameEvents_Unsubscribe(Index, sEventName);
|
||||
else if(Method == 3)
|
||||
Res = Subscribe_GameEvents_Replay(Index, sEventName);
|
||||
|
||||
EventArrayResponse.AppendInt(Res);
|
||||
}
|
||||
delete EventArray;
|
||||
|
||||
Response.Set("events", EventArrayResponse);
|
||||
return 0;
|
||||
}
|
||||
|
||||
JSONObject jError = new JSONObject();
|
||||
jError.SetString("error", "No handler found for requested module.");
|
||||
Response.Set("error", jError);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int GetFreeSubscriberIndex()
|
||||
{
|
||||
for(int i = 0; i < MAX_SUBSCRIBERS; i++)
|
||||
{
|
||||
if(!g_Subscriber_Active[i])
|
||||
return i;
|
||||
}
|
||||
return eSubscribeError_OutOfRange;
|
||||
}
|
||||
|
||||
/* GameEvents */
|
||||
static int Subscribe_GameEvents_Subscribe(int Index, const char[] sEventName)
|
||||
{
|
||||
if(Index < 0 || Index >= MAX_SUBSCRIBERS)
|
||||
return eSubscribeError_OutOfRange;
|
||||
|
||||
if(!g_Subscriber_Active[Index])
|
||||
return eSubscribeError_Inactive;
|
||||
|
||||
int Find = g_Subscriber_GameEvents[Index].FindString(sEventName);
|
||||
if(Find != -1)
|
||||
return Find;
|
||||
|
||||
if(GameEvents_Hook(sEventName) < 0)
|
||||
return eSubscribeError_GameEvent;
|
||||
|
||||
return g_Subscriber_GameEvents[Index].PushString(sEventName);
|
||||
}
|
||||
|
||||
static int Subscribe_GameEvents_Unsubscribe(int Index, const char[] sEventName)
|
||||
{
|
||||
if(Index < 0 || Index >= MAX_SUBSCRIBERS)
|
||||
return eSubscribeError_OutOfRange;
|
||||
|
||||
if(!g_Subscriber_Active[Index])
|
||||
return eSubscribeError_Inactive;
|
||||
|
||||
int Find = g_Subscriber_GameEvents[Index].FindString(sEventName);
|
||||
if(Find == -1)
|
||||
return 0;
|
||||
|
||||
if(GameEvents_Unhook(sEventName) < 0)
|
||||
return eSubscribeError_GameEvent;
|
||||
|
||||
g_Subscriber_GameEvents[Index].Erase(Find);
|
||||
return Find;
|
||||
}
|
||||
|
||||
static int Subscribe_GameEvents_Replay(int Index, const char[] sEventName)
|
||||
{
|
||||
if(Index < 0 || Index >= MAX_SUBSCRIBERS)
|
||||
return eSubscribeError_OutOfRange;
|
||||
|
||||
if(!g_Subscriber_Active[Index])
|
||||
return eSubscribeError_Inactive;
|
||||
|
||||
if(StrEqual(sEventName, "player_connect"))
|
||||
{
|
||||
for(int client = 1; client <= MaxClients; client++)
|
||||
{
|
||||
if(!IsClientConnected(client))
|
||||
continue;
|
||||
|
||||
char sName[MAX_NAME_LENGTH];
|
||||
GetClientName(client, sName, sizeof(sName));
|
||||
|
||||
char sSteamID[32];
|
||||
GetClientAuthId(client, AuthId_Engine, sSteamID, sizeof(sSteamID), false);
|
||||
|
||||
char sAddress[32];
|
||||
GetClientIP(client, sAddress, sizeof(sAddress), false);
|
||||
|
||||
JSONObject jEventData = new JSONObject();
|
||||
jEventData.SetString("name", sName);
|
||||
char sBuf[MAX_NAME_LENGTH];
|
||||
jEventData.GetString("name", sBuf, sizeof(sBuf));
|
||||
jEventData.SetInt("index", client - 1);
|
||||
jEventData.SetInt("userid", GetClientUserId(client));
|
||||
jEventData.SetString("networkid", sSteamID);
|
||||
jEventData.SetString("address", sAddress);
|
||||
jEventData.SetBool("bot", IsFakeClient(client));
|
||||
|
||||
Subscribe_GameEvents_FakePublish(g_Subscriber_Client[Index], sEventName, jEventData);
|
||||
}
|
||||
}
|
||||
else if(StrEqual(sEventName, "player_activate"))
|
||||
{
|
||||
for(int client = 1; client <= MaxClients; client++)
|
||||
{
|
||||
if(!IsClientInGame(client))
|
||||
continue;
|
||||
|
||||
JSONObject jEventData = new JSONObject();
|
||||
jEventData.SetInt("userid", GetClientUserId(client));
|
||||
|
||||
Subscribe_GameEvents_FakePublish(g_Subscriber_Client[Index], sEventName, jEventData);
|
||||
}
|
||||
}
|
||||
else
|
||||
return eSubscribeError_GameEvent;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int Subscribe_GameEvents_FakePublish(int Index, const char[] sEventName, JSONObject jEventData)
|
||||
{
|
||||
if(Index < 0 || Index >= MAX_SUBSCRIBERS)
|
||||
return eSubscribeError_OutOfRange;
|
||||
|
||||
if(!g_Subscriber_Active[Index])
|
||||
return eSubscribeError_Inactive;
|
||||
|
||||
JSONObject jEvent = new JSONObject();
|
||||
jEvent.SetString("name", sEventName);
|
||||
jEvent.Set("data", jEventData);
|
||||
|
||||
JSONObject jPublish = new JSONObject();
|
||||
jPublish.SetString("method", "publish");
|
||||
jPublish.SetString("module", "gameevents");
|
||||
jPublish.Set("event", jEvent);
|
||||
|
||||
PublishEvent(g_Subscriber_Client[Index], jPublish);
|
||||
delete jPublish;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Subscribe_GameEvents_Publish(const char[] sEventName, JSONObject jEvent)
|
||||
{
|
||||
JSONObject jPublish = new JSONObject();
|
||||
jPublish.SetString("method", "publish");
|
||||
jPublish.SetString("module", "gameevents");
|
||||
jPublish.Set("event", jEvent);
|
||||
|
||||
for(int Index = 0; Index < MAX_SUBSCRIBERS; Index++)
|
||||
{
|
||||
if(!g_Subscriber_Active[Index])
|
||||
continue;
|
||||
|
||||
if(g_Subscriber_GameEvents[Index].FindString(sEventName) == -1)
|
||||
continue;
|
||||
|
||||
PublishEvent(g_Subscriber_Client[Index], jPublish);
|
||||
}
|
||||
|
||||
delete jPublish;
|
||||
}
|
||||
/* GameEvents */
|
1
SMJSONAPI/scripting/include/AsyncSocket.inc
Symbolic link
1
SMJSONAPI/scripting/include/AsyncSocket.inc
Symbolic link
@ -0,0 +1 @@
|
||||
../../../includes/AsyncSocket.inc
|
1
SMJSONAPI/scripting/include/smjansson.inc
Symbolic link
1
SMJSONAPI/scripting/include/smjansson.inc
Symbolic link
@ -0,0 +1 @@
|
||||
../../../includes/smjansson.inc
|
Loading…
Reference in New Issue
Block a user