Compare commits

..
Author SHA1 Message Date
David Anderson 49e2303a5b Bumped version to 1.3.3 for release. 2010-06-23 23:44:14 -07:00
David Anderson fe0b9f7320 Updated changelog. 2010-06-23 23:43:09 -07:00
David Anderson b16c758f88 Removed code now dead from CS:S Orange Box move (bug 4399, r+a13=ds). 2010-06-23 23:35:28 -07:00
Nicholas Hastings da729c3c08 Removed cstrike ep1 and cstrike_beta builds and references. (bug 4399, r=dvander) 2010-06-23 23:53:16 -04:00
Erik Minekus f1bcb2ad3e Fixed lack of error checking on sm_motd. (bug 4460, r=dvander) 2010-06-23 23:42:22 -04:00
Nicholas Hastings 9270399eb1 Forcing (re)build(?) since Windows had a strange fail. 2010-06-23 10:33:51 -04:00
Nicholas Hastings 76e6edbad4 Cstrike ext now recognizes and loads on cstrike_beta (bug 4399, r=fyren) 2010-06-23 10:12:55 -04:00
devicenull 58ca1508bc Fixed inaccuracy in CommandListener documentation 2010-06-23 09:23:23 -04:00
Greyscale eed1df28ec Removed unnecessary tag from return value of SetArrayCell 2010-06-23 09:17:53 -04:00
Nicholas Hastings a602d7d107 Ep2v cstrike ext now gets added to package. 2010-06-23 09:02:04 -04:00
Nicholas Hastings 9a08986fd1 Silly AMBuild 2010-06-23 08:32:25 -04:00
Nicholas Hastings 5d1820853a Adding building of cstrike ext for ep2v (bug 4399, r=fyren) 2010-06-23 08:29:15 -04:00
Nicholas Hastings 753aced2a3 Added missing TF2 critcola condflag define (bug 4464, r=fyren) 2010-06-22 19:31:33 -04:00
Nicholas Hastings df47457321 Updated TF2 'Burn' signature (bug 4463, r=fyren) 2010-06-22 19:26:07 -04:00
Fyren d9e818e5d9 Possible dynamic array dimension fix (bug 4428, r=dvander) 2010-06-19 15:17:10 -07:00
Nicholas Hastings 47c840c9b4 Fixed outputname null pointer crash in sdktools (bug 4422, r=fyren) 2010-06-14 09:32:50 -04:00
David Anderson 2bfc5d3e1e Fixed switch case comparisons failing with large numbers (bug 4457, r=pred). 2010-06-13 20:26:58 -07:00
Nicholas Hastings 4307c57697 Added missing FireOutput and PlayerRunCmd gamedata for zombie_master (bug 4452, r=fyren) 2010-06-07 19:39:15 -04:00
Nicholas Hastings bff0faff52 Added new player condition (TFCond_CritCola) to tf2.inc. (bug 4447, r=fyren) 2010-06-06 20:55:25 -04:00
Matt Woodrow 749966ae66 Fixed clientprefs deleting cookies twice in rare cases (bug 4412, r=Fyren) 2010-06-07 10:30:33 +12:00
Nicholas Hastings 9f11132fb5 Fixed OnClientConnected forward not firing for bots (bug 4443, r=fyren) 2010-06-06 17:53:38 -04:00
Fyren 2dfbd1fc1f Fix sdktools voice memory corruption (bug 4415, r=dvander) 2010-06-05 23:21:33 -07:00
Nicholas Hastings 7c659837bf Updated Obsidian Conflict gamedata (bug 4439, r=fyren) 2010-06-02 07:54:15 -04:00
Nicholas Hastings 7cf342a1a7 Fixed tf2.inc incorrectly attempting to load tf2 ext on all games (bug 4197, r=fyren) 2010-05-31 16:36:10 -04:00
Scott Ehlert e8d6aab989 Triggering build. 2010-05-29 00:55:06 -05:00
Nicholas Hastings 0819278465 Updated/fixed SourceForts gamedata (bug 4429, r=fyren) 2010-05-28 13:29:13 -04:00
Nicholas Hastings d89c57ba79 Fixed SDKTools sm_dump_datamaps crash on improperly created entities (bug 4424, r=pred) 2010-05-26 08:31:48 -04:00
Nicholas Hastings 23b10fc559 Added gamedata for Resistance and Liberation (bug 4418, r=fyren) 2010-05-21 14:04:19 -04:00
Nicholas Hastings 36e8e881e8 Empires gamedata fixes (bug 4417, r=fyren). 2010-05-21 13:55:29 -04:00
Nicholas Hastings 67011834df Updated gamedata for ep2v cstrike(_beta) (bug 4399, r=fyren) 2010-05-11 20:40:14 -04:00
Scott Ehlert ed9f68814f Added missing -dev back to product.version. 2010-05-13 09:35:30 -05:00
Nicholas Hastings 79a8008280 Fixed TF2 natives not being marked optional when ext not required (bug 4389, r=fyren) 2010-05-10 18:18:34 -04:00
Nicholas Hastings 643dce8cb1 Updated Empires gamedata (bug 4390, r=fyren) 2010-05-08 21:39:50 -04:00
Scott Ehlert 3669b98986 Fixed SendConVarValue() on TF2, DOD:S, L4D, and L4D2 (bug 4273, r=dvander, a=blocking). 2010-05-04 22:49:46 -04:00
David Anderson e075b7b9b2 Bumped version to 1.3.3-dev. 2010-05-02 14:41:51 -07:00
David Anderson b95fda8342 Added tag sourcemod-1.3.2 for changeset a3e8f7a7fdf7 2010-05-02 14:39:43 -07:00
David Anderson 5abec70579 Bumped for release. 2010-05-02 14:16:34 -07:00
Nicholas Hastings 8800d5311c Added TF2_StunPlayer native and TF2_GetPlayerConditionFlags stock to TF2 ext. (bug 4331, r=pred) 2010-03-31 08:51:25 -04:00
Nicholas Hastings 3705210879 Added 4 new natives to TF2 ext. (bug 4166, r=pred)
Added natives for Regenerate, add/remove condition, and SetPlayerPowerPlay. Also updated TF2 test plugin.
2010-03-18 11:35:05 -04:00
Scott Ehlert 5f4befcb6a Argh, really fixed HookEntityOutput() crash on TF2 (bug 4375). 2010-04-30 10:54:34 -04:00
Scott Ehlert 314011f118 Fixed HookEntityOutput() crash with recent updates to TF2 and L4D2 (bug 4375, r=pred, a=blocking). 2010-04-30 03:51:01 -04:00
Fyren a9b7a5dc5c Triggering build 2010-04-29 20:55:16 -07:00
Scott Ehlert 9b78c68b1b Updated sample extension makefiles to compile against latest changes for L4D2 and TF2 (bug 4374, r=dvander). 2010-04-29 16:04:47 -04:00
Nicholas Hastings 328109be1f Fixed SetUserCvar offset for ep2v (bug 4371, r=fyren) 2010-04-29 14:17:44 -04:00
Nicholas Hastings aba0f29666 ep2v gamedata (bug 4371, r=fyren) 2010-04-28 23:48:26 -07:00
Fyren bdefb58e5f ep2v build changes (bug 4371, r=dvander) 2010-04-28 19:44:20 -07:00
David Anderson 7ad3a57c47 Check return value of GetPlayerNetInfo (bug 4315, r=fyren). 2010-04-27 23:40:04 -07:00
Nicholas Hastings 5a2f3cf433 Fixed entity output hooks not working in Insurgency (bug 4365, r=fyren) 2010-04-24 21:10:15 -04:00
Nicholas Hastings fffc27a348 Added obsidian to list of games which support tempents with ep2 gamedata (thread 75480, r=me). 2010-04-24 21:08:13 -04:00
Nicholas Hastings cecb7cb6a2 Fixed functions.inc not having double-include prevention (bug 4342, r=fyren) 2010-04-24 21:05:48 -04:00
Zach Kanzler f5cc5eb757 Fixed IGamePlayer->GetUserId() returning junk (bug 3916, r=fyren) 2010-04-24 21:02:40 -04:00
Nicholas Hastings 689406744b Updated L4D2 gamedata for The Passing update (bug 4361, r=pending) 2010-04-23 12:11:49 -04:00
Nicholas Hastings 603da899b7 Updated Insurgency gamedata for Insurgency 2010-04-19 update (bug 4356, r=fyren) 2010-04-23 10:38:37 -04:00
Fyren 9b4d1f6972 Build stuff for L4D2 DLC (bug 4361, r=what's a review?) 2010-04-23 07:33:58 -07:00
David Anderson d56b222637 Merge backout. 2010-04-23 02:31:15 -04:00
David Anderson dfefda81e1 Backed out changeset 6b5fa86c1a0d (bug 4315). 2010-04-23 02:31:07 -04:00
David Anderson 0c463b1f86 Merge. 2010-04-22 17:55:55 -04:00
David Anderson bf345eea8c Attempting fix for SendConVarValue crash (bug 4315, r=fyren, a13=me). 2010-04-22 17:55:35 -04:00
Nicholas Hastings 5328447b74 Merge 2010-04-19 11:15:51 -04:00
Nicholas Hastings db6881b7e3 Updated Empires gamedata for Empires 2.25a release (bug 4108, r=fyren) 2010-04-19 10:38:50 -04:00
David Anderson 3e96b1617a Added obsidian to list of games which need menu redraws (thread 123237, r=me). 2010-04-04 23:51:20 -07:00
Nicholas Hastings 7ef8b415bb Added Gamerules SDKCall support to CSPromod gamedata (bug 4320, r=pred) 2010-03-23 19:42:58 -04:00
Nicholas Hastings 9a5d6957b9 Fixed bad caller crash with HookEntityOutput (bug 4311, r=fyren) 2010-03-20 11:08:48 -04:00
Nicholas Hastings b5a2ec7a5e Added missing core voting cvars to sourcemod.cfg (bug 4309, r=fyren) 2010-03-11 22:01:11 -05:00
Nicholas Hastings 373136af4e Added missing core voting cvars to sourcemod.cfg (bug 4224, r=pred) 2010-03-11 17:44:41 -05:00
Nicholas Hastings 8673c11341 Fixed incorrect DispatchSpawn signature for ZPS and added ShowMenu and Hudtext support (bug 4279, r=Fyren) 2010-03-09 20:40:06 -05:00
Nicholas Hastings 8c082de148 Re-enabled ShowMenu support for FortressForever (bug 4028, r=dvander) 2010-03-09 18:50:57 -05:00
Nicholas Hastings e62d47a85e Fixed FireOutput signature for FortressForever (bug 4062, r=dvander) 2010-03-09 18:48:03 -05:00
Nicholas Hastings 2d32c587ba Fixed sm_rename on L4D2 on Windows (bug 4131, r=dvander) 2010-03-09 18:44:28 -05:00
Nicholas Hastings 31e29ee94c Fixed inaccurate description for sm_unban (bug 4245, r=dvander) 2010-03-09 18:41:43 -05:00
Nicholas Hastings e95e453258 Fixed CSPromod SDKTools Support (bug 4255, r=dvander) 2010-03-09 18:36:51 -05:00
Nicholas Hastings 48b0f61551 Updated PVKII support for PVKII 2.3 (bug 4276, r=dvander) 2010-03-09 18:30:15 -05:00
Nicholas Hastings ef88fc21a1 Fixed CreateGameRulesObject sig for ZPS (bug 4285, r=dvander). 2010-03-09 18:15:23 -05:00
Erik Minekus 558c8c9745 Fixed Insurgency gamedata file (bug 4282, r+a13=dvander). 2010-02-24 23:41:06 -08:00
Fyren 2f60680cfb maxClients -> MaxClients in sdktools_sound.inc (fix bug 3985, r=psychonicsux) 2010-02-10 10:53:54 -08:00
David Anderson 1ffcf7a664 Bumped version to 1.3.2-dev. 2010-02-09 22:00:28 -08:00
David Anderson c00b688ab7 Added tag sourcemod-1.3.1 for changeset 3f33d01fcc28 2010-02-09 21:59:41 -08:00
David Anderson 4169e25451 Removed -dev tag for release. 2010-02-09 21:12:39 -08:00
David Anderson 85fc65bae5 Updated changelog for 1.3.1. 2010-02-08 20:58:15 -08:00
Nicholas Hastings aed62d5670 Added missing file for Battlegrounds support (bug 4146). 2010-02-08 20:47:51 -08:00
Nicholas Hastings 01d46b8c9c Added SDKTools support for CSProMod (bug 4255, r+a13=dvander) 2010-02-08 20:25:11 -08:00
Nicholas Hastings f70b48276e Fixed base plugins using GetMaxClients() instead of MaxClients (bug 3985, r+a13=dvander). 2010-02-08 20:14:52 -08:00
Nicholas Hastings f0070e45a0 Fixed CreateEntityByName for Insurgency (bug 4180, r+a13=dvander). 2010-02-08 20:10:24 -08:00
Nicholas Hastings 11782cee90 Updated Garry's Mod offsets (bug 4230, r+a13=dvander). 2010-02-08 20:08:14 -08:00
Nicholas Hastings 24b86584a2 Fixed nextmap errors on Garry's Mod (bug 4268, r+a13=dvander). 2010-02-08 20:06:48 -08:00
Fyren 01b3eee1b8 Compiler confused |any| tag with |String| on array arguments (bug 4274, r=dvander, a13=blocking). 2010-02-08 20:00:06 -08:00
David Anderson 2fb3f8ab0f Fixed GetClientCookieTime not being exported (bug 4237, r=fyren, a13=blocking). 2010-02-08 19:58:36 -08:00
Nicholas Hastings 2c7b0e04e9 Fixed FindEntityByClassname crash in Synergy (bug 4235, r=dvander, a13=blocking). 2010-02-08 19:57:20 -08:00
Fyren 9f3e9a2ff4 Fixed NULL-deref in entity handling code (bug 4249, r=dvander, a13=blocking). 2010-02-08 19:55:14 -08:00
Nicholas Hastings d9d5b65f2c Fixed Day of Defeat offsets for 20100203 update (bug 4262, r=dvander, a13=blocking). 2010-02-04 19:28:06 -06:00
Scott Ehlert 90cc2d6c37 Webternet and Updater extensions now load on Windows 2000 (bug 4234, r+a13=dvander). 2010-01-20 15:11:13 -06:00
David Anderson 1ab5403f9f Fixed accidental hook against garbage offset (bug 4231, r=fyren, a13=blocking). 2010-01-20 04:03:46 -08:00
David Anderson 4d03a4ef60 Added PlayerRunCmd offset for DoD:s (bug 4231 mitigation, r=me). 2010-01-20 04:01:39 -08:00
Scott Ehlert 46b714108a Updated .hgignore for Explorer files beginning with a lowercase letter (argh!) 2010-01-20 02:39:52 -06:00
David Anderson 242e1c99e2 Bumped version to 1.3.1-dev. 2010-01-14 23:34:20 -08:00
David Anderson 3d0e661cd6 Added tag sourcemod-1.3.0 for changeset a71318396392 2010-01-14 23:33:20 -08:00
David Anderson d076aca9ea Forgotten file needed version bump. 2010-01-14 22:26:57 -08:00
David Anderson f824a53f21 Another credits update. 2010-01-14 03:34:26 -08:00
David Anderson 87ca5e6e05 Prep for release. 2010-01-14 03:30:20 -08:00
David Anderson 23af5357c0 Updated credits for 1.3 release. 2010-01-14 03:29:16 -08:00
David Anderson d6b82d5dcc Updated changelog. 2010-01-14 03:26:16 -08:00
David Anderson 664da97c42 Registering "sm" logs an error, but will not throw. 2010-01-14 01:11:38 -08:00
Greyscale b6507b12d4 Fixed missing #endif in adminmenu.inc (bug 4216, r+a13=dvander). 2010-01-14 00:22:45 -08:00
David Anderson a5ab381c0a Fixed command listener spew on server shutdown (bug 4198, r=fyren, a13=blocking). 2010-01-13 21:48:51 -08:00
David Anderson 8ec5e42c7a Merge. 2010-01-11 20:10:57 -08:00
David Anderson 006423dcf2 Triggering build. 2010-01-11 20:10:38 -08:00
Nicholas Hastings d0f4d943b6 Added missing SDK define for L4D2 (bug 4209, r+a13=dvander). 2010-01-10 17:38:03 -08:00
Nicholas Hastings 2fd9674e09 Follow-up to bug 4194 (r=dvander). 2010-01-10 17:29:32 -08:00
David Anderson 23fca5e645 Merge. 2010-01-10 17:17:22 -08:00
David Anderson 4beb7fe869 Backed out changeset f8861500d3bc (bug 4211). 2010-01-10 17:17:16 -08:00
David Anderson 2e832f2d01 Fixed reentrancy problems with iterators, forwards, and function removals (bug
4059, r=fyren, a13=blocking).
2010-01-10 16:58:17 -08:00
Fyren 43602da743 Fixed GuessSDKVersion() not working on ep2v (bug 4194, r=dvander, a13=blocking). 2010-01-09 11:33:19 -08:00
Nicholas Hastings 763b73b9c5 Fixed SetUserCvar (sm_rename) on TF/DoD Linux (bug 4196, r=dvander, a13=blocking). 2010-01-07 01:26:01 -08:00
Nicholas Hastings ffb6e84b45 Add Insurgency to list of games that support HUD messages (bug 4136, r+a13=dvander). 2009-12-19 20:42:32 -08:00
David Anderson 025f216e09 Fixed crashes from rare plugin loading errors (bug 4153, r=ds). 2009-12-19 18:19:28 -08:00
David Anderson 603ac75a08 Fixed SourceMod crashing after flushing the profiler (bug 4149, r=ds). 2009-12-19 18:18:17 -08:00
David Anderson 1b07722848 Add ability to change dontBroadcast status on hooked events (bug 3886, r=ds). 2009-12-19 18:16:41 -08:00
Nicholas Hastings 4de8d67e27 Another TF2 gamedata fix (bug 4151, r=dvander). 2009-12-19 12:57:26 -08:00
Nicholas Hastings 83baabe00a Battlegrounds 2 gamedata support (bug 4146, r+a13=dvander). 2009-12-19 00:03:57 -08:00
Nicholas Hastings 3080ca1ccb TF2 gamedata updates (bug 4147, r=dvander). 2009-12-18 22:01:41 -08:00
David Anderson c3b0f8a4d2 Fixed infinite loop in Windows build failure path (bug 4144, r=ds). 2009-12-14 23:07:54 -08:00
David Anderson 726ee43736 Fixed profiler being set to NULL (bug 4143, r=fyren). 2009-12-14 23:08:15 -08:00
Fyren 8e1f37a5d2 Improve/fix GetEntity (bug 4092, r=pred) 2009-12-15 23:13:53 -08:00
Dog ce342ef6fc Fixed CommitSuicide offset on DoD:S (bug 4109, r=dvander). 2009-12-14 20:26:45 -08:00
Nicholas Hastings 0a6acda737 Fixed CreateEntityByName for Insurgency (bug 4046, r+a13=dvander). 2009-12-14 20:31:16 -08:00
Nicholas Hastings c907c723c3 Updated Synergy gamedata (bug 3987, r=dvander). 2009-12-14 20:30:44 -08:00
Nicholas Hastings 479815911d Added HudText support for Zombie Master (bug 4004, r+a13=dvander). 2009-12-14 20:30:04 -08:00
Nicholas Hastings 29954ec122 Added Neotokyo support (bug 4126, r+a13=dvander). 2009-12-14 20:29:23 -08:00
David Anderson 75455b65da Fixed basecomm description spelling (bug 4112, r=me). 2009-12-14 20:27:26 -08:00
Fyren 5688eb55ec Fix wonky handling of path separators for "sm plugins" commands (bug 3857, r=dvander) 2009-11-23 02:27:24 -08:00
Scott Ehlert 2e4aae95db Updated .hgignore to ignore some Windows and OS X files. 2009-11-22 01:39:29 -06:00
Scott Ehlert cc43b63508 Updated sample_ext and mms_sample_ext for Orange Box Valve and Left 4 Dead 2 (bug 4118, r=pred). 2009-11-22 01:33:08 -06:00
David Anderson 59593a2d5f Use GetVSPInfo() from MM:S 1.8 legacy API (bug 4081, r=ds). 2009-11-20 15:18:58 -06:00
Fyren e3f5d5b6cf Fix leak in nominations plugin (bug 4104, r=pred) 2009-11-18 15:44:51 -08:00
Fyren 6085125367 Fix rare basevotes map vote problem (bug 3905, r=dvander) 2009-11-18 15:42:21 -08:00
Scott Ehlert 27805463e3 Added IMemoryUtils::ResolveSymbol() for resolving symbols hidden via GCC's -fvisibility=hidden (bug 4091, r=dvander,pred).
Right now, this is only used on L4D2 where it is needed.
2009-11-06 16:24:40 -06:00
David Anderson 45f2b9f8ca Clarified handle invariants in clientprefs.inc (no bug, r=me). 2009-11-04 13:52:12 -05:00
Fyren 2bd979d62e Don't call edict_t::StateChanged(ushort) on L4D2 (bug 4090, r=dvander) 2009-11-01 02:53:34 -08:00
Scott Ehlert e434c43e28 Use SOURCE_ENGINE_ORANGEBOXVALVE constant from MM:S 1.8 (bug 4087, r=dvander). 2009-10-30 14:04:43 -05:00
Fyren 02922df1cd More L4D2 gamedata changes 2009-10-30 01:24:55 -07:00
Scott Ehlert 035875f5c1 Fixed Windows build, I think. 2009-10-30 00:03:54 -05:00
Fyren e3a3dda1d8 Typo fix 2009-10-29 20:34:00 -07:00
Scott Ehlert 7187dde64d Changed name in credits. 2009-10-29 17:35:00 -05:00
Matt Woodrow fd09d7b176 New sdk uses _linux for vstdlib/tier0 2009-10-30 15:20:48 +13:00
Matt Woodrow 4e8fc2749b AMBuild updated to use new MM:S version 2009-10-30 14:58:17 +13:00
Fyren 8b362700ff Updated GuessSDKVersion 2009-10-30 14:34:34 +13:00
Matt Woodrow e926a3b94b SourceMod MSVC project files updated, windows tested and loading, gamedata fix. 2009-10-30 14:29:45 +13:00
Matt Woodrow 83d1fc9abe L4D2 gamedata updates 2009-10-30 13:27:05 +13:00
Matt Woodrow d6a5d99e55 AMBuild updated for new L4D2 engine 2009-10-30 13:27:19 +13:00
Fyren 6322a711c2 Inital SM fixes for l4d2 and linux makefile updates 2009-10-30 13:26:13 +13:00
David Anderson e024871b50 Use GetSourceEngineBuild() from MM:S 1.8 legacy API (bug 4083, r=ds). 2009-10-29 01:33:57 -07:00
David Anderson b4e939e273 Let SourceMod use OnUnlinkConCommandBase from MM:S 1.8 legacy API (bug 4080, r=ds). 2009-10-29 00:53:31 -07:00
David Anderson 13743376ee Build against MM:S 1.8 with core-legacy (bug 4076, r=ds). 2009-10-28 23:30:52 -07:00
David Anderson 69cfd36054 Fix iloop race when using AddCommandListener and SourceMod unloads (bug 4077, r=pred). 2009-10-29 00:07:15 -07:00
David Anderson 7d15ec4d15 Fixed crash when activating command listeners on EP1 while inside a command callback (bug 4072, r=pred). 2009-10-28 00:50:48 -07:00
David Anderson b52a10f28b Added feature testing functionality (bug 4021, r=pred). 2009-10-28 00:37:34 -07:00
David Anderson da7c65f0e3 Fix maphistory command not returning a value (bug 4069, r=pred, a13=blocking). 2009-10-28 01:55:42 -07:00
David Anderson a5d2945fc5 Added @spec target (bug 2718, r=fyren). 2009-10-27 03:41:36 -07:00
1497 changed files with 197035 additions and 410394 deletions
-5
View File
@@ -1,5 +0,0 @@
{
"project_id" : "sourcemod",
"conduit_uri" : "https://phabricator.alliedmods.net/",
"history.immutable" : false
}
-37
View File
@@ -1,37 +0,0 @@
# Binaries
*.dll
*.dylib
*.exe
*.so
# Files generated by Visual Studio
*.aps
*.ipch
*.ncb
*.opensdf
*.sdf
*.suo
*.user
# Build directories
CrazyDebug*/
Debug*/
Release*/
LIB-Release/
LIB-Debug/
# Files generated by Mac OS X Finder
.DS_Store
# Files generated by Windows Explorer
[Dd]esktop.ini
[Tt]humbs.db
# AMBuild build directories
build/
obj-*/
*~
*.rej
*.orig
*.smx
*.swp
+22
View File
@@ -0,0 +1,22 @@
# Binaries
\.dll$
\.exe$
\.so$
# Files generated by Visual Studio
\.aps$
\.ncb$
\.suo$
\.user$
# Build directories
/CrazyDebug.*
/Debug.*
/Release.*
# Files generated by Mac OS X Finder
(^|/)\.DS_Store$
# Files generated by Windows Explorer
(^|/)[dD]esktop\.ini$
(^|/)[tT]humbs\.db$
+8
View File
@@ -0,0 +1,8 @@
54539fa4e51f98d7841c853c1370dff6ccd3cdf2 sourcemod-1.0.0
e6ef5ecdf8d75740ca2685a709bf321f8873bc3b sourcemod-1.1.0
e877885fac80be71822641f7a9122cebc9812521 sourcemod-1.1.1
b3ffa8a4511c4eadaf533fc790aa6b14f7f0c6ea sourcemod-1.1.2
3a73bbf60f34befa9b66be03fa5974b394bb3411 sourcemod-1.2.0
a71318396392e3c6d0ff31e069a60fbde59e0cea sourcemod-1.3.0
3f33d01fcc28b509bed30f7be07ed215cc000538 sourcemod-1.3.1
a3e8f7a7fdf7f012dd02ad491a2e1ccdad151687 sourcemod-1.3.2
-11
View File
@@ -1,11 +0,0 @@
language: cpp
compiler:
- clang
before_script:
- sudo apt-get update -qq
- sudo apt-get install -y g++-multilib libc6-dev-i386 lib32stdc++6 lib32z1-dev
- CHECKOUT_DIR=$PWD && cd .. && $CHECKOUT_DIR/tools/checkout-deps.sh && cd $CHECKOUT_DIR
script:
- mkdir build && cd build
- python ../configure.py --enable-optimize --sdks=episode1,tf2,l4d2,csgo,dota
- ambuild
+303 -518
View File
@@ -1,526 +1,311 @@
# vim: set sts=2 ts=8 sw=2 tw=99 et ft=python:
import os, sys
# vim: set ts=2 sw=2 tw=99 noet ft=python:
import os
import sys
from ambuild.command import SymlinkCommand
class SDK(object):
def __init__(self, sdk, ext, aDef, name, platform, dir):
self.folder = 'hl2sdk-' + dir
self.envvar = sdk
self.ext = ext
self.code = aDef
self.define = name
self.platform = platform
self.name = dir
self.path = None # Actual path
class SM:
def __init__(self):
self.compiler = Cpp.Compiler()
WinOnly = ['windows']
WinLinux = ['windows', 'linux']
WinLinuxMac = ['windows', 'linux', 'mac']
#Build SDK info
self.sdkInfo = { }
self.sdkInfo['ep1'] = {'sdk': 'HL2SDK', 'ext': '1.ep1', 'def': '1',
'name': 'EPISODEONE'}
self.sdkInfo['ep2'] = {'sdk': 'HL2SDKOB', 'ext': '2.ep2', 'def': '3',
'name': 'ORANGEBOX'}
self.sdkInfo['ep2v'] = {'sdk': 'HL2SDKOBVALVE', 'ext': '2.ep2v', 'def': '4',
'name': 'ORANGEBOXVALVE'}
self.sdkInfo['l4d'] = {'sdk': 'HL2SDKL4D', 'ext': '2.l4d', 'def': '5',
'name': 'LEFT4DEAD'}
self.sdkInfo['l4d2'] = {'sdk': 'HL2SDKL4D2', 'ext': '2.l4d2', 'def': '6',
'name': 'LEFT4DEAD2'}
if AMBuild.target['platform'] == 'windows':
self.sdkInfo['darkm'] = {'sdk': 'HL2SDK-DARKM', 'ext': '2.darkm', 'def': '2',
'name': 'DARKMESSIAH'}
PossibleSDKs = {
'episode1': SDK('HL2SDK', '1.ep1', '1', 'EPISODEONE', WinLinux, 'episode1'),
'ep2': SDK('HL2SDKOB', '2.ep2', '3', 'ORANGEBOX', WinLinux, 'orangebox'),
'css': SDK('HL2SDKCSS', '2.css', '6', 'CSS', WinLinuxMac, 'css'),
'hl2dm': SDK('HL2SDKHL2DM', '2.hl2dm', '7', 'HL2DM', WinLinuxMac, 'hl2dm'),
'dods': SDK('HL2SDKDODS', '2.dods', '8', 'DODS', WinLinuxMac, 'dods'),
'sdk2013': SDK('HL2SDK2013', '2.sdk2013', '9', 'SDK2013', WinLinuxMac, 'sdk2013'),
'tf2': SDK('HL2SDKTF2', '2.tf2', '10', 'TF2', WinLinuxMac, 'tf2'),
'l4d': SDK('HL2SDKL4D', '2.l4d', '11', 'LEFT4DEAD', WinLinuxMac, 'l4d'),
'nucleardawn': SDK('HL2SDKND', '2.nd', '12', 'NUCLEARDAWN', WinLinuxMac, 'nucleardawn'),
'l4d2': SDK('HL2SDKL4D2', '2.l4d2', '14', 'LEFT4DEAD2', WinLinuxMac, 'l4d2'),
'darkm': SDK('HL2SDK-DARKM', '2.darkm', '2', 'DARKMESSIAH', WinOnly, 'darkm'),
'swarm': SDK('HL2SDK-SWARM', '2.swarm', '15', 'ALIENSWARM', WinOnly, 'swarm'),
'bgt': SDK('HL2SDK-BGT', '2.bgt', '4', 'BLOODYGOODTIME', WinOnly, 'bgt'),
'eye': SDK('HL2SDK-EYE', '2.eye', '5', 'EYE', WinOnly, 'eye'),
'csgo': SDK('HL2SDKCSGO', '2.csgo', '19', 'CSGO', WinLinuxMac, 'csgo'),
'dota': SDK('HL2SDKDOTA', '2.dota', '20', 'DOTA', WinLinuxMac, 'dota'),
'portal2': SDK('HL2SDKPORTAL2', '2.portal2', '16', 'PORTAL2', [], 'portal2'),
'blade': SDK('HL2SDKBLADE', '2.blade', '17', 'BLADE', WinLinux, 'blade'),
'insurgency': SDK('HL2SDKINSURGENCY', '2.insurgency', '18', 'INSURGENCY', WinLinuxMac, 'insurgency'),
'contagion': SDK('HL2SDKCONTAGION', '2.contagion', '13', 'CONTAGION', WinOnly, 'contagion'),
if AMBuild.mode == 'config':
#Detect compilers
self.compiler.DetectAll(AMBuild)
#Detect variables
envvars = { 'MMSOURCE18': 'mmsource-1.8',
'HL2SDK': 'hl2sdk',
'HL2SDKOB': 'hl2sdk-ob',
'HL2SDKL4D': 'hl2sdk-l4d',
'HL2SDKOBVALVE': 'hl2sdk-ob-valve',
'HL2SDKL4D2': 'hl2sdk-l4d2',
'MYSQL5': 'mysql-5.0'
}
#Dark Messiah is Windows-only
if AMBuild.target['platform'] == 'windows':
envvars['HL2SDK-DARKM'] = 'hl2sdk-darkm'
#Must have a path for each envvar (file a bug if you don't like this)
for i in envvars:
if i in os.environ:
path = os.environ[i]
if not os.path.isdir(path):
raise Exception('Path for {0} was not found: {1}'.format(i, path))
else:
head = os.getcwd()
oldhead = None
while head != None and head != oldhead:
path = os.path.join(head, envvars[i])
if os.path.isdir(path):
break
oldhead = head
head, tail = os.path.split(head)
if head == None or head == oldhead:
raise Exception('Could not find a valid path for {0}'.format(i))
AMBuild.cache.CacheVariable(i, path)
#Set up defines
cxx = self.compiler.cxx
if isinstance(cxx, Cpp.GCC):
self.vendor = 'gcc'
self.compiler.AddToListVar('CDEFINES', 'stricmp=strcasecmp')
self.compiler.AddToListVar('CDEFINES', '_stricmp=strcasecmp')
self.compiler.AddToListVar('CDEFINES', '_snprintf=snprintf')
self.compiler.AddToListVar('CDEFINES', '_vsnprintf=vsnprintf')
self.compiler.AddToListVar('CFLAGS', '-pipe')
self.compiler.AddToListVar('CFLAGS', '-fno-strict-aliasing')
if cxx.majorVersion >= 4:
self.compiler.AddToListVar('CFLAGS', '-fvisibility=hidden')
self.compiler.AddToListVar('CXXFLAGS', '-fvisibility-inlines-hidden')
self.compiler.AddToListVar('CFLAGS', '-Wall')
self.compiler.AddToListVar('CFLAGS', '-Werror')
self.compiler.AddToListVar('CFLAGS', '-Wno-uninitialized')
self.compiler.AddToListVar('CFLAGS', '-Wno-unused')
self.compiler.AddToListVar('CFLAGS', '-Wno-switch')
self.compiler.AddToListVar('CFLAGS', '-mfpmath=sse')
self.compiler.AddToListVar('CFLAGS', '-msse')
self.compiler.AddToListVar('CFLAGS', '-m32')
self.compiler.AddToListVar('CFLAGS', '-static-libgcc')
self.compiler.AddToListVar('CXXFLAGS', '-fno-exceptions')
self.compiler.AddToListVar('CXXFLAGS', '-fno-rtti')
self.compiler.AddToListVar('CXXFLAGS', '-fno-threadsafe-statics')
self.compiler.AddToListVar('CXXFLAGS', '-Wno-non-virtual-dtor')
self.compiler.AddToListVar('CDEFINES', 'HAVE_STDINT_H')
elif isinstance(cxx, Cpp.MSVC):
self.vendor = 'msvc'
if AMBuild.options.debug == '1':
self.compiler.AddToListVar('CFLAGS', '/MTd')
else:
self.compiler.AddToListVar('CFLAGS', '/MT')
self.compiler.AddToListVar('CDEFINES', '_CRT_SECURE_NO_DEPRECATE')
self.compiler.AddToListVar('CDEFINES', '_CRT_SECURE_NO_WARNINGS')
self.compiler.AddToListVar('CDEFINES', '_CRT_NONSTDC_NO_DEPRECATE')
self.compiler.AddToListVar('CXXFLAGS', '/EHsc')
self.compiler.AddToListVar('CXXFLAGS', '/GR-')
self.compiler.AddToListVar('CFLAGS', '/W3')
self.compiler.AddToListVar('CFLAGS', '/nologo')
self.compiler.AddToListVar('CFLAGS', '/Zi')
self.compiler.AddToListVar('CXXFLAGS', '/TP')
self.compiler.AddToListVar('POSTLINKFLAGS', '/DEBUG')
self.compiler.AddToListVar('POSTLINKFLAGS', '/MACHINE:X86')
self.compiler.AddToListVar('POSTLINKFLAGS', '/SUBSYSTEM:WINDOWS')
self.compiler.AddToListVar('POSTLINKFLAGS', 'kernel32.lib')
self.compiler.AddToListVar('POSTLINKFLAGS', 'user32.lib')
self.compiler.AddToListVar('POSTLINKFLAGS', 'gdi32.lib')
self.compiler.AddToListVar('POSTLINKFLAGS', 'winspool.lib')
self.compiler.AddToListVar('POSTLINKFLAGS', 'comdlg32.lib')
self.compiler.AddToListVar('POSTLINKFLAGS', 'advapi32.lib')
self.compiler.AddToListVar('POSTLINKFLAGS', 'shell32.lib')
self.compiler.AddToListVar('POSTLINKFLAGS', 'ole32.lib')
self.compiler.AddToListVar('POSTLINKFLAGS', 'oleaut32.lib')
self.compiler.AddToListVar('POSTLINKFLAGS', 'uuid.lib')
self.compiler.AddToListVar('POSTLINKFLAGS', 'odbc32.lib')
self.compiler.AddToListVar('POSTLINKFLAGS', 'odbccp32.lib')
#Optimization
if AMBuild.options.opt == '1':
self.compiler.AddToListVar('CDEFINES', 'NDEBUG')
if self.vendor == 'gcc':
self.compiler.AddToListVar('CFLAGS', '-O3')
elif self.vendor == 'msvc':
self.compiler.AddToListVar('CFLAGS', '/Ot')
self.compiler.AddToListVar('POSTLINKFLAGS', '/OPT:ICF')
#Debugging
if AMBuild.options.debug == '1':
self.compiler.AddToListVar('CDEFINES', 'DEBUG')
self.compiler.AddToListVar('CDEFINES', '_DEBUG')
if self.vendor == 'gcc':
self.compiler.AddToListVar('CFLAGS', '-g3')
elif self.vendor == 'msvc':
self.compiler.AddToListVar('CFLAGS', '/Od')
self.compiler.AddToListVar('CFLAGS', '/RTC1')
#Platform-specifics
if AMBuild.target['platform'] == 'linux':
self.compiler.AddToListVar('CDEFINES', '_LINUX')
elif AMBuild.target['platform'] == 'windows':
self.compiler.AddToListVar('CDEFINES', 'WIN32')
self.compiler.AddToListVar('CDEFINES', '_WINDOWS')
#Finish up
self.compiler.AddToListVar('CDEFINES', 'SOURCEMOD_BUILD')
self.compiler.AddToListVar('CDEFINES', 'SM_GENERATED_BUILD')
self.compiler.AddToListVar('CINCLUDES',
os.path.join(AMBuild.outputFolder, 'includes'))
self.compiler.ToConfig(AMBuild, 'compiler')
AMBuild.cache.CacheVariable('vendor', self.vendor)
self.targetMap = { }
AMBuild.cache.CacheVariable('targetMap', self.targetMap)
else:
self.compiler.FromConfig(AMBuild, 'compiler')
self.targetMap = AMBuild.cache['targetMap']
if AMBuild.target['platform'] == 'windows':
self.compiler.AddToListVar('RCINCLUDES', os.path.join(AMBuild.sourceFolder, 'public'))
self.compiler.AddToListVar('RCINCLUDES',
os.path.join(AMBuild.outputFolder, 'includes'))
self.mmsPath = AMBuild.cache['MMSOURCE18']
def DefaultCompiler(self):
return self.compiler.Clone()
def JobMatters(self, jobname):
file = sys._getframe().f_code.co_filename
if AMBuild.mode == 'config':
self.targetMap[jobname] = file
return True
if len(AMBuild.args) == 0:
return True
if not jobname in AMBuild.args:
return False
def DefaultExtCompiler(self, path):
compiler = self.DefaultCompiler()
compiler['CXXINCLUDES'].append(os.path.join(AMBuild.sourceFolder, path))
compiler['CXXINCLUDES'].append(os.path.join(AMBuild.sourceFolder, path, 'sdk'))
compiler['CXXINCLUDES'].append(os.path.join(AMBuild.sourceFolder, 'public'))
compiler['CXXINCLUDES'].append(os.path.join(AMBuild.sourceFolder, 'public', 'extensions'))
compiler['CXXINCLUDES'].append(os.path.join(AMBuild.sourceFolder, 'public', 'sourcepawn'))
return compiler
def AutoVersion(self, folder, binary):
if AMBuild.target['platform'] != 'windows':
return
env = {'RCDEFINES': ['BINARY_NAME="' + binary.binaryFile + '"', 'SM_GENERATED_BUILD']}
binary.AddResourceFile(os.path.join(folder, 'version.rc' ), env)
def PreSetupHL2Job(self, job, builder, sdk):
info = self.sdkInfo[sdk]
sdkPath = AMBuild.cache[info['sdk']]
if AMBuild.target['platform'] == 'linux':
if sdk == 'ep1':
staticLibs = os.path.join(sdkPath, 'linux_sdk')
else:
staticLibs = os.path.join(sdkPath, 'lib', 'linux')
workFolder = os.path.join(AMBuild.outputFolder, job.workFolder)
if sdk == 'ep2v' or sdk == 'l4d2':
for i in ['tier1_i486.a', 'mathlib_i486.a', 'libvstdlib.so', 'libtier0.so']:
link = os.path.join(workFolder, i)
target = os.path.join(staticLibs, i)
try:
os.lstat(link)
except:
job.AddCommand(SymlinkCommand(link, target))
else:
for i in ['tier1_i486.a', 'mathlib_i486.a', 'vstdlib_i486.so', 'tier0_i486.so']:
link = os.path.join(workFolder, i)
target = os.path.join(staticLibs, i)
try:
os.lstat(link)
except:
job.AddCommand(SymlinkCommand(link, target))
elif AMBuild.target['platform'] == 'windows':
for lib in ['tier0', 'tier1', 'vstdlib', 'mathlib']:
libPath = os.path.join(sdkPath, 'lib', 'public', lib) + '.lib'
builder.RebuildIfNewer(libPath)
builder['POSTLINKFLAGS'].append(libPath)
def PostSetupHL2Job(self, job, builder, sdk):
if AMBuild.target['platform'] == 'linux':
builder.AddObjectFiles(['tier1_i486.a', 'mathlib_i486.a'])
def DefaultHL2Compiler(self, path, sdk, noLink = False, oldMms = '-legacy'):
compiler = self.DefaultExtCompiler(path)
mms = 'core'
if sdk == 'ep1':
mms += oldMms
compiler['CXXINCLUDES'].append(os.path.join(self.mmsPath, mms))
compiler['CXXINCLUDES'].append(os.path.join(self.mmsPath, mms, 'sourcehook'))
info = self.sdkInfo
compiler['CDEFINES'].extend(['SE_' + info[i]['name'] + '=' + info[i]['def'] for i in info])
compiler['CDEFINES'].append('SE_DARKMESSIAH=2')
paths = [['public'], ['public', 'engine'], ['public', 'mathlib'], ['public', 'vstdlib'],
['public', 'tier0'], ['public', 'tier1']]
if sdk == 'ep1' or sdk == 'darkm':
paths.append(['public', 'dlls'])
paths.append(['game_shared'])
else:
paths.append(['public', 'game', 'server'])
paths.append(['game', 'shared'])
paths.append(['common'])
info = self.sdkInfo[sdk]
sdkPath = AMBuild.cache[info['sdk']]
compiler['CDEFINES'].append('SOURCE_ENGINE=' + info['def'])
if sdk == 'ep1':
if AMBuild.target['platform'] == 'linux':
staticLibs = os.path.join(sdkPath, 'linux_sdk')
else:
if AMBuild.target['platform'] == 'linux':
staticLibs = os.path.join(sdkPath, 'lib', 'linux')
for i in paths:
compiler['CXXINCLUDES'].append(os.path.join(sdkPath, *i))
if not noLink:
if AMBuild.target['platform'] == 'linux':
compiler['POSTLINKFLAGS'][0:0] = ['-lm']
if sdk == 'ep2v' or sdk == 'l4d2':
compiler['POSTLINKFLAGS'][0:0] = ['libtier0.so']
compiler['POSTLINKFLAGS'][0:0] = ['libvstdlib.so']
else:
compiler['POSTLINKFLAGS'][0:0] = ['tier0_i486.so']
compiler['POSTLINKFLAGS'][0:0] = ['vstdlib_i486.so']
return compiler
sm = SM()
globals = {
'SM': sm
}
def ResolveEnvPath(env, folder):
if env in os.environ:
path = os.environ[env]
if os.path.isdir(path):
return path
return None
AMBuild.Include(os.path.join('tools', 'buildbot', 'Versioning'), globals)
head = os.getcwd()
oldhead = None
while head != None and head != oldhead:
path = os.path.join(head, folder)
if os.path.isdir(path):
return path
oldhead = head
head, tail = os.path.split(head)
FileList = [
['loader', 'AMBuilder'],
['core', 'AMBuilder'],
['core', 'logic', 'AMBuilder'],
['extensions', 'bintools', 'AMBuilder'],
['extensions', 'clientprefs', 'AMBuilder'],
['extensions', 'cstrike', 'AMBuilder'],
['extensions', 'curl', 'AMBuilder'],
['extensions', 'geoip', 'AMBuilder'],
['extensions', 'mysql', 'AMBuilder'],
['extensions', 'sdktools', 'AMBuilder'],
['extensions', 'topmenus', 'AMBuilder'],
['extensions', 'updater', 'AMBuilder'],
['extensions', 'sqlite', 'AMBuilder'],
['extensions', 'regex', 'AMBuilder'],
['extensions', 'tf2', 'AMBuilder'],
['sourcepawn', 'jit', 'AMBuilder'],
['sourcepawn', 'compiler', 'AMBuilder'],
['plugins', 'AMBuilder'],
['tools', 'buildbot', 'PackageScript']
]
return None
for parts in FileList:
AMBuild.Include(os.path.join(*parts), globals)
def Normalize(path):
return os.path.abspath(os.path.normpath(path))
class SMConfig(object):
def __init__(self):
self.sdks = {}
self.binaries = []
self.extensions = []
self.generated_headers = None
self.mms_root = None
self.mysql_root = None
self.spcomp = None
self.smx_files = {}
self.versionlib = None
def use_auto_versioning(self):
if builder.backend != 'amb2':
return False
return not getattr(builder.options, 'disable_auto_versioning', False)
@property
def tag(self):
if builder.options.debug == '1':
return 'Debug'
return 'Release'
def detectProductVersion(self):
builder.AddConfigureFile('product.version')
# For OS X dylib versioning
import re
with open(os.path.join(builder.sourcePath, 'product.version'), 'r') as fp:
productContents = fp.read()
m = re.match('(\d+)\.(\d+)\.(\d+).*', productContents)
if m == None:
self.productVersion = '1.0.0'
else:
major, minor, release = m.groups()
self.productVersion = '{0}.{1}.{2}'.format(major, minor, release)
def detectSDKs(self):
sdk_list = builder.options.sdks.split(',')
use_all = sdk_list[0] == 'all'
use_present = sdk_list[0] == 'present'
for sdk_name in PossibleSDKs:
sdk = PossibleSDKs[sdk_name]
if builder.target_platform in sdk.platform:
if builder.options.hl2sdk_root:
sdk_path = os.path.join(builder.options.hl2sdk_root, sdk.folder)
else:
sdk_path = ResolveEnvPath(sdk.envvar, sdk.folder)
if sdk_path is None or not os.path.isdir(sdk_path):
if use_all or sdk_name in sdk_list:
raise Exception('Could not find a valid path for {0}'.format(sdk.envvar))
continue
if use_all or use_present or sdk_name in sdk_list:
sdk.path = Normalize(sdk_path)
self.sdks[sdk_name] = sdk
if len(self.sdks) < 1:
raise Exception('At least one SDK must be available.')
if builder.options.mms_path:
self.mms_root = builder.options.mms_path
else:
self.mms_root = ResolveEnvPath('MMSOURCE110', 'mmsource-1.10')
if not self.mms_root:
self.mms_root = ResolveEnvPath('MMSOURCE_DEV', 'metamod-source')
if not self.mms_root:
self.mms_root = ResolveEnvPath('MMSOURCE_DEV', 'mmsource-central')
if not self.mms_root or not os.path.isdir(self.mms_root):
raise Exception('Could not find a source copy of Metamod:Source')
self.mms_root = Normalize(self.mms_root)
if builder.options.hasMySql:
if builder.options.mysql_path:
self.mysql_root = builder.options.mysql_path
else:
for i in range(7):
self.mysql_root = ResolveEnvPath('MYSQL5', 'mysql-5.' + str(i))
if self.mysql_root:
break
if not self.mysql_root or not os.path.isdir(self.mysql_root):
raise Exception('Could not find a path to MySQL!')
self.mysql_root = Normalize(self.mysql_root)
def configure(self):
builder.AddConfigureFile('pushbuild.txt')
cxx = builder.DetectCompilers()
if cxx.like('gcc'):
cxx.defines += [
'stricmp=strcasecmp',
'_stricmp=strcasecmp',
'_snprintf=snprintf',
'_vsnprintf=vsnprintf',
'HAVE_STDINT_H',
'GNUC',
]
cxx.cflags += [
'-pipe',
'-fno-strict-aliasing',
'-Wall',
'-Werror',
'-Wno-unused',
'-Wno-switch',
'-Wno-array-bounds',
'-msse',
'-m32',
]
cxx.cxxflags += [
'-std=c++11',
]
have_gcc = cxx.vendor == 'gcc'
have_clang = cxx.vendor == 'clang'
if have_clang or (have_gcc and cxx.version >= '4'):
cxx.cflags += ['-fvisibility=hidden']
cxx.cxxflags += ['-fvisibility-inlines-hidden']
if have_clang or (have_gcc and cxx.version >= '4.6'):
cxx.cflags += ['-Wno-narrowing']
if (have_gcc and cxx.version >= '4.7') or (have_clang and cxx.version >= '3'):
cxx.cxxflags += ['-Wno-delete-non-virtual-dtor']
if have_gcc and cxx.version >= '4.8':
cxx.cflags += ['-Wno-unused-result']
if have_clang:
cxx.cxxflags += ['-Wno-implicit-exception-spec-mismatch']
if cxx.version >= 'apple-clang-5.1' or cxx.version >= 'clang-3.4':
cxx.cxxflags += ['-Wno-deprecated-register']
else:
cxx.cxxflags += ['-Wno-deprecated']
cxx.cflags += ['-Wno-sometimes-uninitialized']
cxx.linkflags += ['-m32']
cxx.cxxflags += [
'-fno-exceptions',
'-fno-threadsafe-statics',
'-Wno-non-virtual-dtor',
'-Wno-overloaded-virtual',
]
if have_gcc:
cxx.cflags += ['-mfpmath=sse']
elif cxx.vendor == 'msvc':
if builder.options.debug == '1':
cxx.cflags += ['/MTd']
cxx.linkflags += ['/NODEFAULTLIB:libcmt']
else:
cxx.cflags += ['/MT']
cxx.defines += [
'_CRT_SECURE_NO_DEPRECATE',
'_CRT_SECURE_NO_WARNINGS',
'_CRT_NONSTDC_NO_DEPRECATE',
'_ITERATOR_DEBUG_LEVEL=0',
]
if cxx.version < 1800:
cxx.defines += 'strtoull=_strtoui64'
cxx.cflags += [
'/W3',
]
cxx.cxxflags += [
'/EHsc',
'/GR-',
'/TP',
]
cxx.linkflags += [
'/MACHINE:X86',
'/SUBSYSTEM:WINDOWS',
'kernel32.lib',
'user32.lib',
'gdi32.lib',
'winspool.lib',
'comdlg32.lib',
'advapi32.lib',
'shell32.lib',
'ole32.lib',
'oleaut32.lib',
'uuid.lib',
'odbc32.lib',
'odbccp32.lib',
]
# Optimization
if builder.options.opt == '1':
cxx.defines += ['NDEBUG']
if cxx.like('gcc'):
cxx.cflags += ['-O3']
elif cxx.like('msvc'):
cxx.cflags += ['/Ox', '/Zo']
cxx.linkflags += ['/OPT:ICF', '/OPT:REF']
# Debugging
if builder.options.debug == '1':
cxx.defines += ['DEBUG', '_DEBUG']
if cxx.like('msvc'):
cxx.cflags += ['/Od', '/RTC1']
# This needs to be after our optimization flags which could otherwise disable it.
if cxx.vendor == 'msvc':
# Don't omit the frame pointer.
cxx.cflags += ['/Oy-']
# Platform-specifics
if builder.target_platform == 'linux':
cxx.defines += ['_LINUX', 'POSIX']
if cxx.vendor == 'gcc':
cxx.linkflags += ['-static-libgcc']
elif cxx.vendor == 'clang':
cxx.linkflags += ['-lgcc_eh']
elif builder.target_platform == 'mac':
cxx.defines += ['OSX', '_OSX', 'POSIX']
cxx.cflags += ['-mmacosx-version-min=10.5']
cxx.linkflags += [
'-mmacosx-version-min=10.5',
'-arch', 'i386',
'-lstdc++',
'-stdlib=libstdc++',
]
cxx.cxxflags += ['-stdlib=libstdc++']
elif builder.target_platform == 'windows':
cxx.defines += ['WIN32', '_WINDOWS']
# Finish up.
cxx.defines += [
'SOURCEMOD_BUILD',
'SM_USE_VERSIONLIB',
]
if self.use_auto_versioning():
cxx.defines += ['SM_GENERATED_BUILD']
cxx.includes += [os.path.join(builder.buildPath, 'includes')]
cxx.includes += [os.path.join(builder.sourcePath, 'versionlib')]
def AddVersioning(self, binary):
if builder.target_platform == 'windows':
binary.sources += ['version.rc']
binary.compiler.rcdefines += [
'BINARY_NAME="{0}"'.format(binary.outputFile),
'RC_COMPILE',
]
if self.use_auto_versioning():
binary.compiler.rcdefines += ['SM_GENERATED_BUILD']
elif builder.target_platform == 'mac':
if binary.type == 'library':
binary.compiler.postlink += [
'-compatibility_version', '1.0.0',
'-current_version', self.productVersion
]
if self.use_auto_versioning():
binary.compiler.linkflags += [self.versionlib]
binary.compiler.sourcedeps += SM.generated_headers
return binary
def Library(self, context, name):
binary = context.compiler.Library(name)
return self.AddVersioning(binary)
def Program(self, context, name):
binary = context.compiler.Program(name)
return self.AddVersioning(binary)
def ConfigureForExtension(self, context, compiler):
compiler.cxxincludes += [
os.path.join(context.currentSourcePath),
os.path.join(context.currentSourcePath, 'sdk'),
os.path.join(builder.sourcePath, 'public'),
os.path.join(builder.sourcePath, 'public', 'extensions'),
os.path.join(builder.sourcePath, 'public', 'sourcepawn'),
os.path.join(builder.sourcePath, 'public', 'amtl'),
]
return compiler
def ExtLibrary(self, context, name):
binary = context.compiler.Library(name)
self.ConfigureForExtension(context, binary.compiler)
return self.AddVersioning(binary)
def ConfigureForHL2(self, binary, sdk):
compiler = binary.compiler
if sdk.name == 'episode1':
mms_path = os.path.join(self.mms_root, 'core-legacy')
else:
mms_path = os.path.join(self.mms_root, 'core')
compiler.cxxincludes += [
os.path.join(mms_path),
os.path.join(mms_path, 'sourcehook'),
]
defines = ['SE_' + PossibleSDKs[i].define + '=' + PossibleSDKs[i].code for i in PossibleSDKs]
compiler.defines += defines
paths = [
['public'],
['public', 'engine'],
['public', 'mathlib'],
['public', 'vstdlib'],
['public', 'tier0'],
['public', 'tier1']
]
if sdk.name == 'episode1' or sdk.name == 'darkm':
paths.append(['public', 'dlls'])
paths.append(['game_shared'])
else:
paths.append(['public', 'game', 'server'])
paths.append(['public', 'toolframework'])
paths.append(['game', 'shared'])
paths.append(['common'])
compiler.defines += ['SOURCE_ENGINE=' + sdk.code]
if sdk.name == 'sdk2013' and compiler.like('gcc'):
# The 2013 SDK already has these in public/tier0/basetypes.h
compiler.defines.remove('stricmp=strcasecmp')
compiler.defines.remove('_stricmp=strcasecmp')
compiler.defines.remove('_snprintf=snprintf')
compiler.defines.remove('_vsnprintf=vsnprintf')
if compiler.like('msvc'):
compiler.defines += ['COMPILER_MSVC', 'COMPILER_MSVC32']
else:
compiler.defines += ['COMPILER_GCC']
# For everything after Swarm, this needs to be defined for entity networking
# to work properly with sendprop value changes.
if sdk.name in ['blade', 'insurgency', 'csgo', 'dota']:
compiler.defines += ['NETWORK_VARS_ENABLED']
if sdk.name in ['css', 'hl2dm', 'dods', 'sdk2013', 'tf2', 'l4d', 'nucleardawn', 'l4d2', 'dota']:
if builder.target_platform in ['linux', 'mac']:
compiler.defines += ['NO_HOOK_MALLOC', 'NO_MALLOC_OVERRIDE']
if sdk.name == 'csgo' and builder.target_platform == 'linux':
compiler.linkflags += ['-lstdc++']
for path in paths:
compiler.cxxincludes += [os.path.join(sdk.path, *path)]
if builder.target_platform == 'linux':
if sdk.name == 'episode1':
lib_folder = os.path.join(sdk.path, 'linux_sdk')
elif sdk.name == 'sdk2013':
lib_folder = os.path.join(sdk.path, 'lib', 'public', 'linux32')
else:
lib_folder = os.path.join(sdk.path, 'lib', 'linux')
elif builder.target_platform == 'mac':
if sdk.name == 'sdk2013':
lib_folder = os.path.join(sdk.path, 'lib', 'public', 'osx32')
else:
lib_folder = os.path.join(sdk.path, 'lib', 'mac')
if builder.target_platform in ['linux', 'mac']:
if sdk.name == 'sdk2013':
compiler.postlink += [
compiler.Dep(os.path.join(lib_folder, 'tier1.a')),
compiler.Dep(os.path.join(lib_folder, 'mathlib.a'))
]
else:
compiler.postlink += [
compiler.Dep(os.path.join(lib_folder, 'tier1_i486.a')),
compiler.Dep(os.path.join(lib_folder, 'mathlib_i486.a'))
]
if sdk.name in ['blade', 'insurgency', 'csgo', 'dota']:
compiler.postlink += [compiler.Dep(os.path.join(lib_folder, 'interfaces_i486.a'))]
self.AddVersioning(binary)
dynamic_libs = []
if builder.target_platform == 'linux':
compiler.linkflags[0:0] = ['-lm']
if sdk.name in ['css', 'hl2dm', 'dods', 'tf2', 'sdk2013', 'nucleardawn', 'l4d2']:
dynamic_libs = ['libtier0_srv.so', 'libvstdlib_srv.so']
elif sdk.name in ['l4d', 'blade', 'insurgency', 'csgo', 'dota']:
dynamic_libs = ['libtier0.so', 'libvstdlib.so']
else:
dynamic_libs = ['tier0_i486.so', 'vstdlib_i486.so']
elif builder.target_platform == 'mac':
compiler.linkflags.append('-liconv')
dynamic_libs = ['libtier0.dylib', 'libvstdlib.dylib']
elif builder.target_platform == 'windows':
libs = ['tier0', 'tier1', 'vstdlib', 'mathlib']
if sdk.name in ['swarm', 'blade', 'insurgency', 'csgo', 'dota']:
libs.append('interfaces')
for lib in libs:
lib_path = os.path.join(sdk.path, 'lib', 'public', lib) + '.lib'
compiler.linkflags.append(compiler.Dep(lib_path))
for library in dynamic_libs:
source_path = os.path.join(lib_folder, library)
output_path = os.path.join(binary.localFolder, library)
def make_linker(source_path, output_path):
def link(context, binary):
cmd_node, (output,) = context.AddSymlink(source_path, output_path)
return output
return link
linker = make_linker(source_path, output_path)
compiler.linkflags[0:0] = [compiler.Dep(library, linker)]
return binary
def HL2Library(self, context, name, sdk):
binary = context.compiler.Library(name)
self.ConfigureForExtension(context, binary.compiler)
return self.ConfigureForHL2(binary, sdk)
def HL2Project(self, context, name):
project = context.compiler.LibraryProject(name)
self.ConfigureForExtension(context, project.compiler)
return project
def HL2Config(self, project, name, sdk):
binary = project.Configure(name, '{0} - {1}'.format(self.tag, sdk.name))
return self.ConfigureForHL2(binary, sdk)
SM = SMConfig()
SM.detectProductVersion()
SM.detectSDKs()
SM.configure()
if SM.use_auto_versioning():
SM.generated_headers = builder.RunScript(
'tools/buildbot/Versioning',
{ 'SM': SM }
)
SM.versionlib = builder.RunScript(
'versionlib/AMBuilder',
{ 'SM': SM }
)
BuildScripts = [
'loader/AMBuilder',
'core/AMBuilder',
'core/logic/AMBuilder',
'extensions/bintools/AMBuilder',
'extensions/clientprefs/AMBuilder',
'extensions/curl/AMBuilder',
'extensions/cstrike/AMBuilder',
'extensions/geoip/AMBuilder',
'extensions/mysql/AMBuilder',
'extensions/regex/AMBuilder',
'extensions/sdkhooks/AMBuilder',
'extensions/sdktools/AMBuilder',
'extensions/sqlite/AMBuilder',
'extensions/tf2/AMBuilder',
'extensions/topmenus/AMBuilder',
'extensions/updater/AMBuilder',
'sourcepawn/compiler/AMBuilder',
'sourcepawn/jit/AMBuilder',
]
if builder.backend == 'amb2':
BuildScripts += [
'plugins/AMBuilder',
'tools/buildbot/PackageScript',
]
builder.RunBuildScripts(BuildScripts, { 'SM': SM })
if builder.options.breakpad_dump:
builder.RunScript('tools/buildbot/BreakpadSymbols', { 'SM': SM })
+6
View File
@@ -0,0 +1,6 @@
CONFIGURE YOUR IDENTITY FOR MERCURIAL!
IF YOU ARE A DEVELOPER WITH PUSH ACCESS, DO IT NOW KPLZTHX.
http://wiki.alliedmods.net/Mercurial_Tutorial#Identity
-17
View File
@@ -1,17 +0,0 @@
SourceMod
=========
General
-------
- [SourceMod website](http://www.sourcemod.net): Source Engine scripting and server administration
- [Forum](https://forums.alliedmods.net/forumdisplay.php?f=52): Discussion forum including plugin/extension development
- [General documentation](https://wiki.alliedmods.net/Category:SourceMod_Documentation): Miscellaneous information about SourceMod
- [Latest release](http://www.sourcemod.net/downloads.php): The latest stable SourceMod release
- [Build snapshots](http://www.sourcemod.net/snapshots.php): Builds of recent development versions
Development
-----------
- [Issue tracker](https://bugs.alliedmods.net): Issues that require back and forth communication
- [Building SourceMod](https://wiki.alliedmods.net/Building_SourceMod): Instructions on how to build SourceMod itself using [AMBuild](https://github.com/alliedmodders/ambuild)
- [SourcePawn scripting](https://wiki.alliedmods.net/Category:SourceMod_Scripting): SourcePawn examples and introduction to the language
- [SourceMod extension development](https://wiki.alliedmods.net/Category:SourceMod_Development): C++ examples and introduction to various extension interfaces
-762
View File
@@ -1,767 +1,5 @@
SourceMod Changelog
SourceMod 1.7.1 [2015-04-18]
URL: http://wiki.alliedmods.net/SourceMod_1.7.1_Release_Notes
User Changes:
- Updated game compatibility for CS:GO, TF2, Dota 2, Insurgency, and Fortress Forever.
- Fixed regression causing crash in games that do not support radio menus (PR 286) (Peace-Maker).
- Fixed sm_rename not working on some games, including CS:S and CS:GO (PR 313).
- Fixed some core.cfg values being ignored on start (PR 322).
- Fixed crash when plugins close a menu handle during menu draw (PR 268)
Developer Changes:
- Added tagged TF2_SetClientTeam to provide symmetry to TF2_GetClientTeam (PR 267) (Wliu).
- Added block parameter to FindValueInArray native (PR 213) (splewis).
- Added explicit return types to forwards missing them to avoid future compatibility issues (PR 294).
- Added new SetClientName native to reliably change a player's name on any game (PR 313).
- Fixed tag mismatch warning when using SQLite_UseDatabase (bug 6310) (PR 262) (VoiDeD).
- Fixed not actually being able to block CS_OnCSWeaponDrop (bug 6334) (PR 316).
- Fixed DirExists to throw an error when passed empty string (PR 315).
- Fixed ReadUint16 on File methodmap throwing "not bound" error (PR 265).
- Fixed various include docs (PR 288) (PR 290) (PR 295).
- Fixed issues with declaring variable on same line after array (SP PR 7) (Peace-Maker).
- Fixed debug info for multidimensional strings not being written to smx (SP PR 8) (Peace-Maker).
- Fixed issues with nesting methodmap calls (bug 6329) (SP PR 11) (SP PR 13).
- Improved diagnostic given when function prototype doesn't match an existing definition (PR 291) (VoiDeD).
----------------------------------------------------------
SourceMod 1.7.0 [2015-02-04]
URL: http://wiki.alliedmods.net/SourceMod_1.7.0_Release_Notes
User Changes:
- Updated game compatibility for TF2, CS:GO, and Dota 2.
- Fixed regression in SM 1.6.3 causing load failure on games older than Orangebox. (PR 237)
- Rewrote internal Steam auth ID handling (PR 147, PR 153, PR 155, PR 162, PR 204, PR 210, PR 222, PR 246).
--- admins.cfg now supports Steam2, Steam3, and SteamID 64 formats for the Steam auth provider.
--- admins-simple.ini now supports Steam3 auth IDs in addition to Steam2 IDs.
--- Command targeting now supports both Steam3 auth IDs in addition to Steam2 IDs.
- Added default timeout for MySQL connections to avoid hangs. (PR 248).
- SDKTools' gamerules gamedata is now far less likely to break on updates (PR 220).
- Fixed crash with sm_dump_admcache on Windows (PR 163).
- Fixed SDKHooks causing crash on player join/leave or plugin load/unload if gamedata missing (PR 236).
- Changed default sm_trigger_show ConVar value to 0 / disabled.
Developer Changes:
- Added new SourcePawn Transitional Syntax!
--- New methodmap-based APIs have been added for many existing functions and handle types.
--- New work-in-progress API doc page.
- Added Blocked hook type to SDKHooks (PR 119) (VoiDeD).
- Added OnTakeDamage_Alive hook type to SDKHooks (PR 149).
- Many more File natives now support Valve FS (PR 120, PR 169, PR 178).
- Added SetFilePermissions native (PR 43) (hlstriker).
- Added API for iterating StringMaps (formerly "tries").
- Added natives for accessing command line parameters (PR 164) (VoiDeD).
- Exposed engine Message_DetermineMulticastRecipients as GetClientsInRange native. (PR 234).
- CloseHandle (or delete) on INVALID_HANDLE is now a no-op, instead of an error (PR 74).
- GetClientAuthString is now deprecated. Use GetClientAuthId instead.
- Added OnCoreMapEnd to extension interface (PR 127).
- Fixed IThreader threads leaking if they're not joined. (bug 3460, PR 241).
- TFHoliday updates no longer require a plugin recompile (PR 217).
- Fixed FindFlagChar returning false when passing AdminFlag_Custom6 (bug 6248, PR 203).
- Added support for (entity) CLASSPTR and EDICT Prop_Data fields with GetEntPropEnt and SetEntPropEnt (PR 83).
- Doubled maximum handle count per plugin to 32,768 (PR 215), (Thordin).
- Added support for custom default values with GetEvent* natives, rather than using ""/0 for unset fields (PR 157) (VoiDeD).
- Removed old profiler, and added new, pluggable profiler (with hooks to VProf) (PR 54).
- Added command to dump profiler output (PR 128) (VoiDeD).
- Fixed ICommandLine and related features being reported as unavailable on Dark Messiah.
- Fixed OnPlayerRunCommand forward in SDKTools being unavailable on Dark Messiah.
- SourceMod now uses some C++11 and has newer compiler requirements.
- Added --disable-auto-versioning option to ambuild configure script.
----------------------------------------------------------
SourceMod 1.6.3 [2014-11-25]
URL: http://wiki.alliedmods.net/SourceMod_1.6.3_Release_Notes
User Changes:
- Updated game support for TF2, CS:GO, No More Room in Hell, Insurgency, PVK2 and Fistful of Frags.
- Made changes to make TF2, CSS, DoDS, HL2DM, and SDK 2013 mods less likely to break on game update (PR 174, PR 192).
- Added support for longer key names in languages.cfg (to fix Portuguese) (bug 6282, PR 208).
Developer Changes:
- Updated TF2 player condition and holiday enums (Ross "Powerlord" Bemrose) (PR 183, PR 181).
- Add support for TF2 player conditions >= 96 for condition functions/forwards (PR 205).
----------------------------------------------------------
SourceMod 1.6.2 [2014-09-20]
URL: http://wiki.alliedmods.net/SourceMod_1.6.2_Release_Notes
User Changes:
- Updated game support for TF2, CS:GO, No More Room in Hell and Fistful of Frags.
- Added compatibility shim to force Steam player auth strings to be in "Steam2" rendered format (PR 136).
- Fixed possible performance regression in DBI handling.
Developer Changes:
- Added new GetClientAuthId native to retrieve player auth strings in desired format (PR 159).
- Updated TF2 weapon and player condition enums (FlaminSarge).
----------------------------------------------------------
SourceMod 1.6.1 [2014-08-17]
URL: http://wiki.alliedmods.net/SourceMod_1.6.1_Release_Notes
User Changes:
- Updated game support for CS:GO and Fistful of Frags.
- Added support for Romanian language.
- Re-added languages.cfg, missing from 1.6.0, causing all clients to use server language.
- Fixed a regression in version 1.6.0 that caused certain SDKHooks usage patterns to cause a server crash (PR 107).
- Improved error reporting in basebans plugin when banreasons.txt is missing (PR 115).
- Fixed incorrect logged gravity value for sm_gravity command (Ryan "VoiDeD" Stecker) (PR 116).
- Fixed a regression in version 1.6.0 causing SDKHook_ReloadPost hooks to not fire in plugins (Peace-Maker) (PR 96).
- Added workaround for game bug in TF2_RemoveWeaponSlot to avoid wearable entities left on map (Ryan "VoiDeD" Stecker) (bug 6206, PR 121).
- Removed DisableJIT option from core.cfg. (It was never meant for normal use.)
Developer Changes:
- Added new TF2_RemoveWearable native (Ryan "VoiDeD" Stecker, WildCard65) (PR 114).
- Added new functions for interacting with and playing scripted game sounds (Ross "Powerlord" Bemrose) (bug 5942, PR 65).
- Added new StringToKeyValues natives (Ryan "VoiDeD" Stecker) (PR 74).
----------------------------------------------------------
SourceMod 1.6.0 [2014-07-03]
URL: http://wiki.alliedmods.net/SourceMod_1.6.0_Release_Notes
User Changes:
- Added support for Dota 2 (bug 5656, bug 6068).
- Added support for Source SDK 2013 mods (bug 5917).
- Added support for Insurgency (bug 5951).
- Added support for Contagion (bug 6007).
- Added support for Blade Symphony (bug 5949).
- Updated support for some mods that moved to SDK 2013 - No More Room In Hell, Fistful of Frags, Empires, Synergy.
- Updated gamedata and other support for TF2, DoD:S, HL2:DM, CS:S, CS:GO, Left 4 Dead, and Nuclear Dawn.
- Added support for customizing ban reasons in basebans.sp (bug 5762) (Matthias "House" Kollek).
- Added support for searching all gameinfo search paths when seeking mapcycle file (bug 5839).
- Added sm_reload_translations command (bug 5750).
- Added support for single-file gamedata custom overrides (bug 5386) (Ondrej "RavuAlHemio" Hošek).
- Re-enabled SteamAuthstringValidation config option by default (bug 5791, PR 20).
- Fixed plugins not reaching ext dep lists, making dependent plugin not unload on ext unload (bug 5851) (Peace-Maker).
- Added printing of SendProp flags to netprop dumps (bug 6082).
- Removed support for obsolete plugin_settings.cfg (bug 5605).
- Fixed topmenu sorting not getting refreshed after reloading sorting config (bug 6032) (Peace-Maker).
- Fixed error log filename date sometimes being incorrect (bug 5761) (Matheus "M28" Valadares).
- Dump handle information when a plugin is forcefully unloaded. (bug 5666).
- Fixed sm_cancelvote not resetting rtv state. (bug 5808) (Peace-Maker).
- Fixed Mapchooser dying on single map rotation servers (bug 5179).
- Fixed various problems with unloading ClientPrefs and SourceMod (bug 5874).
- Fixed "sm version" command reporting incorrect compile time in many cases (bug 6078) (SystematicMania).
- Clear default database driver reference if backing extension is unloaded (bug 5934) (Peace-Maker).
- Moved funcommands material and sound definitions to gamedata for easier cross-game support (bug 6085).
- Implement a watchdog timer for scripts that take too long to execute (bug 5837).
- Use Linux game data for offsets and signatures/symbols on OS X if Mac-specific data is not available (bug 6056).
Developer Changes:
- Added an API for off-thread SQL transactions. (bug 3775, PR 26).
- Added string literal concatenation using ellipses "..." (bug 4261, PR 5) (Peace-Maker).
- Added support for nested datatables. (bug 5446).
- Added PbRemoveRepeatedFieldValue native (bug 6066).
- Added support for getting/setting protobuf enum values with PbGetInt, PbSetInt, and PbAddInt natives.
- Removed deprecated PbReadRepeated natives that existed briefly in 1.5.0-dev prerelease versions.
- Added RequestFrame native for one-off next-frame actions (bug 5965).
- Added CS_DMG_HEADSHOT define for CS:S and CS:GO (PR 7) (Bara20).
- Added CS_SLOT_KNIFE define for CS:S and CS:GO (bug 6131).
- Updated TF_WEAPON enum (PR 37) (FlaminSarge).
- Added TFHoliday_AprilFools to TFHoliday enum (bug 6092) (Ross "Powerlord" Bemrose).
- Added new TF2_IsHolidayActive native to TF2 Ext (bug 6095) (Ross "Powerlord" Bemrose).
- Switch TF2 extension to hook CTFGameRules::IsHolidayActive for holiday forward (bug 6137, PR 42).
- Added GetPlayerJingleFile native. (bug 5690) (FlaminSarge).
- Added PrepSDKCall_SetAddress and Address support to PrepSDKCall_SetFromConf (bug 5261).
- Added ability to disable TopMenu Title Caching (bug 6034) (Peace-Maker).
- Added DisplayTopMenuCategory native (bug 6033) (Peace-Maker).
- Added support for Valve search paths to GetFileSize native (bug 5931).
- Fixed invalid entities sometimes passed to OnEntityCreated and OnEntityDestroyed (bug 6119).
- Fixed inconsistencies with OnClientDisconnected foward calls (bug 5988, PR 16).
- Changed OnClientSayCommand to now pass non-silent chat triggers onward (bug 5926) (SystematicMania).
- Changed OnClientSayCommand forwards to strip quotes from chat (bug 5986) (SystematicMania).
- Fixed FindStringIndex native not returning INVALID_STRING_INDEX when string not found (bug 6144, PR 40).
- Fixed GroundEntChanged hooks not being called (bug 6050) (Peace-Maker).
- Fixed INetChannelInfo natives to no longer require clients to be ingame (bug 5775) (SystematicMania).
- Fixed replace param being respected inconsistently in SetTrieArray (bug 6113).
- Fixed crash creating a timer when there are no handles available. (bug 5317) (Peace-Maker).
- Fixed crash in ReconnectClient and InactivateClient natives when IServer ptr is null (bug 6122).
- Fixed StoreFromAddress and LoadFromAddress continuing with bad values, usually crashing after error (bug 6080).
- Fixed compiler bug with multidimensional array variable release (bug 6100).
- Changed float comparison operators to return false for NaN (bug 6107).
- Added support in spcomp for sp/inc files > 32767 lines (bug 5959).
- Fixed FindFlagChar returning '?' for Admin_Custom6.
- Fixed AllPluginsLoaded activities happening before SM is loaded.
- Deduplicated a number of files used by extensions by moving them to the public directory (bug 5341).
- Removed 'state' keyword from compiler (bug 4572) (Ryan "VoiDeD" Stecker).
- Removed LogMessageEx definition from logging.inc because it never existed (bug 5897) (Peace-Maker).
- Removed native override API (bug 5852).
- Call OnLibraryAdded for all available libraries (bug 5925, PR 4).
- Made IGameConfig::GetMemSig return value clearer (bug 6081).
- Switched StringToInt(Ex) from using strtol to strtoul internally (bug 5939).
- Added an spcomp option to print #included files (bug 5997).
- Recompiled Regex extension libpcre against v8.32, enabling utf8, unicode props, and jit (bug 5593).
- Optimized native calls if statically bound (bug 5842).
Internal Changes:
- Now using new AlliedModders Template Library (AMTL) in many places, https://github.com/alliedmodders/amtl
- Ported buildscripts to new AMBuild2 platform, https://github.com/alliedmodders/ambuild
- Moved much logic from core to logic binary to reduce file sizes and compile times (bug 5606, bug 5607, bug 5680, bug 5953, PR 12, PR 13).
- Refactored the JIT to use a newer, simpler macro assembler. (bug 5827).
- Added sourcepawn interpreter (bug 5902).
- Added support for compiling spcomp with emscripten.
- Rewrite IThreader implementation around new synchronization primitives (bug 5862).
- Rewrite DBManager to use the new synchronization primitives (bug 5870).
- Overhauled internals of ClientPrefs extension for improved stability (bug 5538).
- Changed ShareSys to store C++ native lists more optimally (bug 5852).
- Simplified NativeEntry state (bug 5852).
- Changed NativeEntry to use Refcounted to manage (bug 5852).
- Switched Translator and GameConfigs to hash tables (bug 5878).
- Switched numerous subsystems from KTrie to AMTL NameHashSet (bug 5884).
- Refactored Trie natives to use AMTL HashMap instead of KTrie (bug 5892).
- Removed usages of memtables from many subsystems (bug 5899).
- Changed EventHook name storage to use AMTL AString (bug 6188).
- Replaced SH List usages in game extensions with AMTL variants (PR 23).
- Replaced SourceHook list usages in clientprefs with AMTL (PR 25).
- Changed floating-point operations to use SSE when available (bug 5841).
- Moved tracker related opcodes entirely to C++.
- Statically align the stack at function boundaries (bug 5842).
- Removed InfoVars, reassigned DAT from EBP to ESI to preserve C++ stacktraces in JIT code (5844).
- Fixed dereferencing potential null pointer in CPlugin::GetProperty (bug 5725).
- Fixed memory corruption when parsing natives. (bug 5840).
- Fixed some memory errors (bug 5904).
- Fixed unaligned memory access in spcomp.
- Move versioning to a static library to improve trivial build speed (bug 5997).
- Added many missing handle security checks (bug 5595).
- Made GetEntityClassname get and cache m_iClassname offset from worldspawn for ents not having it in datadesc (bug 5654).
- Cache m_iEFlags offset for datamaps dump instead of getting for each ent (bug 5657).
- Fixed mismatched delete [] on thunks in JIT CompData dtor (bug 5639).
- Fixed various memory issues. (bug 5766).
- Added reference counting and use it for CGameConfig and IDatabase (bug 5876).
- Added atomic reference counting and port DBI (bug 5876).
- Replaced usages of deprecated Sourcehook Add/Remove macros (bug 5631).
- Fixed SDKHooks hook ent validation missing first datatable name (bug 5881).
- Fixed case where bots leave server without disconnect notice (hibernation) (PR 20).
- Changed FindConVar to utilize convar cache for improved performance (PR 27) (VoiDeD).
- Gave define value (of 1) to PLATFORM defs to match the same-name defs in some SDKs (PR 10).
- Wrapped ClientPrintf into IGamePlayer (bug 6021).
- Consolidated FileExists usage in logic bin (bug 5931).
- Removed hardcoded paths to tier0/vstdlib in ICommandLine lookup.
- Use updated IServerTools iface on TF2 for getting tempent list and FindEntityByClassname (PR 33).
- Added early exit in entity output detour if entity has no classname to prevent crash.
- Updated SDKTools entity output functions to use core's GetEntityClassname instead of own (PR 39).
- Consolidated SDKTools entity factory lookups.
- Changed SDKTools PlayerRunCmd to a global vtable hook to improve performance (bug 6051).
- Changed SDKHooks to use global vtable hooks to improve performance (bug 6070).
- Added client validation checks to EmitSound SoundsHooks (bug 5873).
- Added missing meta results to some pre-hooks in SDKHooks.
- Replaced magic numbers for sm_show_activity with named constants (PR 14).
----------------------------------------------------------
SourceMod 1.5.3 [2014-03-22]
URL: http://wiki.alliedmods.net/SourceMod_1.5.3_Release_Notes
User Changes:
- Updated support for CS:GO after multiple breaking game updates.
- Updated gamedata support for GoldenEye: Source (Peace-Maker).
- Fixed crash on SDKHooks extension load in Alien Swarm (bug 6059).
- Fixed memory leak from unmanaged forwards never being freed (bug 6025).
- Fixed possible crash when unloading the CStrike extension.
- Fixed crash in SDKHooks Reload post-hook (Peace-Maker).
- Fixed FakeClientCommandEx always leaking memory (bug 5678).
- Fixed extra entity networking occuring with SetEntProp natives on some games.
- Fixed being able to nominate same map multiple times (bug 5109).
- Fixed spurious FindEntityByClassname error being logged on some games and platforms.
- Fixed an Anti-Flood bypass exploit (bug 5394).
- Removed part of Addresses gamedata error handling which could cause false errors to be logged (bug 6044).
- Fixed mapchooser not resetting nominations count when clearing nominations list (bug 5359).
- Improved performances of client convar query handling (bug 6003).
Developer Changes:
- Added GiveAmmo native to SDKTools (bug 6039) (Peace-Maker).
- Added SQL_SetCharset native to (re)set charset even after reconnect (bug 5786) (Peace-Maker).
- Added support for entity references in SDKHooks natives (bug 6069).
- Added support for server passwords to DisplayAskConnectBox stock (bug 5984) (FlaminSarge).
- Renamed SortFunc2D parameters to match documentation (bug 6014) (Peace-Maker).
- Fixed param order in AddToTopMenu function doc (bug 6035) (Peace-Maker).
- Added |any| tag to WritePackCell and ReadPackCell native param/return values (bug 6001).
- Updated SDKHook_TakeDamage native for game updates.
- Added default infinite value for TF2_AddCondition duration.
- Added support for conditions >= 64 in TF2_OnConditionAdded/Removed (bug 5565, bug 5976) (FlaminSarge).
- Updated TFCond and TF customkill enum values (bug 6012) (FlaminSarge).
- Fixed regression causing incorrect return and inability to block in TF2_OnCalcIsAttackCritical forward.
- Fixed TE_* natives operating on incorrect data for some tempents (bug 6072).
- Fixed CS_AliasToWeaponID not returning a valid weaponID for cz75a.
- Fixed CS_GetWeaponPrice returning incorrect value for M4A1 in CS:GO (bug 6045).
- Increased max gamedata byte signature length.
- Ported SM build scripts to AMBuild2 (bug 5997).
----------------------------------------------------------
SourceMod 1.5.2 [2013-10-29]
URL: http://wiki.alliedmods.net/SourceMod_1.5.2_Release_Notes
User Changes:
- Updated gamedata support for TF2, CS:S, CS:GO, and HL2:DM.
- Fixed crash from regression in SDKTools SetClientListening hook refcounting (bug 5956) (KyleS).
- Fixed potential crash when having maps with format characters in name.
- Fixed some nextmap issues with long map names.
- SDKTools no longer requires gamedata for sm_dump_datamaps on TF2, CS:S, HL2:DM, and DoD:S (bug 5968).
Developer Changes:
- Updated TFCond and TF custom dmg enums.
- Updated TF2 critical hit detection logic in TF2_OnCalcIsAttackCritical to handle more cases, including when criticals are disabled (bug 5894).
- Fixed GetEngineVersion native returning a bad value when running on MM:S 1.9.x or earlier (bug 5697).
----------------------------------------------------------
SourceMod 1.5.1 [2013-09-10]
URL: http://wiki.alliedmods.net/SourceMod_1.5.1_Release_Notes
User Changes:
- Updated gamedata support for TF2.
- Added missing DispatchKeyValue gamedata for HL2 CTF (bug 5114) (peace-maker).
- Fixed translations not being loaded if identifier was not two or three characters (fixes Portuguese) (bug 5888).
- Fixed runoff voting occurring when receiving the exact number of required votes (bug 5890).
- Fixed reserve slot plugin hiding too many slots on Orangebox gamesif SourceTV and/or Replay are present (bug 5499).
- Fixed some crashes in TF2 and unexpected behavior in all games with SDKHook_TakeDamage due to uninitialized var.
- Fixed attempted triggers from gagged users displaying in chat (bug 5918).
- Fixed errors in Italian translation (Oktober).
- Added Norwegian translation (checkster).
Developer Changes:
- Added CS_UpdateClientModel native to CStrike extension for CS:S and CS:GO (bug 5905) (Drifter).
- Fixed setting weapon param in SDKHook_TakeDamage overwriting attacker instead of setting weapon (bug 5911) (KyleS)
----------------------------------------------------------
SourceMod 1.5.0 [2013-08-25]
URL: http://wiki.alliedmods.net/SourceMod_1.5.0_Release_Notes
User Changes:
- Added support for Counter-Strike: Global Offensive (bug 5299, bug 5579).
- Split CS:S, TF2, DoD:S, HL2:DM, and ND to separate binaries (bug 5370, bug 5813).
- Added support for runoff voting in mapchooser (bug 4218).
- Added option to require Steam validation before granting admin access (bug 4837) (VoiDeD).
- Added localization support for many more core and base plugin messages (bug 5120, bug 5146).
- Added the ability to override RegConsoleCommand-created commands (bug 5199).
- Added support for "fuzzy" (partial) map names in map-related natives and cmds for L4D and later (bug 5599).
- Updated Reserved Slots to use max humans as max count (bug 5444).
- Added support for custom maxitems on radio menus (bug 5371).
- Improved console config editing (bug 5470).
- Increased map name buffer sizes in mapchooser to better account for nested maps (bug 5609) (Peace-Maker).
- Fixed JIT conflicts with SELinux (bug 5581).
- Added logged error when PlayerRunCommand offset lookup fails (bug 5535) (GoD-Tony).
- Fixed double print when sending psay to self (bug 5649) (Peace-Maker).
- Fixed check against uninitialized string in extension loader (bug 5546) (KyleS).
- Fixed possible runtime errors in basetriggers for not-ingame clients (bug 5191) (Peace-Maker).
- Check all possible mapcycle paths on newer orangebox games (bug 5719).
- Fixed ReadMapList not seeing maps in all valve search paths (bug 5715) (VoiDeD).
- Fixed typo in too-many-params native error message (Peace-Maker).
- Fixed various issues in clientprefs (bug 5538) (KyleS).
- Removed debug printout from PerformGravity (bug 5679) (KyleS).
- Fixed broken translating in some plugins and natives (bug 5612) (KyleS).
- Fixed issues with COMMAND_FILTER_NO_BOTS and @bots multi-target.
- Fixed crash in SDKHooks when throwing bad ent type error on logical ent (KyleS).
Developer Changes:
- Added support for CS:GO to the CStrike extension (bug 5299) (Drifter).
- Added support for new protobuf usermessages used in newer games (bug 5579, bug 5588, bug 5590, bug 5633).
- Added latest SDKHooks version as first-party extension.
- Updated SQLite to version 3.7.15.1 (bug 5235).
- Added natives for changing team score and mvp stars on CSS/CSGO (bug 5295) (Drifter).
- Added global pre and post forwards for client chat (bug 5394) (KyleS).
- Added TF2_CanPlayerTeleport forward to the TF2 game extension (bug 5283) (VoiDeD).
- Added GetEntityAddress native (bug 5269) (ProdigySim).
- Added more parameters to PlayerRunCommand forward (bug 5346) (GoD-Tony).
- Added forwards to basecomm plugin (bug 5466) (Drifter).
- Added symbol lookup support to gamedata on Windows (bug 5511) (GoD-Tony).
- Exposed GetLanguageInfo in ITranslator interface (bug 5249) (VoiDeD).
- Increase maximum .sp line length to 4095 characters. (bug 5347) (theY4Kman).
- Improved netprop dump output (bug 5471).
- Added int64 typename to netprop dumps (bug 5655).
- Added GetMaxHumanPlayers native exposing IServerGameClients func (bug 5551).
- Added WeaponIDToAlias native to CStrike extension (bug 5460) (KyleS).
- Fixed OnLibraryAdded/Removed not being called in all plugins (bug 5431).
- Made thread worker processing limits configurable at runtime (bug 5326).
- Added support in TF2 ext for detection of player conds >= 64 (bug 5565).
- Updated button defines in entity_prop_stocks (bug 5564).
- Added GetPlayerResourceEntity to SDKTools to replace old, semi-broken TF2-only version (bug 5491).
- Exposed third parameter of TF2's AddCond in TF2_AddCondition (bug 5641) (FlaminSarge).
- Added GetSteamAccountID function to IPlayerHelpers and native for sp (bug 5548) (KyleS).
- Added ISDKHooks interface with entity listeners (bug 5602) (GoD-Tony).
- Added file upload support to webternet extension.
- Added more alternative names for TFClass_Heavy (bug 5338) (Afronanny).
- Throw error instead of crash when calling SetTeamScore between maps (bug 5718) (KyleS).
- Fixed clients not being marked as in kick queue in some cases (bug 5746) (SystematicMania).
- Made compile.sh set working dir to own dir (bug 5710) (KyleS).
- Added CS_IsValidWeaponID native and validity checks to other natives (bug 5566) (Drifter).
- Numerous code documentation fixups (bug 5720) (Tsunami).
- Fixed cmd listener callback return behavior to match func doc (bug 5882).
Internal Changes:
- Fixed handle misuse in clientprefs plugin (bug 5805) (KyleS).
- Removed call to getchar() in debug build of compiler (bug 5626) (KyleS).
- Fixed instability issues with cloned handles (bug 5245, bug 5240) (KyleS).
- Changed extension unload order to avoid exposing finalization window (bug 5556) (KyleS).
- Call OnPluginEnd before finalizer hooks have run (bug 4519).
- Fixed potential for reading out of library bounds in MemoryUtils::FindPattern.
- Fixed typo in TF2 ext asm.c causing accidental assignment instead of compare.
- Overhauled versioning information (bug 5453).
- Changed from RemoveEdict to using the Kill input for TF2_RemoveWeapon.
- Fixed accidental assignment in each of SDKTools and sp compiler (bug 5745) (KyleS).
- Fixed potential deadlock in HandleSystem::TryAndFreeSomeHandles (bug 5665) (KyleS).
----------------------------------------------------------
SourceMod 1.4.7 [2013-02-06]
URL: http://wiki.alliedmods.net/SourceMod_1.4.7_Release_Notes
User Changes:
- Updated support for latest Source 2009 engine changes (CS:S, DoD:S, TF2, HL2DM).
- Updated gamedata for Left 4 Dead 2, Nuclear Dawn, No More Room in Hell, Zombie Panic Source, CSPromod, GoldenEye Source, Synergy, The Hidden, and PVKII.
- Added system to block malware or illegal plugins (bug 5289).
- Fixed a potential crash when a bad entity index is passed to certain functions (bug 5539) (KyleS).
- Added an error message for when auto plugin configs fail to be created due to write error (bug 5465) (Drifter).
- Fixed an issue where a malformed plugin could cause crashes (bug 5478).
Developer Changes:
- Added new values to the TFCond TF2 conditions enum (bug 5537) (FlaminSarge).
- Updated TFHoliday TF2 holidays enum (bug 5526) (Powerlord).
- Fixed regression in SourceMod 1.3.0 causing GetEntPropEnt, GetEntDataEnt2, and GameRules_GetPropEnt to possibly return stale (incorrect) entity indexes in place of -1.
- Added support for < 32-bit unsigned sign extension to GameRules_GetProp lookup (already in GetEntProp since SM 1.4.0).
- Fixed < 32-bit unsigned sign extension in GetEntProp not being applied for array prop elements (bug 5591).
- Fixed value size auto-detection in GetEntProp and GameRules_GetProp for ep2v's new SPROP_VARINT sendprops.
- Fixed Sort_Random sort type not including first value in array sorting functions (bug 4292) (Peace-Maker).
- Fixed GameRules_SetPropVector writing data to unexpected addresses instead of to the gamerules proxy entity (bug 5592) (ProdigySim).
- Fixed VoteMenuToAll stock adding bots to list (bug 5253 (VoiDeD).
----------------------------------------------------------
SourceMod 1.4.6 [2012-09-04]
URL: http://wiki.alliedmods.net/SourceMod_1.4.6_Release_Notes
User Changes:
- Fixed extraneous errors resulting from a bug in 1.4.5.
----------------------------------------------------------
SourceMod 1.4.5 [2012-09-03]
URL: http://wiki.alliedmods.net/SourceMod_1.4.5_Release_Notes
User Changes:
- Updated support for latest Source 2009 engine changes (CS:S, DoD:S, TF2, HL2DM, GMod).
- Updated Nuclear Dawn, Dino D-Day, and Zombie Panic gamedata.
- Added compatibility for running on Metamod:Source 1.9.0.
- Fixed very minor memory leaks in CStrike extension (bug 5456) (KyleS).
- Fixed crash from plugins accessing netprops too early (bug 5297) (KyleS).
- Fixed crash from plugins trying to access nested datadesc members (bug 5446).
Developer Changes:
- Added new TF2 weapon and custom dmg defines.
- Added new TF2 TFHoliday value (bug 5436) (Powerlord).
- Fixed IClientListener::InterceptClientConnect not being able to properly block connections (bug 5461) (PimpinJuice).
- Fixed PrepSDKCall_SetSignature native not working with symbol names on L4D2 linux (bug 5440).
- Fixed resolution of GetProfilerTime native on non-Windows platforms.
-----------------------------
SourceMod 1.4.4 [2012-07-03]
URL: http://wiki.alliedmods.net/SourceMod_1.4.4_Release_Notes
User Changes:
- Updated support for latest Source 2009 engine changes (CS:S, DoD:S, TF2, HL2DM, GMod).
- Updated Nuclear Dawn gamedata.
- Fixed a crash that could occur when selecting an option on a clientprefs prefab menu (bug 5374).
Developer Changes:
- Added new TF2 weapon and custom dmg defines.
- Added new TF2 TFHoliday value (bug 5364) (Powerlord).
- Updated sample extension to properly fill ninvoke with INativeInvoker ptr (bug 5340) (Afronanny).
-----------------------------
SourceMod 1.4.3 [2012-06-09]
URL: http://wiki.alliedmods.net/SourceMod_1.4.3_Release_Notes
User Changes:
- Updated support for latest OrangeBox engine changes (CS:S, DoD:S, TF2, HL2DM, GMod).
- Made clientprefs attempt to reconnect to the database on map change (bug 4745).
- Log functions now respect sv_logecho (bug 5135).
- Fixed client console vote output (bug 5290, bug 5205) (FlaminSarge).
- Fixed error when reloading dependant plugins using aliased natives (bug 5302).
- Fixed intermittent crash when looking for an invalid signature (bug 5301).
- Fixed possible crash when reloading a plugin with an invalid binary (bug 5288).
- Exposed extensions list to clients (bug 5221) (VoiDeD).
- Fixed intermittent crashes in clientprefs (bug 4660).
- Fixed crash when passing an invalid entity reference to ReferenceToEntity (bug 5330).
- Fixed cstrike extension crash on shutdown (bug 5328).
- Lowered threading API think time to 20ms, making threaded MySQL queries complete faster (bug 4733).
Developer Changes:
- Fixed client serials not being unique on Windows (bug 5285).
- Fixed broken SourceTV detection on L4D1 (bug 5216).
- Fixed Float negation operator (bug 5292).
- Updated TF2 condition defines (bug 5259) (FlaminSarge).
- Adding missing SetMenuNoVoteButton native declaration (bug 4522) (GoD-Tony).
- Fixed erroneous const-qualification of name param of GetAdminUsername (bug 5267).
- Added GetGameTickCount native (bug 5209) (GoD-Tony).
-----------------------------
SourceMod 1.4.2 [2011-04-13]
URL: http://wiki.alliedmods.net/SourceMod_1.4.2_Release_Notes
User Changes:
- Updated support for latest OrangeBox engine changes (CS:S, DoD:S, TF2, HL2DM, GMod).
- Fixed regression in SourceMod 1.4.0 causing SM to cause load errors on The Ship (bug 5216).
- Fixed toggling and player lag issues with sm_drug command (bugs 5217, 5218) (FlaminSarge).
Developer Changes:
- Updated TF2-specific defines and enums (bug 5194).
- Fixed StoreToAddress always writing 32 bits and throwing an error (bug 5248) (ProdigySim).
- Fixed crash with StoreToAddress if memory wasn't writable (bug 5252) (Dr!fter).
- Fixed return value of VoteMenuToAll (bug 5254) (VoiDeD).
- Fixed bug in command lower-casing API guarantee
-----------------------------
SourceMod 1.4.1 [2011-12-07]
URL: http://wiki.alliedmods.net/SourceMod_1.4.1_Release_Notes
User Changes:
- Updated support for latest OrangeBox engine changes (CS:S, DoD:S, TF2, HL2DM, GMod).
- Added gamedata for Adrenaline Gamer 2 and No More Room in Hell.
- Fixed "not connected" error in reserve slots plugin (bug 5158) (ostrel).
- Fixed ff trigger output printing to all in triggerer's language (rather than viewer's language) (bug 5161).
- Fixed typo in one of basebans ban reasons (bug 5188).
- Fixed formatting error in Swedish "Vote Count" phrase (bug 5174).
Developer Changes:
- Fixed sp MaxClients not being updated on map changes after load (bug 5160).
- Removed GLIBC_2.7 dependency from spcomp.
- Increased buffer for sm_rcon command to fit larger responses (bug 5169).
- BaseComm now properly registers a library allowing it to be required by other plugins (bug 5156).
- Fixed TFHoliday enum values (bug 5155).
- Updated TF2_OnIsHolidayActive ret behavior to match doc (bug 5155).
- Added new TF2 deathflag and dmg custom defines (bug 5157).
-----------------------------
SourceMod 1.4.0 [2011-10-28]
URL: http://wiki.alliedmods.net/SourceMod_1.4.0_Release_Notes
User Changes:
- Added support for Max OS X (bug 4392).
- Added support for Bloody Good Time (bug 4780).
- Added support for E.Y.E Divine Cybermancy (bug 5035).
- Added gamedata for Nuclear Dawn.
- Added gamedata for International Online Soccer: Source (bug 5019).
- Added gamedata for Half-Life 2 Capture the Flag (bug 5114).
- Updated mapchooser and other base plugins with Nuclear Dawn specific fixes (bug 5117).
- Fixed ServerLang value not being read properly on startup (bug 4675).
- Added support for aliases in languages.cfg (bug 4858).
- Added output display to sm_rcon command (bug 5018).
- Flood protection bypass access can now be overridden with command name sm_flood_access (bug 4584).
- Added a reset argument to sm cvars command to revset cvar values to default (bug 5043).
- Fixed incorrect language identifiers for Chinese (both Trad. and Simplified) and Brazilian Portuguese not matching cl_language values (bug 5067).
- Added translation support for Bulgarian (bg).
- Fixed incorrect number of slots being hidden for reserve with sm_hideslots on Source 2009 with SourceTV or replay (bug 5094).
- sm_hideslots changes now take effect immediately instead of waiting until a client joins or leaves (bug 5094).
- Fixed sv_visiblemaxplayers getting stuck at previous max clients in some cases with reserves and SourceTV or replay (bug 5094).
- Removed error logging if an optional extension is not found (bug 5112).
- Fixed bots with semicolon in name being unkickable (bug 5120).
- Changed strings in ice-related funcommands to be translatable (bug 4540).
- Changed Bintools extension to use a single build for every engine (bug 4548).
Developer Changes:
- Provided native interface for basecomm (bug 2594).
- Client language detection is too late. (bug 3714) (Tony A. "GoD-Tony").
- Added ServerCommandEx native to execute server command and retrieve output (bug 3873).
- Added ability to update clientprefs cookies values on clients not currently connected (bug 3882) (databomb).
- Added library "matchmaking_ds" support to gamedata lookups (bug 4158).
- Rooted menu handles to callbacks (bug 4353).
- Fixed corner cases with ExplodeString (bug 4629). (Michael "LumiStance").
- Fixed return omission with else-after-return (bug 4852).
- Added OnConditionAdded and OnConditionRemoved forwards to TF2 extension (bug 4851).
- Added new natives and forward to the cstrike extension (bug 4732, bug 4985) (Dr!fter).
- Added WaitingForPlayers forwards to the TF2 extension (bug 4704) (CrimsonGT).
- Updated and added more TF2 condition, weapon, and damagecustom defines (multiple bug#s).
- Fixed TF2_RemoveCondition not always removing conditions (bug 4981).
- Fixed MaxClients not being updated correctly in some places with SourceTV or replay active (bug 4986).
- Fixed some vars not being marked for init on first compile pass (bug 4643).
- Increased symbol name limit to 63 characters (bug 4564) (javalia).
- Fixed crash when dynamic arrays run out of memory (bug 4632).
- Fixed a crash that could happen from looking up out-of-bounds edict or entity indexes (bug 5080).
- Fixed client serials not getting cleared on disconnect (bug 5121).
- Added error on declaring arrays that the compiler is too buggy to handle (bug 4977).
- Removed reliance on gamedata for multiple SDKTools functions in ep2 and later (bug 4899).
- Added InvalidateClient and ReconnectClient natives to SDKTools (bug 4931) (Brian "Afronanny" Simon).
- Added ability to lookup and set values on the gamerules class (bug 4983.
- BaseComm now uses AddCommandListener for chat hooks (bug 4991).
- Fixed shutdown bug in SDKTools (bug 5063).
- Fixed MM-enabled extensions continuing to load after failing MM attach (bug 5042).
- Added GetDistGainFromSoundLevel native to SDKTools (bug 5066) (javalia).
- Added CheckAccess native to check an AdminId's command access (bug 5083).
- Fixed GetEntProp not sign-extending unsigned values less than 32 bits (bug 5105).
- Fixed crashing when calling CreateEntityByName or CreateFakeClient when no map is running (now errors) (bug 5119).
- Fixed erring in kick function (e. bad translation) causing client to become unkickable until disconnect (bug 5120).
- Fixed KickClientEx not immediately kicking client if client was in kick queue (bug 5120).
- Added IsClientSourceTV and IsClientReplay natives (bug 5124).
- Added support for getting and setting individual array elements with Get/Set EntProp functions (bug 4160).
- Added support for threaded query handles to SQL_GetInsertId and SQL_GetAffectedRows (bug 4699) (Nephyrin).
- Added a GetGameRules function to ISDKTools for extensions to easily get the GameRules class pointer (bug 4707).
- Added GetMessageName to IUserMessages (bug 4573) (Zach "theY4Kman" Kanzler)
- Added HintTextMsg to IGameHelpers (bug 4950).
- Added ProcessTargetString simple filter API (bug 4404).
- Moved much functionality from core bins to logic bin (bug 4406, bug 4402).
- Fixed bogus asserts in sp compiler (bug 4486, bug 4487).
- Greatly improved sp compiler performance (~5x overall speedup) (bug 3820, bug 4493, bug 4495).
- Changed entity output detours to use CDetour (bug 4416).
- Enhanced nominations API (bug 4677) (CrimsonGT).
- Added Linux support for profiling natives (bug 4927).
- Added a new ValveCallType that allows for arbitrary |this| parameters, as well as associated features in gamedata and for reading/writing memory (bug 3520) (Downtown1).
- Updated TF2 extension to handle Valve's changes to the "holiday" system (bug 5150).
-----------------------------
SourceMod 1.3.8 [2011-06-23]
URL: http://wiki.alliedmods.net/SourceMod_1.3.8_Release_Notes
User Changes:
- Updated support for latest OrangeBox engine changes (CS:S, DoD:S, TF2, HL2DM, GMod).
- Updated support for various games, including Garry's Mod, Zombie Panic, and Dino D-Day.
- Added gamedata for Eternal Silence.
- Fixed libgcc_s.so.1 load error present on some systems (bug 4876).
- Handle leak notices now print to error log (in addition fatal log) (bug 4929).
- Translator now properly falls back on bad server language (bug 4861).
- Fixed invalid client errors from bad MaxClients value when SourceTV is late-loaded (bug 4881).
- Fixed crash on plugin unload when two commands exist with same name, different casing (bug 4698).
Developer Changes:
- Updated TF2 condition defines (bug 4916).
- Fixed var names and docs for TF2_MakeBleed native (bug 4928).
- Removed compiler double include check (bug 4863).
- Fixed plugin compile errors when using GetEntityClassname (bug 4798).
---------------------------
SourceMod 1.3.7 [2011-04-15]
URL: http://wiki.alliedmods.net/SourceMod_1.3.7_Release_Notes
User Changes:
- Updated support for latest OrangeBox engine changes (CS:S, DoD:S, TF2, HL2DM, GMod).
- Updated support for various games, including Zombie Panic, CS ProMod, Empires, and GoldenEye: Source.
- Added gamedata for Dino D-Day.
- Fix precedence of voice mute flag versus specific client overrides (bug 4826).
- Fix mistaken unhooking of voice hooks (bug 4804).
- Fixed graphical glitches with funcommands effects in L4D1 (bug 3486).
- Fixed bug in nominations that could cause "Unknown command" error (bug 4797).
- Removed tv_enable hook to fix rare max client count issue (bug 4791).
- Added missing unhooking of ClientConnect in PlayerManager (bug 4749).
- Fixed sm_rtv printing "unknown command" (bug 4730).
- Fixed voting crash when client console, chat, and SourceTV are enabled (bug 4676).
- Fixed CDetour crash in TF2 extension when last plugin using forward is unloaded (bug 4713).
Developer Changes:
- SetEntProp now marks edict state as changed (bug 4855).
- Added GetEntityClassname stock (bug 4798).
- Fix compiler hanging when #including a directory (bug 4822).
- Added GetEntityFlags and SetEntityFlags natives for better cross-engine compatibility. (bug 4809).
- Fixed ClientPrefs natives not being marked optional when REQUIRE_EXTENSIONS not defined (bug 4839).
- Changed some instances of LogMessage to LogAction (bug 4649).
- Added some new language natives (bug 4613).
- Fixed SetTeamScore not updating score on client (bug 2736).
- Raised MAXPLAYERS from 64 to 65 (bug 4490).
- Added and updated many TF2-specific defines in tf2.inc and tf2_stocks.inc.
- Fixed TF2_GetPlayerConditionFlags no longer necessarily returning all set flags (bug 4726).
- Fixed profiler flush not clearing, added 'report' and 'clear' (bug 4674).
- Fixed GetPlayerDecalFile crash on L4D and L4D2 (bug 4729).
- Fixed TF2_OnGetHoliday detour no longer firing under all circumstances (bug 4700).
- Added TF2_IsPlayerInDuel native to TF2 extension (bug 4695).
----------------------------
SourceMod 1.3.6 [2010-10-31]
URL: http://wiki.alliedmods.net/SourceMod_1.3.6_Release_Notes
User Changes:
- Updated support for latest Left 4 Dead 1 (bug 4681).
Developer Changes:
- Updated TF2 custom kill defines (bug 4682).
----------------------------
SourceMod 1.3.5 [2010-10-17]
URL: http://wiki.alliedmods.net/SourceMod_1.3.5_Release_Notes
User Changes:
- Updated support for CS:S, Garry's Mod, DoD:S, TF2, HL2DM.
- Added support for Firearms: Source (bug 4537).
- Added support for Fistful of Frags (bug 3883).
- Added support for Alien Swarm (bug 4530).
- Fixed living players hearing dead players if alltalk is disabled while deadtalk is on (bug 4533, thanks Zach Callear).
- Fixed timeleft not getting reset on Game_Commencing in CS:S (bug 4557).
- Fixed PlayerRunCmd being hooked when not used (bug 3990).
- Fixed errors and missing effects caused by missing sprites on L4D2 (bug 4512).
- Fixed 'sm plugins' public command skipping plugins in recommended listing (bug 4501).
- Fixed corruption with large database.cfg files (bug 4286).
Developer Changes:
- Added TF2 object stocks (bug 4536).
- Added TF2_MakeBleed native to TF2 ext (bug 4542).
- Added support for logical entities in Synergy (bug 4534).
- Updated TF2 conditions enum and defines (bug 4526).
- Fixed potential crash with IMemUtils::FindPattern on Linux (bug 4554).
----------------------------
SourceMod 1.3.4 [2010-07-18]
URL: http://wiki.alliedmods.net/SourceMod_1.3.4_Release_Notes
User Changes:
- Support for latest TF update (bug 4506).
- Support for latest L4D2 update (bug 4509).
Developer Changes:
- Added FindFlagChar native (bug 3776).
- Added GetConVarDefault native (bug 4502).
- Added forward for TF's GetHoliday function (bug 4462).
----------------------------
SourceMod 1.3.3 [2010-06-23]
-16
View File
@@ -1,16 +0,0 @@
"banreasons"
{
"Abusive" "Abusive"
"Racism" "Racism"
"General cheating/exploits" "General cheating/exploits"
"Wallhack" "Wallhack"
"Aimbot" "Aimbot"
"Speedhacking" "Speedhacking"
"Mic spamming" "Mic spamming"
"Admin disrespect" "Admin disrespect"
"Camping" "Camping"
"Team killing" "Team killing"
"Unacceptable Spray" "Unacceptable Spray"
"Breaking Server Rules" "Breaking Server Rules"
"Other" "Other"
}
-26
View File
@@ -107,30 +107,4 @@
* Currently this will log details about the gamedata updating process.
*/
"DebugSpew" "no"
/**
* If set to yes, SourceMod will validate steamid auth strings with the Steam backend before giving out admin access.
* This can prevent malicious users from impersonating admins with stolen Steam apptickets.
* If Steam is down, admins will not be authenticated until Steam comes back up.
* This option increases the security of your server, but is still experimental.
*/
"SteamAuthstringValidation" "yes"
/**
* Enables or disables whether SourceMod blocks known or potentially malicious plugins from loading.
* It is STRONGLY advised that this is left enabled, there have been cases in the past with plugins that
* allow anyone to delete files on the server, gain full rcon control, etc.
*
* "yes" - Block malware or illegal plugins from loading (default)
* "no" - Warn about malware or illegal plugins loading
*/
"BlockBadPlugins" "yes"
/**
* If a plugin takes too long to execute, hanging or freezing the game server in the process,
* SourceMod will attempt to terminate that plugin after the specified timeout length has
* passed. You can disable this feature by setting the value to "0".
*/
"SlowScriptTimeout" "8"
}
-2
View File
@@ -2,8 +2,6 @@
{
"driver_default" "mysql"
// When specifying "host", you may use an IP address, a hostname, or a socket file path
"default"
{
"driver" "default"
+36
View File
@@ -0,0 +1,36 @@
/**
* Each sub-section of "Plugins" should have a title which specifies a plugin filename.
* Filenames have a wildcard of *. Appending .smx is not required.
* If the filename has no explicit path, it will be patched to any sub-path in the plugins folder.
*
* Available properties for plugins are:
* "pause" - Whether or not the plugin should load paused - "yes" or "no" (default)
* "lifetime" - Lifetime of the plugin. Options:
* "mapsync" - Plugins should be reloaded on mapchange if changed (default)
* "global" - Plugin will never be unloaded or updated
* "blockload" - Plugin will always be blocked from loading. Implicit (automatic) loads
* produce no error, but explicit (manual) loads will show an error message.
* (Options are one of "yes" or "no")
*
* You can also have an "Options" section declaring options to pass onto the JIT:
* "profile" - Bit flags for profiling level. Add flags together to reach a value.
* WARNING: Profiler is _ALPHA_ software! Use it at your own risk for
* development cycles only (not production setups).
* See the wiki article "SourceMod Profiler" for more information.
* 1 - Profile natives
* 2 - Profile callbacks
* 4 - Profile internal plugin function calls
*/
"Plugins"
{
"*"
{
"pause" "no"
"lifetime" "mapsync"
"Options"
{
}
}
}
+3 -29
View File
@@ -1,36 +1,10 @@
# vim: set ts=2 sw=2 tw=99 noet:
import sys
try:
from ambuild2 import run
except:
try:
import ambuild
sys.stderr.write('It looks like you have AMBuild 1 installed, but this project uses AMBuild 2.\n')
sys.stderr.write('Upgrade to the latest version of AMBuild to continue.\n')
except:
sys.stderr.write('AMBuild must be installed to build this project.\n')
sys.stderr.write('http://www.alliedmods.net/ambuild\n')
sys.exit(1)
import ambuild.runner as runner
run = run.PrepareBuild(sourcePath=sys.path[0])
run.default_build_folder = 'obj-' + run.target_platform
run.options.add_option('--hl2sdk-root', type=str, dest='hl2sdk_root', default=None,
help='Root search folder for HL2SDKs')
run.options.add_option('--mysql-path', type=str, dest='mysql_path', default=None,
help='Path to MySQL 5')
run.options.add_option('--mms-path', type=str, dest='mms_path', default=None,
help='Path to Metamod:Source')
run = runner.Runner()
run.options.add_option('--enable-debug', action='store_const', const='1', dest='debug',
help='Enable debugging symbols')
run.options.add_option('--enable-optimize', action='store_const', const='1', dest='opt',
help='Enable optimization')
run.options.add_option('--no-mysql', action='store_false', default=True, dest='hasMySql',
help='Disable building MySQL extension')
run.options.add_option('-s', '--sdks', default='all', dest='sdks',
help='Build against specified SDKs; valid args are "all", "present", or '
'comma-delimited list of engine names (default: %default)')
run.options.add_option('--breakpad-dump', action='store_true', dest='breakpad_dump',
default=False, help='Dump and upload breakpad symbols')
run.options.add_option('--disable-auto-versioning', action='store_true', dest='disable_auto_versioning',
default=False, help='Disable the auto versioning script')
run.Configure()
run.Configure(sys.path[0])
@@ -1,5 +1,5 @@
/**
* vim: set ts=4 sw=4 tw=99 noet :
* vim: set ts=4 :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
@@ -30,6 +30,7 @@
*/
#include "ADTFactory.h"
#include "sm_globals.h"
#include "ShareSys.h"
ADTFactory g_AdtFactory;
@@ -56,30 +57,32 @@ IBasicTrie *ADTFactory::CreateBasicTrie()
BaseTrie::BaseTrie()
{
m_pTrie = sm_trie_create();
}
BaseTrie::~BaseTrie()
{
sm_trie_destroy(m_pTrie);
}
bool BaseTrie::Insert(const char *key, void *value)
{
return map_.insert(key, value);
return sm_trie_insert(m_pTrie, key, value);
}
bool BaseTrie::Retrieve(const char *key, void **value)
{
return map_.retrieve(key, value);
return sm_trie_retrieve(m_pTrie, key, value);
}
bool BaseTrie::Delete(const char *key)
{
return map_.remove(key);
return sm_trie_delete(m_pTrie, key);
}
void BaseTrie::Clear()
{
map_.clear();
sm_trie_clear(m_pTrie);
}
void BaseTrie::Destroy()
@@ -89,5 +92,5 @@ void BaseTrie::Destroy()
bool BaseTrie::Replace(const char *key, void *value)
{
return map_.replace(key, value);
return sm_trie_replace(m_pTrie, key, value);
}
@@ -1,5 +1,5 @@
/**
* vim: set ts=4 sw=4 tw=99 noet :
* vim: set ts=4 :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
@@ -33,8 +33,8 @@
#define _INCLUDE_SOURCEMOD_ADTFACTORY_H_
#include <IADTFactory.h>
#include "common_logic.h"
#include <sm_stringhashmap.h>
#include "sm_globals.h"
#include "sm_trie.h"
using namespace SourceMod;
@@ -50,7 +50,7 @@ public:
virtual void Clear();
virtual void Destroy();
private:
StringHashMap<void *> map_;
Trie *m_pTrie;
};
class ADTFactory :
+85 -113
View File
@@ -1,118 +1,90 @@
# vim: set sts=2 ts=8 sw=2 tw=99 et ft=python:
# vim: set ts=2 sw=2 tw=99 noet ft=python:
import os
project = SM.HL2Project(builder, 'sourcemod')
project.sources += [
'MenuStyle_Valve.cpp',
'logic_bridge.cpp',
'smn_entities.cpp',
'sm_stringutil.cpp',
'MenuVoting.cpp',
'smn_events.cpp',
'CDataPack.cpp',
'frame_hooks.cpp',
'smn_nextmap.cpp',
'sourcemm_api.cpp',
'ChatTriggers.cpp',
'smn_player.cpp',
'sourcemod.cpp',
'concmd_cleaner.cpp',
'HalfLife2.cpp',
'NextMap.cpp',
'ConCmdManager.cpp',
'ConVarManager.cpp',
'LibrarySys.cpp',
'PlayerManager.cpp',
'TimerSys.cpp',
'CoreConfig.cpp',
'Logger.cpp',
'smn_halflife.cpp',
'smn_console.cpp',
'UserMessages.cpp',
'MenuManager.cpp',
'smn_hudtext.cpp',
'smn_usermsgs.cpp',
'MenuStyle_Base.cpp',
'smn_keyvalues.cpp',
'smn_vector.cpp',
'EventManager.cpp',
'MenuStyle_Radio.cpp',
'sm_autonatives.cpp',
'sm_srvcmds.cpp',
'ConsoleDetours.cpp',
'vprof_tool.cpp',
'smn_commandline.cpp',
]
for i in SM.sdkInfo:
sdk = SM.sdkInfo[i]
name = 'sourcemod.' + sdk['ext']
for sdk_name in SM.sdks:
sdk = SM.sdks[sdk_name]
binary_name = 'sourcemod.' + sdk.ext
compiler = SM.DefaultHL2Compiler('core', i)
binary = SM.HL2Config(project, binary_name, sdk)
compiler = binary.compiler
if sdk.name == 'csgo':
compiler.cxxincludes += [
os.path.join(sdk.path, 'common', 'protobuf-2.5.0', 'src'),
os.path.join(sdk.path, 'public', 'engine', 'protobuf'),
os.path.join(sdk.path, 'public', 'game', 'shared', 'csgo', 'protobuf')
]
elif sdk.name == 'dota':
compiler.cxxincludes += [
os.path.join(sdk.path, 'common', 'protobuf-2.6.1', 'src'),
os.path.join(sdk.path, 'public', 'engine', 'protobuf'),
os.path.join(sdk.path, 'public', 'game', 'shared', 'protobuf'),
os.path.join(sdk.path, 'public', 'game', 'shared', 'dota', 'protobuf')
]
if builder.target_platform == 'linux':
compiler.postlink += ['-lpthread', '-lrt']
if sdk.name == 'csgo' or sdk.name == 'dota':
if builder.target_platform == 'linux':
lib_path = os.path.join(sdk.path, 'lib', 'linux32', 'release', 'libprotobuf.a')
elif builder.target_platform == 'mac':
lib_path = os.path.join(sdk.path, 'lib', 'osx32', 'release', 'libprotobuf.a')
elif builder.target_platform == 'windows':
msvc_ver = compiler.version
vs_year = ''
if msvc_ver == 1800:
vs_year = '2013'
elif msvc_ver == 1700:
vs_year = '2012'
elif msvc_ver == 1600:
vs_year = '2010'
else:
raise Exception('Cannot find libprotobuf for MSVC version "' + compiler.version + '"')
if 'DEBUG' in compiler.defines:
lib_path = os.path.join(sdk.path, 'lib', 'win32', 'debug', 'vs' + vs_year, 'libprotobuf.lib')
else:
lib_path = os.path.join(sdk.path, 'lib', 'win32', 'release', 'vs' + vs_year, 'libprotobuf.lib')
compiler.linkflags.insert(0, binary.Dep(lib_path))
if sdk.name in ['csgo', 'dota']:
binary.sources += ['smn_protobuf.cpp']
else:
binary.sources += ['smn_bitbuffer.cpp']
if sdk.name == 'csgo':
binary.sources += [
os.path.join(sdk.path, 'public', 'engine', 'protobuf', 'netmessages.pb.cc'),
os.path.join(sdk.path, 'public', 'game', 'shared', 'csgo', 'protobuf', 'cstrike15_usermessages.pb.cc'),
os.path.join(sdk.path, 'public', 'game', 'shared', 'csgo', 'protobuf', 'cstrike15_usermessage_helpers.cpp'),
]
elif sdk.name == 'dota':
binary.sources += [
os.path.join(sdk.path, 'public', 'engine', 'protobuf', 'networkbasetypes.pb.cc'),
os.path.join(sdk.path, 'public', 'engine', 'protobuf', 'netmessages.pb.cc'),
os.path.join(sdk.path, 'public', 'engine', 'protobuf', 'network_connection.pb.cc'),
os.path.join(sdk.path, 'public', 'game', 'shared', 'protobuf', 'ai_activity.pb.cc'),
os.path.join(sdk.path, 'public', 'game', 'shared', 'protobuf', 'usermessages.pb.cc'),
os.path.join(sdk.path, 'public', 'game', 'shared', 'dota', 'protobuf', 'dota_commonmessages.pb.cc'),
os.path.join(sdk.path, 'public', 'game', 'shared', 'dota', 'protobuf', 'dota_usermessages.pb.cc'),
os.path.join(sdk.path, 'public', 'game', 'shared', 'dota', 'protobuf', 'dota_usermessage_helpers.cpp'),
]
SM.binaries += builder.Add(project)
extension = AMBuild.AddJob(name)
binary = Cpp.LibraryBuilder(name, AMBuild, extension, compiler)
SM.PreSetupHL2Job(extension, binary, i)
files = [
'AdminCache.cpp',
'ExtensionSys.cpp',
'MenuStyle_Valve.cpp',
'sm_crc32.cpp',
'logic_bridge.cpp',
'smn_entities.cpp',
'sm_stringutil.cpp',
'ADTFactory.cpp',
'ForwardSys.cpp',
'MenuVoting.cpp',
'sm_memtable.cpp',
'smn_events.cpp',
'smn_menus.cpp',
'sm_trie.cpp',
'CDataPack.cpp',
'frame_hooks.cpp',
'NativeInvoker.cpp',
'smn_admin.cpp',
'smn_fakenatives.cpp',
'smn_nextmap.cpp',
'sourcemm_api.cpp',
'ChatTriggers.cpp',
'GameConfigs.cpp',
'NativeOwner.cpp',
'smn_filesystem.cpp',
'smn_player.cpp',
'sourcemod.cpp',
'concmd_cleaner.cpp',
'HalfLife2.cpp',
'NextMap.cpp',
'smn_profiler.cpp',
'ConCmdManager.cpp',
'HandleSys.cpp',
'PhraseCollection.cpp',
'ConVarManager.cpp',
'LibrarySys.cpp',
'PlayerManager.cpp',
'smn_banning.cpp',
'smn_gameconfigs.cpp',
'smn_string.cpp',
'TimerSys.cpp',
'CoreConfig.cpp',
'Logger.cpp',
'PluginInfoDatabase.cpp',
'smn_bitbuffer.cpp',
'smn_halflife.cpp',
'Translator.cpp',
'MemoryUtils.cpp',
'PluginSys.cpp',
'smn_console.cpp',
'smn_handles.cpp',
'smn_timers.cpp',
'UserMessages.cpp',
'Database.cpp',
'MenuManager.cpp',
'smn_core.cpp',
'smn_hudtext.cpp',
'smn_usermsgs.cpp',
'DebugReporter.cpp',
'MenuStyle_Base.cpp',
'ShareSys.cpp',
'smn_database.cpp',
'smn_keyvalues.cpp',
'smn_vector.cpp',
'EventManager.cpp',
'MenuStyle_Radio.cpp',
'sm_autonatives.cpp',
'smn_datapacks.cpp',
'smn_lang.cpp',
'sm_srvcmds.cpp',
'ConsoleDetours.cpp'
]
binary.AddSourceFiles('core', files)
SM.PostSetupHL2Job(extension, binary, i)
SM.AutoVersion('core', binary)
binary.SendToJob()
File diff suppressed because it is too large Load Diff
+208 -227
View File
@@ -1,227 +1,208 @@
/**
* vim: set ts=4 sw=4 tw=99 noet :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
* =============================================================================
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 3.0, as published by the
* Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
* As a special exception, AlliedModders LLC gives you permission to link the
* code of this program (as well as its derivative works) to "Half-Life 2," the
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
* by the Valve Corporation. You must obey the GNU General Public License in
* all respects for all other code used. Additionally, AlliedModders LLC grants
* this exception to all derivative works. AlliedModders LLC defines further
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
* or <http://www.sourcemod.net/license.php>.
*
* Version: $Id$
*/
#ifndef _INCLUDE_SOURCEMOD_ADMINCACHE_H_
#define _INCLUDE_SOURCEMOD_ADMINCACHE_H_
#include "common_logic.h"
#include <IAdminSystem.h>
#include "sm_memtable.h"
#include <sm_trie.h>
#include <sh_list.h>
#include <sh_string.h>
#include <IForwardSys.h>
#include <sm_stringhashmap.h>
#include <sm_namehashset.h>
using namespace SourceHook;
#define GRP_MAGIC_SET 0xDEADFADE
#define GRP_MAGIC_UNSET 0xFACEFACE
#define USR_MAGIC_SET 0xDEADFACE
#define USR_MAGIC_UNSET 0xFADEDEAD
typedef StringHashMap<OverrideRule> OverrideMap;
struct AdminGroup
{
uint32_t magic; /* Magic flag, for memory validation (ugh) */
unsigned int immunity_level; /* Immunity level */
/* Immune from target table (-1 = nonexistent)
* [0] = number of entries
* [1...N] = immune targets
*/
int immune_table;
OverrideMap *pCmdTable; /* Command override table (can be NULL) */
OverrideMap *pCmdGrpTable; /* Command group override table (can be NULL) */
int next_grp; /* Next group in the chain */
int prev_grp; /* Previous group in the chain */
int nameidx; /* Name */
FlagBits addflags; /* Additive flags */
};
struct AuthMethod
{
String name;
StringHashMap<AdminId> identities;
AuthMethod(const char *name)
: name(name)
{
}
static inline bool matches(const char *name, const AuthMethod *method)
{
return strcmp(name, method->name.c_str()) == 0;
}
};
struct UserAuth
{
unsigned int index; /* Index into auth table */
int identidx; /* Index into the string table */
};
struct AdminUser
{
uint32_t magic; /* Magic flag, for memory validation */
FlagBits flags; /* Flags */
FlagBits eflags; /* Effective flags */
int nameidx; /* Name index */
int password; /* Password index */
unsigned int grp_count; /* Number of groups */
unsigned int grp_size; /* Size of groups table */
int grp_table; /* Group table itself */
int next_user; /* Next user in the list */
int prev_user; /* Previous user in the list */
UserAuth auth; /* Auth method for this user */
unsigned int immunity_level; /* Immunity level */
unsigned int serialchange; /* Serial # for changes */
};
class AdminCache :
public IAdminSystem,
public SMGlobalClass
{
public:
AdminCache();
~AdminCache();
public: //SMGlobalClass
void OnSourceModStartup(bool late);
void OnSourceModAllInitialized();
void OnSourceModLevelChange(const char *mapName);
void OnSourceModShutdown();
void OnSourceModPluginsLoaded();
public: //IAdminSystem
/** Command cache stuff */
void AddCommandOverride(const char *cmd, OverrideType type, FlagBits flags);
bool GetCommandOverride(const char *cmd, OverrideType type, FlagBits *flags);
void UnsetCommandOverride(const char *cmd, OverrideType type);
/** Group cache stuff */
GroupId AddGroup(const char *group_name);
GroupId FindGroupByName(const char *group_name);
void SetGroupAddFlag(GroupId id, AdminFlag flag, bool enabled);
bool GetGroupAddFlag(GroupId id, AdminFlag flag);
FlagBits GetGroupAddFlags(GroupId id);
void SetGroupGenericImmunity(GroupId id, ImmunityType type, bool enabled);
bool GetGroupGenericImmunity(GroupId id, ImmunityType type);
void InvalidateGroup(GroupId id);
void AddGroupImmunity(GroupId id, GroupId other_id);
unsigned int GetGroupImmunityCount(GroupId id);
GroupId GetGroupImmunity(GroupId id, unsigned int number);
void AddGroupCommandOverride(GroupId id, const char *name, OverrideType type, OverrideRule rule);
bool GetGroupCommandOverride(GroupId id, const char *name, OverrideType type, OverrideRule *pRule);
void DumpAdminCache(AdminCachePart part, bool rebuild);
void AddAdminListener(IAdminListener *pListener);
void RemoveAdminListener(IAdminListener *pListener);
/** User stuff */
void RegisterAuthIdentType(const char *name);
AdminId CreateAdmin(const char *name);
const char *GetAdminName(AdminId id);
bool BindAdminIdentity(AdminId id, const char *auth, const char *ident);
virtual void SetAdminFlag(AdminId id, AdminFlag flag, bool enabled);
bool GetAdminFlag(AdminId id, AdminFlag flag, AccessMode mode);
FlagBits GetAdminFlags(AdminId id, AccessMode mode);
bool AdminInheritGroup(AdminId id, GroupId gid);
unsigned int GetAdminGroupCount(AdminId id);
GroupId GetAdminGroup(AdminId id, unsigned int index, const char **name);
void SetAdminPassword(AdminId id, const char *password);
const char *GetAdminPassword(AdminId id);
AdminId FindAdminByIdentity(const char *auth, const char *identity);
bool InvalidateAdmin(AdminId id);
unsigned int FlagBitsToBitArray(FlagBits bits, bool array[], unsigned int maxSize);
FlagBits FlagBitArrayToBits(const bool array[], unsigned int maxSize);
FlagBits FlagArrayToBits(const AdminFlag array[], unsigned int numFlags);
unsigned int FlagBitsToArray(FlagBits bits, AdminFlag array[], unsigned int maxSize);
bool CheckAdminFlags(AdminId id, FlagBits bits);
bool CanAdminTarget(AdminId id, AdminId target);
void SetAdminFlags(AdminId id, AccessMode mode, FlagBits bits);
bool FindFlag(const char *str, AdminFlag *pFlag);
bool FindFlag(char c, AdminFlag *pAdmFlag);
FlagBits ReadFlagString(const char *flags, const char **end);
size_t FillFlagString(FlagBits bits, char *buffer, size_t maxlen);
unsigned int GetAdminSerialChange(AdminId id);
bool CanAdminUseCommand(int client, const char *cmd);
const char *GetGroupName(GroupId gid);
unsigned int SetGroupImmunityLevel(GroupId gid, unsigned int level);
unsigned int GetGroupImmunityLevel(GroupId gid);
unsigned int SetAdminImmunityLevel(AdminId id, unsigned int level);
unsigned int GetAdminImmunityLevel(AdminId id);
bool CheckAccess(int client,
const char *cmd,
FlagBits flags,
bool override_only);
bool FindFlagChar(AdminFlag flag, char *c);
bool IsValidAdmin(AdminId id);
bool CheckClientCommandAccess(int client, const char *cmd, FlagBits cmdflags);
public:
bool DumpCache(const char *filename);
AdminGroup *GetGroup(GroupId gid);
AdminUser *GetUser(AdminId id);
const char *GetString(int idx);
bool CheckAdminCommandAccess(AdminId adm, const char *cmd, FlagBits flags);
private:
void _UnsetCommandOverride(const char *cmd);
void _UnsetCommandGroupOverride(const char *group);
void InvalidateGroupCache();
void InvalidateAdminCache(bool unlink_admins);
void DumpCommandOverrideCache(OverrideType type);
AuthMethod *GetMethodByIndex(unsigned int index);
bool GetMethodIndex(const char *name, unsigned int *_index);
const char *GetMethodName(unsigned int index);
void NameFlag(const char *str, AdminFlag flag);
bool GetUnifiedSteamIdentity(const char *ident, char *out, size_t maxlen);
public:
typedef StringHashMap<FlagBits> FlagMap;
BaseStringTable *m_pStrings;
BaseMemTable *m_pMemory;
FlagMap m_CmdOverrides;
FlagMap m_CmdGrpOverrides;
int m_FirstGroup;
int m_LastGroup;
int m_FreeGroupList;
StringHashMap<GroupId> m_Groups;
List<IAdminListener *> m_hooks;
List<AuthMethod *> m_AuthMethods;
NameHashSet<AuthMethod *> m_AuthTables;
IForward *m_pCacheFwd;
int m_FirstUser;
int m_LastUser;
int m_FreeUserList;
bool m_InvalidatingAdmins;
bool m_destroying;
StringHashMap<AdminFlag> m_LevelNames;
};
extern AdminCache g_Admins;
#endif //_INCLUDE_SOURCEMOD_ADMINCACHE_H_
/**
* vim: set ts=4 :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
* =============================================================================
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 3.0, as published by the
* Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
* As a special exception, AlliedModders LLC gives you permission to link the
* code of this program (as well as its derivative works) to "Half-Life 2," the
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
* by the Valve Corporation. You must obey the GNU General Public License in
* all respects for all other code used. Additionally, AlliedModders LLC grants
* this exception to all derivative works. AlliedModders LLC defines further
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
* or <http://www.sourcemod.net/license.php>.
*
* Version: $Id$
*/
#ifndef _INCLUDE_SOURCEMOD_ADMINCACHE_H_
#define _INCLUDE_SOURCEMOD_ADMINCACHE_H_
#include "sm_memtable.h"
#include <sm_trie.h>
#include <sh_list.h>
#include <sh_string.h>
#include <IAdminSystem.h>
#include "sm_globals.h"
#include <IForwardSys.h>
using namespace SourceHook;
#define GRP_MAGIC_SET 0xDEADFADE
#define GRP_MAGIC_UNSET 0xFACEFACE
#define USR_MAGIC_SET 0xDEADFACE
#define USR_MAGIC_UNSET 0xFADEDEAD
struct AdminGroup
{
uint32_t magic; /* Magic flag, for memory validation (ugh) */
unsigned int immunity_level; /* Immunity level */
/* Immune from target table (-1 = nonexistent)
* [0] = number of entries
* [1...N] = immune targets
*/
int immune_table;
Trie *pCmdTable; /* Command override table (can be NULL) */
Trie *pCmdGrpTable; /* Command group override table (can be NULL) */
int next_grp; /* Next group in the chain */
int prev_grp; /* Previous group in the chain */
int nameidx; /* Name */
FlagBits addflags; /* Additive flags */
};
struct AuthMethod
{
String name;
Trie *table;
};
struct UserAuth
{
unsigned int index; /* Index into auth table */
int identidx; /* Index into the string table */
};
struct AdminUser
{
uint32_t magic; /* Magic flag, for memory validation */
FlagBits flags; /* Flags */
FlagBits eflags; /* Effective flags */
int nameidx; /* Name index */
int password; /* Password index */
unsigned int grp_count; /* Number of groups */
unsigned int grp_size; /* Size of groups table */
int grp_table; /* Group table itself */
int next_user; /* Next user in the list */
int prev_user; /* Previous user in the list */
UserAuth auth; /* Auth method for this user */
unsigned int immunity_level; /* Immunity level */
unsigned int serialchange; /* Serial # for changes */
};
class AdminCache :
public IAdminSystem,
public SMGlobalClass
{
public:
AdminCache();
~AdminCache();
public: //SMGlobalClass
void OnSourceModStartup(bool late);
void OnSourceModAllInitialized();
void OnSourceModLevelChange(const char *mapName);
void OnSourceModShutdown();
void OnSourceModPluginsLoaded();
public: //IAdminSystem
/** Command cache stuff */
void AddCommandOverride(const char *cmd, OverrideType type, FlagBits flags);
bool GetCommandOverride(const char *cmd, OverrideType type, FlagBits *flags);
void UnsetCommandOverride(const char *cmd, OverrideType type);
/** Group cache stuff */
GroupId AddGroup(const char *group_name);
GroupId FindGroupByName(const char *group_name);
void SetGroupAddFlag(GroupId id, AdminFlag flag, bool enabled);
bool GetGroupAddFlag(GroupId id, AdminFlag flag);
FlagBits GetGroupAddFlags(GroupId id);
void SetGroupGenericImmunity(GroupId id, ImmunityType type, bool enabled);
bool GetGroupGenericImmunity(GroupId id, ImmunityType type);
void InvalidateGroup(GroupId id);
void AddGroupImmunity(GroupId id, GroupId other_id);
unsigned int GetGroupImmunityCount(GroupId id);
GroupId GetGroupImmunity(GroupId id, unsigned int number);
void AddGroupCommandOverride(GroupId id, const char *name, OverrideType type, OverrideRule rule);
bool GetGroupCommandOverride(GroupId id, const char *name, OverrideType type, OverrideRule *pRule);
void DumpAdminCache(AdminCachePart part, bool rebuild);
void AddAdminListener(IAdminListener *pListener);
void RemoveAdminListener(IAdminListener *pListener);
/** User stuff */
void RegisterAuthIdentType(const char *name);
AdminId CreateAdmin(const char *name);
const char *GetAdminName(AdminId id);
bool BindAdminIdentity(AdminId id, const char *auth, const char *ident);
virtual void SetAdminFlag(AdminId id, AdminFlag flag, bool enabled);
bool GetAdminFlag(AdminId id, AdminFlag flag, AccessMode mode);
FlagBits GetAdminFlags(AdminId id, AccessMode mode);
bool AdminInheritGroup(AdminId id, GroupId gid);
unsigned int GetAdminGroupCount(AdminId id);
GroupId GetAdminGroup(AdminId id, unsigned int index, const char **name);
void SetAdminPassword(AdminId id, const char *password);
const char *GetAdminPassword(AdminId id);
AdminId FindAdminByIdentity(const char *auth, const char *identity);
bool InvalidateAdmin(AdminId id);
unsigned int FlagBitsToBitArray(FlagBits bits, bool array[], unsigned int maxSize);
FlagBits FlagBitArrayToBits(const bool array[], unsigned int maxSize);
FlagBits FlagArrayToBits(const AdminFlag array[], unsigned int numFlags);
unsigned int FlagBitsToArray(FlagBits bits, AdminFlag array[], unsigned int maxSize);
bool CheckAdminFlags(AdminId id, FlagBits bits);
bool CanAdminTarget(AdminId id, AdminId target);
void SetAdminFlags(AdminId id, AccessMode mode, FlagBits bits);
bool FindFlag(const char *str, AdminFlag *pFlag);
bool FindFlag(char c, AdminFlag *pAdmFlag);
FlagBits ReadFlagString(const char *flags, const char **end);
size_t FillFlagString(FlagBits bits, char *buffer, size_t maxlen);
unsigned int GetAdminSerialChange(AdminId id);
bool CanAdminUseCommand(int client, const char *cmd);
const char *GetGroupName(GroupId gid);
unsigned int SetGroupImmunityLevel(GroupId gid, unsigned int level);
unsigned int GetGroupImmunityLevel(GroupId gid);
unsigned int SetAdminImmunityLevel(AdminId id, unsigned int level);
unsigned int GetAdminImmunityLevel(AdminId id);
bool CheckAccess(int client,
const char *cmd,
FlagBits flags,
bool override_only);
bool FindFlagChar(AdminFlag flag, char *c);
public:
bool IsValidAdmin(AdminId id);
void DumpCache(FILE *fp);
AdminGroup *GetGroup(GroupId gid);
AdminUser *GetUser(AdminId id);
const char *GetString(int idx);
private:
void _UnsetCommandOverride(const char *cmd);
void _UnsetCommandGroupOverride(const char *group);
void InvalidateGroupCache();
void InvalidateAdminCache(bool unlink_admins);
void DumpCommandOverrideCache(OverrideType type);
Trie *GetMethodByIndex(unsigned int index);
bool GetMethodIndex(const char *name, unsigned int *_index);
const char *GetMethodName(unsigned int index);
void NameFlag(const char *str, AdminFlag flag);
public:
BaseStringTable *m_pStrings;
BaseMemTable *m_pMemory;
Trie *m_pCmdOverrides;
Trie *m_pCmdGrpOverrides;
int m_FirstGroup;
int m_LastGroup;
int m_FreeGroupList;
Trie *m_pGroups;
List<IAdminListener *> m_hooks;
List<AuthMethod> m_AuthMethods;
Trie *m_pAuthTables;
IForward *m_pCacheFwd;
int m_FirstUser;
int m_LastUser;
int m_FreeUserList;
bool m_InvalidatingAdmins;
bool m_destroying;
Trie *m_pLevelNames;
};
extern AdminCache g_Admins;
#endif //_INCLUDE_SOURCEMOD_ADMINCACHE_H_
+10 -84
View File
@@ -76,12 +76,9 @@ void CDataPack::ResetSize()
size_t CDataPack::CreateMemory(size_t size, void **addr)
{
CheckSize(sizeof(char) + sizeof(size_t) + size);
CheckSize(sizeof(size_t) + size);
size_t pos = m_curptr - m_pBase;
*(char *)m_curptr = Raw;
m_curptr += sizeof(char);
*(size_t *)m_curptr = size;
m_curptr += sizeof(size_t);
@@ -91,17 +88,14 @@ size_t CDataPack::CreateMemory(size_t size, void **addr)
}
m_curptr += size;
m_size += sizeof(char) + sizeof(size_t) + size;
m_size += sizeof(size_t) + size;
return pos;
}
void CDataPack::PackCell(cell_t cell)
{
CheckSize(sizeof(char) + sizeof(size_t) + sizeof(cell_t));
*(char *)m_curptr = Cell;
m_curptr += sizeof(char);
CheckSize(sizeof(size_t) + sizeof(cell_t));
*(size_t *)m_curptr = sizeof(cell_t);
m_curptr += sizeof(size_t);
@@ -109,15 +103,12 @@ void CDataPack::PackCell(cell_t cell)
*(cell_t *)m_curptr = cell;
m_curptr += sizeof(cell_t);
m_size += sizeof(char) + sizeof(size_t) + sizeof(cell_t);
m_size += sizeof(size_t) + sizeof(cell_t);
}
void CDataPack::PackFloat(float val)
{
CheckSize(sizeof(char) + sizeof(size_t) + sizeof(float));
*(char *)m_curptr = Float;
m_curptr += sizeof(char);
CheckSize(sizeof(size_t) + sizeof(float));
*(size_t *)m_curptr = sizeof(float);
m_curptr += sizeof(size_t);
@@ -125,18 +116,15 @@ void CDataPack::PackFloat(float val)
*(float *)m_curptr = val;
m_curptr += sizeof(float);
m_size += sizeof(char) + sizeof(size_t) + sizeof(float);
m_size += sizeof(size_t) + sizeof(float);
}
void CDataPack::PackString(const char *string)
{
size_t len = strlen(string);
size_t maxsize = sizeof(char) + sizeof(size_t) + len + 1;
size_t maxsize = sizeof(size_t) + len + 1;
CheckSize(maxsize);
*(char *)m_curptr = String;
m_curptr += sizeof(char);
// Pack the string length first for buffer overrun checking.
*(size_t *)m_curptr = len;
m_curptr += sizeof(size_t);
@@ -172,16 +160,10 @@ bool CDataPack::SetPosition(size_t pos) const
cell_t CDataPack::ReadCell() const
{
if (!IsReadable(sizeof(char) + sizeof(size_t) + sizeof(cell_t)))
if (!IsReadable(sizeof(size_t) + sizeof(cell_t)))
{
return 0;
}
if (*reinterpret_cast<char *>(m_curptr) != Cell)
{
return 0;
}
m_curptr += sizeof(char);
if (*reinterpret_cast<size_t *>(m_curptr) != sizeof(cell_t))
{
return 0;
@@ -196,16 +178,10 @@ cell_t CDataPack::ReadCell() const
float CDataPack::ReadFloat() const
{
if (!IsReadable(sizeof(char) + sizeof(size_t) + sizeof(float)))
if (!IsReadable(sizeof(size_t) + sizeof(float)))
{
return 0;
}
if (*reinterpret_cast<char *>(m_curptr) != Float)
{
return 0;
}
m_curptr += sizeof(char);
if (*reinterpret_cast<size_t *>(m_curptr) != sizeof(float))
{
return 0;
@@ -225,15 +201,10 @@ bool CDataPack::IsReadable(size_t bytes) const
const char *CDataPack::ReadString(size_t *len) const
{
if (!IsReadable(sizeof(char) + sizeof(size_t)))
if (!IsReadable(sizeof(size_t)))
{
return NULL;
}
if (*reinterpret_cast<char *>(m_curptr) != String)
{
return NULL;
}
m_curptr += sizeof(char);
size_t real_len = *(size_t *)m_curptr;
@@ -266,11 +237,6 @@ void *CDataPack::ReadMemory(size_t *size) const
{
return NULL;
}
if (*reinterpret_cast<char *>(m_curptr) != Raw)
{
return NULL;
}
m_curptr += sizeof(char);
size_t bytecount = *(size_t *)m_curptr;
m_curptr += sizeof(size_t);
@@ -291,43 +257,3 @@ void *CDataPack::ReadMemory(size_t *size) const
return ptr;
}
void CDataPack::PackFunction(cell_t function)
{
CheckSize(sizeof(char) + sizeof(size_t) + sizeof(cell_t));
*(char *)m_curptr = Function;
m_curptr += sizeof(char);
*(size_t *)m_curptr = sizeof(cell_t);
m_curptr += sizeof(size_t);
*(cell_t *)m_curptr = function;
m_curptr += sizeof(cell_t);
m_size += sizeof(char) + sizeof(size_t) + sizeof(cell_t);
}
cell_t CDataPack::ReadFunction() const
{
if (!IsReadable(sizeof(char) + sizeof(size_t) + sizeof(cell_t)))
{
return 0;
}
if (*reinterpret_cast<char *>(m_curptr) != Function)
{
return 0;
}
m_curptr += sizeof(char);
if (*reinterpret_cast<size_t *>(m_curptr) != sizeof(cell_t))
{
return 0;
}
m_curptr += sizeof(size_t);
cell_t val = *reinterpret_cast<cell_t *>(m_curptr);
m_curptr += sizeof(cell_t);
return val;
}
-10
View File
@@ -51,14 +51,12 @@ public: //IDataReader
const char *ReadString(size_t *len) const;
void *GetMemory() const;
void *ReadMemory(size_t *size) const;
cell_t ReadFunction() const;
public: //IDataPack
void ResetSize();
void PackCell(cell_t cell);
void PackFloat(float val);
void PackString(const char *string);
size_t CreateMemory(size_t size, void **addr);
void PackFunction(cell_t function);
public:
void Initialize();
private:
@@ -68,14 +66,6 @@ private:
mutable char *m_curptr;
size_t m_capacity;
size_t m_size;
enum DataPackType {
Raw,
Cell,
Float,
String,
Function
};
};
#endif //_INCLUDE_SOURCEMOD_CDATAPACK_H_
+2 -20
View File
@@ -44,11 +44,7 @@ public: //IRecipientFilter
bool IsReliable() const;
bool IsInitMessage() const;
int GetRecipientCount() const;
#if SOURCE_ENGINE == SE_DOTA
CEntityIndex GetRecipientIndex(int slot) const;
#else
int GetRecipientIndex(int slot) const;
#endif
public:
void Initialize(const cell_t *ptr, size_t count);
void SetToReliable(bool isreliable);
@@ -83,27 +79,13 @@ inline int CellRecipientFilter::GetRecipientCount() const
return m_Size;
}
#if SOURCE_ENGINE == SE_DOTA
inline CEntityIndex CellRecipientFilter::GetRecipientIndex(int slot) const
#else
inline int CellRecipientFilter::GetRecipientIndex(int slot) const
#endif
{
int ret;
if ((slot < 0) || (slot >= GetRecipientCount()))
{
ret = -1;
return -1;
}
else
{
ret = static_cast<int>(m_Players[slot]);
}
#if SOURCE_ENGINE == SE_DOTA
return CEntityIndex(ret);
#else
return ret;
#endif
return static_cast<int>(m_Players[slot]);
}
inline void CellRecipientFilter::SetToInit(bool isinitmsg)
+112 -220
View File
@@ -34,40 +34,38 @@
#include "sm_stringutil.h"
#include "ConCmdManager.h"
#include "PlayerManager.h"
#include "Translator.h"
#include "HalfLife2.h"
#include "logic_bridge.h"
#include "sourcemod.h"
#if SOURCE_ENGINE == SE_DOTA
SH_DECL_EXTERN2_void(ConCommand, Dispatch, SH_NOATTRIB, false, const CCommandContext &, const CCommand &);
#elif SOURCE_ENGINE >= SE_ORANGEBOX
SH_DECL_EXTERN1_void(ConCommand, Dispatch, SH_NOATTRIB, false, const CCommand &);
#elif SOURCE_ENGINE == SE_DARKMESSIAH
SH_DECL_EXTERN0_void(ConCommand, Dispatch, SH_NOATTRIB, false);
/* :HACKHACK: We can't SH_DECL here because ConCmdManager.cpp does.
* While the OB build only runs on MM:S 1.6.0+ (SH 5+), the older one
* can technically be compiled against any MM:S version after 1.4.2.
*/
#if SOURCE_ENGINE >= SE_ORANGEBOX
extern bool __SourceHook_FHRemoveConCommandDispatch(void *, bool, class fastdelegate::FastDelegate1<const CCommand &, void>);
extern int __SourceHook_FHAddConCommandDispatch(void *, ISourceHook::AddHookMode, bool, class fastdelegate::FastDelegate1<const CCommand &, void>);
#else
# if SH_IMPL_VERSION >= 4
extern int __SourceHook_FHAddConCommandDispatch(void *,bool,class fastdelegate::FastDelegate0<void>);
# else
extern bool __SourceHook_FHAddConCommandDispatch(void *,bool,class fastdelegate::FastDelegate0<void>);
# endif
extern bool __SourceHook_FHRemoveConCommandDispatch(void *,bool,class fastdelegate::FastDelegate0<void>);
#endif
extern bool __SourceHook_FHRemoveConCommandDispatch(void *, bool, class fastdelegate::FastDelegate0<void>);
#if SH_IMPL_VERSION >= 5
extern int __SourceHook_FHAddConCommandDispatch(void *, ISourceHook::AddHookMode, bool, class fastdelegate::FastDelegate0<void>);
#elif SH_IMPL_VERSION == 4
extern int __SourceHook_FHAddConCommandDispatch(void *, bool, class fastdelegate::FastDelegate0<void>);
#elif SH_IMPL_VERSION == 3
extern bool __SourceHook_FHAddConCommandDispatch(void *, bool, class fastdelegate::FastDelegate0<void>);
#endif //SH_IMPL_VERSION
#endif //SE_ORANGEBOX
ChatTriggers g_ChatTriggers;
bool g_bSupressSilentFails = false;
ChatTriggers::ChatTriggers() : m_pSayCmd(NULL), m_bWillProcessInPost(false),
m_ReplyTo(SM_REPLY_CONSOLE), m_ArgSBackup(NULL)
m_bTriggerWasSilent(false), m_ReplyTo(SM_REPLY_CONSOLE)
{
m_PubTrigger = sm_strdup("!");
m_PrivTrigger = sm_strdup("/");
m_PubTriggerSize = 1;
m_PrivTriggerSize = 1;
m_bIsChatTrigger = false;
m_bPluginIgnored = true;
#if SOURCE_ENGINE == SE_EPISODEONE
m_bIsINS = false;
#endif
}
ChatTriggers::~ChatTriggers()
@@ -76,8 +74,6 @@ ChatTriggers::~ChatTriggers()
m_PubTrigger = NULL;
delete [] m_PrivTrigger;
m_PrivTrigger = NULL;
delete [] m_ArgSBackup;
m_ArgSBackup = NULL;
}
ConfigResult ChatTriggers::OnSourceModConfigChanged(const char *key,
@@ -111,15 +107,13 @@ ConfigResult ChatTriggers::OnSourceModConfigChanged(const char *key,
void ChatTriggers::OnSourceModAllInitialized()
{
m_pShouldFloodBlock = forwardsys->CreateForward("OnClientFloodCheck", ET_Event, 1, NULL, Param_Cell);
m_pDidFloodBlock = forwardsys->CreateForward("OnClientFloodResult", ET_Event, 2, NULL, Param_Cell, Param_Cell);
m_pOnClientSayCmd = forwardsys->CreateForward("OnClientSayCommand", ET_Event, 3, NULL, Param_Cell, Param_String, Param_String);
m_pOnClientSayCmd_Post = forwardsys->CreateForward("OnClientSayCommand_Post", ET_Ignore, 3, NULL, Param_Cell, Param_String, Param_String);
m_pShouldFloodBlock = g_Forwards.CreateForward("OnClientFloodCheck", ET_Event, 1, NULL, Param_Cell);
m_pDidFloodBlock = g_Forwards.CreateForward("OnClientFloodResult", ET_Event, 2, NULL, Param_Cell, Param_Cell);
}
void ChatTriggers::OnSourceModAllInitialized_Post()
{
logicore.AddCorePhraseFile("antiflood.phrases");
g_pCorePhrases->AddPhraseFile("antiflood.phrases");
}
void ChatTriggers::OnSourceModGameInitialized()
@@ -129,76 +123,34 @@ void ChatTriggers::OnSourceModGameInitialized()
if (m_pSayCmd)
{
SH_ADD_HOOK(ConCommand, Dispatch, m_pSayCmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Pre), false);
SH_ADD_HOOK(ConCommand, Dispatch, m_pSayCmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Post), true);
SH_ADD_HOOK_MEMFUNC(ConCommand, Dispatch, m_pSayCmd, this, &ChatTriggers::OnSayCommand_Pre, false);
SH_ADD_HOOK_MEMFUNC(ConCommand, Dispatch, m_pSayCmd, this, &ChatTriggers::OnSayCommand_Post, true);
}
if (m_pSayTeamCmd)
{
SH_ADD_HOOK(ConCommand, Dispatch, m_pSayTeamCmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Pre), false);
SH_ADD_HOOK(ConCommand, Dispatch, m_pSayTeamCmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Post), true);
SH_ADD_HOOK_MEMFUNC(ConCommand, Dispatch, m_pSayTeamCmd, this, &ChatTriggers::OnSayCommand_Pre, false);
SH_ADD_HOOK_MEMFUNC(ConCommand, Dispatch, m_pSayTeamCmd, this, &ChatTriggers::OnSayCommand_Post, true);
}
#if SOURCE_ENGINE == SE_EPISODEONE
m_bIsINS = (strcmp(g_SourceMod.GetGameFolderName(), "insurgency") == 0);
if (m_bIsINS)
{
m_pSay2Cmd = FindCommand("say2");
if (m_pSay2Cmd)
{
SH_ADD_HOOK(ConCommand, Dispatch, m_pSay2Cmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Pre), false);
SH_ADD_HOOK(ConCommand, Dispatch, m_pSay2Cmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Post), true);
}
}
#elif SOURCE_ENGINE == SE_NUCLEARDAWN
m_pSaySquadCmd = FindCommand("say_squad");
if (m_pSaySquadCmd)
{
SH_ADD_HOOK(ConCommand, Dispatch, m_pSaySquadCmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Pre), false);
SH_ADD_HOOK(ConCommand, Dispatch, m_pSaySquadCmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Post), true);
}
#endif
}
void ChatTriggers::OnSourceModShutdown()
{
if (m_pSayCmd)
{
SH_REMOVE_HOOK(ConCommand, Dispatch, m_pSayCmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Post), true);
SH_REMOVE_HOOK(ConCommand, Dispatch, m_pSayCmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Pre), false);
}
if (m_pSayTeamCmd)
{
SH_REMOVE_HOOK(ConCommand, Dispatch, m_pSayTeamCmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Post), true);
SH_REMOVE_HOOK(ConCommand, Dispatch, m_pSayTeamCmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Pre), false);
SH_REMOVE_HOOK_MEMFUNC(ConCommand, Dispatch, m_pSayTeamCmd, this, &ChatTriggers::OnSayCommand_Post, true);
SH_REMOVE_HOOK_MEMFUNC(ConCommand, Dispatch, m_pSayTeamCmd, this, &ChatTriggers::OnSayCommand_Pre, false);
}
if (m_pSayCmd)
{
SH_REMOVE_HOOK_MEMFUNC(ConCommand, Dispatch, m_pSayCmd, this, &ChatTriggers::OnSayCommand_Post, true);
SH_REMOVE_HOOK_MEMFUNC(ConCommand, Dispatch, m_pSayCmd, this, &ChatTriggers::OnSayCommand_Pre, false);
}
#if SOURCE_ENGINE == SE_EPISODEONE
if (m_bIsINS && m_pSay2Cmd)
{
SH_REMOVE_HOOK(ConCommand, Dispatch, m_pSay2Cmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Pre), false);
SH_REMOVE_HOOK(ConCommand, Dispatch, m_pSay2Cmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Post), true);
}
#elif SOURCE_ENGINE == SE_NUCLEARDAWN
if (m_pSaySquadCmd)
{
SH_REMOVE_HOOK(ConCommand, Dispatch, m_pSaySquadCmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Pre), false);
SH_REMOVE_HOOK(ConCommand, Dispatch, m_pSaySquadCmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Post), true);
}
#endif
forwardsys->ReleaseForward(m_pShouldFloodBlock);
forwardsys->ReleaseForward(m_pDidFloodBlock);
forwardsys->ReleaseForward(m_pOnClientSayCmd);
forwardsys->ReleaseForward(m_pOnClientSayCmd_Post);
g_Forwards.ReleaseForward(m_pShouldFloodBlock);
g_Forwards.ReleaseForward(m_pDidFloodBlock);
}
#if SOURCE_ENGINE == SE_DOTA
void ChatTriggers::OnSayCommand_Pre(const CCommandContext &context, const CCommand &command)
{
#elif SOURCE_ENGINE >= SE_ORANGEBOX
#if SOURCE_ENGINE >= SE_ORANGEBOX
void ChatTriggers::OnSayCommand_Pre(const CCommand &command)
{
#else
@@ -206,95 +158,28 @@ void ChatTriggers::OnSayCommand_Pre()
{
CCommand command;
#endif
int client = g_ConCmds.GetCommandClient();
int client;
CPlayer *pPlayer;
client = g_ConCmds.GetCommandClient();
m_bIsChatTrigger = false;
m_bWasFloodedMessage = false;
m_bPluginIgnored = true;
const char *args = command.ArgS();
if (!args)
{
RETURN_META(MRES_IGNORED);
}
/* Save these off for post hook as the command data returned from the engine in older engine versions
* can be NULL, despite the data still being there and valid. */
m_Arg0Backup = command.Arg(0);
size_t len = strlen(args);
#if SOURCE_ENGINE == SE_EPISODEONE
if (m_bIsINS)
{
if (strcmp(m_Arg0Backup, "say2") == 0 && len >= 4)
{
args += 4;
len -= 4;
}
if (len == 0)
{
RETURN_META(MRES_SUPERCEDE);
}
}
#endif
/* The first pair of quotes are stripped from client say commands, but not console ones.
* We do not want the forwards to differ from what is displayed.
* So only strip the first pair of quotes from client say commands. */
bool is_quoted = false;
if (
#if SOURCE_ENGINE == SE_EPISODEONE
!m_bIsINS &&
#endif
client != 0 && args[0] == '"' && args[len-1] == '"')
{
/* The server normally won't display empty say commands, but in this case it does.
* I don't think it's desired so let's block it. */
if (len <= 2)
{
RETURN_META(MRES_SUPERCEDE);
}
args++;
len--;
is_quoted = true;
}
/* Some? engines strip the last quote when printing the string to chat.
* This results in having a double-quoted message passed to the OnClientSayCommand ("message") forward,
* but losing the last quote in the OnClientSayCommand_Post ("message) forward.
* To compensate this, we copy the args into our own buffer where the engine won't mess with
* and strip the quotes. */
delete [] m_ArgSBackup;
m_ArgSBackup = new char[CCommand::MaxCommandLength()+1];
memcpy(m_ArgSBackup, args, len+1);
/* Strip the quotes from the argument */
if (is_quoted)
{
if (m_ArgSBackup[len-1] == '"')
{
m_ArgSBackup[--len] = '\0';
}
}
/* The server console cannot do this */
if (client == 0)
if (client == 0 || (pPlayer = g_Players.GetPlayerByIndex(client)) == NULL)
{
if (CallOnClientSayCommand(client) >= Pl_Handled)
{
RETURN_META(MRES_SUPERCEDE);
}
RETURN_META(MRES_IGNORED);
}
CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
/* We guarantee the client is connected */
if (!pPlayer || !pPlayer->IsConnected())
if (!pPlayer->IsConnected())
{
RETURN_META(MRES_IGNORED);
}
const char *args = command.ArgS();
if (!args)
{
RETURN_META(MRES_IGNORED);
}
@@ -304,8 +189,17 @@ void ChatTriggers::OnSayCommand_Pre()
{
char buffer[128];
if (!logicore.CoreTranslate(buffer, sizeof(buffer), "%T", 2, NULL, "Flooding the server", &client))
if (!CoreTranslate(
buffer,
sizeof(buffer),
"%T",
2,
NULL,
"Flooding the server",
&client))
{
UTIL_Format(buffer, sizeof(buffer), "You are flooding the server!");
}
/* :TODO: we should probably kick people who spam too much. */
@@ -318,41 +212,62 @@ void ChatTriggers::OnSayCommand_Pre()
RETURN_META(MRES_SUPERCEDE);
}
/* Handle quoted string sets */
bool is_quoted = false;
if (args[0] == '"')
{
args++;
is_quoted = true;
}
bool is_trigger = false;
bool is_silent = false;
/* Check for either trigger */
if (m_PubTriggerSize && strncmp(m_ArgSBackup, m_PubTrigger, m_PubTriggerSize) == 0)
if (m_PubTriggerSize && strncmp(args, m_PubTrigger, m_PubTriggerSize) == 0)
{
is_trigger = true;
args = &m_ArgSBackup[m_PubTriggerSize];
args = &args[m_PubTriggerSize];
}
else if (m_PrivTriggerSize && strncmp(m_ArgSBackup, m_PrivTrigger, m_PrivTriggerSize) == 0)
else if (m_PrivTriggerSize && strncmp(args, m_PrivTrigger, m_PrivTriggerSize) == 0)
{
is_trigger = true;
is_silent = true;
args = &m_ArgSBackup[m_PrivTriggerSize];
args = &args[m_PrivTriggerSize];
}
if (!is_trigger)
{
RETURN_META(MRES_IGNORED);
}
/**
* Test if this is actually a command!
*/
if (is_trigger && PreProcessTrigger(PEntityOfEntIndex(client), args))
if (!PreProcessTrigger(PEntityOfEntIndex(client), args, is_quoted))
{
m_bIsChatTrigger = true;
/**
* We'll execute it in post.
*/
m_bWillProcessInPost = true;
CPlayer *pPlayer;
if (is_silent
&& g_bSupressSilentFails
&& client != 0
&& (pPlayer = g_Players.GetPlayerByIndex(client)) != NULL
&& pPlayer->GetAdminId() != INVALID_ADMIN_ID)
{
RETURN_META(MRES_SUPERCEDE);
}
RETURN_META(MRES_IGNORED);
}
if (is_silent && (m_bIsChatTrigger || (g_bSupressSilentFails && pPlayer->GetAdminId() != INVALID_ADMIN_ID)))
{
RETURN_META(MRES_SUPERCEDE);
}
m_bIsChatTrigger = true;
if (CallOnClientSayCommand(client) >= Pl_Handled)
/**
* We'll execute it in post.
*/
m_bWillProcessInPost = true;
m_bTriggerWasSilent = is_silent;
/* If we're silent, block */
if (is_silent)
{
RETURN_META(MRES_SUPERCEDE);
}
@@ -361,44 +276,28 @@ void ChatTriggers::OnSayCommand_Pre()
RETURN_META(MRES_IGNORED);
}
#if SOURCE_ENGINE == SE_DOTA
void ChatTriggers::OnSayCommand_Post(const CCommandContext &context, const CCommand &command)
#elif SOURCE_ENGINE >= SE_ORANGEBOX
#if SOURCE_ENGINE >= SE_ORANGEBOX
void ChatTriggers::OnSayCommand_Post(const CCommand &command)
#else
void ChatTriggers::OnSayCommand_Post()
#endif
{
int client = g_ConCmds.GetCommandClient();
m_bIsChatTrigger = false;
m_bWasFloodedMessage = false;
if (m_bWillProcessInPost)
{
/* Reset this for re-entrancy */
m_bWillProcessInPost = false;
/* Execute the cached command */
int client = g_ConCmds.GetCommandClient();
unsigned int old = SetReplyTo(SM_REPLY_CHAT);
#if SOURCE_ENGINE == SE_DOTA
engine->ClientCommand(client, "%s", m_ToExecute);
#else
serverpluginhelpers->ClientCommand(PEntityOfEntIndex(client), m_ToExecute);
#endif
SetReplyTo(old);
}
if (!m_bPluginIgnored && m_pOnClientSayCmd_Post->GetFunctionCount() != 0)
{
m_pOnClientSayCmd_Post->PushCell(client);
m_pOnClientSayCmd_Post->PushString(m_Arg0Backup);
m_pOnClientSayCmd_Post->PushString(m_ArgSBackup);
m_pOnClientSayCmd_Post->Execute(NULL);
}
m_bIsChatTrigger = false;
m_bWasFloodedMessage = false;
}
bool ChatTriggers::PreProcessTrigger(edict_t *pEdict, const char *args)
bool ChatTriggers::PreProcessTrigger(edict_t *pEdict, const char *args, bool is_quoted)
{
/* Extract a command. This is kind of sloppy. */
char cmd_buf[64];
@@ -440,12 +339,12 @@ bool ChatTriggers::PreProcessTrigger(edict_t *pEdict, const char *args)
{
return false;
}
prepended = true;
}
/* See if we need to do extra string manipulation */
if (prepended)
if (is_quoted || prepended)
{
size_t len;
@@ -456,6 +355,15 @@ bool ChatTriggers::PreProcessTrigger(edict_t *pEdict, const char *args)
} else {
len = strncopy(m_ToExecute, args, sizeof(m_ToExecute));
}
/* Check if we need to strip a quote */
if (is_quoted)
{
if (m_ToExecute[len-1] == '"')
{
m_ToExecute[--len] = '\0';
}
}
} else {
strncopy(m_ToExecute, args, sizeof(m_ToExecute));
}
@@ -463,22 +371,6 @@ bool ChatTriggers::PreProcessTrigger(edict_t *pEdict, const char *args)
return true;
}
cell_t ChatTriggers::CallOnClientSayCommand(int client)
{
cell_t res = Pl_Continue;
if (m_pOnClientSayCmd->GetFunctionCount() != 0)
{
m_pOnClientSayCmd->PushCell(client);
m_pOnClientSayCmd->PushString(m_Arg0Backup);
m_pOnClientSayCmd->PushString(m_ArgSBackup);
m_pOnClientSayCmd->Execute(&res);
}
m_bPluginIgnored = (res >= Pl_Stop);
return res;
}
unsigned int ChatTriggers::SetReplyTo(unsigned int reply)
{
unsigned int old = m_ReplyTo;
+3 -19
View File
@@ -54,10 +54,7 @@ public: //SMGlobalClass
char *error,
size_t maxlength);
private: //ConCommand
#if SOURCE_ENGINE == SE_DOTA
void OnSayCommand_Pre(const CCommandContext &, const CCommand &command);
void OnSayCommand_Post(const CCommandContext &, const CCommand &command);
#elif SOURCE_ENGINE >= SE_ORANGEBOX
#if SOURCE_ENGINE >= SE_ORANGEBOX
void OnSayCommand_Pre(const CCommand &command);
void OnSayCommand_Post(const CCommand &command);
#else
@@ -70,36 +67,23 @@ public:
bool IsChatTrigger();
bool WasFloodedMessage();
private:
bool PreProcessTrigger(edict_t *pEdict, const char *args);
bool PreProcessTrigger(edict_t *pEdict, const char *args, bool is_quoted);
bool ClientIsFlooding(int client);
cell_t CallOnClientSayCommand(int client);
private:
ConCommand *m_pSayCmd;
ConCommand *m_pSayTeamCmd;
#if SOURCE_ENGINE == SE_EPISODEONE
ConCommand *m_pSay2Cmd;
#elif SOURCE_ENGINE == SE_NUCLEARDAWN
ConCommand *m_pSaySquadCmd;
#endif
char *m_PubTrigger;
size_t m_PubTriggerSize;
char *m_PrivTrigger;
size_t m_PrivTriggerSize;
bool m_bWillProcessInPost;
bool m_bTriggerWasSilent;
bool m_bIsChatTrigger;
bool m_bWasFloodedMessage;
bool m_bPluginIgnored;
unsigned int m_ReplyTo;
char m_ToExecute[300];
const char *m_Arg0Backup;
char *m_ArgSBackup;
IForward *m_pShouldFloodBlock;
IForward *m_pDidFloodBlock;
IForward *m_pOnClientSayCmd;
IForward *m_pOnClientSayCmd_Post;
#if SOURCE_ENGINE == SE_EPISODEONE
bool m_bIsINS;
#endif
};
extern ChatTriggers g_ChatTriggers;
+571 -240
View File
File diff suppressed because it is too large Load Diff
+33 -55
View File
@@ -1,5 +1,5 @@
/**
* vim: set ts=4 sw=4 tw=99 noet :
* vim: set ts=4 :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
@@ -34,90 +34,71 @@
#include "sm_globals.h"
#include "sourcemm_api.h"
#include <IForwardSys.h>
#include "ForwardSys.h"
#include "sm_trie.h"
#include "sm_memtable.h"
#include <sh_list.h>
#include <sh_string.h>
#include <IRootConsoleMenu.h>
#include <IAdminSystem.h>
#include "concmd_cleaner.h"
#include <sm_stringhashmap.h>
#include <am-utility.h>
#include <am-inlinelist.h>
#include <am-linkedlist.h>
#include <am-refcounting.h>
using namespace SourceHook;
struct CmdHook;
struct ConCmdInfo;
struct CommandGroup : public ke::Refcounted<CommandGroup>
enum CmdType
{
ke::LinkedList<CmdHook *> hooks;
Cmd_Server,
Cmd_Console,
Cmd_Admin,
};
struct AdminCmdInfo
{
AdminCmdInfo(const ke::Ref<CommandGroup> &group, FlagBits flags)
: group(group),
flags(flags),
eflags(0)
AdminCmdInfo()
{
cmdGrpId = -1;
flags = 0;
eflags = 0;
}
ke::Ref<CommandGroup> group;
int cmdGrpId; /* index into cmdgroup string table */
FlagBits flags; /* default flags */
FlagBits eflags; /* effective flags */
};
struct CmdHook : public ke::InlineListNode<CmdHook>
struct CmdHook
{
enum Type {
Server,
Client
};
CmdHook(Type type, ConCmdInfo *cmd, IPluginFunction *fun, const char *description)
: type(type),
info(cmd),
pf(fun),
helptext(description)
CmdHook()
{
pf = NULL;
pAdmin = NULL;
}
Type type;
ConCmdInfo *info;
IPluginFunction *pf; /* function hook */
ke::AString helptext; /* help text */
ke::AutoPtr<AdminCmdInfo> admin; /* admin requirements, if any */
IPluginFunction *pf; /* function hook */
String helptext; /* help text */
AdminCmdInfo *pAdmin; /* admin requirements, if any */
};
typedef ke::InlineList<CmdHook> CmdHookList;
struct ConCmdInfo
{
ConCmdInfo()
{
sourceMod = false;
pCmd = NULL;
eflags = 0;
}
bool sourceMod; /**< Determines whether or not concmd was created by a SourceMod plugin */
ConCommand *pCmd; /**< Pointer to the command itself */
CmdHookList hooks; /**< Hook list */
FlagBits eflags; /**< Effective admin flags */
List<CmdHook *> srvhooks; /**< Hooks as a server command */
List<CmdHook *> conhooks; /**< Hooks as a console command */
AdminCmdInfo admin; /**< Admin info, if any */
bool is_admin_set; /**< Whether or not admin info is set */
};
typedef List<ConCmdInfo *> ConCmdList;
class ConCmdManager :
public SMGlobalClass,
public IRootConsoleCommand,
public IPluginsListener,
public IConCommandTracker
{
#if SOURCE_ENGINE == SE_DOTA
friend void CommandCallback(const CCommandContext &context, const CCommand &command);
#elif SOURCE_ENGINE >= SE_ORANGEBOX
#if SOURCE_ENGINE >= SE_ORANGEBOX
friend void CommandCallback(const CCommand &command);
#else
friend void CommandCallback();
@@ -136,6 +117,7 @@ public: //IConCommandTracker
void OnUnlinkConCommandBase(ConCommandBase *pBase, const char *name, bool is_read_safe);
public:
bool AddServerCommand(IPluginFunction *pFunction, const char *name, const char *description, int flags);
bool AddConsoleCommand(IPluginFunction *pFunction, const char *name, const char *description, int flags);
bool AddAdminCommand(IPluginFunction *pFunction,
const char *name,
const char *group,
@@ -146,6 +128,7 @@ public:
void UpdateAdminCmdFlags(const char *cmd, OverrideType type, FlagBits bits, bool remove);
bool LookForSourceModCommand(const char *cmd);
bool LookForCommandAdminFlags(const char *cmd, FlagBits *pFlags);
bool CheckCommandAccess(int client, const char *cmd, FlagBits flags);
private:
void InternalDispatch(const CCommand &command);
ResultType RunAdminCommand(ConCmdInfo *pInfo, int client, int args);
@@ -153,13 +136,9 @@ private:
void SetCommandClient(int client);
void AddToCmdList(ConCmdInfo *info);
void RemoveConCmd(ConCmdInfo *info, const char *cmd, bool is_read_safe, bool untrack);
void RemoveConCmds(List<CmdHook *> &cmdlist);
void RemoveConCmds(List<CmdHook *> &cmdlist, IPluginContext *pContext);
bool CheckAccess(int client, const char *cmd, AdminCmdInfo *pAdmin);
// Case insensitive
ConCmdList::iterator FindInList(const char *name);
// Case sensitive
ConCmdInfo *FindInTrie(const char *name);
public:
inline int GetCommandClient()
{
@@ -170,12 +149,11 @@ public:
return m_CmdList;
}
private:
typedef StringHashMap<ke::Ref<CommandGroup> > GroupMap;
StringHashMap<ConCmdInfo *> m_Cmds; /* command lookup */
GroupMap m_CmdGrps; /* command group map */
ConCmdList m_CmdList; /* command list */
Trie *m_pCmds; /* command lookup */
Trie *m_pCmdGrps; /* command group lookup */
List<ConCmdInfo *> m_CmdList; /* command list */
int m_CmdClient; /* current client */
BaseStringTable m_Strings; /* string table */
};
extern ConCmdManager g_ConCmds;
+36 -36
View File
@@ -2,7 +2,7 @@
* vim: set ts=4 sw=4 tw=99 noet :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2010 AlliedModders LLC. All rights reserved.
* Copyright (C) 2004-2009 AlliedModders LLC. All rights reserved.
* =============================================================================
*
* This program is free software; you can redistribute it and/or modify it under
@@ -31,59 +31,59 @@
#ifndef _INCLUDE_SOURCEMOD_CON_COMMAND_BASE_ITERATOR_H_
#define _INCLUDE_SOURCEMOD_CON_COMMAND_BASE_ITERATOR_H_
#if SOURCE_ENGINE >= SE_LEFT4DEAD
class ConCommandBaseIterator
{
public:
inline ConCommandBaseIterator() : iter(icvar)
{
iter.SetFirst();
}
inline bool IsValid()
{
return iter.IsValid();
}
inline void Next()
{
iter.Next();
}
inline ConCommandBase *Get()
{
return iter.Get();
}
private:
ICvar::Iterator iter;
};
#if (SOURCE_ENGINE == SE_LEFT4DEAD) || (SOURCE_ENGINE == SE_LEFT4DEAD2)
ICvarIteratorInternal *cvarIter;
#else
class ConCommandBaseIterator
{
ConCommandBase *cvarIter;
#endif
public:
inline ConCommandBaseIterator()
ConCommandBaseIterator()
{
iter = icvar->GetCommands();
#if (SOURCE_ENGINE == SE_LEFT4DEAD) || (SOURCE_ENGINE == SE_LEFT4DEAD2)
cvarIter = icvar->FactoryInternalIterator();
cvarIter->SetFirst();
#else
cvarIter = icvar->GetCommands();
#endif
}
~ConCommandBaseIterator()
{
#if (SOURCE_ENGINE == SE_LEFT4DEAD) || (SOURCE_ENGINE == SE_LEFT4DEAD2)
g_pMemAlloc->Free(cvarIter);
#endif
}
inline bool IsValid()
{
return iter != NULL;
#if (SOURCE_ENGINE == SE_LEFT4DEAD) || (SOURCE_ENGINE == SE_LEFT4DEAD2)
return cvarIter->IsValid();
#else
return cvarIter != NULL;
#endif
}
inline void Next()
{
iter = const_cast<ConCommandBase *>(iter->GetNext());
#if (SOURCE_ENGINE == SE_LEFT4DEAD) || (SOURCE_ENGINE == SE_LEFT4DEAD2)
cvarIter->Next();
#else
cvarIter = const_cast<ConCommandBase*>(cvarIter->GetNext());
#endif
}
inline ConCommandBase *Get()
{
return iter;
}
private:
ConCommandBase *iter;
};
#if (SOURCE_ENGINE == SE_LEFT4DEAD) || (SOURCE_ENGINE == SE_LEFT4DEAD2)
return cvarIter->Get();
#else
return cvarIter;
#endif
}
};
#endif /* _INCLUDE_SOURCEMOD_CON_COMMAND_BASE_ITERATOR_H_ */
+63 -130
View File
@@ -29,31 +29,34 @@
#include "ConVarManager.h"
#include "HalfLife2.h"
#include "PluginSys.h"
#include "ForwardSys.h"
#include "HandleSys.h"
#include "sm_srvcmds.h"
#include "sm_stringutil.h"
#include <sh_vector.h>
#include <sm_namehashset.h>
#include "logic_bridge.h"
#include <sm_trie_tpl.h>
ConVarManager g_ConVarManager;
#if SOURCE_ENGINE <= SE_DARKMESSIAH
#define CallGlobalChangeCallbacks CallGlobalChangeCallback
#endif
#if SOURCE_ENGINE >= SE_ORANGEBOX
SH_DECL_HOOK3_void(ICvar, CallGlobalChangeCallbacks, SH_NOATTRIB, false, ConVar *, const char *, float);
#else
SH_DECL_HOOK2_void(ICvar, CallGlobalChangeCallback, SH_NOATTRIB, false, ConVar *, const char *);
SH_DECL_HOOK2_void(ICvar, CallGlobalChangeCallbacks, SH_NOATTRIB, false, ConVar *, const char *);
#endif
#if SOURCE_ENGINE == SE_DOTA
SH_DECL_HOOK5_void(IServerGameDLL, OnQueryCvarValueFinished, SH_NOATTRIB, 0, QueryCvarCookie_t, CEntityIndex, EQueryCvarValueStatus, const char *, const char *);
SH_DECL_HOOK5_void(IServerPluginCallbacks, OnQueryCvarValueFinished, SH_NOATTRIB, 0, QueryCvarCookie_t, CEntityIndex, EQueryCvarValueStatus, const char *, const char *);
#elif SOURCE_ENGINE != SE_DARKMESSIAH
#if SOURCE_ENGINE != SE_DARKMESSIAH
SH_DECL_HOOK5_void(IServerGameDLL, OnQueryCvarValueFinished, SH_NOATTRIB, 0, QueryCvarCookie_t, edict_t *, EQueryCvarValueStatus, const char *, const char *);
SH_DECL_HOOK5_void(IServerPluginCallbacks, OnQueryCvarValueFinished, SH_NOATTRIB, 0, QueryCvarCookie_t, edict_t *, EQueryCvarValueStatus, const char *, const char *);
#endif
const ParamType CONVARCHANGE_PARAMS[] = {Param_Cell, Param_String, Param_String};
typedef List<const ConVar *> ConVarList;
NameHashSet<ConVarInfo *> convar_cache;
KTrie<ConVarInfo *> convar_cache;
class ConVarReentrancyGuard
{
@@ -107,7 +110,7 @@ void ConVarManager::OnSourceModStartup(bool late)
sec.access[HandleAccess_Clone] = HANDLE_RESTRICT_IDENTITY | HANDLE_RESTRICT_OWNER;
/* Create the 'ConVar' handle type */
m_ConVarType = handlesys->CreateType("ConVar", this, 0, NULL, &sec, g_pCoreIdent, NULL);
m_ConVarType = g_HandleSys.CreateType("ConVar", this, 0, NULL, &sec, g_pCoreIdent, NULL);
}
void ConVarManager::OnSourceModAllInitialized()
@@ -118,20 +121,14 @@ void ConVarManager::OnSourceModAllInitialized()
#if SOURCE_ENGINE == SE_EPISODEONE
if (g_SMAPI->GetGameDLLVersion() >= 6)
{
SH_ADD_HOOK(IServerGameDLL, OnQueryCvarValueFinished, gamedll, SH_MEMBER(this, &ConVarManager::OnQueryCvarValueFinished), false);
SH_ADD_HOOK_MEMFUNC(IServerGameDLL, OnQueryCvarValueFinished, gamedll, this, &ConVarManager::OnQueryCvarValueFinished, false);
m_bIsDLLQueryHooked = true;
}
#endif
g_Players.AddClientListener(this);
SH_ADD_HOOK_STATICFUNC(ICvar, CallGlobalChangeCallbacks, icvar, OnConVarChanged, false);
#if SOURCE_ENGINE >= SE_ORANGEBOX
SH_ADD_HOOK(ICvar, CallGlobalChangeCallbacks, icvar, SH_STATIC(OnConVarChanged), false);
#else
SH_ADD_HOOK(ICvar, CallGlobalChangeCallback, icvar, SH_STATIC(OnConVarChanged), false);
#endif
scripts->AddPluginsListener(this);
g_PluginSys.AddPluginsListener(this);
/* Add the 'convars' option to the 'sm' console command */
g_RootMenu.AddRootConsoleCommand("cvars", "View convars created by a plugin", this);
@@ -149,10 +146,10 @@ void ConVarManager::OnSourceModShutdown()
iter = m_ConVars.erase(iter);
handlesys->FreeHandle(pInfo->handle, &sec);
g_HandleSys.FreeHandle(pInfo->handle, &sec);
if (pInfo->pChangeForward != NULL)
{
forwardsys->ReleaseForward(pInfo->pChangeForward);
g_Forwards.ReleaseForward(pInfo->pChangeForward);
}
if (pInfo->sourceMod)
{
@@ -184,33 +181,25 @@ void ConVarManager::OnSourceModShutdown()
/* Unhook things */
if (m_bIsDLLQueryHooked)
{
SH_REMOVE_HOOK(IServerGameDLL, OnQueryCvarValueFinished, gamedll, SH_MEMBER(this, &ConVarManager::OnQueryCvarValueFinished), false);
SH_REMOVE_HOOK_MEMFUNC(IServerGameDLL, OnQueryCvarValueFinished, gamedll, this, &ConVarManager::OnQueryCvarValueFinished, false);
m_bIsDLLQueryHooked = false;
}
else if (m_bIsVSPQueryHooked)
{
#if SOURCE_ENGINE != SE_DOTA
SH_REMOVE_HOOK(IServerPluginCallbacks, OnQueryCvarValueFinished, vsp_interface, SH_MEMBER(this, &ConVarManager::OnQueryCvarValueFinished), false);
#endif
SH_REMOVE_HOOK_MEMFUNC(IServerPluginCallbacks, OnQueryCvarValueFinished, vsp_interface, this, &ConVarManager::OnQueryCvarValueFinished, false);
m_bIsVSPQueryHooked = false;
}
#endif
g_Players.RemoveClientListener(this);
#if SOURCE_ENGINE >= SE_ORANGEBOX
SH_REMOVE_HOOK(ICvar, CallGlobalChangeCallbacks, icvar, SH_STATIC(OnConVarChanged), false);
#else
SH_REMOVE_HOOK(ICvar, CallGlobalChangeCallback, icvar, SH_STATIC(OnConVarChanged), false);
#endif
SH_REMOVE_HOOK_STATICFUNC(ICvar, CallGlobalChangeCallbacks, icvar, OnConVarChanged, false);
/* Remove the 'convars' option from the 'sm' console command */
g_RootMenu.RemoveRootConsoleCommand("cvars", this);
scripts->RemovePluginsListener(this);
g_PluginSys.RemovePluginsListener(this);
/* Remove the 'ConVar' handle type */
handlesys->RemoveType(m_ConVarType, g_pCoreIdent);
g_HandleSys.RemoveType(m_ConVarType, g_pCoreIdent);
}
/**
@@ -240,15 +229,24 @@ void ConVarManager::OnSourceModVSPReceived()
}
#endif
#if SOURCE_ENGINE != SE_DARKMESSIAH && SOURCE_ENGINE != SE_DOTA
SH_ADD_HOOK(IServerPluginCallbacks, OnQueryCvarValueFinished, vsp_interface, SH_MEMBER(this, &ConVarManager::OnQueryCvarValueFinished), false);
#if SOURCE_ENGINE != SE_DARKMESSIAH
SH_ADD_HOOK_MEMFUNC(IServerPluginCallbacks, OnQueryCvarValueFinished, vsp_interface, this, &ConVarManager::OnQueryCvarValueFinished, false);
m_bIsVSPQueryHooked = true;
#endif
}
bool convar_cache_lookup(const char *name, ConVarInfo **pVar)
{
return convar_cache.retrieve(name, pVar);
ConVarInfo **pLookup = convar_cache.retrieve(name);
if (pLookup != NULL)
{
*pVar = *pLookup;
return true;
}
else
{
return false;
}
}
void ConVarManager::OnUnlinkConCommandBase(ConCommandBase *pBase, const char *name, bool is_read_safe)
@@ -267,7 +265,7 @@ void ConVarManager::OnUnlinkConCommandBase(ConCommandBase *pBase, const char *na
convar_cache.remove(name);
/* Now make sure no plugins are referring to this pointer */
IPluginIterator *pl_iter = scripts->GetPluginIterator();
IPluginIterator *pl_iter = g_PluginSys.GetPluginIterator();
while (pl_iter->MorePlugins())
{
IPlugin *pl = pl_iter->GetPlugin();
@@ -283,7 +281,7 @@ void ConVarManager::OnUnlinkConCommandBase(ConCommandBase *pBase, const char *na
}
/* Free resources */
handlesys->FreeHandle(pInfo->handle, &sec);
g_HandleSys.FreeHandle(pInfo->handle, &sec);
delete pInfo;
}
@@ -298,35 +296,14 @@ void ConVarManager::OnPluginUnloaded(IPlugin *plugin)
delete pConVarList;
}
const IPluginRuntime * pRuntime = plugin->GetRuntime();
/* Remove convar queries for this plugin that haven't returned results yet */
for (iter = m_ConVarQueries.begin(); iter != m_ConVarQueries.end();)
for (iter = m_ConVarQueries.begin(); iter != m_ConVarQueries.end(); iter++)
{
ConVarQuery &query = (*iter);
if (query.pCallback->GetParentRuntime() == pRuntime)
if (query.pCallback->GetParentRuntime() == plugin->GetRuntime())
{
iter = m_ConVarQueries.erase(iter);
continue;
m_ConVarQueries.erase(iter);
}
++iter;
}
}
void ConVarManager::OnClientDisconnected(int client)
{
/* Remove convar queries for this client that haven't returned results yet */
for (List<ConVarQuery>::iterator iter = m_ConVarQueries.begin(); iter != m_ConVarQueries.end();)
{
ConVarQuery &query = (*iter);
if (query.client == client)
{
iter = m_ConVarQueries.erase(iter);
continue;
}
++iter;
}
}
@@ -345,18 +322,11 @@ void ConVarManager::OnRootConsoleCommand(const char *cmdname, const CCommand &co
int argcount = command.ArgC();
if (argcount >= 3)
{
bool wantReset = false;
/* Get plugin index that was passed */
const char *arg = command.Arg(2);
if (argcount >= 4 && strcmp(arg, "reset") == 0)
{
wantReset = true;
arg = command.Arg(3);
}
/* Get plugin object */
IPlugin *plugin = scripts->FindPluginByConsoleArg(arg);
CPlugin *plugin = g_PluginSys.FindPluginByConsoleArg(arg);
if (!plugin)
{
@@ -378,34 +348,21 @@ void ConVarManager::OnRootConsoleCommand(const char *cmdname, const CCommand &co
return;
}
if (!wantReset)
{
g_RootMenu.ConsolePrint("[SM] Listing %d convars for: %s", pConVarList->size(), plname);
g_RootMenu.ConsolePrint(" %-32.31s %s", "[Name]", "[Value]");
}
/* Iterate convar list and display/reset each one */
g_RootMenu.ConsolePrint("[SM] Listing %d convars for: %s", pConVarList->size(), plname);
g_RootMenu.ConsolePrint(" %-32.31s %s", "[Name]", "[Value]");
/* Iterate convar list and display each one */
for (iter = pConVarList->begin(); iter != pConVarList->end(); iter++)
{
/*const */ConVar *pConVar = const_cast<ConVar *>(*iter);
if (!wantReset)
{
g_RootMenu.ConsolePrint(" %-32.31s %s", pConVar->GetName(), pConVar->GetString());
} else {
pConVar->Revert();
}
}
if (wantReset)
{
g_RootMenu.ConsolePrint("[SM] Reset %d convars for: %s", pConVarList->size(), plname);
const ConVar *pConVar = (*iter);
g_RootMenu.ConsolePrint(" %-32.31s %s", pConVar->GetName(), pConVar->GetString());
}
return;
}
/* Display usage of subcommand */
g_RootMenu.ConsolePrint("[SM] Usage: sm cvars [reset] <plugin #>");
g_RootMenu.ConsolePrint("[SM] Usage: sm cvars <plugin #>");
}
Handle_t ConVarManager::CreateConVar(IPluginContext *pContext, const char *name, const char *defaultVal, const char *description, int flags, bool hasMin, float min, bool hasMax, float max)
@@ -437,7 +394,7 @@ Handle_t ConVarManager::CreateConVar(IPluginContext *pContext, const char *name,
pInfo->pVar = pConVar;
/* If we don't, then create a new handle from the convar */
hndl = handlesys->CreateHandle(m_ConVarType, pInfo, NULL, g_pCoreIdent, NULL);
hndl = g_HandleSys.CreateHandle(m_ConVarType, pInfo, NULL, g_pCoreIdent, NULL);
if (hndl == BAD_HANDLE)
{
delete pInfo;
@@ -468,7 +425,7 @@ Handle_t ConVarManager::CreateConVar(IPluginContext *pContext, const char *name,
pInfo->pChangeForward = NULL;
/* Create a handle from the new convar */
hndl = handlesys->CreateHandle(m_ConVarType, pInfo, NULL, g_pCoreIdent, NULL);
hndl = g_HandleSys.CreateHandle(m_ConVarType, pInfo, NULL, g_pCoreIdent, NULL);
if (hndl == BAD_HANDLE)
{
delete pInfo;
@@ -497,13 +454,7 @@ Handle_t ConVarManager::FindConVar(const char *name)
ConVarInfo *pInfo;
Handle_t hndl;
/* Check convar cache to find out if we already have a handle */
if (convar_cache_lookup(name, &pInfo))
{
return pInfo->handle;
}
/* Couldn't find it in cache, so search for it */
/* Search for convar */
pConVar = icvar->FindVar(name);
/* If it doesn't exist, then return an invalid handle */
@@ -512,6 +463,12 @@ Handle_t ConVarManager::FindConVar(const char *name)
return BAD_HANDLE;
}
/* At this point, the convar exists. So, find out if we already have a handle */
if (convar_cache_lookup(name, &pInfo))
{
return pInfo->handle;
}
/* Create and initialize ConVarInfo structure */
pInfo = new ConVarInfo();
pInfo->sourceMod = false;
@@ -519,7 +476,7 @@ Handle_t ConVarManager::FindConVar(const char *name)
pInfo->pVar = pConVar;
/* If we don't have a handle, then create a new one */
hndl = handlesys->CreateHandle(m_ConVarType, pInfo, NULL, g_pCoreIdent, NULL);
hndl = g_HandleSys.CreateHandle(m_ConVarType, pInfo, NULL, g_pCoreIdent, NULL);
if (hndl == BAD_HANDLE)
{
delete pInfo;
@@ -577,7 +534,7 @@ void ConVarManager::HookConVarChange(ConVar *pConVar, IPluginFunction *pFunction
/* If forward does not exist, create it */
if (!pForward)
{
pForward = forwardsys->CreateForwardEx(NULL, ET_Ignore, 3, CONVARCHANGE_PARAMS);
pForward = g_Forwards.CreateForwardEx(NULL, ET_Ignore, 3, CONVARCHANGE_PARAMS);
pInfo->pChangeForward = pForward;
}
@@ -617,7 +574,7 @@ void ConVarManager::UnhookConVarChange(ConVar *pConVar, IPluginFunction *pFuncti
!ConVarReentrancyGuard::IsCvarInChain(pConVar))
{
/* Free this forward */
forwardsys->ReleaseForward(pForward);
g_Forwards.ReleaseForward(pForward);
pInfo->pChangeForward = NULL;
}
}
@@ -631,28 +588,19 @@ QueryCvarCookie_t ConVarManager::QueryClientConVar(edict_t *pPlayer, const char
/* Call StartQueryCvarValue() in either the IVEngineServer or IServerPluginHelpers depending on situation */
if (m_bIsDLLQueryHooked)
{
#if SOURCE_ENGINE == SE_DOTA
cookie = engine->StartQueryCvarValue(CEntityIndex(IndexOfEdict(pPlayer)), name);
#else
cookie = engine->StartQueryCvarValue(pPlayer, name);
#endif
}
#if SOURCE_ENGINE != SE_DOTA
else if (m_bIsVSPQueryHooked)
{
cookie = serverpluginhelpers->StartQueryCvarValue(pPlayer, name);
}
#endif
else
{
return InvalidQueryCvarCookie;
}
if (pCallback != NULL)
{
ConVarQuery query = { cookie, pCallback, (cell_t) hndl, IndexOfEdict(pPlayer) };
m_ConVarQueries.push_back(query);
}
ConVarQuery query = {cookie, pCallback, hndl};
m_ConVarQueries.push_back(query);
#endif
return cookie;
@@ -665,7 +613,7 @@ void ConVarManager::AddConVarToPluginList(IPluginContext *pContext, const ConVar
bool inserted = false;
const char *orig = pConVar->GetName();
IPlugin *plugin = scripts->FindPluginByContext(pContext->GetContext());
IPlugin *plugin = g_PluginSys.FindPluginByContext(pContext->GetContext());
/* Check plugin for an existing convar list */
if (!plugin->GetProperty("ConVarList", (void **)&pConVarList))
@@ -750,19 +698,8 @@ bool ConVarManager::IsQueryingSupported()
}
#if SOURCE_ENGINE != SE_DARKMESSIAH
#if SOURCE_ENGINE == SE_DOTA
void ConVarManager::OnQueryCvarValueFinished(QueryCvarCookie_t cookie, CEntityIndex player, EQueryCvarValueStatus result, const char *cvarName, const char *cvarValue)
#else
void ConVarManager::OnQueryCvarValueFinished(QueryCvarCookie_t cookie, edict_t *pPlayer, EQueryCvarValueStatus result, const char *cvarName, const char *cvarValue)
#endif // SE_DOTA
{
#if SOURCE_ENGINE == SE_CSGO
if (g_Players.HandleConVarQuery(cookie, pPlayer, result, cvarName, cvarValue))
{
return;
}
#endif
IPluginFunction *pCallback = NULL;
cell_t value = 0;
List<ConVarQuery>::iterator iter;
@@ -783,11 +720,7 @@ void ConVarManager::OnQueryCvarValueFinished(QueryCvarCookie_t cookie, edict_t *
cell_t ret;
pCallback->PushCell(cookie);
#if SOURCE_ENGINE == SE_DOTA
pCallback->PushCell(player.Get());
#else
pCallback->PushCell(IndexOfEdict(pPlayer));
#endif
pCallback->PushCell(result);
pCallback->PushString(cvarName);
@@ -813,7 +746,7 @@ HandleError ConVarManager::ReadConVarHandle(Handle_t hndl, ConVar **pVar)
ConVarInfo *pInfo;
HandleError error;
if ((error = handlesys->ReadHandle(hndl, m_ConVarType, NULL, (void **)&pInfo)) != HandleError_None)
if ((error = g_HandleSys.ReadHandle(hndl, m_ConVarType, NULL, (void **)&pInfo)) != HandleError_None)
{
return error;
}
+3 -17
View File
@@ -1,5 +1,5 @@
/**
* vim: set ts=4 sw=4 tw=99 noet :
* vim: set ts=4 :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
@@ -39,10 +39,8 @@
#include <IForwardSys.h>
#include <IHandleSys.h>
#include <IRootConsoleMenu.h>
#include <IPlayerHelpers.h>
#include <compat_wrappers.h>
#include "concmd_cleaner.h"
#include "PlayerManager.h"
#if SOURCE_ENGINE == SE_DARKMESSIAH
class EQueryCvarValueStatus;
@@ -67,11 +65,6 @@ struct ConVarInfo
IChangeableForward *pChangeForward; /**< Forward associated with convar */
ConVar *pVar; /**< The actual convar */
List<IConVarChangeListener *> changeListeners;
static inline bool matches(const char *name, const ConVarInfo *info)
{
return strcmp(name, info->pVar->GetName()) == 0;
}
};
/**
@@ -82,7 +75,6 @@ struct ConVarQuery
QueryCvarCookie_t cookie; /**< Cookie that identifies query */
IPluginFunction *pCallback; /**< Function that will be called when query is finished */
cell_t value; /**< Optional value passed to query function */
cell_t client; /**< Only used for cleaning up on client disconnection */
};
class ConVarManager :
@@ -90,8 +82,7 @@ class ConVarManager :
public IHandleTypeDispatch,
public IPluginsListener,
public IRootConsoleCommand,
public IConCommandTracker,
public IClientListener
public IConCommandTracker
{
public:
ConVarManager();
@@ -110,8 +101,6 @@ public: //IRootConsoleCommand
void OnRootConsoleCommand(const char *cmdname, const CCommand &command);
public: //IConCommandTracker
void OnUnlinkConCommandBase(ConCommandBase *pBase, const char *name, bool is_read_safe);
public: //IClientListener
void OnClientDisconnected(int client);
public:
/**
* Create a convar and return a handle to it.
@@ -165,10 +154,7 @@ private:
/**
* Callback for when StartQueryCvarValue() has finished.
*/
#if SOURCE_ENGINE == SE_DOTA
void OnQueryCvarValueFinished(QueryCvarCookie_t cookie, CEntityIndex player, EQueryCvarValueStatus result,
const char *cvarName, const char *cvarValue);
#elif SOURCE_ENGINE != SE_DARKMESSIAH
#if SOURCE_ENGINE != SE_DARKMESSIAH
void OnQueryCvarValueFinished(QueryCvarCookie_t cookie, edict_t *pPlayer, EQueryCvarValueStatus result,
const char *cvarName, const char *cvarValue);
#endif
+49 -46
View File
@@ -44,15 +44,14 @@
#include "Logger.h"
#include "compat_wrappers.h"
#include "ConsoleDetours.h"
#include <IGameConfigs.h>
#include "GameConfigs.h"
#include "sm_stringutil.h"
#include "ConCmdManager.h"
#include "HalfLife2.h"
#include "ConCommandBaseIterator.h"
#include "logic_bridge.h"
#include <am-utility.h>
#include "ShareSys.h"
#if defined PLATFORM_POSIX
#if defined PLATFORM_LINUX
# include <dlfcn.h>
# include <sys/mman.h>
# include <stdint.h>
@@ -60,9 +59,7 @@
#endif
#if SH_IMPL_VERSION >= 5
# if SOURCE_ENGINE == SE_DOTA
SH_DECL_EXTERN2_void(ConCommand, Dispatch, SH_NOATTRIB, false, const CCommandContext &, const CCommand &);
# elif SOURCE_ENGINE >= SE_ORANGEBOX
# if SOURCE_ENGINE >= SE_ORANGEBOX
SH_DECL_EXTERN1_void(ConCommand, Dispatch, SH_NOATTRIB, false, const CCommand &);
# else
SH_DECL_EXTERN0_void(ConCommand, Dispatch, SH_NOATTRIB, false);
@@ -134,9 +131,7 @@ class GenericCommandHooker : public IConCommandLinkListener
}
}
# if SOURCE_ENGINE == SE_DOTA
void Dispatch(const CCommandContext &context, const CCommand& args)
# elif SOURCE_ENGINE >= SE_ORANGEBOX
# if SOURCE_ENGINE >= SE_ORANGEBOX
void Dispatch(const CCommand& args)
# else
void Dispatch()
@@ -195,7 +190,7 @@ class GenericCommandHooker : public IConCommandLinkListener
size_t index;
if (!FindVtable(vtable, index))
{
logger->LogError("Console detour tried to unhook command \"%s\" but it wasn't found", pBase->GetName());
g_Logger.LogError("Console detour tried to unhook command \"%s\" but it wasn't found", pBase->GetName());
return;
}
@@ -219,7 +214,7 @@ public:
if (dispatch.thisptroffs < 0)
{
logger->LogError("Command filter could not determine ConCommand layout");
g_Logger.LogError("Command filter could not determine ConCommand layout");
return false;
}
@@ -228,7 +223,7 @@ public:
if (!vtables.size())
{
logger->LogError("Command filter could not find any cvars!");
g_Logger.LogError("Command filter could not find any cvars!");
return false;
}
@@ -579,21 +574,23 @@ ConsoleDetours::ConsoleDetours() : status(FeatureStatus_Unknown)
void ConsoleDetours::OnSourceModAllInitialized()
{
m_pForward = forwardsys->CreateForwardEx("OnAnyCommand", ET_Hook, 3, NULL, Param_Cell,
m_pForward = g_Forwards.CreateForwardEx("OnAnyCommand", ET_Hook, 3, NULL, Param_Cell,
Param_String, Param_Cell);
sharesys->AddCapabilityProvider(NULL, this, FEATURECAP_COMMANDLISTENER);
g_ShareSys.AddCapabilityProvider(NULL, this, FEATURECAP_COMMANDLISTENER);
}
void ConsoleDetours::OnSourceModShutdown()
{
for (StringHashMap<IChangeableForward *>::iterator iter = m_Listeners.iter();
!iter.empty();
iter.next())
List<Listener*>::iterator iter = m_Listeners.begin();
while (iter != m_Listeners.end())
{
forwardsys->ReleaseForward(iter->value);
Listener *listener = (*iter);
g_Forwards.ReleaseForward(listener->forward);
delete listener;
iter = m_Listeners.erase(iter);
}
forwardsys->ReleaseForward(m_pForward);
g_Forwards.ReleaseForward(m_pForward);
s_GenericHooker.Disable();
}
@@ -622,15 +619,22 @@ bool ConsoleDetours::AddListener(IPluginFunction *fun, const char *command)
}
else
{
ke::AutoArray<char> str(UTIL_ToLowerCase(command));
IChangeableForward *forward;
if (!m_Listeners.retrieve(str, &forward))
const char *str = UTIL_ToLowerCase(command);
Listener *listener;
Listener **plistener = m_CmdLookup.retrieve(str);
if (plistener == NULL)
{
forward = forwardsys->CreateForwardEx(NULL, ET_Hook, 3, NULL, Param_Cell,
Param_String, Param_Cell);
m_Listeners.insert(str, forward);
listener = new Listener;
listener->forward = g_Forwards.CreateForwardEx(NULL, ET_Hook, 3, NULL, Param_Cell,
Param_String, Param_Cell);
m_CmdLookup.insert(str, listener);
}
forward->AddFunction(fun);
else
{
listener = *plistener;
}
listener->forward->AddFunction(fun);
delete [] str;
}
return true;
@@ -644,11 +648,14 @@ bool ConsoleDetours::RemoveListener(IPluginFunction *fun, const char *command)
}
else
{
ke::AutoArray<char> str(UTIL_ToLowerCase(command));
IChangeableForward *forward;
if (!m_Listeners.retrieve(str, &forward))
const char *str = UTIL_ToLowerCase(command);
Listener *listener;
Listener **plistener = m_CmdLookup.retrieve(str);
delete [] str;
if (plistener == NULL)
return false;
return forward->RemoveFunction(fun);
listener = *plistener;
return listener->forward->RemoveFunction(fun);
}
}
@@ -657,11 +664,6 @@ cell_t ConsoleDetours::InternalDispatch(int client, const CCommand& args)
char name[255];
const char *realname = args.Arg(0);
size_t len = strlen(realname);
// Disallow command strings that are too long, for now.
if (len >= sizeof(name) - 1)
return Pl_Continue;
for (size_t i = 0; i < len; i++)
{
if (realname[i] >= 'A' && realname[i] <= 'Z')
@@ -681,20 +683,21 @@ cell_t ConsoleDetours::InternalDispatch(int client, const CCommand& args)
if (strcmp(name, "sm") == 0)
result = Pl_Continue;
if (result >= Pl_Handled)
if (result >= Pl_Stop)
return result;
IChangeableForward *forward;
if (!m_Listeners.retrieve(name, &forward))
Listener **plistener = m_CmdLookup.retrieve(name);
if (plistener == NULL)
return result;
if (forward->GetFunctionCount() == 0)
Listener *listener = *plistener;
if (listener->forward->GetFunctionCount() == 0)
return result;
cell_t result2 = Pl_Continue;
forward->PushCell(client);
forward->PushString(name);
forward->PushCell(args.ArgC() - 1);
forward->Execute(&result2, NULL);
listener->forward->PushCell(client);
listener->forward->PushString(name);
listener->forward->PushCell(args.ArgC() - 1);
listener->forward->Execute(&result2, NULL);
if (result2 > result)
result = result2;
@@ -723,10 +726,10 @@ cell_t ConsoleDetours::Dispatch(ConCommand *pBase)
/* See bug 4020 - we can't optimize this because looking at the vtable
* is probably more expensive, since there's no SH_GET_ORIG_VFNPTR_ENTRY.
*/
SH_ADD_HOOK(ConCommand, Dispatch, pBase, SH_STATIC(DummyHook), false);
SH_ADD_HOOK_STATICFUNC(ConCommand, Dispatch, pBase, DummyHook, false);
dummy_hook_set = true;
pBase->Dispatch();
SH_REMOVE_HOOK(ConCommand, Dispatch, pBase, SH_STATIC(DummyHook), false);
SH_REMOVE_HOOK_STATICFUNC(ConCommand, Dispatch, pBase, DummyHook, false);
}
else
{
+8 -3
View File
@@ -33,8 +33,8 @@
#include "sm_globals.h"
#include "sourcemm_api.h"
#include <IForwardSys.h>
#include <sm_stringhashmap.h>
#include "ForwardSys.h"
#include <sm_trie_tpl.h>
class ConsoleDetours :
public SMGlobalClass,
@@ -43,6 +43,10 @@ class ConsoleDetours :
friend class PlayerManager;
friend class GenericCommandHooker;
struct Listener
{
IChangeableForward *forward;
};
public:
ConsoleDetours();
public: //SMGlobalClass
@@ -69,7 +73,8 @@ public:
private:
FeatureStatus status;
IChangeableForward *m_pForward;
StringHashMap<IChangeableForward *> m_Listeners;
KTrie<Listener*> m_CmdLookup;
List<Listener*> m_Listeners;
};
extern ConsoleDetours g_ConsoleDetours;
+39 -57
View File
@@ -1,5 +1,5 @@
/**
* vim: set ts=4 sw=4 tw=99 noet :
* vim: set ts=4 :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
@@ -34,12 +34,13 @@
#include "sourcemod.h"
#include "sourcemm_api.h"
#include "sm_srvcmds.h"
#include <sourcemod_version.h>
#include "sm_stringutil.h"
#include "LibrarySys.h"
#include "Logger.h"
#include "PluginSys.h"
#include "ForwardSys.h"
#include "frame_hooks.h"
#include "logic_bridge.h"
#include <sourcemod_version.h>
#ifdef PLATFORM_WINDOWS
ConVar sm_corecfgfile("sm_corecfgfile", "addons\\sourcemod\\configs\\core.cfg", 0, "SourceMod core configuration file");
@@ -60,10 +61,7 @@ ConVar *g_ServerCfgFile = NULL;
void CheckAndFinalizeConfigs();
#if SOURCE_ENGINE == SE_DOTA
SH_DECL_EXTERN2_void(ConCommand, Dispatch, SH_NOATTRIB, false, const CCommandContext &, const CCommand &);
void Hook_ExecDispatchPre(const CCommandContext &context, const CCommand &cmd)
#elif SOURCE_ENGINE >= SE_ORANGEBOX
#if SOURCE_ENGINE >= SE_ORANGEBOX
SH_DECL_EXTERN1_void(ConCommand, Dispatch, SH_NOATTRIB, false, const CCommand &);
void Hook_ExecDispatchPre(const CCommand &cmd)
#elif SOURCE_ENGINE == SE_DARKMESSIAH
@@ -91,9 +89,7 @@ void Hook_ExecDispatchPre()
}
}
#if SOURCE_ENGINE == SE_DOTA
void Hook_ExecDispatchPost(const CCommandContext &context, const CCommand &cmd)
#elif SOURCE_ENGINE >= SE_ORANGEBOX
#if SOURCE_ENGINE >= SE_ORANGEBOX
void Hook_ExecDispatchPost(const CCommand &cmd)
#else
void Hook_ExecDispatchPost()
@@ -118,12 +114,12 @@ void CheckAndFinalizeConfigs()
void CoreConfig::OnSourceModAllInitialized()
{
g_RootMenu.AddRootConsoleCommand("config", "Set core configuration options", this);
g_pOnServerCfg = forwardsys->CreateForward("OnServerCfg", ET_Ignore, 0, NULL);
g_pOnConfigsExecuted = forwardsys->CreateForward("OnConfigsExecuted", ET_Ignore, 0, NULL);
g_pOnAutoConfigsBuffered = forwardsys->CreateForward("OnAutoConfigsBuffered", ET_Ignore, 0, NULL);
g_pOnServerCfg = g_Forwards.CreateForward("OnServerCfg", ET_Ignore, 0, NULL);
g_pOnConfigsExecuted = g_Forwards.CreateForward("OnConfigsExecuted", ET_Ignore, 0, NULL);
g_pOnAutoConfigsBuffered = g_Forwards.CreateForward("OnAutoConfigsBuffered", ET_Ignore, 0, NULL);
}
CoreConfig::CoreConfig()
CoreConfig::CoreConfig() : m_Strings(512)
{
}
@@ -134,14 +130,14 @@ CoreConfig::~CoreConfig()
void CoreConfig::OnSourceModShutdown()
{
g_RootMenu.RemoveRootConsoleCommand("config", this);
forwardsys->ReleaseForward(g_pOnServerCfg);
forwardsys->ReleaseForward(g_pOnConfigsExecuted);
forwardsys->ReleaseForward(g_pOnAutoConfigsBuffered);
g_Forwards.ReleaseForward(g_pOnServerCfg);
g_Forwards.ReleaseForward(g_pOnConfigsExecuted);
g_Forwards.ReleaseForward(g_pOnAutoConfigsBuffered);
if (g_pExecPtr != NULL)
{
SH_REMOVE_HOOK(ConCommand, Dispatch, g_pExecPtr, SH_STATIC(Hook_ExecDispatchPre), false);
SH_REMOVE_HOOK(ConCommand, Dispatch, g_pExecPtr, SH_STATIC(Hook_ExecDispatchPost), true);
SH_REMOVE_HOOK_STATICFUNC(ConCommand, Dispatch, g_pExecPtr, Hook_ExecDispatchPre, false);
SH_REMOVE_HOOK_STATICFUNC(ConCommand, Dispatch, g_pExecPtr, Hook_ExecDispatchPost, true);
g_pExecPtr = NULL;
}
}
@@ -166,8 +162,8 @@ void CoreConfig::OnSourceModLevelChange(const char *mapName)
g_pExecPtr = FindCommand("exec");
if (g_pExecPtr != NULL)
{
SH_ADD_HOOK(ConCommand, Dispatch, g_pExecPtr, SH_STATIC(Hook_ExecDispatchPre), false);
SH_ADD_HOOK(ConCommand, Dispatch, g_pExecPtr, SH_STATIC(Hook_ExecDispatchPost), true);
SH_ADD_HOOK_STATICFUNC(ConCommand, Dispatch, g_pExecPtr, Hook_ExecDispatchPre, false);
SH_ADD_HOOK_STATICFUNC(ConCommand, Dispatch, g_pExecPtr, Hook_ExecDispatchPost, true);
}
else
{
@@ -197,30 +193,17 @@ void CoreConfig::OnRootConsoleCommand(const char *cmdname, const CCommand &comma
if (res == ConfigResult_Reject)
{
g_RootMenu.ConsolePrint("[SM] Could not set config option \"%s\" to \"%s\". (%s)", option, value, error);
g_RootMenu.ConsolePrint("[SM] Could not set config option \"%s\" to \"%s\" (%s)", option, value, error);
} else if (res == ConfigResult_Ignore) {
g_RootMenu.ConsolePrint("[SM] No such config option \"%s\" exists.", option);
} else {
g_RootMenu.ConsolePrint("[SM] Config option \"%s\" successfully set to \"%s\".", option, value);
g_RootMenu.ConsolePrint("Config option \"%s\" successfully set to \"%s.\"", option, value);
}
return;
} else if (argcount >= 3) {
const char *option = command.Arg(2);
const char *value = GetCoreConfigValue(option);
if (value == NULL)
{
g_RootMenu.ConsolePrint("[SM] No such config option \"%s\" exists.", option);
} else {
g_RootMenu.ConsolePrint("[SM] Config option \"%s\" is set to \"%s\".", option, value);
}
return;
}
g_RootMenu.ConsolePrint("[SM] Usage: sm config <option> [value]");
g_RootMenu.ConsolePrint("[SM] Usage: sm config <option> <value>");
}
void CoreConfig::Initialize()
@@ -256,13 +239,14 @@ void CoreConfig::Initialize()
/* Reset cached key values */
m_KeyValues.clear();
m_Strings.Reset();
/* Parse config file */
if ((err=textparsers->ParseFile_SMC(filePath, this, NULL)) != SMCError_Okay)
{
/* :TODO: This won't actually log or print anything :( - So fix that somehow */
const char *error = textparsers->GetSMCErrorString(err);
logger->LogFatal("[SM] Error encountered parsing core config file: %s", error ? error : "");
g_Logger.LogFatal("[SM] Error encountered parsing core config file: %s", error ? error : "");
}
}
@@ -274,7 +258,7 @@ SMCResult CoreConfig::ReadSMC_KeyValue(const SMCStates *states, const char *key,
if (err == ConfigResult_Reject)
{
/* This is a fatal error */
logger->LogFatal("Config error (key: %s) (value: %s) %s", key, value, error);
g_Logger.LogFatal("Config error (key: %s) (value: %s) %s", key, value, error);
}
return SMCResult_Continue;
@@ -295,18 +279,19 @@ ConfigResult CoreConfig::SetConfigOption(const char *option, const char *value,
pBase = pBase->m_pGlobalClassNext;
}
ke::AString vstr(value);
m_KeyValues.replace(option, ke::Move(vstr));
m_KeyValues.replace(option, m_Strings.AddString(value));
return ConfigResult_Ignore;
}
const char *CoreConfig::GetCoreConfigValue(const char *key)
{
StringHashMap<ke::AString>::Result r = m_KeyValues.find(key);
if (!r.found())
int *pKey = m_KeyValues.retrieve(key);
if (pKey == NULL)
{
return NULL;
return r->value.chars();
}
return m_Strings.GetString(*pKey);
}
bool SM_AreConfigsExecuted()
@@ -323,7 +308,7 @@ inline bool IsPathSepChar(char c)
#endif
}
bool SM_ExecuteConfig(IPlugin *pl, AutoConfig *cfg, bool can_create)
bool SM_ExecuteConfig(CPlugin *pl, AutoConfig *cfg, bool can_create)
{
bool will_create = false;
@@ -410,7 +395,7 @@ bool SM_ExecuteConfig(IPlugin *pl, AutoConfig *cfg, bool can_create)
FILE *fp = fopen(file, "wt");
if (fp)
{
fprintf(fp, "// This file was auto-generated by SourceMod (v%s)\n", SOURCEMOD_VERSION);
fprintf(fp, "// This file was auto-generated by SourceMod (v%s)\n", SM_FULL_VERSION);
fprintf(fp, "// ConVars for plugin \"%s\"\n", pl->GetFilename());
fprintf(fp, "\n\n");
@@ -467,11 +452,6 @@ bool SM_ExecuteConfig(IPlugin *pl, AutoConfig *cfg, bool can_create)
can_create = false;
fclose(fp);
}
else
{
logger->LogError("Failed to auto generate config for %s, make sure the directory has write permission.", pl->GetFilename());
return can_create;
}
}
}
@@ -502,10 +482,10 @@ void SM_DoSingleExecFwds(IPluginContext *ctx)
void SM_ConfigsExecuted_Plugin(unsigned int serial)
{
IPluginIterator *iter = scripts->GetPluginIterator();
IPluginIterator *iter = g_PluginSys.GetPluginIterator();
while (iter->MorePlugins())
{
IPlugin *plugin = iter->GetPlugin();
CPlugin *plugin = (CPlugin *)(iter->GetPlugin());
if (plugin->GetSerial() == serial)
{
SM_DoSingleExecFwds(plugin->GetBaseContext());
@@ -518,7 +498,7 @@ void SM_ConfigsExecuted_Plugin(unsigned int serial)
void SM_ExecuteForPlugin(IPluginContext *ctx)
{
SMPlugin *plugin = scripts->FindPluginByContext(ctx->GetContext());
CPlugin *plugin = (CPlugin *)g_PluginSys.GetPluginByCtx(ctx->GetContext());
unsigned int num = plugin->GetConfigCount();
if (!num)
@@ -547,17 +527,19 @@ void SM_ExecuteAllConfigs()
engine->ServerCommand("exec sourcemod/sourcemod.cfg\n");
AutoPluginList plugins(scripts);
for (size_t i = 0; i < plugins->size(); i++)
IPluginIterator *iter = g_PluginSys.GetPluginIterator();
while (iter->MorePlugins())
{
SMPlugin *plugin = plugins->at(i);
CPlugin *plugin = (CPlugin *)(iter->GetPlugin());
unsigned int num = plugin->GetConfigCount();
bool can_create = true;
for (unsigned int i=0; i<num; i++)
{
can_create = SM_ExecuteConfig(plugin, plugin->GetConfig(i), can_create);
}
iter->NextPlugin();
}
iter->Release();
g_bGotServerStart = true;
CheckAndFinalizeConfigs();
+5 -4
View File
@@ -1,5 +1,5 @@
/**
* vim: set ts=4 sw=4 tw=99 noet :
* vim: set ts=4 :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
@@ -35,8 +35,8 @@
#include "sm_globals.h"
#include <ITextParsers.h>
#include <IRootConsoleMenu.h>
#include <am-string.h>
#include <sm_stringhashmap.h>
#include <sm_trie_tpl.h>
#include "sm_memtable.h"
using namespace SourceMod;
@@ -68,7 +68,8 @@ private:
*/
ConfigResult SetConfigOption(const char *option, const char *value, ConfigSource, char *Error, size_t maxlength);
private:
StringHashMap<ke::AString> m_KeyValues;
BaseStringTable m_Strings;
KTrie<int> m_KeyValues;
};
extern bool SM_AreConfigsExecuted();
+119 -144
View File
@@ -1,5 +1,5 @@
/**
* vim: set ts=4 sw=4 tw=99 noet :
* vim: set ts=4 :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
@@ -30,10 +30,12 @@
*/
#include "Database.h"
#include "ISourceMod.h"
#include "HandleSys.h"
#include "ShareSys.h"
#include "sourcemod.h"
#include "sm_stringutil.h"
#include "Logger.h"
#include "ExtensionSys.h"
#include "PluginSys.h"
#include <stdlib.h>
#include <IThreader.h>
@@ -45,18 +47,10 @@ DBManager g_DBMan;
static bool s_OneTimeThreaderErrorMsg = false;
DBManager::DBManager()
: m_Terminate(false),
m_ParseLevel(0),
m_ParseState(0),
m_pDefault(NULL)
: m_StrTab(512), m_ParseLevel(0), m_ParseState(0), m_pDefault(NULL)
{
}
static void FrameHook(bool simulating)
{
g_DBMan.RunFrame();
}
void DBManager::OnSourceModAllInitialized()
{
HandleAccess sec;
@@ -70,11 +64,13 @@ void DBManager::OnSourceModAllInitialized()
g_ShareSys.AddInterface(NULL, this);
g_pSM->BuildPath(Path_SM, m_Filename, sizeof(m_Filename), "configs/databases.cfg");
g_SourceMod.BuildPath(Path_SM, m_Filename, sizeof(m_Filename), "configs/databases.cfg");
m_pConfigLock = g_pThreader->MakeMutex();
m_pThinkLock = g_pThreader->MakeMutex();
m_pQueueLock = g_pThreader->MakeMutex();
g_PluginSys.AddPluginsListener(this);
g_pSM->AddGameFrameHook(&FrameHook);
}
void DBManager::OnSourceModLevelChange(const char *mapName)
@@ -86,26 +82,28 @@ void DBManager::OnSourceModLevelChange(const char *mapName)
* This way the thread's search won't be searching through a
* potentially empty/corrupt list, which would be very bad.
*/
ke::AutoLock lock(&m_ConfigLock);
m_pConfigLock->Lock();
if ((err = textparsers->ParseFile_SMC(m_Filename, this, &states)) != SMCError_Okay)
{
logger->LogError("[SM] Detected parse error(s) in file \"%s\"", m_Filename);
g_Logger.LogError("[SM] Detected parse error(s) in file \"%s\"", m_Filename);
if (err != SMCError_Custom)
{
const char *txt = textparsers->GetSMCErrorString(err);
logger->LogError("[SM] Line %d: %s", states.line, txt);
g_Logger.LogError("[SM] Line %d: %s", states.line, txt);
}
}
m_pConfigLock->Unlock();
}
void DBManager::OnSourceModShutdown()
{
g_pSM->RemoveGameFrameHook(&FrameHook);
KillWorkerThread();
g_PluginSys.RemovePluginsListener(this);
m_pConfigLock->DestroyThis();
m_pThinkLock->DestroyThis();
m_pQueueLock->DestroyThis();
g_HandleSys.RemoveType(m_DatabaseType, g_pCoreIdent);
g_HandleSys.RemoveType(m_DriverType, g_pCoreIdent);
ClearConfigs();
}
unsigned int DBManager::GetInterfaceVersion()
@@ -135,20 +133,13 @@ void DBManager::OnHandleDestroy(HandleType_t type, void *object)
void DBManager::ReadSMC_ParseStart()
{
ClearConfigs();
m_confs.clear();
m_ParseLevel = 0;
m_ParseState = DBPARSE_LEVEL_NONE;
m_StrTab.Reset();
m_DefDriver.clear();
}
void DBManager::ClearConfigs()
{
List<ConfDbInfo *>::iterator iter;
for (iter=m_confs.begin(); iter!=m_confs.end(); iter++)
delete (*iter);
m_confs.clear();
}
ConfDbInfo s_CurInfo;
SMCResult DBManager::ReadSMC_NewSection(const SMCStates *states, const char *name)
{
@@ -168,7 +159,7 @@ SMCResult DBManager::ReadSMC_NewSection(const SMCStates *states, const char *nam
}
} else if (m_ParseState == DBPARSE_LEVEL_MAIN) {
s_CurInfo = ConfDbInfo();
s_CurInfo.name = name;
s_CurInfo.name = m_StrTab.AddString(name);
m_ParseState = DBPARSE_LEVEL_DATABASE;
} else if (m_ParseState == DBPARSE_LEVEL_DATABASE) {
m_ParseLevel++;
@@ -195,16 +186,16 @@ SMCResult DBManager::ReadSMC_KeyValue(const SMCStates *states, const char *key,
{
if (strcmp(value, "default") != 0)
{
s_CurInfo.driver = value;
s_CurInfo.driver = m_StrTab.AddString(value);
}
} else if (strcmp(key, "database") == 0) {
s_CurInfo.database = value;
s_CurInfo.database = m_StrTab.AddString(value);
} else if (strcmp(key, "host") == 0) {
s_CurInfo.host = value;
s_CurInfo.host = m_StrTab.AddString(value);
} else if (strcmp(key, "user") == 0) {
s_CurInfo.user = value;
s_CurInfo.user = m_StrTab.AddString(value);
} else if (strcmp(key, "pass") == 0) {
s_CurInfo.pass = value;
s_CurInfo.pass = m_StrTab.AddString(value);
} else if (strcmp(key, "timeout") == 0) {
s_CurInfo.info.maxTimeout = atoi(value);
} else if (strcmp(key, "port") == 0) {
@@ -215,6 +206,13 @@ SMCResult DBManager::ReadSMC_KeyValue(const SMCStates *states, const char *key,
return SMCResult_Continue;
}
#define ASSIGN_VAR(var) \
if (s_CurInfo.var == -1) { \
s_CurInfo.info.var = ""; \
} else { \
s_CurInfo.info.var = m_StrTab.GetString(s_CurInfo.var); \
}
SMCResult DBManager::ReadSMC_LeavingSection(const SMCStates *states)
{
if (m_ParseLevel)
@@ -225,26 +223,17 @@ SMCResult DBManager::ReadSMC_LeavingSection(const SMCStates *states)
if (m_ParseState == DBPARSE_LEVEL_DATABASE)
{
ConfDbInfo *cdb = new ConfDbInfo();
cdb->name = s_CurInfo.name;
cdb->driver = s_CurInfo.driver;
cdb->host = s_CurInfo.host;
cdb->user = s_CurInfo.user;
cdb->pass = s_CurInfo.pass;
cdb->database = s_CurInfo.database;
cdb->realDriver = s_CurInfo.realDriver;
cdb->info.maxTimeout = s_CurInfo.info.maxTimeout;
cdb->info.port = s_CurInfo.info.port;
cdb->info.driver = cdb->driver.c_str();
cdb->info.database = cdb->database.c_str();
cdb->info.host = cdb->host.c_str();
cdb->info.user = cdb->user.c_str();
cdb->info.pass = cdb->pass.c_str();
/* Set all of the info members to either a blank string
* or the string pointer from the string table.
*/
ASSIGN_VAR(driver);
ASSIGN_VAR(database);
ASSIGN_VAR(host);
ASSIGN_VAR(user);
ASSIGN_VAR(pass);
/* Save it.. */
m_confs.push_back(cdb);
m_confs.push_back(s_CurInfo);
/* Go up one level */
m_ParseState = DBPARSE_LEVEL_MAIN;
@@ -255,6 +244,7 @@ SMCResult DBManager::ReadSMC_LeavingSection(const SMCStates *states)
return SMCResult_Continue;
}
#undef ASSIGN_VAR
void DBManager::ReadSMC_ParseEnd(bool halted, bool failed)
{
@@ -271,7 +261,7 @@ bool DBManager::Connect(const char *name, IDBDriver **pdr, IDatabase **pdb, bool
*pdr = NULL;
}
*pdb = NULL;
g_pSM->Format(error, maxlength, "Configuration \"%s\" not found", name);
UTIL_Format(error, maxlength, "Configuration \"%s\" not found", name);
return false;
}
@@ -308,7 +298,7 @@ bool DBManager::Connect(const char *name, IDBDriver **pdr, IDatabase **pdb, bool
}
*pdb = NULL;
g_pSM->Format(error, maxlength, "Driver \"%s\" not found", dname);
UTIL_Format(error, maxlength, "Driver \"%s\" not found", dname);
return false;
}
@@ -343,22 +333,16 @@ void DBManager::RemoveDriver(IDBDriver *pDriver)
}
/* Make sure NOTHING references this! */
List<ConfDbInfo *>::iterator iter;
List<ConfDbInfo>::iterator iter;
for (iter=m_confs.begin(); iter!=m_confs.end(); iter++)
{
ConfDbInfo &db = *(*iter);
ConfDbInfo &db = (*iter);
if (db.realDriver == pDriver)
{
db.realDriver = NULL;
}
}
/* Someone unloaded the default driver? Silly.. */
if (pDriver == m_pDefault)
{
m_pDefault = NULL;
}
/* Now that the driver is gone, we have to test the think queue.
* Whatever happens therein is up to the db op!
*/
@@ -464,12 +448,12 @@ const DatabaseInfo *DBManager::FindDatabaseConf(const char *name)
ConfDbInfo *DBManager::GetDatabaseConf(const char *name)
{
List<ConfDbInfo *>::iterator iter;
List<ConfDbInfo>::iterator iter;
for (iter=m_confs.begin(); iter!=m_confs.end(); iter++)
{
ConfDbInfo &conf = *(*iter);
if (conf.name == name)
ConfDbInfo &conf = (*iter);
if (strcmp(m_StrTab.GetString(conf.name), name) == 0)
{
return &conf;
}
@@ -490,7 +474,7 @@ IDBDriver *DBManager::FindOrLoadDriver(const char *name)
}
char filename[PLATFORM_MAX_PATH];
g_pSM->Format(filename, sizeof(filename), "dbi.%s.ext", name);
UTIL_Format(filename, sizeof(filename), "dbi.%s.ext", name);
IExtension *pExt = g_Extensions.LoadAutoExtension(filename);
if (!pExt || !pExt->IsLoaded() || m_drivers.size() <= last_size)
@@ -511,17 +495,12 @@ IDBDriver *DBManager::FindOrLoadDriver(const char *name)
void DBManager::KillWorkerThread()
{
if (m_Worker)
if (m_pWorker)
{
{
ke::AutoLock lock(&m_QueueEvent);
m_Terminate = true;
m_QueueEvent.Notify();
}
m_Worker->Join();
m_Worker = NULL;
m_pWorker->Stop(false);
g_pThreader->DestroyWorker(m_pWorker);
m_pWorker = NULL;
s_OneTimeThreaderErrorMsg = false;
m_Terminate = false;
}
}
@@ -534,106 +513,99 @@ bool DBManager::AddToThreadQueue(IDBThreadOperation *op, PrioQueueLevel prio)
return false;
}
if (!m_Worker)
if (!m_pWorker)
{
m_Worker = new ke::Thread(this, "SM SQL Worker");
if (!m_Worker->Succeeded())
m_pWorker = g_pThreader->MakeWorker(this, true);
if (!m_pWorker)
{
if (!s_OneTimeThreaderErrorMsg)
{
logger->LogError("[SM] Unable to create db threader (error unknown)");
g_Logger.LogError("[SM] Unable to create db threader (error unknown)");
s_OneTimeThreaderErrorMsg = true;
}
m_Worker = NULL;
return false;
}
if (!m_pWorker->Start())
{
if (!s_OneTimeThreaderErrorMsg)
{
g_Logger.LogError("[SM] Unable to start db threader (error unknown)");
s_OneTimeThreaderErrorMsg = true;
}
g_pThreader->DestroyWorker(m_pWorker);
m_pWorker = NULL;
return false;
}
}
/* Add to the queue */
{
ke::AutoLock lock(&m_QueueEvent);
m_pQueueLock->Lock();
Queue<IDBThreadOperation *> &queue = m_OpQueue.GetQueue(prio);
queue.push(op);
m_QueueEvent.Notify();
m_pQueueLock->Unlock();
}
/* Make the thread */
m_pWorker->MakeThread(this);
return true;
}
void DBManager::Run()
void DBManager::OnWorkerStart(IThreadWorker *pWorker)
{
// Initialize DB threadsafety.
for (size_t i=0; i < m_drivers.size(); i++)
m_drSafety.clear();
for (size_t i=0; i<m_drivers.size(); i++)
{
if (m_drivers[i]->IsThreadSafe())
{
m_drSafety.push_back(m_drivers[i]->InitializeThreadSafety());
else
} else {
m_drSafety.push_back(false);
}
}
}
// Run actual worker thread logic.
ThreadMain();
// Shutdown DB threadsafety.
void DBManager::OnWorkerStop(IThreadWorker *pWorker)
{
for (size_t i=0; i<m_drivers.size(); i++)
{
if (m_drSafety[i])
{
m_drivers[i]->ShutdownThreadSafety();
}
}
m_drSafety.clear();
}
void DBManager::ThreadMain()
void DBManager::RunThread(IThreadHandle *pThread)
{
ke::AutoLock lock(&m_QueueEvent);
IDBThreadOperation *op = NULL;
while (true) {
// The lock has been acquired. Grab everything we can out of the
// queue. Since we want to flush the queue even if we're terminated,
// we process all operations we can before checking to terminate.
// There's no risk of starvation since the main thread blocks on us
// terminating.
while (true)
/* Get something from the queue */
{
m_pQueueLock->Lock();
Queue<IDBThreadOperation *> &queue = m_OpQueue.GetLikelyQueue();
if (!queue.empty())
{
Queue<IDBThreadOperation *> &queue = m_OpQueue.GetLikelyQueue();
if (queue.empty())
break;
IDBThreadOperation *op = queue.first();
op = queue.first();
queue.pop();
// Unlock the queue when we run the query, so the main thread can
// keep pumping events. We re-acquire the lock to check for more
// items. It's okay if we terminate while unlocked; the main
// thread would be blocked and we'd need to flush the queue
// anyway, so after we've depleted the queue here, we'll just
// reach the terminate at the top of the loop.
{
ke::AutoUnlock unlock(&m_QueueEvent);
op->RunThreadPart();
ke::AutoLock lock(&m_ThinkLock);
m_ThinkQueue.push(op);
}
if (!m_Terminate)
{
ke::AutoUnlock unlock(&m_QueueEvent);
#ifdef _WIN32
Sleep(20);
#else
usleep(20000);
#endif
}
}
if (m_Terminate)
return;
// Release the lock and wait for a signal.
m_QueueEvent.Wait();
m_pQueueLock->Unlock();
}
/* whoa. hi. did we get something? we should have. */
if (!op)
{
/* wtf? */
return;
}
op->RunThreadPart();
m_pThinkLock->Lock();
m_ThinkQueue.push(op);
m_pThinkLock->Unlock();
}
void DBManager::RunFrame()
@@ -645,16 +617,19 @@ void DBManager::RunFrame()
}
/* Dump one thing per-frame so the server stays sane. */
IDBThreadOperation *op;
{
ke::AutoLock lock(&m_ThinkLock);
op = m_ThinkQueue.first();
m_ThinkQueue.pop();
}
m_pThinkLock->Lock();
IDBThreadOperation *op = m_ThinkQueue.first();
m_ThinkQueue.pop();
m_pThinkLock->Unlock();
op->RunThinkPart();
op->Destroy();
}
void DBManager::OnTerminate(IThreadHandle *pThread, bool cancel)
{
/* Do nothing */
}
void DBManager::OnSourceModIdentityDropped(IdentityToken_t *pToken)
{
s_pAddBlock = pToken;
@@ -730,12 +705,12 @@ void DBManager::OnPluginUnloaded(IPlugin *plugin)
void DBManager::LockConfig()
{
m_ConfigLock.Lock();
m_pConfigLock->Lock();
}
void DBManager::UnlockConfig()
{
m_ConfigLock.Unlock();
m_pConfigLock->Unlock();
}
const char *DBManager::GetDefaultDriverName()
+27 -23
View File
@@ -1,5 +1,5 @@
/**
* vim: set ts=4 sw=4 tw=99 noet :
* vim: set ts=4 :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
@@ -33,29 +33,30 @@
#define _INCLUDE_DATABASE_MANAGER_H_
#include <IDBDriver.h>
#include "common_logic.h"
#include "sm_globals.h"
#include <sh_vector.h>
#include <sh_string.h>
#include <sh_list.h>
#include <ITextParsers.h>
#include "sm_memtable.h"
#include <IThreader.h>
#include <IPluginSys.h>
#include <am-thread-utils.h>
#include "sm_simple_prioqueue.h"
#include "PluginSys.h"
using namespace SourceHook;
struct ConfDbInfo
{
ConfDbInfo() : realDriver(NULL)
ConfDbInfo() : name(-1), driver(-1), host(-1), user(-1), pass(-1),
database(-1), realDriver(NULL)
{
}
String name;
String driver;
String host;
String user;
String pass;
String database;
int name;
int driver;
int host;
int user;
int pass;
int database;
IDBDriver *realDriver;
DatabaseInfo info;
};
@@ -65,8 +66,9 @@ class DBManager :
public SMGlobalClass,
public IHandleTypeDispatch,
public ITextListener_SMC,
public IPluginsListener,
public ke::IRunnable
public IThread,
public IThreadWorkerCallbacks,
public IPluginsListener
{
public:
DBManager();
@@ -97,9 +99,12 @@ public: //ITextListener_SMC
SMCResult ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value);
SMCResult ReadSMC_LeavingSection(const SMCStates *states);
void ReadSMC_ParseEnd(bool halted, bool failed);
public: //ke::IRunnable
void Run();
void ThreadMain();
public: //IThread
void RunThread(IThreadHandle *pThread);
void OnTerminate(IThreadHandle *pThread, bool cancel);
public: //IThreadWorkerCallbacks
void OnWorkerStart(IThreadWorker *pWorker);
void OnWorkerStop(IThreadWorker *pWorker);
public: //IPluginsListener
void OnPluginUnloaded(IPlugin *plugin);
public:
@@ -116,7 +121,6 @@ public:
return m_DatabaseType;
}
private:
void ClearConfigs();
void KillWorkerThread();
private:
CVector<IDBDriver *> m_drivers;
@@ -125,16 +129,16 @@ private:
PrioQueue<IDBThreadOperation *> m_OpQueue;
Queue<IDBThreadOperation *> m_ThinkQueue;
CVector<bool> m_drSafety; /* which drivers are safe? */
ke::AutoPtr<ke::Thread> m_Worker;
ke::ConditionVariable m_QueueEvent;
ke::Mutex m_ConfigLock;
ke::Mutex m_ThinkLock;
bool m_Terminate;
IThreadWorker *m_pWorker; /* Worker thread object */
IMutex *m_pConfigLock; /* Configuration lock */
IMutex *m_pQueueLock; /* Queue safety lock */
IMutex *m_pThinkLock; /* Think-queue lock */
List<ConfDbInfo *> m_confs;
List<ConfDbInfo> m_confs;
HandleType_t m_DriverType;
HandleType_t m_DatabaseType;
String m_DefDriver;
BaseStringTable m_StrTab;
char m_Filename[PLATFORM_MAX_PATH];
unsigned int m_ParseLevel;
unsigned int m_ParseState;
@@ -29,10 +29,10 @@
* Version: $Id$
*/
#include <IPluginSys.h>
#include <stdarg.h>
#include "DebugReporter.h"
#include "Logger.h"
#include "PluginSys.h"
#include "sm_stringutil.h"
DebugReport g_DbgReporter;
@@ -47,7 +47,7 @@ void DebugReport::OnDebugSpew(const char *msg, ...)
char buffer[512];
va_start(ap, msg);
smcore.FormatArgs(buffer, sizeof(buffer), msg, ap);
UTIL_FormatArgs(buffer, sizeof(buffer), msg, ap);
va_end(ap);
g_Logger.LogMessage("[SM] %s", buffer);
@@ -56,18 +56,13 @@ void DebugReport::OnDebugSpew(const char *msg, ...)
void DebugReport::GenerateError(IPluginContext *ctx, cell_t func_idx, int err, const char *message, ...)
{
va_list ap;
char buffer[512];
va_start(ap, message);
GenerateErrorVA(ctx, func_idx, err, message, ap);
UTIL_FormatArgs(buffer, sizeof(buffer), message, ap);
va_end(ap);
}
void DebugReport::GenerateErrorVA(IPluginContext *ctx, cell_t func_idx, int err, const char *message, va_list ap)
{
char buffer[512];
smcore.FormatArgs(buffer, sizeof(buffer), message, ap);
const char *plname = pluginsys->FindPluginByContext(ctx->GetContext())->GetFilename();
const char *plname = g_PluginSys.FindPluginByContext(ctx->GetContext())->GetFilename();
const char *error = g_pSourcePawn2->GetErrorString(err);
if (error)
@@ -99,10 +94,10 @@ void DebugReport::GenerateCodeError(IPluginContext *pContext, uint32_t code_addr
char buffer[512];
va_start(ap, message);
smcore.FormatArgs(buffer, sizeof(buffer), message, ap);
UTIL_FormatArgs(buffer, sizeof(buffer), message, ap);
va_end(ap);
const char *plname = pluginsys->FindPluginByContext(pContext->GetContext())->GetFilename();
const char *plname = g_PluginSys.FindPluginByContext(pContext->GetContext())->GetFilename();
const char *error = g_pSourcePawn2->GetErrorString(err);
if (error)
@@ -135,7 +130,7 @@ void DebugReport::GenerateCodeError(IPluginContext *pContext, uint32_t code_addr
void DebugReport::OnContextExecuteError(IPluginContext *ctx, IContextTrace *error)
{
const char *lastname;
const char *plname = pluginsys->FindPluginByContext(ctx->GetContext())->GetFilename();
const char *plname = g_PluginSys.FindPluginByContext(ctx->GetContext())->GetFilename();
int n_err = error->GetErrorCode();
if (n_err != SP_ERROR_NATIVE)
@@ -180,7 +175,7 @@ void DebugReport::OnContextExecuteError(IPluginContext *ctx, IContextTrace *erro
int DebugReport::_GetPluginIndex(IPluginContext *ctx)
{
int id = 1;
IPluginIterator *iter = pluginsys->GetPluginIterator();
IPluginIterator *iter = g_PluginSys.GetPluginIterator();
for (; iter->MorePlugins(); iter->NextPlugin(), id++)
{
@@ -196,6 +191,6 @@ int DebugReport::_GetPluginIndex(IPluginContext *ctx)
/* If we don't know which plugin this is, it's one being loaded. Fake its index for now. */
return pluginsys->GetPluginCount() + 1;
return g_PluginSys.GetPluginCount() + 1;
}
@@ -33,7 +33,7 @@
#define _INCLUDE_SOURCEMOD_CDBGREPORTER_H_
#include "sp_vm_api.h"
#include "common_logic.h"
#include "sm_globals.h"
class DebugReport :
public SMGlobalClass,
@@ -46,7 +46,6 @@ public: // IDebugListener
void OnDebugSpew(const char *msg, ...);
public:
void GenerateError(IPluginContext *ctx, cell_t func_idx, int err, const char *message, ...);
void GenerateErrorVA(IPluginContext *ctx, cell_t func_idx, int err, const char *message, va_list ap);
void GenerateCodeError(IPluginContext *ctx, uint32_t code_addr, int err, const char *message, ...);
private:
int _GetPluginIndex(IPluginContext *ctx);
+39 -36
View File
@@ -2,7 +2,7 @@
* vim: set ts=4 sw=4 tw=99 noet :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2010 AlliedModders LLC. All rights reserved.
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
* =============================================================================
*
* This program is free software; you can redistribute it and/or modify it under
@@ -30,8 +30,10 @@
*/
#include "EventManager.h"
#include "ForwardSys.h"
#include "HandleSys.h"
#include "PluginSys.h"
#include "sm_stringutil.h"
#include "logic_bridge.h"
EventManager g_EventManager;
@@ -56,10 +58,14 @@ public:
EventManager::EventManager() : m_EventType(0)
{
/* Create an event lookup trie */
m_EventHooks = sm_trie_create();
}
EventManager::~EventManager()
{
sm_trie_destroy(m_EventHooks);
/* Free memory used by EventInfo structs if any */
CStack<EventInfo *>::iterator iter;
for (iter = m_FreeEvents.begin(); iter != m_FreeEvents.end(); iter++)
@@ -73,8 +79,8 @@ EventManager::~EventManager()
void EventManager::OnSourceModAllInitialized()
{
/* Add a hook for IGameEventManager2::FireEvent() */
SH_ADD_HOOK(IGameEventManager2, FireEvent, gameevents, SH_MEMBER(this, &EventManager::OnFireEvent), false);
SH_ADD_HOOK(IGameEventManager2, FireEvent, gameevents, SH_MEMBER(this, &EventManager::OnFireEvent_Post), true);
SH_ADD_HOOK_MEMFUNC(IGameEventManager2, FireEvent, gameevents, this, &EventManager::OnFireEvent, false);
SH_ADD_HOOK_MEMFUNC(IGameEventManager2, FireEvent, gameevents, this, &EventManager::OnFireEvent_Post, true);
HandleAccess sec;
@@ -84,17 +90,17 @@ void EventManager::OnSourceModAllInitialized()
sec.access[HandleAccess_Clone] = HANDLE_RESTRICT_IDENTITY | HANDLE_RESTRICT_OWNER;
/* Create the 'GameEvent' handle type */
m_EventType = handlesys->CreateType("GameEvent", this, 0, NULL, &sec, g_pCoreIdent, NULL);
m_EventType = g_HandleSys.CreateType("GameEvent", this, 0, NULL, &sec, g_pCoreIdent, NULL);
}
void EventManager::OnSourceModShutdown()
{
/* Remove hook for IGameEventManager2::FireEvent() */
SH_REMOVE_HOOK(IGameEventManager2, FireEvent, gameevents, SH_MEMBER(this, &EventManager::OnFireEvent), false);
SH_REMOVE_HOOK(IGameEventManager2, FireEvent, gameevents, SH_MEMBER(this, &EventManager::OnFireEvent_Post), true);
SH_REMOVE_HOOK_MEMFUNC(IGameEventManager2, FireEvent, gameevents, this, &EventManager::OnFireEvent, false);
SH_REMOVE_HOOK_MEMFUNC(IGameEventManager2, FireEvent, gameevents, this, &EventManager::OnFireEvent_Post, true);
/* Remove the 'GameEvent' handle type */
handlesys->RemoveType(m_EventType, g_pCoreIdent);
g_HandleSys.RemoveType(m_EventType, g_pCoreIdent);
/* Remove ourselves as listener for events */
gameevents->RemoveListener(this);
@@ -132,12 +138,12 @@ void EventManager::OnPluginUnloaded(IPlugin *plugin)
{
if (pHook->pPreHook)
{
forwardsys->ReleaseForward(pHook->pPreHook);
g_Forwards.ReleaseForward(pHook->pPreHook);
}
if (pHook->pPostHook)
{
forwardsys->ReleaseForward(pHook->pPostHook);
g_Forwards.ReleaseForward(pHook->pPostHook);
}
delete pHook;
@@ -155,13 +161,6 @@ void EventManager::FireGameEvent(IGameEvent *pEvent)
Just need to add ourselves as a listener to make our hook on IGameEventManager2::FireEvent work */
}
#if SOURCE_ENGINE >= SE_LEFT4DEAD && SOURCE_ENGINE != SE_DOTA
int EventManager::GetEventDebugID()
{
return EVENT_DEBUG_ID_INIT;
}
#endif
EventHookError EventManager::HookEvent(const char *name, IPluginFunction *pFunction, EventHookMode mode)
{
EventHook *pHook;
@@ -178,10 +177,10 @@ EventHookError EventManager::HookEvent(const char *name, IPluginFunction *pFunct
}
/* If a hook structure does not exist... */
if (!m_EventHooks.retrieve(name, &pHook))
if (!sm_trie_retrieve(m_EventHooks, name, (void **)&pHook))
{
EventHookList *pHookList;
IPlugin *plugin = scripts->FindPluginByContext(pFunction->GetParentContext()->GetContext());
IPlugin *plugin = g_PluginSys.GetPluginByCtx(pFunction->GetParentContext()->GetContext());
/* Check plugin for an existing EventHook list */
if (!plugin->GetProperty("EventHooks", (void **)&pHookList))
@@ -196,12 +195,12 @@ EventHookError EventManager::HookEvent(const char *name, IPluginFunction *pFunct
if (mode == EventHookMode_Pre)
{
/* Create forward for a pre hook */
pHook->pPreHook = forwardsys->CreateForwardEx(NULL, ET_Hook, 3, GAMEEVENT_PARAMS);
pHook->pPreHook = g_Forwards.CreateForwardEx(NULL, ET_Hook, 3, GAMEEVENT_PARAMS);
/* Add to forward list */
pHook->pPreHook->AddFunction(pFunction);
} else {
/* Create forward for a post hook */
pHook->pPostHook = forwardsys->CreateForwardEx(NULL, ET_Ignore, 3, GAMEEVENT_PARAMS);
pHook->pPostHook = g_Forwards.CreateForwardEx(NULL, ET_Ignore, 3, GAMEEVENT_PARAMS);
/* Should we copy data from a pre hook to the post hook? */
pHook->postCopy = (mode == EventHookMode_Post);
/* Add to forward list */
@@ -209,14 +208,14 @@ EventHookError EventManager::HookEvent(const char *name, IPluginFunction *pFunct
}
/* Cache the name for post hooks */
pHook->name = name;
pHook->name = sm_strdup(name);
/* Increase reference count */
pHook->refCount++;
/* Add hook structure to hook lists */
pHookList->push_back(pHook);
m_EventHooks.insert(name, pHook);
sm_trie_insert(m_EventHooks, name, pHook);
return EventHookErr_Okay;
}
@@ -228,7 +227,7 @@ EventHookError EventManager::HookEvent(const char *name, IPluginFunction *pFunct
/* Create pre hook forward if necessary */
if (!pHook->pPreHook)
{
pHook->pPreHook = forwardsys->CreateForwardEx(NULL, ET_Event, 3, GAMEEVENT_PARAMS);
pHook->pPreHook = g_Forwards.CreateForwardEx(NULL, ET_Event, 3, GAMEEVENT_PARAMS);
}
/* Add plugin function to forward list */
@@ -237,7 +236,7 @@ EventHookError EventManager::HookEvent(const char *name, IPluginFunction *pFunct
/* Create post hook forward if necessary */
if (!pHook->pPostHook)
{
pHook->pPostHook = forwardsys->CreateForwardEx(NULL, ET_Ignore, 3, GAMEEVENT_PARAMS);
pHook->pPostHook = g_Forwards.CreateForwardEx(NULL, ET_Ignore, 3, GAMEEVENT_PARAMS);
}
/* If postCopy is false, then we may want to set it to true */
@@ -262,7 +261,7 @@ EventHookError EventManager::UnhookEvent(const char *name, IPluginFunction *pFun
IChangeableForward **pEventForward;
/* If hook does not exist at all */
if (!m_EventHooks.retrieve(name, &pHook))
if (!sm_trie_retrieve(m_EventHooks, name, (void **)&pHook))
{
return EventHookErr_NotActive;
}
@@ -284,7 +283,7 @@ EventHookError EventManager::UnhookEvent(const char *name, IPluginFunction *pFun
/* If forward's list contains 0 functions now, free it */
if ((*pEventForward)->GetFunctionCount() == 0)
{
forwardsys->ReleaseForward(*pEventForward);
g_Forwards.ReleaseForward(*pEventForward);
*pEventForward = NULL;
}
@@ -294,7 +293,7 @@ EventHookError EventManager::UnhookEvent(const char *name, IPluginFunction *pFun
/* If reference count is now 0, free hook structure */
EventHookList *pHookList;
IPlugin *plugin = scripts->FindPluginByContext(pFunction->GetParentContext()->GetContext());
IPlugin *plugin = g_PluginSys.GetPluginByCtx(pFunction->GetParentContext()->GetContext());
/* Get plugin's event hook list */
if (!plugin->GetProperty("EventHooks", (void**)&pHookList))
@@ -312,7 +311,10 @@ EventHookError EventManager::UnhookEvent(const char *name, IPluginFunction *pFun
pHookList->remove(pHook);
/* Delete entry in trie */
m_EventHooks.remove(name);
sm_trie_delete(m_EventHooks, name);
/* Free the cached name */
delete pHook->name;
/* And finally free structure memory */
delete pHook;
@@ -388,7 +390,7 @@ bool EventManager::OnFireEvent(IGameEvent *pEvent, bool bDontBroadcast)
name = pEvent->GetName();
if (m_EventHooks.retrieve(name, &pHook))
if (sm_trie_retrieve(m_EventHooks, name, reinterpret_cast<void **>(&pHook)))
{
/* Push the event onto the event stack. The reference count is increased to make sure
* the structure is not garbage collected in between now and the post hook.
@@ -402,7 +404,7 @@ bool EventManager::OnFireEvent(IGameEvent *pEvent, bool bDontBroadcast)
{
EventInfo info(pEvent, NULL);
HandleSecurity sec(NULL, g_pCoreIdent);
Handle_t hndl = handlesys->CreateHandle(m_EventType, &info, NULL, g_pCoreIdent, NULL);
Handle_t hndl = g_HandleSys.CreateHandle(m_EventType, &info, NULL, g_pCoreIdent, NULL);
info.bDontBroadcast = bDontBroadcast;
@@ -415,7 +417,7 @@ bool EventManager::OnFireEvent(IGameEvent *pEvent, bool bDontBroadcast)
broadcast = info.bDontBroadcast;
handlesys->FreeHandle(hndl, &sec);
g_HandleSys.FreeHandle(hndl, &sec);
}
if (pHook->postCopy)
@@ -467,14 +469,14 @@ bool EventManager::OnFireEvent_Post(IGameEvent *pEvent, bool bDontBroadcast)
info.bDontBroadcast = bDontBroadcast;
info.pEvent = m_EventCopies.front();
info.pOwner = NULL;
hndl = handlesys->CreateHandle(m_EventType, &info, NULL, g_pCoreIdent, NULL);
hndl = g_HandleSys.CreateHandle(m_EventType, &info, NULL, g_pCoreIdent, NULL);
pForward->PushCell(hndl);
} else {
pForward->PushCell(BAD_HANDLE);
}
pForward->PushString(pHook->name.chars());
pForward->PushString(pHook->name);
pForward->PushCell(bDontBroadcast);
pForward->Execute(NULL);
@@ -482,7 +484,7 @@ bool EventManager::OnFireEvent_Post(IGameEvent *pEvent, bool bDontBroadcast)
{
/* Free handle */
HandleSecurity sec(NULL, g_pCoreIdent);
handlesys->FreeHandle(hndl, &sec);
g_HandleSys.FreeHandle(hndl, &sec);
/* Free event structure */
gameevents->FreeEvent(info.pEvent);
@@ -495,7 +497,8 @@ bool EventManager::OnFireEvent_Post(IGameEvent *pEvent, bool bDontBroadcast)
{
assert(pHook->pPostHook == NULL);
assert(pHook->pPreHook == NULL);
m_EventHooks.remove(pHook->name.chars());
sm_trie_delete(m_EventHooks, pHook->name);
delete pHook->name;
delete pHook;
}
}
+5 -13
View File
@@ -1,8 +1,8 @@
/**
* vim: set ts=4 sw=4 tw=99 noet :
* vim: set ts=4 :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2010 AlliedModders LLC. All rights reserved.
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
* =============================================================================
*
* This program is free software; you can redistribute it and/or modify it under
@@ -34,7 +34,7 @@
#include "sm_globals.h"
#include "sourcemm_api.h"
#include <sm_namehashset.h>
#include "sm_trie.h"
#include <sh_list.h>
#include <sh_stack.h>
#include <IHandleSys.h>
@@ -69,12 +69,7 @@ struct EventHook
IChangeableForward *pPostHook;
bool postCopy;
unsigned int refCount;
ke::AString name;
static inline bool matches(const char *name, const EventHook *hook)
{
return strcmp(name, hook->name.chars()) == 0;
}
char *name;
};
enum EventHookMode
@@ -110,9 +105,6 @@ public: // IPluginsListener
void OnPluginUnloaded(IPlugin *plugin);
public: // IGameEventListener2
void FireGameEvent(IGameEvent *pEvent);
#if SOURCE_ENGINE >= SE_LEFT4DEAD && SOURCE_ENGINE != SE_DOTA
int GetEventDebugID();
#endif
public:
/**
* Get the 'GameEvent' handle type ID.
@@ -132,7 +124,7 @@ private: // IGameEventManager2 hooks
bool OnFireEvent_Post(IGameEvent *pEvent, bool bDontBroadcast);
private:
HandleType_t m_EventType;
NameHashSet<EventHook *> m_EventHooks;
Trie *m_EventHooks;
CStack<EventInfo *> m_FreeEvents;
CStack<EventHook *> m_EventStack;
CStack<IGameEvent *> m_EventCopies;
@@ -2,7 +2,7 @@
* vim: set ts=4 sw=4 tw=99 noet :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2010 AlliedModders LLC. All rights reserved.
* Copyright (C) 2004-2009 AlliedModders LLC. All rights reserved.
* =============================================================================
*
* This program is free software; you can redistribute it and/or modify it under
@@ -31,11 +31,12 @@
#include <stdlib.h>
#include "ExtensionSys.h"
#include <ILibrarySys.h>
#include <ISourceMod.h>
#include "common_logic.h"
#include "PluginSys.h"
#include <am-utility.h>
#include "LibrarySys.h"
#include "ShareSys.h"
#include "Logger.h"
#include "sourcemm_api.h"
#include "sm_srvcmds.h"
#include "sm_stringutil.h"
CExtensionManager g_Extensions;
IdentityType_t g_ExtType;
@@ -49,7 +50,7 @@ void CExtension::Initialize(const char *filename, const char *path)
m_File.assign(filename);
m_Path.assign(path);
char real_name[PLATFORM_MAX_PATH];
libsys->GetFileFromPath(real_name, sizeof(real_name), m_Path.c_str());
g_LibSys.GetFileFromPath(real_name, sizeof(real_name), m_Path.c_str());
m_RealFile.assign(real_name);
}
@@ -59,6 +60,24 @@ CRemoteExtension::CRemoteExtension(IExtensionInterface *pAPI, const char *filena
m_pAPI = pAPI;
}
#if defined METAMOD_PLAPI_VERSION
#if SOURCE_ENGINE == SE_LEFT4DEAD
#define GAMEFIX "2.l4d"
#elif SOURCE_ENGINE == SE_LEFT4DEAD2
#define GAMEFIX "2.l4d2"
#elif SOURCE_ENGINE == SE_ORANGEBOX
#define GAMEFIX "2.ep2"
#elif SOURCE_ENGINE == SE_ORANGEBOXVALVE
#define GAMEFIX "2.ep2v"
#elif SOURCE_ENGINE == SE_DARKMESSIAH
#define GAMEFIX "2.darkm"
#else
#define GAMEFIX "2.ep1"
#endif //(SOURCE_ENGINE == SE_LEFT4DEAD) || (SOURCE_ENGINE == SE_LEFT4DEAD2)
#else //METAMOD_PLAPI_VERSION
#define GAMEFIX "1.ep1"
#endif //METAMOD_PLAPI_VERSION
CLocalExtension::CLocalExtension(const char *filename)
{
m_PlId = 0;
@@ -66,69 +85,29 @@ CLocalExtension::CLocalExtension(const char *filename)
char path[PLATFORM_MAX_PATH];
/* Special case for new bintools binary */
if (strcmp(filename, "bintools.ext") == 0)
{
goto normal;
}
/* Zeroth, see if there is an engine specific build in the new place. */
g_pSM->BuildPath(Path_SM,
g_SourceMod.BuildPath(Path_SM,
path,
PLATFORM_MAX_PATH,
"extensions/%s.%s." PLATFORM_LIB_EXT,
filename,
smcore.gamesuffix);
"extensions/%s." GAMEFIX "." PLATFORM_LIB_EXT,
filename);
if (libsys->IsPathFile(path))
if (g_LibSys.IsPathFile(path))
{
goto found;
}
/* COMPAT HACK: One-halfth, if ep2v, see if there is an engine specific build in the new place with old naming */
if (strcmp(smcore.gamesuffix, "2.tf2") == 0
|| strcmp(smcore.gamesuffix, "2.dods") == 0
|| strcmp(smcore.gamesuffix, "2.hl2dm") == 0
)
{
g_pSM->BuildPath(Path_SM,
path,
PLATFORM_MAX_PATH,
"extensions/%s.2.ep2v." PLATFORM_LIB_EXT,
filename);
if (libsys->IsPathFile(path))
{
goto found;
}
}
else if (strcmp(smcore.gamesuffix, "2.nd") == 0)
{
g_pSM->BuildPath(Path_SM,
path,
PLATFORM_MAX_PATH,
"extensions/%s.2.l4d2." PLATFORM_LIB_EXT,
filename);
if (libsys->IsPathFile(path))
{
goto found;
}
}
/* First see if there is an engine specific build! */
g_pSM->BuildPath(Path_SM,
g_SourceMod.BuildPath(Path_SM,
path,
PLATFORM_MAX_PATH,
"extensions/auto.%s/%s." PLATFORM_LIB_EXT,
filename,
smcore.gamesuffix);
"extensions/auto." GAMEFIX "/%s." PLATFORM_LIB_EXT,
filename);
/* Try the "normal" version */
if (!libsys->IsPathFile(path))
if (!g_LibSys.IsPathFile(path))
{
normal:
g_pSM->BuildPath(Path_SM,
g_SourceMod.BuildPath(Path_SM,
path,
PLATFORM_MAX_PATH,
"extensions/%s." PLATFORM_LIB_EXT,
@@ -158,7 +137,7 @@ bool CRemoteExtension::Load(char *error, size_t maxlength)
bool CLocalExtension::Load(char *error, size_t maxlength)
{
m_pLib = libsys->OpenLibrary(m_Path.c_str(), error, maxlength);
m_pLib = g_LibSys.OpenLibrary(m_Path.c_str(), error, maxlength);
if (m_pLib == NULL)
{
@@ -190,16 +169,8 @@ bool CLocalExtension::Load(char *error, size_t maxlength)
/* Load as MM:S */
if (m_pAPI->IsMetamodExtension())
{
bool ok;
m_PlId = smcore.LoadMMSPlugin(m_Path.c_str(), &ok, error, maxlength);
if (!m_PlId || !ok)
{
m_pLib->CloseLibrary();
m_pLib = NULL;
m_pAPI = NULL;
return false;
}
bool already;
m_PlId = g_pMMPlugins->Load(m_Path.c_str(), g_PLID, already, error, maxlength);
}
if (!CExtension::Load(error, maxlength))
@@ -208,7 +179,8 @@ bool CLocalExtension::Load(char *error, size_t maxlength)
{
if (m_PlId)
{
smcore.UnloadMMSPlugin(m_PlId);
char dummy[255];
g_pMMPlugins->Unload(m_PlId, true, dummy, sizeof(dummy));
m_PlId = 0;
}
}
@@ -229,7 +201,8 @@ void CLocalExtension::Unload()
{
if (m_pAPI != NULL && m_PlId)
{
smcore.UnloadMMSPlugin(m_PlId);
char temp_buffer[255];
g_pMMPlugins->Unload(m_PlId, true, temp_buffer, sizeof(temp_buffer));
m_PlId = 0;
}
@@ -292,7 +265,7 @@ bool CExtension::PerformAPICheck(char *error, size_t maxlength)
bool CExtension::Load(char *error, size_t maxlength)
{
CreateIdentity();
if (!m_pAPI->OnExtensionLoad(this, &g_ShareSys, error, maxlength, !smcore.IsMapLoading()))
if (!m_pAPI->OnExtensionLoad(this, &g_ShareSys, error, maxlength, !g_SourceMod.IsMapLoading()))
{
DestroyIdentity();
return false;
@@ -300,7 +273,7 @@ bool CExtension::Load(char *error, size_t maxlength)
else
{
/* Check if we're past load time */
if (!smcore.IsMapLoading())
if (!g_SourceMod.IsMapLoading())
{
m_pAPI->OnExtensionsAllLoaded();
}
@@ -343,7 +316,7 @@ void CExtension::MarkAllLoaded()
void CExtension::AddPlugin(CPlugin *pPlugin)
{
/* Unfortunately we have to do this :( */
if (m_Dependents.find(pPlugin) == m_Dependents.end())
if (m_Dependents.find(pPlugin) != m_Dependents.end())
{
m_Dependents.push_back(pPlugin);
}
@@ -364,11 +337,6 @@ const char *CExtension::GetFilename()
return m_RealFile.c_str();
}
const char *CExtension::GetPath() const
{
return m_Path.c_str();
}
IdentityToken_t *CExtension::GetIdentity()
{
return m_pIdentToken;
@@ -510,15 +478,14 @@ void CExtension::AddLibrary(const char *library)
void CExtensionManager::OnSourceModAllInitialized()
{
g_ExtType = g_ShareSys.CreateIdentType("EXTENSION");
pluginsys->AddPluginsListener(this);
rootmenu->AddRootConsoleCommand("exts", "Manage extensions", this);
g_PluginSys.AddPluginsListener(this);
g_RootMenu.AddRootConsoleCommand("exts", "Manage extensions", this);
g_ShareSys.AddInterface(NULL, this);
}
void CExtensionManager::OnSourceModShutdown()
{
rootmenu->RemoveRootConsoleCommand("exts", this);
pluginsys->RemovePluginsListener(this);
g_RootMenu.RemoveRootConsoleCommand("exts", this);
g_ShareSys.DestroyIdentType(g_ExtType);
}
@@ -536,11 +503,13 @@ void CExtensionManager::TryAutoload()
{
char path[PLATFORM_MAX_PATH];
g_pSM->BuildPath(Path_SM, path, sizeof(path), "extensions");
g_SourceMod.BuildPath(Path_SM, path, sizeof(path), "extensions");
ke::AutoPtr<IDirectory> pDir(libsys->OpenDirectory(path));
IDirectory *pDir = g_LibSys.OpenDirectory(path);
if (!pDir)
{
return;
}
const char *lfile;
size_t len;
@@ -567,7 +536,7 @@ void CExtensionManager::TryAutoload()
}
char file[PLATFORM_MAX_PATH];
len = smcore.Format(file, sizeof(file), "%s", lfile);
len = UTIL_Format(file, sizeof(file), "%s", lfile);
strcpy(&file[len - 9], ".ext");
LoadAutoExtension(file);
@@ -576,16 +545,16 @@ void CExtensionManager::TryAutoload()
}
}
IExtension *CExtensionManager::LoadAutoExtension(const char *path, bool bErrorOnMissing)
IExtension *CExtensionManager::LoadAutoExtension(const char *path)
{
/* Remove platform extension if it's there. Compat hack. */
const char *ext = libsys->GetFileExtension(path);
const char *ext = g_LibSys.GetFileExtension(path);
if (strcmp(ext, PLATFORM_LIB_EXT) == 0)
{
char path2[PLATFORM_MAX_PATH];
smcore.Format(path2, sizeof(path2), "%s", path);
UTIL_Format(path2, sizeof(path2), "%s", path);
path2[strlen(path) - strlen(PLATFORM_LIB_EXT) - 1] = '\0';
return LoadAutoExtension(path2, bErrorOnMissing);
return LoadAutoExtension(path2);
}
IExtension *pAlready;
@@ -604,11 +573,7 @@ IExtension *CExtensionManager::LoadAutoExtension(const char *path, bool bErrorOn
if (!p->Load(error, sizeof(error)) || !p->IsLoaded())
{
if (bErrorOnMissing || libsys->IsPathFile(p->GetPath()))
{
logger->LogError("[SM] Unable to load extension \"%s\": %s", path, error);
}
g_Logger.LogError("[SM] Unable to load extension \"%s\": %s", path, error);
p->SetError(error);
}
@@ -622,7 +587,7 @@ IExtension *CExtensionManager::FindExtensionByFile(const char *file)
/* Chomp off the path */
char lookup[PLATFORM_MAX_PATH];
libsys->GetFileFromPath(lookup, sizeof(lookup), file);
g_LibSys.GetFileFromPath(lookup, sizeof(lookup), file);
for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++)
{
@@ -671,11 +636,11 @@ IExtension *CExtensionManager::FindExtensionByName(const char *ext)
IExtension *CExtensionManager::LoadExtension(const char *file, char *error, size_t maxlength)
{
/* Remove platform extension if it's there. Compat hack. */
const char *ext = libsys->GetFileExtension(file);
const char *ext = g_LibSys.GetFileExtension(file);
if (strcmp(ext, PLATFORM_LIB_EXT) == 0)
{
char path2[PLATFORM_MAX_PATH];
smcore.Format(path2, sizeof(path2), "%s", file);
UTIL_Format(path2, sizeof(path2), "%s", file);
path2[strlen(file) - strlen(PLATFORM_LIB_EXT) - 1] = '\0';
return LoadExtension(path2, error, maxlength);
}
@@ -737,11 +702,11 @@ void CExtensionManager::AddInterface(IExtension *pOwner, SMInterface *pInterface
pExt->AddInterface(pInterface);
}
void CExtensionManager::BindChildPlugin(IExtension *pParent, SMPlugin *pPlugin)
void CExtensionManager::BindChildPlugin( IExtension *pParent, CPlugin *pPlugin )
{
CExtension *pExt = (CExtension *)pParent;
pExt->AddPlugin(static_cast<CPlugin *>(pPlugin));
pExt->AddPlugin(pPlugin);
}
void CExtensionManager::OnPluginDestroyed(IPlugin *plugin)
@@ -750,7 +715,7 @@ void CExtensionManager::OnPluginDestroyed(IPlugin *plugin)
for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++)
{
(*iter)->DropRefsTo(static_cast<CPlugin *>(plugin));
(*iter)->DropRefsTo((CPlugin *)plugin);
}
}
@@ -778,21 +743,18 @@ CExtension *CExtensionManager::FindByOrder(unsigned int num)
bool CExtensionManager::UnloadExtension(IExtension *_pExt)
{
if (!_pExt)
{
return false;
}
CExtension *pExt = (CExtension *)_pExt;
if (m_Libs.find(pExt) == m_Libs.end())
{
return false;
}
/* Tell it to unload */
if (pExt->IsLoaded())
pExt->GetAPI()->OnExtensionUnload();
// Remove us from internal lists. Note that because we do this, it's
// possible that our extension could be added back if another plugin
// tries to load during this process. If we ever find this to happen,
// we can just block plugin loading.
/* First remove us from internal lists */
g_ShareSys.RemoveInterfaces(_pExt);
m_Libs.remove(pExt);
@@ -806,7 +768,7 @@ bool CExtensionManager::UnloadExtension(IExtension *_pExt)
while (p_iter != pExt->m_Dependents.end())
{
/* We have to manually unlink ourselves here, since we're no longer being managed */
scripts->UnloadPlugin((*p_iter));
g_PluginSys.UnloadPlugin((*p_iter));
p_iter = pExt->m_Dependents.erase(p_iter);
}
@@ -815,7 +777,7 @@ bool CExtensionManager::UnloadExtension(IExtension *_pExt)
s_iter != pExt->m_Libraries.end();
s_iter++)
{
scripts->OnLibraryAction((*s_iter).c_str(), LibraryAction_Removed);
g_PluginSys.OnLibraryAction((*s_iter).c_str(), false, true);
}
/* Notify and/or unload all dependencies */
@@ -826,9 +788,13 @@ bool CExtensionManager::UnloadExtension(IExtension *_pExt)
{
pDep = (*c_iter);
if ((pAPI=pDep->GetAPI()) == NULL)
{
continue;
}
if (pDep == pExt)
{
continue;
}
/* Now, get its dependency list */
bool dropped = false;
List<IfaceInfo>::iterator i_iter = pDep->m_Deps.begin();
@@ -857,9 +823,13 @@ bool CExtensionManager::UnloadExtension(IExtension *_pExt)
while (i_iter != pDep->m_ChildDeps.end())
{
if ((*i_iter).owner == pExt)
{
i_iter = pDep->m_ChildDeps.erase(i_iter);
}
else
{
i_iter++;
}
}
}
@@ -878,10 +848,12 @@ bool CExtensionManager::UnloadExtension(IExtension *_pExt)
}
}
// Everything has been informed that we're unloading, so give the
// extension one last notification.
if (pExt->IsLoaded() && pExt->GetAPI()->GetExtensionVersion() >= 7)
pExt->GetAPI()->OnDependenciesDropped();
/* Tell it to unload */
if (pExt->IsLoaded())
{
IExtensionInterface *pAPI = pExt->GetAPI();
pAPI->OnExtensionUnload();
}
pExt->Unload();
delete pExt;
@@ -930,10 +902,10 @@ void CExtensionManager::AddDependency(IExtension *pSource, const char *file, boo
void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const CCommand &command)
{
int argcount = smcore.Argc(command);
int argcount = command.ArgC();
if (argcount >= 3)
{
const char *cmd = smcore.Arg(command, 2);
const char *cmd = command.Arg(2);
if (strcmp(cmd, "list") == 0)
{
List<CExtension *>::iterator iter;
@@ -943,17 +915,17 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const CCommand
{
case 1:
{
rootmenu->ConsolePrint("[SM] Displaying 1 extension:");
g_RootMenu.ConsolePrint("[SM] Displaying 1 extension:");
break;
}
case 0:
{
rootmenu->ConsolePrint("[SM] No extensions are loaded.");
g_RootMenu.ConsolePrint("[SM] No extensions are loaded.");
break;
}
default:
{
rootmenu->ConsolePrint("[SM] Displaying %d extensions:", m_Libs.size());
g_RootMenu.ConsolePrint("[SM] Displaying %d extensions:", m_Libs.size());
break;
}
}
@@ -965,7 +937,7 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const CCommand
char error[255];
if (!pExt->IsRunning(error, sizeof(error)))
{
rootmenu->ConsolePrint("[%02d] <FAILED> file \"%s\": %s", num, pExt->GetFilename(), error);
g_RootMenu.ConsolePrint("[%02d] <FAILED> file \"%s\": %s", num, pExt->GetFilename(), error);
}
else
{
@@ -973,10 +945,10 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const CCommand
const char *name = pAPI->GetExtensionName();
const char *version = pAPI->GetExtensionVerString();
const char *descr = pAPI->GetExtensionDescription();
rootmenu->ConsolePrint("[%02d] %s (%s): %s", num, name, version, descr);
g_RootMenu.ConsolePrint("[%02d] %s (%s): %s", num, name, version, descr);
}
} else {
rootmenu->ConsolePrint("[%02d] <FAILED> file \"%s\": %s", num, pExt->GetFilename(), pExt->m_Error.c_str());
g_RootMenu.ConsolePrint("[%02d] <FAILED> file \"%s\": %s", num, pExt->GetFilename(), pExt->m_Error.c_str());
}
}
return;
@@ -985,29 +957,29 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const CCommand
{
if (argcount < 4)
{
rootmenu->ConsolePrint("[SM] Usage: sm exts load <file>");
g_RootMenu.ConsolePrint("[SM] Usage: sm exts load <file>");
return;
}
const char *filename = smcore.Arg(command, 3);
const char *filename = command.Arg(3);
char path[PLATFORM_MAX_PATH];
char error[256];
smcore.Format(path, sizeof(path), "%s%s%s", filename, !strstr(filename, ".ext") ? ".ext" : "",
UTIL_Format(path, sizeof(path), "%s%s%s", filename, !strstr(filename, ".ext") ? ".ext" : "",
!strstr(filename, "." PLATFORM_LIB_EXT) ? "." PLATFORM_LIB_EXT : "");
if (FindExtensionByFile(path) != NULL)
{
rootmenu->ConsolePrint("[SM] Extension %s is already loaded.", path);
g_RootMenu.ConsolePrint("[SM] Extension %s is already loaded.", path);
return;
}
if (LoadExtension(path, error, sizeof(error)))
{
rootmenu->ConsolePrint("[SM] Loaded extension %s successfully.", path);
g_RootMenu.ConsolePrint("[SM] Loaded extension %s successfully.", path);
} else
{
rootmenu->ConsolePrint("[SM] Extension %s failed to load: %s", path, error);
g_RootMenu.ConsolePrint("[SM] Extension %s failed to load: %s", path, error);
}
return;
@@ -1016,27 +988,27 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const CCommand
{
if (argcount < 4)
{
rootmenu->ConsolePrint("[SM] Usage: sm exts info <#>");
g_RootMenu.ConsolePrint("[SM] Usage: sm info <#>");
return;
}
const char *sId = smcore.Arg(command, 3);
const char *sId = command.Arg(3);
unsigned int id = atoi(sId);
if (id <= 0)
{
rootmenu->ConsolePrint("[SM] Usage: sm exts info <#>");
g_RootMenu.ConsolePrint("[SM] Usage: sm info <#>");
return;
}
if (m_Libs.size() == 0)
{
rootmenu->ConsolePrint("[SM] No extensions are loaded.");
g_RootMenu.ConsolePrint("[SM] No extensions are loaded.");
return;
}
if (id > m_Libs.size())
{
rootmenu->ConsolePrint("[SM] No extension was found with id %d.", id);
g_RootMenu.ConsolePrint("[SM] No extension was found with id %d.", id);
return;
}
@@ -1054,44 +1026,44 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const CCommand
/* This should never happen */
if (!pExt)
{
rootmenu->ConsolePrint("[SM] No extension was found with id %d.", id);
g_RootMenu.ConsolePrint("[SM] No extension was found with id %d.", id);
return;
}
if (!pExt->IsLoaded())
{
rootmenu->ConsolePrint(" File: %s", pExt->GetFilename());
rootmenu->ConsolePrint(" Loaded: No (%s)", pExt->m_Error.c_str());
g_RootMenu.ConsolePrint(" File: %s", pExt->GetFilename());
g_RootMenu.ConsolePrint(" Loaded: No (%s)", pExt->m_Error.c_str());
}
else
{
char error[255];
if (!pExt->IsRunning(error, sizeof(error)))
{
rootmenu->ConsolePrint(" File: %s", pExt->GetFilename());
rootmenu->ConsolePrint(" Loaded: Yes");
rootmenu->ConsolePrint(" Running: No (%s)", error);
g_RootMenu.ConsolePrint(" File: %s", pExt->GetFilename());
g_RootMenu.ConsolePrint(" Loaded: Yes");
g_RootMenu.ConsolePrint(" Running: No (%s)", error);
}
else
{
IExtensionInterface *pAPI = pExt->GetAPI();
rootmenu->ConsolePrint(" File: %s", pExt->GetFilename());
rootmenu->ConsolePrint(" Loaded: Yes (version %s)", pAPI->GetExtensionVerString());
rootmenu->ConsolePrint(" Name: %s (%s)", pAPI->GetExtensionName(), pAPI->GetExtensionDescription());
rootmenu->ConsolePrint(" Author: %s (%s)", pAPI->GetExtensionAuthor(), pAPI->GetExtensionURL());
rootmenu->ConsolePrint(" Binary info: API version %d (compiled %s)", pAPI->GetExtensionVersion(), pAPI->GetExtensionDateString());
g_RootMenu.ConsolePrint(" File: %s", pExt->GetFilename());
g_RootMenu.ConsolePrint(" Loaded: Yes (version %s)", pAPI->GetExtensionVerString());
g_RootMenu.ConsolePrint(" Name: %s (%s)", pAPI->GetExtensionName(), pAPI->GetExtensionDescription());
g_RootMenu.ConsolePrint(" Author: %s (%s)", pAPI->GetExtensionAuthor(), pAPI->GetExtensionURL());
g_RootMenu.ConsolePrint(" Binary info: API version %d (compiled %s)", pAPI->GetExtensionVersion(), pAPI->GetExtensionDateString());
if (pExt->IsExternal())
{
rootmenu->ConsolePrint(" Method: Loaded by Metamod:Source, attached to SourceMod");
g_RootMenu.ConsolePrint(" Method: Loaded by Metamod:Source, attached to SourceMod");
}
else if (pAPI->IsMetamodExtension())
{
rootmenu->ConsolePrint(" Method: Loaded by SourceMod, attached to Metamod:Source");
g_RootMenu.ConsolePrint(" Method: Loaded by SourceMod, attached to Metamod:Source");
}
else
{
rootmenu->ConsolePrint(" Method: Loaded by SourceMod");
g_RootMenu.ConsolePrint(" Method: Loaded by SourceMod");
}
}
}
@@ -1101,33 +1073,33 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const CCommand
{
if (argcount < 4)
{
rootmenu->ConsolePrint("[SM] Usage: sm exts unload <#> [code]");
g_RootMenu.ConsolePrint("[SM] Usage: sm unload <#> [code]");
return;
}
const char *arg = smcore.Arg(command, 3);
const char *arg = command.Arg(3);
unsigned int num = atoi(arg);
CExtension *pExt = FindByOrder(num);
if (!pExt)
{
rootmenu->ConsolePrint("[SM] Extension number %d was not found.", num);
g_RootMenu.ConsolePrint("[SM] Extension number %d was not found.", num);
return;
}
if (argcount > 4 && pExt->unload_code)
{
const char *unload = smcore.Arg(command, 4);
const char *unload = command.Arg(4);
if (pExt->unload_code == (unsigned)atoi(unload))
{
char filename[PLATFORM_MAX_PATH];
snprintf(filename, PLATFORM_MAX_PATH, "%s", pExt->GetFilename());
UnloadExtension(pExt);
rootmenu->ConsolePrint("[SM] Extension %s is now unloaded.", filename);
g_RootMenu.ConsolePrint("[SM] Extension %s is now unloaded.", filename);
}
else
{
rootmenu->ConsolePrint("[SM] Please try again, the correct unload code is \"%d\"", pExt->unload_code);
g_RootMenu.ConsolePrint("[SM] Please try again, the correct unload code is \"%d\"", pExt->unload_code);
}
return;
}
@@ -1138,7 +1110,7 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const CCommand
char filename[PLATFORM_MAX_PATH];
snprintf(filename, PLATFORM_MAX_PATH, "%s", pExt->GetFilename());
UnloadExtension(pExt);
rootmenu->ConsolePrint("[SM] Extension %s is now unloaded.", filename);
g_RootMenu.ConsolePrint("[SM] Extension %s is now unloaded.", filename);
return;
}
else
@@ -1146,7 +1118,7 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const CCommand
List<CPlugin *> plugins;
if (pExt->m_ChildDeps.size())
{
rootmenu->ConsolePrint("[SM] Unloading %s will unload the following extensions: ", pExt->GetFilename());
g_RootMenu.ConsolePrint("[SM] Unloading %s will unload the following extensions: ", pExt->GetFilename());
List<CExtension *>::iterator iter;
CExtension *pOther;
/* Get list of all extensions */
@@ -1171,7 +1143,7 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const CCommand
/* Will our dependent care? */
if (!pExt->GetAPI()->QueryInterfaceDrop((*i_iter).iface))
{
rootmenu->ConsolePrint(" -> %s", pExt->GetFilename());
g_RootMenu.ConsolePrint(" -> %s", pExt->GetFilename());
/* Add to plugin unload list */
List<CPlugin *>::iterator p_iter;
for (p_iter=pOther->m_Dependents.begin();
@@ -1189,7 +1161,7 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const CCommand
}
if (pExt->m_Dependents.size())
{
rootmenu->ConsolePrint("[SM] Unloading %s will unload the following plugins: ", pExt->GetFilename());
g_RootMenu.ConsolePrint("[SM] Unloading %s will unload the following plugins: ", pExt->GetFilename());
List<CPlugin *>::iterator iter;
CPlugin *pPlugin;
for (iter = pExt->m_Dependents.begin(); iter != pExt->m_Dependents.end(); iter++)
@@ -1203,13 +1175,13 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const CCommand
for (iter = plugins.begin(); iter != plugins.end(); iter++)
{
pPlugin = (*iter);
rootmenu->ConsolePrint(" -> %s", pPlugin->GetFilename());
g_RootMenu.ConsolePrint(" -> %s", pPlugin->GetFilename());
}
}
srand(static_cast<int>(time(NULL)));
pExt->unload_code = (rand() % 877) + 123; //123 to 999
rootmenu->ConsolePrint("[SM] To verify unloading %s, please use the following: ", pExt->GetFilename());
rootmenu->ConsolePrint("[SM] sm exts unload %d %d", num, pExt->unload_code);
g_RootMenu.ConsolePrint("[SM] To verify unloading %s, please use the following: ", pExt->GetFilename());
g_RootMenu.ConsolePrint("[SM] sm exts unload %d %d", num, pExt->unload_code);
return;
}
@@ -1218,17 +1190,17 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const CCommand
{
if (argcount < 4)
{
rootmenu->ConsolePrint("[SM] Usage: sm exts reload <#>");
g_RootMenu.ConsolePrint("[SM] Usage: sm exts reload <#>");
return;
}
const char *arg = smcore.Arg(command, 3);
const char *arg = command.Arg(3);
unsigned int num = atoi(arg);
CExtension *pExt = FindByOrder(num);
if (!pExt)
{
rootmenu->ConsolePrint("[SM] Extension number %d was not found.", num);
g_RootMenu.ConsolePrint("[SM] Extension number %d was not found.", num);
return;
}
@@ -1241,18 +1213,18 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const CCommand
if (pExt->Reload(error, sizeof(error)))
{
rootmenu->ConsolePrint("[SM] Extension %s is now reloaded.", filename);
g_RootMenu.ConsolePrint("[SM] Extension %s is now reloaded.", filename);
}
else
{
rootmenu->ConsolePrint("[SM] Extension %s failed to reload: %s", filename, error);
g_RootMenu.ConsolePrint("[SM] Extension %s failed to reload: %s", filename, error);
}
return;
}
else
{
rootmenu->ConsolePrint("[SM] Extension %s is not loaded.", pExt->GetFilename());
g_RootMenu.ConsolePrint("[SM] Extension %s is not loaded.", pExt->GetFilename());
return;
}
@@ -1260,12 +1232,12 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const CCommand
}
}
rootmenu->ConsolePrint("SourceMod Extensions Menu:");
rootmenu->DrawGenericOption("info", "Extra extension information");
rootmenu->DrawGenericOption("list", "List extensions");
rootmenu->DrawGenericOption("load", "Load an extension");
rootmenu->DrawGenericOption("reload", "Reload an extension");
rootmenu->DrawGenericOption("unload", "Unload an extension");
g_RootMenu.ConsolePrint("SourceMod Extensions Menu:");
g_RootMenu.DrawGenericOption("info", "Extra extension information");
g_RootMenu.DrawGenericOption("list", "List extensions");
g_RootMenu.DrawGenericOption("load", "Load an extension");
g_RootMenu.DrawGenericOption("reload", "Reload an extension");
g_RootMenu.DrawGenericOption("unload", "Unload an extension");
}
CExtension *CExtensionManager::GetExtensionFromIdent(IdentityToken_t *ptr)
@@ -1290,7 +1262,7 @@ void CExtensionManager::AddLibrary(IExtension *pSource, const char *library)
{
CExtension *pExt = (CExtension *)pSource;
pExt->AddLibrary(library);
scripts->OnLibraryAction(library, LibraryAction_Added);
g_PluginSys.OnLibraryAction(library, false, false);
}
bool CExtensionManager::LibraryExists(const char *library)
@@ -1360,37 +1332,6 @@ void CExtensionManager::CallOnCoreMapStart(edict_t *pEdictList, int edictCount,
}
}
void CExtensionManager::CallOnCoreMapEnd()
{
IExtensionInterface *pAPI;
List<CExtension *>::iterator iter;
for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++)
{
if ((pAPI = (*iter)->GetAPI()) == NULL)
{
continue;
}
if (pAPI->GetExtensionVersion() > 7)
{
pAPI->OnCoreMapEnd();
}
}
}
const CVector<IExtension *> *CExtensionManager::ListExtensions()
{
CVector<IExtension *> *list = new CVector<IExtension *>();
for (List<CExtension *>::iterator iter = m_Libs.begin(); iter != m_Libs.end(); iter++)
list->push_back(*iter);
return list;
}
void CExtensionManager::FreeExtensionList(const CVector<IExtension *> *list)
{
delete const_cast<CVector<IExtension *> *>(list);
}
bool CLocalExtension::IsSameFile(const char *file)
{
/* Only care about the shortened name. */
@@ -36,13 +36,14 @@
#include <ILibrarySys.h>
#include <sh_list.h>
#include <sh_string.h>
#include "common_logic.h"
#include <sm_trie_tpl.h>
#include "sm_globals.h"
#include "ShareSys.h"
#include <ISmmAPI.h>
#include <IPluginSys.h>
#include <IRootConsoleMenu.h>
#include "PluginSys.h"
#include "NativeOwner.h"
#include "ShareSys.h"
class CPlayer;
using namespace SourceMod;
using namespace SourceHook;
@@ -65,7 +66,6 @@ public:
public: //IExtension
IExtensionInterface *GetAPI();
const char *GetFilename();
const char *GetPath() const;
IdentityToken_t *GetIdentity();
ITERATOR *FindFirstDependency(IExtension **pOwner, SMInterface **pInterface);
bool FindNextDependency(ITERATOR *iter, IExtension **pOwner, SMInterface **pInterface);
@@ -117,7 +117,7 @@ public:
bool IsExternal();
bool IsSameFile(const char *file);
private:
int m_PlId;
PluginId m_PlId;
ILibrary *m_pLib;
};
@@ -135,7 +135,7 @@ public:
};
class CExtensionManager :
public IExtensionSys,
public IExtensionManager,
public SMGlobalClass,
public IPluginsListener,
public IRootConsoleCommand
@@ -163,20 +163,17 @@ public: //IPluginsListener
public: //IRootConsoleCommand
void OnRootConsoleCommand(const char *cmdname, const CCommand &command);
public:
IExtension *LoadAutoExtension(const char *path, bool bErrorOnMissing=true);
IExtension *LoadAutoExtension(const char *path);
void BindDependency(IExtension *pOwner, IfaceInfo *pInfo);
void AddInterface(IExtension *pOwner, SMInterface *pInterface);
void BindChildPlugin(IExtension *pParent, SMPlugin *pPlugin);
void BindChildPlugin(IExtension *pParent, CPlugin *pPlugin);
void MarkAllLoaded();
void AddDependency(IExtension *pSource, const char *file, bool required, bool autoload);
void TryAutoload();
void AddLibrary(IExtension *pSource, const char *library);
bool LibraryExists(const char *library);
void CallOnCoreMapStart(edict_t *pEdictList, int edictCount, int clientMax);
void CallOnCoreMapEnd();
void AddRawDependency(IExtension *ext, IdentityToken_t *other, void *iface);
const CVector<IExtension *> *ListExtensions();
void FreeExtensionList(const CVector<IExtension *> *list);
public:
CExtension *GetExtensionFromIdent(IdentityToken_t *ptr);
void Shutdown();
@@ -33,8 +33,9 @@
#include <stdarg.h>
#include <string.h>
#include "ForwardSys.h"
#include "PluginSys.h"
#include "ShareSys.h"
#include "DebugReporter.h"
#include "common_logic.h"
CForwardManager g_Forwards;
@@ -62,8 +63,8 @@ CForwardManager::~CForwardManager()
void CForwardManager::OnSourceModAllInitialized()
{
scripts->AddPluginsListener(this);
sharesys->AddInterface(NULL, this);
g_PluginSys.AddPluginsListener(this);
g_ShareSys.AddInterface(NULL, this);
}
IForward *CForwardManager::CreateForward(const char *name, ExecType et, unsigned int num_params, const ParamType *types, ...)
@@ -78,7 +79,7 @@ IForward *CForwardManager::CreateForward(const char *name, ExecType et, unsigned
if (fwd)
{
scripts->AddFunctionsToForward(name, fwd);
g_PluginSys.AddFunctionsToForward(name, fwd);
m_managed.push_back(fwd);
}
@@ -192,7 +193,6 @@ void CForwardManager::ForwardFree(CForward *fwd)
m_FreeForwards.push(fwd);
m_managed.remove(fwd);
m_unmanaged.remove(fwd);
}
CForward *CForwardManager::ForwardMake()
@@ -210,23 +210,7 @@ CForward *CForwardManager::ForwardMake()
void CForwardManager::OnPluginPauseChange(IPlugin *plugin, bool paused)
{
if(paused)
return;
/* Attach any globally managed forwards */
List<CForward *>::iterator iter;
CForward *fwd;
for (iter=m_managed.begin(); iter!=m_managed.end(); iter++)
{
fwd = (*iter);
IPluginFunction *pFunc = plugin->GetBaseContext()->GetFunctionByName(fwd->GetForwardName());
// Only add functions, if they aren't registered yet!
if (pFunc && !fwd->IsFunctionRegistered(pFunc))
{
fwd->AddFunction(pFunc);
}
}
/* No longer used */
}
/*************************************
@@ -699,7 +683,7 @@ bool CForward::RemoveFunction(IPluginFunction *func)
lst = &m_paused;
}
for (iter=lst->begin(); iter!=lst->end(); iter++)
for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
{
if ((*iter) == func)
{
@@ -757,28 +741,6 @@ bool CForward::AddFunction(IPluginFunction *func)
return true;
}
bool CForward::IsFunctionRegistered(IPluginFunction *func)
{
FuncIter iter;
List<IPluginFunction *> *lst;
if (func->IsRunnable())
{
lst = &m_functions;
} else {
lst = &m_paused;
}
for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
{
if ((*iter) == func)
{
return true;
}
}
return false;
}
const char *CForward::GetForwardName()
{
return m_name;
+25 -3
View File
@@ -34,10 +34,10 @@
#include <IForwardSys.h>
#include <IPluginSys.h>
#include "common_logic.h"
#include "sm_globals.h"
#include <sh_list.h>
#include <sh_stack.h>
#include "ISourceMod.h"
#include "sourcemod.h"
using namespace SourceHook;
@@ -46,6 +46,29 @@ typedef List<IPluginFunction *>::iterator FuncIter;
/* :TODO: a global name max define for sourcepawn, should mirror compiler's sNAMEMAX */
#define FORWARDS_NAME_MAX 64
struct ByrefInfo
{
unsigned int cells;
cell_t *orig_addr;
int flags;
int sz_flags;
};
struct FwdParamInfo
{
cell_t val;
ByrefInfo byref;
ParamType pushedas;
};
class SourceMod::IForwardFilter
{
public:
virtual void Preprocess(IPluginFunction *fun, FwdParamInfo *params)
{
}
};
class FuncIteratorGuard
{
bool triggered;
@@ -118,7 +141,6 @@ public:
unsigned int num_params,
const ParamType *types,
va_list ap);
bool IsFunctionRegistered(IPluginFunction *func);
private:
void _Int_PushArray(cell_t *inarray, unsigned int cells, int flags);
void _Int_PushString(cell_t *inarray, unsigned int cells, int sz_flags, int cp_flags);
+300 -116
View File
@@ -1,8 +1,8 @@
/**
* vim: set ts=4 :
* vim: set ts=4 sw=4 tw=99 noet :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
* Copyright (C) 2004-2009 AlliedModders LLC. All rights reserved.
* =============================================================================
*
* This program is free software; you can redistribute it and/or modify it under
@@ -25,27 +25,31 @@
* this exception to all derivative works. AlliedModders LLC defines further
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
* or <http://www.sourcemod.net/license.php>.
*
* Version: $Id$
*/
#include <string.h>
#include <stdlib.h>
#include "GameConfigs.h"
//#include "sm_stringutil.h"
//#include "sourcemod.h"
//#include "sourcemm_api.h"
//#include "HalfLife2.h"
//#include "Logger.h"
//#include "ShareSys.h"
//#include "MemoryUtils.h"
//#include "LibrarySys.h"
//#include "HandleSys.h"
//#include "sm_crc32.h"
#include "sm_stringutil.h"
#include "sourcemod.h"
#include "sourcemm_api.h"
#include "HalfLife2.h"
#include "Logger.h"
#include "ShareSys.h"
#include "MemoryUtils.h"
#include "LibrarySys.h"
#include "HandleSys.h"
#include "sm_crc32.h"
//#if defined PLATFORM_LINUX
//#include <dlfcn.h>
//#endif
#if defined PLATFORM_LINUX
#include <dlfcn.h>
#endif
GameConfigManager g_GameConfigs;
IGameConfig *g_pGameConf = NULL;
static char g_Game[256];
static char g_GameDesc[256] = {'!', '\0'};
static char g_GameName[256] = {'$', '\0'};
#define PSTATE_NONE 0
#define PSTATE_GAMES 1
@@ -60,42 +64,76 @@
#define PSTATE_GAMEDEFS_CRC_BINARY 10
#define PSTATE_GAMEDEFS_CUSTOM 11
#define WIN 0
#define LIN 1
#if defined PLATFORM_WINDOWS
#define PLATFORM_NAME "windows"
#define PLATFORM_SERVER_BINARY "server.dll"
#elif defined PLATFORM_LINUX
#define PLATFORM_NAME "linux"
#define PLATFORM_SERVER_BINARY "server_i486.so"
#elif defined PLATFORM_APPLE
#define PLATFORM_NAME "undef"
#define PLATFORM_SERVER_BINARY "undef.dylib"
#endif
Offset *tempOffset;
Sig *tempSig;
struct TempSigInfo
{
void Reset()
{
library[0] = '\0';
sig[0] = '\0';
}
char sig[512];
char library[64];
} s_TempSig;
unsigned int s_ServerBinCRC;
bool s_ServerBinCRC_Ok = false;
bool /*CGameConfig::*/DoesGameMatch(const char *value)
static bool DoesGameMatch(const char *value)
{
if (strcmp(value, /*m_gdcG*/game) == 0)
#if defined PLATFORM_WINDOWS
if (strcasecmp(value, g_Game) == 0 ||
#else
if (strcmp(value, g_Game) == 0 ||
#endif
strcmp(value, g_GameDesc) == 0 ||
strcmp(value, g_GameName) == 0)
{
return true;
}
return false;
}
bool /*CGameConfig::*/DoesEngineMatch(const char *value)
static bool DoesEngineMatch(const char *value)
{
if (strcmp(value, /*m_gdcE*/engine) == 0)
#if SOURCE_ENGINE == SE_EPISODEONE
if (strcmp(value, "original") == 0)
#elif SOURCE_ENGINE == SE_DARKMESSIAH
if (strcmp(value, "darkmessiah") == 0)
#elif SOURCE_ENGINE == SE_ORANGEBOX
if (strcmp(value, "orangebox") == 0)
#elif SOURCE_ENGINE == SE_ORANGEBOXVALVE
if (strcmp(value, "orangebox_valve") == 0)
#elif SOURCE_ENGINE == SE_LEFT4DEAD
if (strcmp(value, "left4dead") == 0)
#elif SOURCE_ENGINE == SE_LEFT4DEAD2
if (strcmp(value, "left4dead2") == 0)
#else
#error "Unknown engine type"
#endif
{
return true;
}
return false;
}
CGameConfig::CGameConfig()//const char *file)//, const char *game, const char *engine)
CGameConfig::CGameConfig(const char *file)
{
// strncopy(m_File, file, sizeof(m_File));
// strncopy(m_gdcGame, game, sizeof(m_gdcGame));
// strncopy(m_gdcEngine, engine, sizeof(m_gdcEngine));
//m_pStrings = new BaseStringTable(512);
strncopy(m_File, file, sizeof(m_File));
m_pOffsets = sm_trie_create();
m_pProps = sm_trie_create();
m_pKeys = sm_trie_create();
m_pSigs = sm_trie_create();
m_pStrings = new BaseStringTable(512);
m_RefCount = 0;
m_CustomLevel = 0;
@@ -104,7 +142,11 @@ CGameConfig::CGameConfig()//const char *file)//, const char *game, const char *e
CGameConfig::~CGameConfig()
{
// delete m_pStrings;
sm_trie_destroy(m_pOffsets);
sm_trie_destroy(m_pProps);
sm_trie_destroy(m_pKeys);
sm_trie_destroy(m_pSigs);
delete m_pStrings;
}
SMCResult CGameConfig::ReadSMC_NewSection(const SMCStates *states, const char *name)
@@ -167,14 +209,11 @@ SMCResult CGameConfig::ReadSMC_NewSection(const SMCStates *states, const char *n
}
else if (strcmp(name, "CRC") == 0)
{
#if 0
m_ParseState = PSTATE_GAMEDEFS_CRC;
bShouldBeReadingDefault = false;
#endif
}
else
{
#if 0
ITextListener_SMC **pListen = g_GameConfigs.m_customHandlers.retrieve(name);
if (pListen != NULL)
@@ -185,7 +224,8 @@ SMCResult CGameConfig::ReadSMC_NewSection(const SMCStates *states, const char *n
m_CustomHandler->ReadSMC_ParseStart();
break;
}
#endif
m_IgnoreLevel++;
}
break;
}
@@ -193,19 +233,17 @@ SMCResult CGameConfig::ReadSMC_NewSection(const SMCStates *states, const char *n
{
m_Prop[0] = '\0';
m_Class[0] = '\0';
tempOffset = new Offset();
tempOffset->setName(name);
strncopy(m_offset, name, sizeof(m_offset));
m_ParseState = PSTATE_GAMEDEFS_OFFSETS_OFFSET;
break;
}
case PSTATE_GAMEDEFS_SIGNATURES:
{
tempSig = new Sig();
tempSig->setName(name);
strncopy(m_offset, name, sizeof(m_offset));
s_TempSig.Reset();
m_ParseState = PSTATE_GAMEDEFS_SIGNATURES_SIG;
break;
}
#if 0
case PSTATE_GAMEDEFS_CRC:
{
char error[255];
@@ -255,7 +293,6 @@ SMCResult CGameConfig::ReadSMC_NewSection(const SMCStates *states, const char *n
return m_CustomHandler->ReadSMC_NewSection(states, name);
break;
}
#endif
/* No sub-sections allowed:
case PSTATE_GAMEDEFS_OFFSETS_OFFSET:
case PSTATE_GAMEDEFS_KEYS:
@@ -288,17 +325,13 @@ SMCResult CGameConfig::ReadSMC_KeyValue(const SMCStates *states, const char *key
strncopy(m_Class, value, sizeof(m_Class));
} else if (strcmp(key, "prop") == 0) {
strncopy(m_Prop, value, sizeof(m_Prop));
} else /*if (strcmp(key, PLATFORM_NAME) == 0) */ {
} else if (strcmp(key, PLATFORM_NAME) == 0) {
int val = atoi(value);
// sm_trie_replace(m_pOffsets, m_offset, (void *)val);
if (strcmp(key, "windows") == 0) tempOffset->setWin(val);
else if (strcmp(key, "linux") == 0) tempOffset->setLin(val);
sm_trie_replace(m_pOffsets, m_offset, (void *)val);
}
} else if (m_ParseState == PSTATE_GAMEDEFS_KEYS) {
m_Keys[key] = value;
// printf("Inserting %s - %s\n", key, value);
// int id = m_pStrings->AddString(value);
// sm_trie_replace(m_pKeys, key, (void *)id);
int id = m_pStrings->AddString(value);
sm_trie_replace(m_pKeys, key, (void *)id);
} else if (m_ParseState == PSTATE_GAMEDEFS_SUPPORTED) {
if (strcmp(key, "game") == 0)
{
@@ -325,9 +358,12 @@ SMCResult CGameConfig::ReadSMC_KeyValue(const SMCStates *states, const char *key
}
}
} else if (m_ParseState == PSTATE_GAMEDEFS_SIGNATURES_SIG) {
if (strcmp(key, "windows") == 0) tempSig->setWin(value);
else if (strcmp(key, "linux") == 0) tempSig->setLin(value);
else if (strcmp(key, "library") == 0) tempSig->setLib(value);
if (strcmp(key, PLATFORM_NAME) == 0)
{
strncopy(s_TempSig.sig, value, sizeof(s_TempSig.sig));
} else if (strcmp(key, "library") == 0) {
strncopy(s_TempSig.library, value, sizeof(s_TempSig.library));
}
} else if (m_ParseState == PSTATE_GAMEDEFS_CRC_BINARY) {
if (strcmp(key, PLATFORM_NAME) == 0
&& s_ServerBinCRC_Ok
@@ -388,8 +424,6 @@ SMCResult CGameConfig::ReadSMC_LeavingSection(const SMCStates *states)
}
case PSTATE_GAMEDEFS_OFFSETS_OFFSET:
{
m_Offsets.push_back(*tempOffset);
#if 0
/* Parse the offset... */
if (m_Class[0] != '\0'
&& m_Prop[0] != '\0')
@@ -413,7 +447,6 @@ SMCResult CGameConfig::ReadSMC_LeavingSection(const SMCStates *states)
}
}
}
#endif
m_ParseState = PSTATE_GAMEDEFS_OFFSETS;
break;
}
@@ -442,8 +475,6 @@ SMCResult CGameConfig::ReadSMC_LeavingSection(const SMCStates *states)
}
case PSTATE_GAMEDEFS_SIGNATURES_SIG:
{
m_Sigs.push_back(*tempSig);
#if 0
if (s_TempSig.library[0] == '\0')
{
/* assume server */
@@ -473,7 +504,11 @@ SMCResult CGameConfig::ReadSMC_LeavingSection(const SMCStates *states)
void *handle = dlopen(info.dli_fname, RTLD_NOW);
if (handle)
{
#if (SOURCE_ENGINE == SE_ORANGEBOXVALVE) || (SOURCE_ENGINE == SE_LEFT4DEAD2)
final_addr = g_MemUtils.ResolveSymbol(handle, &s_TempSig.sig[1]);
#else
final_addr = dlsym(handle, &s_TempSig.sig[1]);
#endif
dlclose(handle);
} else {
g_Logger.LogError("[SM] Unable to load library \"%s\" (gameconf \"%s\")",
@@ -492,45 +527,18 @@ SMCResult CGameConfig::ReadSMC_LeavingSection(const SMCStates *states)
}
#endif
/* First, preprocess the signature */
char real_sig[511];
unsigned char real_sig[511];
size_t real_bytes;
size_t length;
real_bytes = 0;
length = strlen(s_TempSig.sig);
for (size_t i=0; i<length; i++)
{
if (real_bytes >= sizeof(real_sig))
{
break;
}
real_sig[real_bytes++] = s_TempSig.sig[i];
if (s_TempSig.sig[i] == '\\'
&& s_TempSig.sig[i+1] == 'x')
{
if (i + 3 >= length)
{
continue;
}
/* Get the hex part */
char s_byte[3];
int r_byte;
s_byte[0] = s_TempSig.sig[i+2];
s_byte[1] = s_TempSig.sig[i+3];
s_byte[2] = '\0';
/* Read it as an integer */
sscanf(s_byte, "%x", &r_byte);
/* Save the value */
real_sig[real_bytes-1] = r_byte;
/* Adjust index */
i += 3;
}
}
real_bytes = UTIL_DecodeHexString(real_sig, sizeof(real_sig), s_TempSig.sig);
if (real_bytes >= 1)
{
final_addr = g_MemUtils.FindPattern(addrInBase, real_sig, real_bytes);
final_addr = g_MemUtils.FindPattern(addrInBase, (char*)real_sig, real_bytes);
}
}
@@ -538,7 +546,6 @@ SMCResult CGameConfig::ReadSMC_LeavingSection(const SMCStates *states)
skip_find:
#endif
sm_trie_replace(m_pSigs, m_offset, final_addr);
#endif
m_ParseState = PSTATE_GAMEDEFS_SIGNATURES;
break;
@@ -663,7 +670,7 @@ public:
return SMCResult_Continue;
}
public:
list<char*> *fileList;
List<String> *fileList;
unsigned int state;
unsigned int ignoreLevel;
char cur_file[PLATFORM_MAX_PATH];
@@ -678,21 +685,26 @@ static MasterReader master_reader;
bool CGameConfig::Reparse(char *error, size_t maxlength)
{
/* Reset cached data */
// m_pStrings->Reset();
m_Offsets.clear();
m_Sigs.clear();
m_pStrings->Reset();
sm_trie_clear(m_pOffsets);
sm_trie_clear(m_pProps);
sm_trie_clear(m_pKeys);
char path[PLATFORM_MAX_PATH];
/* See if we can use the extended gamedata format. */
//TODO pass in path to gamedata somehow
// g_SourceMod.BuildPath(Path_SM, path, sizeof(path), "gamedata/%s/master.games.txt", m_File);
g_SourceMod.BuildPath(Path_SM, path, sizeof(path), "gamedata/%s/master.games.txt", m_File);
if (!g_LibSys.PathExists(path))
{
/* Nope, use the old mechanism. */
UTIL_Format(path, sizeof(path), "%s.txt", m_File);
return EnterFile(path, error, maxlength);
}
/* Otherwise, it's time to parse the master. */
SMCError err;
SMCStates state = {0, 0};
list<char*> fileList;
List<String> fileList;
master_reader.fileList = &fileList;
err = textparsers->ParseSMCFile(path, &master_reader, &state, error, maxlength);
@@ -700,26 +712,64 @@ bool CGameConfig::Reparse(char *error, size_t maxlength)
{
const char *msg = textparsers->GetSMCErrorString(err);
printf("[SM] Error parsing master gameconf file \"%s\":", path);
printf("[SM] Error %d on line %d, col %d: %s",
g_Logger.LogError("[SM] Error parsing master gameconf file \"%s\":", path);
g_Logger.LogError("[SM] Error %d on line %d, col %d: %s",
err,
state.line,
state.col,
msg ? msg : "Unknown error");
exit(PARSE_ERROR);
return false;
}
/* Go through each file we found and parse it. */
list<char*>::iterator iter;
List<String>::iterator iter;
for (iter = fileList.begin(); iter != fileList.end(); iter++)
{
UTIL_Format(path, sizeof(path), "%s/%s", m_File, *iter);
UTIL_Format(path, sizeof(path), "%s/%s", m_File, (*iter).c_str());
if (!EnterFile(path, error, maxlength))
{
return false;
}
}
/* Parse the contents of the 'custom' directory */
g_SourceMod.BuildPath(Path_SM, path, sizeof(path), "gamedata/%s/custom", m_File);
IDirectory *customDir = g_LibSys.OpenDirectory(path);
if (!customDir)
{
return true;
}
while (customDir->MoreFiles())
{
if (!customDir->IsEntryFile())
{
customDir->NextEntry();
continue;
}
const char *curFile = customDir->GetEntryName();
/* Only allow .txt files */
int len = strlen(curFile);
if (len > 4 && strcmp(&curFile[len-4], ".txt") != 0)
{
customDir->NextEntry();
continue;
}
UTIL_Format(path, sizeof(path), "%s/custom/%s", m_File, curFile);
if (!EnterFile(path, error, maxlength))
{
g_LibSys.CloseDirectory(customDir);
return false;
}
customDir->NextEntry();
}
g_LibSys.CloseDirectory(customDir);
return true;
}
@@ -728,20 +778,22 @@ bool CGameConfig::EnterFile(const char *file, char *error, size_t maxlength)
SMCError err;
SMCStates state = {0, 0};
g_SourceMod.BuildPath(Path_SM, m_CurFile, sizeof(m_CurFile), "gamedata/%s", file);
/* Initialize parse states */
m_IgnoreLevel = 0;
bShouldBeReadingDefault = true;
m_ParseState = PSTATE_NONE;
if ((err=textparsers->ParseSMCFile(file, this, &state, error, maxlength))
if ((err=textparsers->ParseSMCFile(m_CurFile, this, &state, error, maxlength))
!= SMCError_Okay)
{
const char *msg;
msg = textparsers->GetSMCErrorString(err);
printf("[SM] Error parsing gameconfig file \"%s\":\n", file);
printf("[SM] Error %d on line %d, col %d: %s\n",
g_Logger.LogError("[SM] Error parsing gameconfig file \"%s\":", m_CurFile);
g_Logger.LogError("[SM] Error %d on line %d, col %d: %s",
err,
state.line,
state.col,
@@ -755,13 +807,12 @@ bool CGameConfig::EnterFile(const char *file, char *error, size_t maxlength)
m_CustomLevel = 0;
}
exit(PARSE_ERROR);
return false;
}
return true;
}
#if 0
bool CGameConfig::GetOffset(const char *key, int *value)
{
void *obj;
@@ -813,16 +864,149 @@ unsigned int CGameConfig::DecRefCount()
m_RefCount--;
return m_RefCount;
}
#endif
const char *CGameConfig::GetKeyValue(const char *key)
GameConfigManager::GameConfigManager()
{
map<const char*,const char*,cmp_str>::iterator it = m_Keys.find(key);
if (it == m_Keys.end()) return NULL;
return it->second;
m_pLookup = sm_trie_create();
}
list<Offset> CGameConfig::GetOffsets() { return m_Offsets; }
list<Sig> CGameConfig::GetSigs() { return m_Sigs; }
GameConfigManager::~GameConfigManager()
{
sm_trie_destroy(m_pLookup);
}
void GameConfigManager::OnSourceModStartup(bool late)
{
LoadGameConfigFile("core.games", &g_pGameConf, NULL, 0);
strncopy(g_Game, g_SourceMod.GetGameFolderName(), sizeof(g_Game));
strncopy(g_GameDesc + 1, SERVER_CALL(GetGameDescription)(), sizeof(g_GameDesc) - 1);
KeyValues *pGameInfo = new KeyValues("GameInfo");
if (g_HL2.KVLoadFromFile(pGameInfo, basefilesystem, "gameinfo.txt"))
{
const char *str;
if ((str = pGameInfo->GetString("game", NULL)) != NULL)
{
strncopy(g_GameName + 1, str, sizeof(g_GameName) - 1);
}
}
pGameInfo->deleteThis();
}
void GameConfigManager::OnSourceModAllInitialized()
{
/* NOW initialize the game file */
CGameConfig *pGameConf = (CGameConfig *)g_pGameConf;
char error[255];
if (!pGameConf->Reparse(error, sizeof(error)))
{
/* :TODO: log */
}
g_ShareSys.AddInterface(NULL, this);
}
void GameConfigManager::OnSourceModAllShutdown()
{
CloseGameConfigFile(g_pGameConf);
}
bool GameConfigManager::LoadGameConfigFile(const char *file, IGameConfig **_pConfig, char *error, size_t maxlength)
{
#if 0
/* A crash was detected during last load - We block the gamedata loading so it hopefully won't happen again */
if (g_blockGameDataLoad)
{
UTIL_Format(error, maxlength, "GameData loaded blocked due to detected crash");
return false;
}
#endif
CGameConfig *pConfig;
if (sm_trie_retrieve(m_pLookup, file, (void **)&pConfig))
{
pConfig->IncRefCount();
*_pConfig = pConfig;
return true;
}
pConfig = new CGameConfig(file);
/* :HACKHACK: Don't parse the main config file */
bool retval = true;
if (_pConfig != &g_pGameConf)
{
retval = pConfig->Reparse(error, maxlength);
}
m_cfgs.push_back(pConfig);
sm_trie_insert(m_pLookup, file, pConfig);
pConfig->IncRefCount();
*_pConfig = pConfig;
return retval;
}
void GameConfigManager::CloseGameConfigFile(IGameConfig *cfg)
{
CGameConfig *pConfig = (CGameConfig *)cfg;
if (pConfig->DecRefCount() == 0)
{
sm_trie_delete(m_pLookup, pConfig->m_File);
delete pConfig;
}
}
extern HandleType_t g_GameConfigsType;
IGameConfig *GameConfigManager::ReadHandle(Handle_t hndl, IdentityToken_t *ident, HandleError *err)
{
HandleSecurity sec(ident, g_pCoreIdent);
IGameConfig *conf = NULL;
HandleError _err = g_HandleSys.ReadHandle(hndl, g_GameConfigsType, &sec, (void **)&conf);
if (err)
{
*err = _err;
}
return conf;
}
void GameConfigManager::AddUserConfigHook(const char *sectionname, ITextListener_SMC *listener)
{
m_customHandlers.insert(sectionname, listener);
}
void GameConfigManager::RemoveUserConfigHook(const char *sectionname, ITextListener_SMC *listener)
{
ITextListener_SMC **pListener = m_customHandlers.retrieve(sectionname);
if (pListener == NULL)
{
return;
}
if (*pListener != listener)
{
return;
}
m_customHandlers.remove(sectionname);
return;
}
void GameConfigManager::AcquireLock()
{
}
void GameConfigManager::ReleaseLock()
{
}
+20 -45
View File
@@ -1,5 +1,5 @@
/**
* vim: set ts=4 sw=4 tw=99 noet:
* vim: set ts=4 :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
@@ -32,12 +32,13 @@
#ifndef _INCLUDE_SOURCEMOD_CGAMECONFIGS_H_
#define _INCLUDE_SOURCEMOD_CGAMECONFIGS_H_
#include "common_logic.h"
#include <IGameConfigs.h>
#include <ITextParsers.h>
#include <am-refcounting.h>
#include <sm_stringhashmap.h>
#include <sm_namehashset.h>
#include <sh_list.h>
#include "sm_trie.h"
#include "sm_globals.h"
#include "sm_memtable.h"
#include "sm_trie_tpl.h"
using namespace SourceMod;
using namespace SourceHook;
@@ -46,18 +47,15 @@ class SendProp;
class CGameConfig :
public ITextListener_SMC,
public IGameConfig,
public ke::Refcounted<CGameConfig>
public IGameConfig
{
friend class GameConfigManager;
public:
CGameConfig(const char *file, const char *engine = NULL);
CGameConfig(const char *file);
~CGameConfig();
public:
bool Reparse(char *error, size_t maxlength);
bool EnterFile(const char *file, char *error, size_t maxlength);
void SetBaseEngine(const char *engine);
void SetParseEngine(const char *engine);
public: //ITextListener_SMC
SMCResult ReadSMC_NewSection(const SMCStates *states, const char *name);
SMCResult ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value);
@@ -67,19 +65,18 @@ public: //IGameConfig
bool GetOffset(const char *key, int *value);
SendProp *GetSendProp(const char *key);
bool GetMemSig(const char *key, void **addr);
bool GetAddress(const char *key, void **addr);
public: //NameHashSet
static inline bool matches(const char *key, const CGameConfig *value)
{
return strcmp(key, value->m_File) == 0;
}
public:
void IncRefCount();
unsigned int DecRefCount();
private:
BaseStringTable *m_pStrings;
char m_File[PLATFORM_MAX_PATH];
char m_CurFile[PLATFORM_MAX_PATH];
StringHashMap<int> m_Offsets;
StringHashMap<SendProp *> m_Props;
StringHashMap<ke::AString> m_Keys;
StringHashMap<void *> m_Sigs;
Trie *m_pOffsets;
Trie *m_pProps;
Trie *m_pKeys;
Trie *m_pSigs;
unsigned int m_RefCount;
/* Parse states */
int m_ParseState;
unsigned int m_IgnoreLevel;
@@ -92,31 +89,10 @@ private:
bool matched_game;
bool had_engine;
bool matched_engine;
bool matched_platform;
/* Custom Sections */
unsigned int m_CustomLevel;
ITextListener_SMC *m_CustomHandler;
/* Support for reading Addresses */
struct AddressConf
{
char signatureName[64];
int readCount;
int read[8];
AddressConf(char *sigName, unsigned sigLength, unsigned readCount, int *read);
AddressConf() {}
};
char m_Address[64];
char m_AddressSignature[64];
int m_AddressReadCount;
int m_AddressRead[8];
StringHashMap<AddressConf> m_Addresses;
const char *m_pEngine;
const char *m_pBaseEngine;
};
class GameConfigManager :
@@ -140,12 +116,11 @@ public: //SMGlobalClass
void OnSourceModStartup(bool late);
void OnSourceModAllInitialized();
void OnSourceModAllShutdown();
public:
void RemoveCachedConfig(CGameConfig *config);
private:
NameHashSet<CGameConfig *> m_Lookup;
List<CGameConfig *> m_cfgs;
Trie *m_pLookup;
public:
StringHashMap<ITextListener_SMC *> m_customHandlers;
KTrie<ITextListener_SMC *> m_customHandlers;
};
extern GameConfigManager g_GameConfigs;
+112 -473
View File
@@ -1,5 +1,5 @@
/**
* vim: set ts=4 sw=4 tw=99 noet :
* vim: set ts=4 :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
@@ -35,77 +35,61 @@
#include "UserMessages.h"
#include "PlayerManager.h"
#include "sm_stringutil.h"
#include <IGameConfigs.h>
#include "GameConfigs.h"
#include <compat_wrappers.h>
#include <Logger.h>
#include "LibrarySys.h"
#include "logic_bridge.h"
#include <tier0/mem.h>
#if SOURCE_ENGINE == SE_DOTA
#include <game/shared/protobuf/usermessages.pb.h>
#elif SOURCE_ENGINE == SE_CSGO
#include <cstrike15_usermessages.pb.h>
#endif
typedef ICommandLine *(*FakeGetCommandLine)();
#if defined _WIN32
#define TIER0_NAME "tier0.dll"
#define VSTDLIB_NAME "vstdlib.dll"
#elif defined __APPLE__
#define TIER0_NAME "libtier0.dylib"
#define VSTDLIB_NAME "libvstdlib.dylib"
#elif defined __linux__
#if SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_TF2 \
|| SOURCE_ENGINE == SE_SDK2013 || SOURCE_ENGINE == SE_LEFT4DEAD2 || SOURCE_ENGINE == SE_NUCLEARDAWN
#define TIER0_NAME "libtier0_srv.so"
#define VSTDLIB_NAME "libvstdlib_srv.so"
#elif SOURCE_ENGINE >= SE_LEFT4DEAD
#define TIER0_NAME "libtier0.so"
#define VSTDLIB_NAME "libvstdlib.so"
#else
#define TIER0_NAME "tier0_i486.so"
#define VSTDLIB_NAME "vstdlib_i486.so"
#endif
#endif
CHalfLife2 g_HL2;
ConVar *sv_lan = NULL;
static void *g_EntList = NULL;
static void **g_pEntInfoList = NULL;
static int entInfoOffset = -1;
static CEntInfo *EntInfoArray()
namespace SourceHook
{
if (g_EntList != NULL)
template<>
int HashFunction<datamap_t *>(datamap_t * const &k)
{
return (CEntInfo *)((intp)g_EntList + entInfoOffset);
return reinterpret_cast<int>(k);
}
else if (g_pEntInfoList)
template<>
int Compare<datamap_t *>(datamap_t * const &k1, datamap_t * const &k2)
{
return *(CEntInfo **)g_pEntInfoList;
return (k1-k2);
}
return NULL;
}
CHalfLife2::CHalfLife2()
{
m_Maps.init();
m_pGetCommandLine = NULL;
m_pClasses = sm_trie_create();
}
CHalfLife2::~CHalfLife2()
{
for (NameHashSet<DataTableInfo *>::iterator iter = m_Classes.iter(); !iter.empty(); iter.next())
delete *iter;
sm_trie_destroy(m_pClasses);
for (DataTableMap::iterator iter = m_Maps.iter(); !iter.empty(); iter.next())
delete iter->value;
List<DataTableInfo *>::iterator iter;
DataTableInfo *pInfo;
for (iter=m_Tables.begin(); iter!=m_Tables.end(); iter++)
{
pInfo = (*iter);
delete pInfo;
}
m_Tables.clear();
THash<datamap_t *, DataMapTrie>::iterator h_iter;
for (h_iter=m_Maps.begin(); h_iter!=m_Maps.end(); h_iter++)
{
if (h_iter->val.trie)
{
sm_trie_destroy(h_iter->val.trie);
h_iter->val.trie = NULL;
}
}
m_Maps.clear();
}
#if SOURCE_ENGINE != SE_DARKMESSIAH
@@ -142,141 +126,52 @@ void CHalfLife2::OnSourceModAllInitialized()
m_HinTextMsg = g_UserMsgs.GetMessageIndex("HintText");
m_SayTextMsg = g_UserMsgs.GetMessageIndex("SayText");
m_VGUIMenu = g_UserMsgs.GetMessageIndex("VGUIMenu");
sharesys->AddInterface(NULL, this);
g_ShareSys.AddInterface(NULL, this);
}
void CHalfLife2::OnSourceModAllInitialized_Post()
{
InitLogicalEntData();
InitCommandLine();
}
void CHalfLife2::InitLogicalEntData()
{
#if SOURCE_ENGINE == SE_TF2 \
|| SOURCE_ENGINE == SE_DODS \
|| SOURCE_ENGINE == SE_HL2DM \
|| SOURCE_ENGINE == SE_CSS \
|| SOURCE_ENGINE == SE_SDK2013
if (g_SMAPI->GetServerFactory(false)("VSERVERTOOLS003", nullptr))
{
g_EntList = servertools->GetEntityList();
}
#endif
char *addr = NULL;
#ifdef PLATFORM_WINDOWS
int offset;
/*
* gEntList and/or g_pEntityList
*
* First try to lookup pointer directly for platforms with symbols.
* If symbols aren't present (Windows or stripped Linux/Mac),
* attempt find via LevelShutdown + offset
*/
if (!g_EntList)
/* gEntList and/or g_pEntityList */
if (!g_pGameConf->GetMemSig("LevelShutdown", (void **)&addr))
{
if (g_pGameConf->GetMemSig("gEntList", (void **) &addr))
{
#if !defined PLATFORM_WINDOWS
if (!addr)
{
// Key exists so notify if lookup fails, but try other method.
logger->LogError("Failed lookup of gEntList directly - Reverting to lookup via LevelShutdown");
}
else
{
#endif
g_EntList = reinterpret_cast<void *>(addr);
#if !defined PLATFORM_WINDOWS
}
#endif
}
}
if (!g_EntList)
{
if (g_pGameConf->GetMemSig("LevelShutdown", (void **) &addr) && addr)
{
int offset;
if (!g_pGameConf->GetOffset("gEntList", &offset))
{
logger->LogError("Logical Entities not supported by this mod (gEntList) - Reverting to networkable entities only");
return;
}
g_EntList = *reinterpret_cast<void **>(addr + offset);
}
}
// If we have g_EntList from either of the above methods, make sure we can get the offset from it to EntInfo as well
if (g_EntList && !g_pGameConf->GetOffset("EntInfo", &entInfoOffset))
{
logger->LogError("Logical Entities not supported by this mod (EntInfo) - Reverting to networkable entities only");
g_EntList = NULL;
g_Logger.LogError("Logical Entities not supported by this mod (LevelShutdown) - Reverting to networkable entities only");
return;
}
// If we don't have g_EntList or have it but don't know where EntInfo is on it, use fallback.
if (!g_EntList || entInfoOffset == -1)
if (!addr)
{
g_pGameConf->GetAddress("EntInfosPtr", (void **)&g_pEntInfoList);
}
if (!g_EntList && !g_pEntInfoList)
{
logger->LogError("Failed lookup of gEntList - Reverting to networkable entities only");
g_Logger.LogError("Failed lookup of LevelShutdown - Reverting to networkable entities only");
return;
}
}
void CHalfLife2::InitCommandLine()
{
char error[256];
#if SOURCE_ENGINE != SE_DARKMESSIAH
if (!is_original_engine)
if (!g_pGameConf->GetOffset("gEntList", &offset))
{
ke::AutoPtr<ILibrary> lib(g_LibSys.OpenLibrary(TIER0_NAME, error, sizeof(error)));
if (lib == NULL)
{
logger->LogError("Could not load %s: %s", TIER0_NAME, error);
return;
}
m_pGetCommandLine = lib->GetSymbolAddress("CommandLine_Tier0");
/* '_Tier0' dropped on Alien Swarm version */
if (m_pGetCommandLine == NULL)
{
m_pGetCommandLine = lib->GetSymbolAddress("CommandLine");
}
g_Logger.LogError("Logical Entities not supported by this mod (gEntList) - Reverting to networkable entities only");
return;
}
else
g_EntList = *reinterpret_cast<void **>(addr + offset);
#elif defined PLATFORM_LINUX
/* gEntList and/or g_pEntityList */
if (!g_pGameConf->GetMemSig("gEntList", (void **)&addr))
{
g_Logger.LogError("Logical Entities not supported by this mod (gEntList) - Reverting to networkable entities only");
return;
}
if (!addr)
{
g_Logger.LogError("Failed lookup of gEntList - Reverting to networkable entities only");
return;
}
g_EntList = reinterpret_cast<void *>(addr);
#endif
if (!g_pGameConf->GetOffset("EntInfo", &entInfoOffset))
{
ke::AutoPtr<ILibrary> lib(g_LibSys.OpenLibrary(VSTDLIB_NAME, error, sizeof(error)));
if (lib == NULL)
{
logger->LogError("Could not load %s: %s", VSTDLIB_NAME, error);
return;
}
m_pGetCommandLine = lib->GetSymbolAddress("CommandLine");
g_Logger.LogError("Logical Entities not supported by this mod (EntInfo) - Reverting to networkable entities only");
return;
}
if (m_pGetCommandLine == NULL)
{
logger->LogError("Could not locate any command line functionality");
}
}
ICommandLine *CHalfLife2::GetValveCommandLine()
{
if (!m_pGetCommandLine)
return NULL;
return ((FakeGetCommandLine)((FakeGetCommandLine *)m_pGetCommandLine))();
}
#if !defined METAMOD_PLAPI_VERSION || PLAPI_VERSION < 11
@@ -289,11 +184,7 @@ bool CHalfLife2::IsOriginalEngine()
#if SOURCE_ENGINE != SE_DARKMESSIAH
IChangeInfoAccessor *CBaseEdict::GetChangeAccessor()
{
#if SOURCE_ENGINE == SE_DOTA
return engine->GetChangeAccessor( IndexOfEdict((const edict_t *)this) );
#else
return engine->GetChangeAccessor( (const edict_t *)this );
#endif
}
#endif
@@ -332,11 +223,11 @@ bool UTIL_FindInSendTable(SendTable *pTable,
return false;
}
bool UTIL_FindDataMapInfo(datamap_t *pMap, const char *name, sm_datatable_info_t *pDataTable)
typedescription_t *UTIL_FindInDataMap(datamap_t *pMap, const char *name)
{
while (pMap)
{
for (int i = 0; i < pMap->dataNumFields; ++i)
for (int i=0; i<pMap->dataNumFields; i++)
{
if (pMap->dataDesc[i].fieldName == NULL)
{
@@ -344,23 +235,21 @@ bool UTIL_FindDataMapInfo(datamap_t *pMap, const char *name, sm_datatable_info_t
}
if (strcmp(name, pMap->dataDesc[i].fieldName) == 0)
{
pDataTable->prop = &(pMap->dataDesc[i]);
pDataTable->actual_offset = GetTypeDescOffs(pDataTable->prop);
return true;
return &(pMap->dataDesc[i]);
}
if (pMap->dataDesc[i].td == NULL || !UTIL_FindDataMapInfo(pMap->dataDesc[i].td, name, pDataTable))
if (pMap->dataDesc[i].td)
{
continue;
typedescription_t *_td;
if ((_td=UTIL_FindInDataMap(pMap->dataDesc[i].td, name)) != NULL)
{
return _td;
}
}
pDataTable->actual_offset += GetTypeDescOffs(&(pMap->dataDesc[i]));
return true;
}
pMap = pMap->baseMap;
}
return false;
return NULL;
}
ServerClass *CHalfLife2::FindServerClass(const char *classname)
@@ -368,7 +257,9 @@ ServerClass *CHalfLife2::FindServerClass(const char *classname)
DataTableInfo *pInfo = _FindServerClass(classname);
if (!pInfo)
{
return NULL;
}
return pInfo->sc;
}
@@ -376,21 +267,26 @@ ServerClass *CHalfLife2::FindServerClass(const char *classname)
DataTableInfo *CHalfLife2::_FindServerClass(const char *classname)
{
DataTableInfo *pInfo = NULL;
if (!m_Classes.retrieve(classname, &pInfo))
if (!sm_trie_retrieve(m_pClasses, classname, (void **)&pInfo))
{
ServerClass *sc = gamedll->GetAllServerClasses();
while (sc)
{
if (strcmp(classname, sc->GetName()) == 0)
{
pInfo = new DataTableInfo(sc);
m_Classes.insert(classname, pInfo);
pInfo = new DataTableInfo;
pInfo->sc = sc;
sm_trie_insert(m_pClasses, classname, pInfo);
m_Tables.push_back(pInfo);
break;
}
sc = sc->m_pNext;
}
if (!pInfo)
{
return NULL;
}
}
return pInfo;
@@ -399,13 +295,14 @@ DataTableInfo *CHalfLife2::_FindServerClass(const char *classname)
bool CHalfLife2::FindSendPropInfo(const char *classname, const char *offset, sm_sendprop_info_t *info)
{
DataTableInfo *pInfo;
sm_sendprop_info_t *prop;
if ((pInfo = _FindServerClass(classname)) == NULL)
{
return false;
}
if (!pInfo->lookup.retrieve(offset, info))
if ((prop = pInfo->lookup.retrieve(offset)) == NULL)
{
sm_sendprop_info_t temp_info;
@@ -417,6 +314,10 @@ bool CHalfLife2::FindSendPropInfo(const char *classname, const char *offset, sm_
pInfo->lookup.insert(offset, temp_info);
*info = temp_info;
}
else
{
*info = *prop;
}
return true;
}
@@ -435,32 +336,22 @@ SendProp *CHalfLife2::FindInSendTable(const char *classname, const char *offset)
typedescription_t *CHalfLife2::FindInDataMap(datamap_t *pMap, const char *offset)
{
sm_datatable_info_t dt_info;
if (!(this->FindDataMapInfo(pMap, offset, &dt_info)))
typedescription_t *td = NULL;
DataMapTrie &val = m_Maps[pMap];
if (!val.trie)
{
return NULL;
val.trie = sm_trie_create();
}
return dt_info.prop;
}
bool CHalfLife2::FindDataMapInfo(datamap_t *pMap, const char *offset, sm_datatable_info_t *pDataTable)
{
DataTableMap::Insert i = m_Maps.findForAdd(pMap);
if (!i.found())
m_Maps.add(i, pMap, new DataMapCache());
DataMapCache *cache = i->value;
if (!cache->retrieve(offset, pDataTable))
if (!sm_trie_retrieve(val.trie, offset, (void **)&td))
{
if (!UTIL_FindDataMapInfo(pMap, offset, pDataTable))
return false;
cache->insert(offset, *pDataTable);
if ((td = UTIL_FindInDataMap(pMap, offset)) != NULL)
{
sm_trie_insert(val.trie, offset, td);
}
}
return true;
return td;
}
void CHalfLife2::SetEdictStateChanged(edict_t *pEdict, unsigned short offset)
@@ -468,11 +359,13 @@ void CHalfLife2::SetEdictStateChanged(edict_t *pEdict, unsigned short offset)
#if SOURCE_ENGINE != SE_DARKMESSIAH
if (g_pSharedChangeInfo != NULL)
{
#if SOURCE_ENGINE != SE_LEFT4DEAD2
if (offset)
{
pEdict->StateChanged(offset);
}
else
#endif
{
pEdict->StateChanged();
}
@@ -486,9 +379,7 @@ void CHalfLife2::SetEdictStateChanged(edict_t *pEdict, unsigned short offset)
bool CHalfLife2::TextMsg(int client, int dest, const char *msg)
{
#ifndef USE_PROTOBUF_USERMESSAGES
bf_write *pBitBuf = NULL;
#endif
cell_t players[] = {client};
if (dest == HUD_PRINTTALK)
@@ -501,28 +392,7 @@ bool CHalfLife2::TextMsg(int client, int dest, const char *msg)
char buffer[192];
UTIL_Format(buffer, sizeof(buffer), "%s\1\n", msg);
#if SOURCE_ENGINE == SE_DOTA
CUserMsg_SayText *pMsg;
if ((pMsg = (CUserMsg_SayText *)g_UserMsgs.StartProtobufMessage(m_SayTextMsg, players, 1, USERMSG_RELIABLE)) == NULL)
{
return false;
}
pMsg->set_client(0);
pMsg->set_text(buffer);
pMsg->set_chat(false);
#elif SOURCE_ENGINE == SE_CSGO
CCSUsrMsg_SayText *pMsg;
if ((pMsg = (CCSUsrMsg_SayText *)g_UserMsgs.StartProtobufMessage(m_SayTextMsg, players, 1, USERMSG_RELIABLE)) == NULL)
{
return false;
}
pMsg->set_ent_idx(0);
pMsg->set_text(buffer);
pMsg->set_chat(false);
#else
if ((pBitBuf = g_UserMsgs.StartBitBufMessage(m_SayTextMsg, players, 1, USERMSG_RELIABLE)) == NULL)
if ((pBitBuf = g_UserMsgs.StartMessage(m_SayTextMsg, players, 1, USERMSG_RELIABLE)) == NULL)
{
return false;
}
@@ -530,7 +400,6 @@ bool CHalfLife2::TextMsg(int client, int dest, const char *msg)
pBitBuf->WriteByte(0);
pBitBuf->WriteString(buffer);
pBitBuf->WriteByte(1);
#endif
g_UserMsgs.EndMessage();
@@ -538,38 +407,13 @@ bool CHalfLife2::TextMsg(int client, int dest, const char *msg)
}
}
#if SOURCE_ENGINE == SE_DOTA
CUserMsg_TextMsg *pMsg;
if ((pMsg = (CUserMsg_TextMsg *)g_UserMsgs.StartProtobufMessage(m_MsgTextMsg, players, 1, USERMSG_RELIABLE)) == NULL)
{
return false;
}
pMsg->set_dest(dest);
pMsg->add_param(msg);
#elif SOURCE_ENGINE == SE_CSGO
CCSUsrMsg_TextMsg *pMsg;
if ((pMsg = (CCSUsrMsg_TextMsg *)g_UserMsgs.StartProtobufMessage(m_MsgTextMsg, players, 1, USERMSG_RELIABLE)) == NULL)
{
return false;
}
// Client tries to read all 5 'params' and will crash if less
pMsg->set_msg_dst(dest);
pMsg->add_params(msg);
pMsg->add_params("");
pMsg->add_params("");
pMsg->add_params("");
pMsg->add_params("");
#else
if ((pBitBuf = g_UserMsgs.StartBitBufMessage(m_MsgTextMsg, players, 1, USERMSG_RELIABLE)) == NULL)
if ((pBitBuf = g_UserMsgs.StartMessage(m_MsgTextMsg, players, 1, USERMSG_RELIABLE)) == NULL)
{
return false;
}
pBitBuf->WriteByte(dest);
pBitBuf->WriteString(msg);
#endif
g_UserMsgs.EndMessage();
@@ -578,28 +422,10 @@ bool CHalfLife2::TextMsg(int client, int dest, const char *msg)
bool CHalfLife2::HintTextMsg(int client, const char *msg)
{
bf_write *pBitBuf = NULL;
cell_t players[] = {client};
#if SOURCE_ENGINE == SE_DOTA
CUserMsg_HintText *pMsg;
if ((pMsg = (CUserMsg_HintText *)g_UserMsgs.StartProtobufMessage(m_HinTextMsg, players, 1, USERMSG_RELIABLE)) == NULL)
{
return false;
}
pMsg->set_message(msg);
#elif SOURCE_ENGINE == SE_CSGO
CCSUsrMsg_HintText *pMsg;
if ((pMsg = (CCSUsrMsg_HintText *)g_UserMsgs.StartProtobufMessage(m_HinTextMsg, players, 1, USERMSG_RELIABLE)) == NULL)
{
return false;
}
pMsg->set_text(msg);
#else
bf_write *pBitBuf = NULL;
if ((pBitBuf = g_UserMsgs.StartBitBufMessage(m_HinTextMsg, players, 1, USERMSG_RELIABLE)) == NULL)
if ((pBitBuf = g_UserMsgs.StartMessage(m_HinTextMsg, players, 1, USERMSG_RELIABLE)) == NULL)
{
return false;
}
@@ -610,7 +436,6 @@ bool CHalfLife2::HintTextMsg(int client, const char *msg)
pBitBuf->WriteByte(1);
}
pBitBuf->WriteString(msg);
#endif
g_UserMsgs.EndMessage();
return true;
@@ -618,26 +443,9 @@ bool CHalfLife2::HintTextMsg(int client, const char *msg)
bool CHalfLife2::HintTextMsg(cell_t *players, int count, const char *msg)
{
#if SOURCE_ENGINE == SE_DOTA
CUserMsg_HintText *pMsg;
if ((pMsg = (CUserMsg_HintText *)g_UserMsgs.StartProtobufMessage(m_HinTextMsg, players, count, USERMSG_RELIABLE)) == NULL)
{
return false;
}
pMsg->set_message(msg);
#elif SOURCE_ENGINE == SE_CSGO
CCSUsrMsg_HintText *pMsg;
if ((pMsg = (CCSUsrMsg_HintText *)g_UserMsgs.StartProtobufMessage(m_HinTextMsg, players, count, USERMSG_RELIABLE)) == NULL)
{
return false;
}
pMsg->set_text(msg);
#else
bf_write *pBitBuf = NULL;
if ((pBitBuf = g_UserMsgs.StartBitBufMessage(m_HinTextMsg, players, count, USERMSG_RELIABLE)) == NULL)
if ((pBitBuf = g_UserMsgs.StartMessage(m_HinTextMsg, players, count, USERMSG_RELIABLE)) == NULL)
{
return false;
}
@@ -648,8 +456,6 @@ bool CHalfLife2::HintTextMsg(cell_t *players, int count, const char *msg)
pBitBuf->WriteByte(1);
}
pBitBuf->WriteString(msg);
#endif
g_UserMsgs.EndMessage();
return true;
@@ -657,29 +463,15 @@ bool CHalfLife2::HintTextMsg(cell_t *players, int count, const char *msg)
bool CHalfLife2::ShowVGUIMenu(int client, const char *name, KeyValues *data, bool show)
{
bf_write *pBitBuf = NULL;
KeyValues *SubKey = NULL;
int count = 0;
cell_t players[] = {client};
#if SOURCE_ENGINE == SE_DOTA
CUserMsg_VGUIMenu *pMsg;
if ((pMsg = (CUserMsg_VGUIMenu *)g_UserMsgs.StartProtobufMessage(m_VGUIMenu, players, 1, USERMSG_RELIABLE)) == NULL)
if ((pBitBuf = g_UserMsgs.StartMessage(m_VGUIMenu, players, 1, USERMSG_RELIABLE)) == NULL)
{
return false;
}
#elif SOURCE_ENGINE == SE_CSGO
CCSUsrMsg_VGUIMenu *pMsg;
if ((pMsg = (CCSUsrMsg_VGUIMenu *)g_UserMsgs.StartProtobufMessage(m_VGUIMenu, players, 1, USERMSG_RELIABLE)) == NULL)
{
return false;
}
#else
bf_write *pBitBuf = NULL;
if ((pBitBuf = g_UserMsgs.StartBitBufMessage(m_VGUIMenu, players, 1, USERMSG_RELIABLE)) == NULL)
{
return false;
}
#endif
if (data)
{
@@ -692,29 +484,6 @@ bool CHalfLife2::ShowVGUIMenu(int client, const char *name, KeyValues *data, boo
SubKey = data->GetFirstSubKey();
}
#if SOURCE_ENGINE == SE_DOTA
pMsg->set_name(name);
pMsg->set_show(show);
while (SubKey)
{
CUserMsg_VGUIMenu_Keys *key = pMsg->add_keys();
key->set_name(SubKey->GetName());
key->set_value(SubKey->GetString());
SubKey = SubKey->GetNextKey();
}
#elif SOURCE_ENGINE == SE_CSGO
pMsg->set_name(name);
pMsg->set_show(show);
while (SubKey)
{
CCSUsrMsg_VGUIMenu_Subkey *key = pMsg->add_subkeys();
key->set_name(SubKey->GetName());
key->set_str(SubKey->GetString());
SubKey = SubKey->GetNextKey();
}
#else
pBitBuf->WriteString(name);
pBitBuf->WriteByte((show) ? 1 : 0);
pBitBuf->WriteByte(count);
@@ -724,8 +493,6 @@ bool CHalfLife2::ShowVGUIMenu(int client, const char *name, KeyValues *data, boo
pBitBuf->WriteString(SubKey->GetString());
SubKey = SubKey->GetNextKey();
}
#endif
g_UserMsgs.EndMessage();
return true;
@@ -759,15 +526,10 @@ void CHalfLife2::ProcessFakeCliCmdQueue()
if (g_Players.GetClientOfUserId(pFake->userid) == pFake->client)
{
CPlayer *pPlayer = g_Players.GetPlayerByIndex(pFake->client);
#if SOURCE_ENGINE == SE_DOTA
engine->ClientCommand(pPlayer->GetIndex(), "%s", pFake->cmd.c_str());
#else
serverpluginhelpers->ClientCommand(pPlayer->GetEdict(), pFake->cmd.c_str());
#endif
}
m_CmdQueue.pop();
m_FreeCmds.push(pFake);
}
}
@@ -862,14 +624,6 @@ const char *CHalfLife2::CurrentCommandName()
void CHalfLife2::AddDelayedKick(int client, int userid, const char *msg)
{
CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
if (!pPlayer || !pPlayer->IsConnected() || pPlayer->IsInKickQueue())
{
return;
}
pPlayer->MarkAsBeingKicked();
DelayedKickInfo kick;
kick.client = client;
@@ -974,11 +728,6 @@ cell_t CHalfLife2::EntityToReference(CBaseEntity *pEntity)
CBaseEntity *CHalfLife2::ReferenceToEntity(cell_t entRef)
{
if ((unsigned)entRef == INVALID_EHANDLE_INDEX)
{
return NULL;
}
CEntInfo *pInfo = NULL;
if (entRef & (1<<31))
@@ -988,7 +737,7 @@ CBaseEntity *CHalfLife2::ReferenceToEntity(cell_t entRef)
CBaseHandle hndl(hndlValue);
pInfo = LookupEntity(hndl.GetEntryIndex());
if (!pInfo || pInfo->m_SerialNumber != hndl.GetSerialNumber())
if (pInfo->m_SerialNumber != hndl.GetSerialNumber())
{
return NULL;
}
@@ -1018,15 +767,7 @@ CBaseEntity *CHalfLife2::ReferenceToEntity(cell_t entRef)
*/
CEntInfo *CHalfLife2::LookupEntity(int entIndex)
{
// Make sure that our index is within the bounds of the global ent array
if (entIndex < 0 || entIndex >= NUM_ENT_ENTRIES)
{
return NULL;
}
CEntInfo *entInfos = EntInfoArray();
if (!entInfos)
if (!g_EntList || entInfoOffset == -1)
{
/* Attempt to use engine interface instead */
static CEntInfo tempInfo;
@@ -1053,7 +794,8 @@ CEntInfo *CHalfLife2::LookupEntity(int entIndex)
return &tempInfo;
}
return &entInfos[entIndex];
CEntInfo *pArray = (CEntInfo *)(((unsigned char *)g_EntList) + entInfoOffset);
return &pArray[entIndex];
}
/**
@@ -1114,11 +856,6 @@ cell_t CHalfLife2::EntityToBCompatRef(CBaseEntity *pEntity)
IServerUnknown *pUnknown = (IServerUnknown *)pEntity;
CBaseHandle hndl = pUnknown->GetRefEHandle();
if (hndl == INVALID_EHANDLE_INDEX)
{
return INVALID_EHANDLE_INDEX;
}
if (hndl.GetEntryIndex() >= MAX_EDICTS)
{
return (hndl.ToInt() | (1<<31));
@@ -1151,101 +888,3 @@ void *CHalfLife2::GetGlobalEntityList()
{
return g_EntList;
}
int CHalfLife2::GetSendPropOffset(SendProp *prop)
{
return prop->GetOffset();
}
const char *CHalfLife2::GetEntityClassname(edict_t * pEdict)
{
if (pEdict == NULL || pEdict->IsFree())
{
return NULL;
}
IServerUnknown *pUnk = pEdict->GetUnknown();
if (pUnk == NULL)
{
return NULL;
}
CBaseEntity * pEntity = pUnk->GetBaseEntity();
if (pEntity == NULL)
{
return NULL;
}
return GetEntityClassname(pEntity);
}
const char *CHalfLife2::GetEntityClassname(CBaseEntity *pEntity)
{
static int offset = -1;
if (offset == -1)
{
CBaseEntity *pGetterEnt = ReferenceToEntity(0);
if (pGetterEnt == NULL)
{
// If we don't have a world entity yet, we'll have to rely on the given entity
pGetterEnt = pEntity;
}
datamap_t *pMap = GetDataMap(pGetterEnt);
sm_datatable_info_t info;
if (!FindDataMapInfo(pMap, "m_iClassname", &info))
{
return NULL;
}
offset = info.actual_offset;
}
return *(const char **)(((unsigned char *)pEntity) + offset);
}
#if SOURCE_ENGINE >= SE_LEFT4DEAD
static bool ResolveFuzzyMapName(const char *fuzzyName, char *outFullname, int size)
{
static ConCommand *pHelperCmd = g_pCVar->FindCommand("changelevel");
if (!pHelperCmd || !pHelperCmd->CanAutoComplete())
return false;
static size_t helperCmdLen = strlen(pHelperCmd->GetName());
CUtlVector<CUtlString> results;
pHelperCmd->AutoCompleteSuggest(fuzzyName, results);
if (results.Count() == 0)
return false;
// Results come back as you'd see in autocomplete. (ie. "changelevel fullmapnamehere"),
// so skip ahead to start of map path/name
// Like the engine, we're only going to deal with the first match.
strncopy(outFullname, &results[0][helperCmdLen + 1], size);
return true;
}
#endif
bool CHalfLife2::IsMapValid(const char *map)
{
if (!map || !map[0])
return false;
bool ret = engine->IsMapValid(map);
#if SOURCE_ENGINE >= SE_LEFT4DEAD
if (!ret)
{
static char szFuzzyName[PLATFORM_MAX_PATH];
if (ResolveFuzzyMapName(map, szFuzzyName, sizeof(szFuzzyName)))
{
ret = engine->IsMapValid(szFuzzyName);
}
}
#endif
return ret;
}
+10 -54
View File
@@ -1,5 +1,5 @@
/**
* vim: set ts=4 sw=4 tw=99 noet :
* vim: set ts=4 :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
@@ -35,10 +35,8 @@
#include <sh_list.h>
#include <sh_string.h>
#include <sh_tinyhash.h>
#include <am-utility.h>
#include <am-hashmap.h>
#include <sm_stringhashmap.h>
#include <sm_namehashset.h>
#include <sm_trie_tpl.h>
#include "sm_trie.h"
#include "sm_globals.h"
#include "sm_queue.h"
#include <IGameHelpers.h>
@@ -46,10 +44,6 @@
#include <server_class.h>
#include <datamap.h>
#include <ihandleentity.h>
#include <tier0/icommandline.h>
#if SOURCE_ENGINE >= SE_PORTAL2
#include <string_t.h>
#endif
class CCommand;
@@ -61,38 +55,16 @@ using namespace SourceMod;
struct DataTableInfo
{
struct SendPropPolicy
{
static inline bool matches(const char *name, const sm_sendprop_info_t &info)
{
return strcmp(name, info.prop->GetName()) == 0;
}
};
static inline bool matches(const char *name, const DataTableInfo *info)
{
return strcmp(name, info->sc->GetName()) == 0;
}
DataTableInfo(ServerClass *sc)
: sc(sc)
{
}
ServerClass *sc;
NameHashSet<sm_sendprop_info_t, SendPropPolicy> lookup;
KTrie<sm_sendprop_info_t> lookup;
};
struct DataMapCachePolicy
struct DataMapTrie
{
static inline bool matches(const char *name, const sm_datatable_info_t &info)
{
return strcmp(name, info.prop->fieldName) == 0;
}
DataMapTrie() : trie(NULL) {}
Trie *trie;
};
typedef NameHashSet<sm_datatable_info_t, DataMapCachePolicy> DataMapCache;
struct DelayedFakeCliCmd
{
String cmd;
@@ -115,7 +87,6 @@ struct DelayedKickInfo
char buffer[384];
};
// copy from game/shared/entitylist_base.h
class CEntInfo
{
public:
@@ -123,10 +94,6 @@ public:
int m_SerialNumber;
CEntInfo *m_pPrev;
CEntInfo *m_pNext;
#if (SOURCE_ENGINE >= SE_PORTAL2) && (SOURCE_ENGINE != SE_DOTA)
string_t m_iName;
string_t m_iClassName;
#endif
};
class CHalfLife2 :
@@ -147,7 +114,6 @@ public: //IGameHelpers
datamap_t *GetDataMap(CBaseEntity *pEntity);
ServerClass *FindServerClass(const char *classname);
typedescription_t *FindInDataMap(datamap_t *pMap, const char *offset);
bool FindDataMapInfo(datamap_t *pMap, const char *offset, sm_datatable_info_t *pDataTable);
void SetEdictStateChanged(edict_t *pEdict, unsigned short offset);
bool TextMsg(int client, int dest, const char *msg);
bool HintTextMsg(int client, const char *msg);
@@ -169,11 +135,6 @@ public: //IGameHelpers
CEntInfo *LookupEntity(int entIndex);
cell_t EntityToBCompatRef(CBaseEntity *pEntity);
void *GetGlobalEntityList();
int GetSendPropOffset(SendProp *prop);
ICommandLine *GetValveCommandLine();
const char *GetEntityClassname(edict_t *pEdict);
const char *GetEntityClassname(CBaseEntity *pEntity);
bool IsMapValid(const char *map);
public:
void AddToFakeCliCmdQueue(int client, int userid, const char *cmd);
void ProcessFakeCliCmdQueue();
@@ -190,13 +151,9 @@ public:
private:
DataTableInfo *_FindServerClass(const char *classname);
private:
void InitLogicalEntData();
void InitCommandLine();
private:
typedef ke::HashMap<datamap_t *, DataMapCache *, ke::PointerPolicy<datamap_t> > DataTableMap;
NameHashSet<DataTableInfo *> m_Classes;
DataTableMap m_Maps;
Trie *m_pClasses;
List<DataTableInfo *> m_Tables;
THash<datamap_t *, DataMapTrie> m_Maps;
int m_MsgTextMsg;
int m_HinTextMsg;
int m_SayTextMsg;
@@ -205,7 +162,6 @@ private:
CStack<DelayedFakeCliCmd *> m_FreeCmds;
CStack<CachedCommandInfo> m_CommandStack;
Queue<DelayedKickInfo> m_DelayedKicks;
void *m_pGetCommandLine;
};
extern CHalfLife2 g_HL2;
+90 -168
View File
@@ -1,5 +1,5 @@
/**
* vim: set ts=4 sw=4 tw=99 noet :
* vim: set ts=4 :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
@@ -30,12 +30,13 @@
*/
#include "HandleSys.h"
#include "ShareSys.h"
#include "PluginSys.h"
#include "ExtensionSys.h"
#include "Logger.h"
#include <assert.h>
#include <string.h>
#include "common_logic.h"
#include "ShareSys.h"
#include "ExtensionSys.h"
#include "PluginSys.h"
#include "sm_stringutil.h"
HandleSystem g_HandleSys;
@@ -59,6 +60,9 @@ HandleSystem::HandleSystem()
m_Types = new QHandleType[HANDLESYS_TYPEARRAY_SIZE];
memset(m_Types, 0, sizeof(QHandleType) * HANDLESYS_TYPEARRAY_SIZE);
m_TypeLookup = sm_trie_create();
m_strtab = new BaseStringTable(512);
m_TypeTail = 0;
}
@@ -66,6 +70,8 @@ HandleSystem::~HandleSystem()
{
delete [] m_Handles;
delete [] m_Types;
sm_trie_destroy(m_TypeLookup);
delete m_strtab;
}
@@ -139,10 +145,12 @@ HandleType_t HandleSystem::CreateType(const char *name,
if (name && name[0] != '\0')
{
if (m_TypeLookup.contains(name))
if (sm_trie_retrieve(m_TypeLookup, name, NULL))
{
if (err)
{
*err = HandleError_Parameter;
}
return 0;
}
}
@@ -204,8 +212,10 @@ HandleType_t HandleSystem::CreateType(const char *name,
pType->dispatch = dispatch;
if (name && name[0] != '\0')
{
pType->name = new ke::AString(name);
m_TypeLookup.insert(name, pType);
pType->nameIdx = m_strtab->AddString(name);
sm_trie_insert(m_TypeLookup, name, (void *)pType);
} else {
pType->nameIdx = -1;
}
pType->opened = 0;
@@ -233,14 +243,21 @@ HandleType_t HandleSystem::CreateType(const char *name,
return index;
}
bool HandleSystem::FindHandleType(const char *name, HandleType_t *aResult)
bool HandleSystem::FindHandleType(const char *name, HandleType_t *type)
{
QHandleType *type;
if (!m_TypeLookup.retrieve(name, &type))
return false;
QHandleType *_type;
if (aResult)
*aResult = type - m_Types;
if (!sm_trie_retrieve(m_TypeLookup, name, (void **)&_type))
{
return false;
}
unsigned int offset = _type - m_Types;
if (type)
{
*type = offset;
}
return true;
}
@@ -562,7 +579,6 @@ HandleError HandleSystem::CloneHandle(QHandle *pHandle, unsigned int index, Hand
}
pNewHandle->clone = index;
pNewHandle->object = NULL;
pHandle->refcount++;
*newhandle = new_handle;
@@ -604,53 +620,8 @@ HandleError HandleSystem::CloneHandle(Handle_t handle, Handle_t *newhandle, Iden
return CloneHandle(pHandle, index, newhandle, newOwner);
}
Handle_t HandleSystem::FastCloneHandle(QHandle *pHandle, unsigned int index)
{
if (pHandle->clone)
return FastCloneHandle(&m_Handles[pHandle->clone], pHandle->clone);
Handle_t hndl;
if (CloneHandle(pHandle, index, &hndl, g_pCoreIdent) != HandleError_None)
return BAD_HANDLE;
return hndl;
}
Handle_t HandleSystem::FastCloneHandle(Handle_t hndl)
{
QHandle *pHandle;
unsigned int index;
GetHandleUnchecked(hndl, pHandle, index);
return FastCloneHandle(pHandle, index);
}
void HandleSystem::GetHandleUnchecked(Handle_t hndl, QHandle *& pHandle, unsigned int &index)
{
#ifndef NDEBUG
unsigned int serial = (hndl >> 16);
#endif
index = (hndl & HANDLESYS_HANDLE_MASK);
assert(index != 0 && index <= m_HandleTail && index < HANDLESYS_MAX_HANDLES);
pHandle = &m_Handles[index];
assert(pHandle->set && pHandle->set != HandleSet_Freed);
assert(pHandle->serial == serial);
}
HandleError HandleSystem::FreeHandle(QHandle *pHandle, unsigned int index)
{
if (pHandle->is_destroying)
{
/* Someone tried to free this recursively.
* We'll just ignore this safely.
*/
return HandleError_None;
}
QHandleType *pType = &m_Types[pHandle->type];
if (pHandle->clone)
@@ -665,7 +636,6 @@ HandleError HandleSystem::FreeHandle(QHandle *pHandle, unsigned int index)
pMaster = &m_Handles[master];
/* Release the clone now */
pHandle->is_destroying = true;
ReleasePrimHandle(index);
/* Decrement the master's reference count */
@@ -674,27 +644,20 @@ HandleError HandleSystem::FreeHandle(QHandle *pHandle, unsigned int index)
/* Type should be the same but do this anyway... */
pType = &m_Types[pMaster->type];
pMaster->is_destroying = true;
if (pMaster->object)
{
pType->dispatch->OnHandleDestroy(pMaster->type, pMaster->object);
}
pType->dispatch->OnHandleDestroy(pMaster->type, pMaster->object);
ReleasePrimHandle(master);
}
} else if (pHandle->set == HandleSet_Identity) {
/* If we're an identity, skip all this stuff!
* NOTE: SHARESYS DOES NOT CARE ABOUT THE DESTRUCTOR
*/
pHandle->is_destroying = true;
ReleasePrimHandle(index);
} else {
/* Decrement, free if necessary */
if (--pHandle->refcount == 0)
{
pHandle->is_destroying = true;
if (pHandle->object)
{
pType->dispatch->OnHandleDestroy(pHandle->type, pHandle->object);
}
pType->dispatch->OnHandleDestroy(pHandle->type, pHandle->object);
ReleasePrimHandle(index);
} else {
/* We must be cloned, so mark ourselves as freed */
@@ -727,6 +690,14 @@ HandleError HandleSystem::FreeHandle(Handle_t handle, const HandleSecurity *pSec
return HandleError_Access;
}
if (pHandle->is_destroying)
{
/* Someone tried to free this recursively.
* We'll just ignore this safely.
*/
return HandleError_None;
}
return FreeHandle(pHandle, index);
}
@@ -785,9 +756,6 @@ void HandleSystem::UnlinkHandleFromOwner(QHandle *pHandle, unsigned int index)
assert(pHandle->owner == 0);
return;
}
pHandle->owner = NULL;
/* Note that since 0 is an invalid handle, if any of these links are 0,
* the data can still be set.
*/
@@ -897,6 +865,10 @@ bool HandleSystem::RemoveType(HandleType_t type, IdentityToken_t *ident)
m_Types[++m_FreeTypes].freeID = type;
}
/* Invalidate the type now */
IHandleTypeDispatch *dispatch = pType->dispatch;
pType->dispatch = NULL;
/* Make sure nothing is using this type. */
if (pType->opened)
{
@@ -908,9 +880,29 @@ bool HandleSystem::RemoveType(HandleType_t type, IdentityToken_t *ident)
{
continue;
}
FreeHandle(pHandle, i);
if (pHandle->clone)
{
/* Get parent */
QHandle *pOther = &m_Handles[pHandle->clone];
if (--pOther->refcount == 0)
{
/* Free! */
dispatch->OnHandleDestroy(type, pOther->object);
ReleasePrimHandle(pHandle->clone);
}
/* Unlink ourselves since we don't have a reference count */
ReleasePrimHandle(i);
} else {
/* If it's not a clone, we still have to check the reference count.
* Either way, we'll be destroyed eventually because the handle types do not change.
*/
if (--pHandle->refcount == 0)
{
/* Free! */
dispatch->OnHandleDestroy(type, pHandle->object);
ReleasePrimHandle(i);
}
}
if (pType->opened == 0)
{
break;
@@ -918,12 +910,14 @@ bool HandleSystem::RemoveType(HandleType_t type, IdentityToken_t *ident)
}
}
/* Invalidate the type now */
pType->dispatch = NULL;
/* Remove it from the type cache. */
if (pType->name)
m_TypeLookup.remove(pType->name->chars());
if (pType->nameIdx != -1)
{
const char *typeName;
typeName = m_strtab->GetString(pType->nameIdx);
sm_trie_delete(m_TypeLookup, typeName);
}
return true;
}
@@ -956,17 +950,14 @@ bool HandleSystem::InitAccessDefaults(TypeAccess *pTypeAccess, HandleAccess *pHa
return true;
}
#define HANDLE_LOG_VERY_BAD(message, ...) \
logger->LogFatal(message, ##__VA_ARGS__); \
logger->LogError(message, ##__VA_ARGS__);
bool HandleSystem::TryAndFreeSomeHandles()
{
IPluginIterator *pl_iter = g_PluginSys.GetPluginIterator();
IPlugin *highest_owner = NULL;
unsigned int highest_handle_count = 0;
/* Search all plugins */
for (IPluginIterator *pl_iter = g_PluginSys.GetPluginIterator(); pl_iter->MorePlugins(); pl_iter->NextPlugin())
while (pl_iter->MorePlugins())
{
IPlugin *plugin = pl_iter->GetPlugin();
IdentityToken_t *identity = plugin->GetIdentity();
@@ -995,6 +986,8 @@ bool HandleSystem::TryAndFreeSomeHandles()
highest_owner = plugin;
highest_handle_count = handle_count;
}
pl_iter->NextPlugin();
}
if (highest_owner == NULL || highest_handle_count == 0)
@@ -1002,66 +995,13 @@ bool HandleSystem::TryAndFreeSomeHandles()
return false;
}
HANDLE_LOG_VERY_BAD("[SM] MEMORY LEAK DETECTED IN PLUGIN (file \"%s\")", highest_owner->GetFilename());
HANDLE_LOG_VERY_BAD("[SM] Unloading plugin to free %d handles.", highest_handle_count);
HANDLE_LOG_VERY_BAD("[SM] Contact the author(s) of this plugin to correct this error.", highest_handle_count);
HANDLE_LOG_VERY_BAD("--------------------------------------------------------------------------");
const IdentityToken_t *pIdentity = highest_owner->GetIdentity();
unsigned int total = 0, highest_index = 0, total_size = 0, size;
unsigned int * pCount = new unsigned int[HANDLESYS_TYPEARRAY_SIZE+1];
memset(pCount, 0, ((HANDLESYS_TYPEARRAY_SIZE + 1) * sizeof(unsigned int)));
for (unsigned int i = 1; i <= m_HandleTail; ++i)
{
const QHandle &Handle = m_Handles[i];
if (Handle.set != HandleSet_Used || Handle.owner != pIdentity)
{
continue;
}
++pCount[Handle.type];
++total;
if (Handle.type >= highest_index)
{
highest_index = ((Handle.type) + 1);
}
if (Handle.clone != 0)
{
continue;
}
if (m_Types[Handle.type].dispatch->GetHandleApproxSize(Handle.type, Handle.object, &size))
{
total_size += size;
}
}
const char * pTypeName = NULL;
for (unsigned int i = 0; i < highest_index; ++i)
{
if (pCount[i] == 0)
{
continue; /* We may have gaps, it's fine. */
}
if (m_Types[i].name)
pTypeName = m_Types[i].name->chars();
else
pTypeName = "ANON";
HANDLE_LOG_VERY_BAD("Type\t%-20.20s|\tCount\t%u", pTypeName, pCount[i]);
}
HANDLE_LOG_VERY_BAD("-- Approximately %d bytes of memory are in use by (%u) Handles.\n", total_size, total);
delete [] pCount;
g_Logger.LogFatal("[SM] MEMORY LEAK DETECTED IN PLUGIN (file \"%s\")", highest_owner->GetFilename());
g_Logger.LogFatal("[SM] Unloading plugin to free %d handles.", highest_handle_count);
g_Logger.LogFatal("[SM] Contact the author(s) of this plugin to correct this error.", highest_handle_count);
highest_owner->GetBaseContext()->ThrowNativeErrorEx(SP_ERROR_MEMACCESS, "Memory leak");
return scripts->UnloadPlugin(highest_owner);
return g_PluginSys.UnloadPlugin(highest_owner);
}
void HandleSystem::Dump(HANDLE_REPORTER rep)
@@ -1086,20 +1026,20 @@ void HandleSystem::Dump(HANDLE_REPORTER rep)
{
owner = "CORE";
}
else if (pOwner == scripts->GetIdentity())
else if (pOwner == g_PluginSys.GetIdentity())
{
owner = "PLUGINSYS";
}
else
{
IExtension *ext = g_Extensions.GetExtensionFromIdent(pOwner);
CExtension *ext = g_Extensions.GetExtensionFromIdent(pOwner);
if (ext)
{
owner = ext->GetFilename();
}
else
{
SMPlugin *pPlugin = scripts->FindPluginByIdentity(pOwner);
CPlugin *pPlugin = g_PluginSys.GetPluginFromIdentity(pOwner);
if (pPlugin)
{
owner = pPlugin->GetFilename();
@@ -1114,37 +1054,19 @@ void HandleSystem::Dump(HANDLE_REPORTER rep)
const char *type = "ANON";
QHandleType *pType = &m_Types[m_Handles[i].type];
unsigned int size = 0;
unsigned int parentIdx;
bool bresult;
if (pType->name)
type = pType->name->chars();
if ((parentIdx = m_Handles[i].clone) != 0)
if (pType->nameIdx != -1)
{
if (m_Handles[parentIdx].refcount > 0)
{
size = 0;
bresult = true;
}
else
{
bresult = pType->dispatch->GetHandleApproxSize(m_Handles[parentIdx].type, m_Handles[parentIdx].object, &size);
}
type = m_strtab->GetString(pType->nameIdx);
}
else
{
bresult = pType->dispatch->GetHandleApproxSize(m_Handles[i].type, m_Handles[i].object, &size);
}
if (pType->dispatch->GetDispatchVersion() < HANDLESYS_MEMUSAGE_MIN_VERSION
|| !bresult)
|| !pType->dispatch->GetHandleApproxSize(m_Handles[i].type, m_Handles[i].object, &size))
{
rep("0x%08x\t%-20.20s\t%-20.20s\t%-10.10s", index, owner, type, "-1");
}
else
{
char buffer[32];
smcore.Format(buffer, sizeof(buffer), "%d", size);
UTIL_Format(buffer, sizeof(buffer), "%d", size);
rep("0x%08x\t%-20.20s\t%-20.20s\t%-10.10s", index, owner, type, buffer);
total_size += size;
}
+9 -41
View File
@@ -1,5 +1,5 @@
/**
* vim: set ts=4 sw=4 tw=99 noet :
* vim: set ts=4 :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
@@ -34,11 +34,12 @@
#include <IHandleSys.h>
#include <stdio.h>
#include <sm_namehashset.h>
#include <am-string.h>
#include "common_logic.h"
#include "sm_globals.h"
#include "sm_trie.h"
#include "sourcemod.h"
#include "sm_memtable.h"
#define HANDLESYS_MAX_HANDLES (1<<15)
#define HANDLESYS_MAX_HANDLES (1<<14)
#define HANDLESYS_MAX_TYPES (1<<9)
#define HANDLESYS_MAX_SUBTYPES 0xF
#define HANDLESYS_SUBTYPE_MASK 0xF
@@ -103,12 +104,7 @@ struct QHandleType
TypeAccess typeSec;
HandleAccess hndlSec;
unsigned int opened;
ke::AutoPtr<ke::AString> name;
static inline bool matches(const char *key, const QHandleType *type)
{
return type->name && type->name->compare(key) == 0;
}
int nameIdx;
};
typedef void (HANDLE_REPORTER)(const char *str, ...);
@@ -164,9 +160,6 @@ public: //IHandleSystem
HandleError *err);
void Dump(HANDLE_REPORTER rep);
/* Bypasses security checks. */
Handle_t FastCloneHandle(Handle_t hndl);
protected:
/**
* Decodes a handle with sanity and security checking.
@@ -177,9 +170,6 @@ protected:
unsigned int *index,
bool ignoreFree=false);
Handle_t FastCloneHandle(QHandle *pHandle, unsigned int index);
void GetHandleUnchecked(Handle_t hndl, QHandle *& pHandle, unsigned int &index);
/**
* Creates a basic handle and sets its reference count to 1.
* Does not do any type or security checking.
@@ -221,37 +211,15 @@ protected:
private:
QHandle *m_Handles;
QHandleType *m_Types;
NameHashSet<QHandleType *> m_TypeLookup;
Trie *m_TypeLookup;
unsigned int m_TypeTail;
unsigned int m_FreeTypes;
unsigned int m_HandleTail;
unsigned int m_FreeHandles;
unsigned int m_HSerial;
BaseStringTable *m_strtab;
};
extern HandleSystem g_HandleSys;
struct AutoHandleRooter
{
public:
AutoHandleRooter(Handle_t hndl)
{
if (hndl != BAD_HANDLE)
this->hndl = g_HandleSys.FastCloneHandle(hndl);
else
this->hndl = BAD_HANDLE;
}
~AutoHandleRooter()
{
if (hndl != BAD_HANDLE)
{
HandleSecurity sec(g_pCoreIdent, g_pCoreIdent);
g_HandleSys.FreeHandle(hndl, &sec);
}
}
private:
Handle_t hndl;
};
#endif //_INCLUDE_SOURCEMOD_HANDLESYSTEM_H_
+2 -2
View File
@@ -241,7 +241,7 @@ bool LibrarySystem::IsPathDirectory(const char *path)
return true;
}
#elif defined PLATFORM_POSIX
#elif defined PLATFORM_LINUX
struct stat s;
if (stat(path, &s) != 0)
@@ -410,7 +410,7 @@ size_t LibrarySystem::GetFileFromPath(char *buffer, size_t maxlength, const char
size_t length = strlen(path);
for (size_t i = length - 1;
i <= length - 1;
i >= 0 && i <= length - 1;
i--)
{
if (path[i] == '/'
+505 -25
View File
@@ -36,35 +36,515 @@
#include "Logger.h"
#include "LibrarySys.h"
#include "TimerSys.h"
#include "logic_bridge.h"
#include <sourcemod_version.h>
Logger g_Logger;
/**
* :TODO: This should be creating the log folder if it doesn't exist
*/
ConfigResult Logger::OnSourceModConfigChanged(const char *key,
const char *value,
ConfigSource source,
char *error,
size_t maxlength)
{
if (strcasecmp(key, "Logging") == 0)
{
bool state;
if (strcasecmp(value, "on") == 0)
{
state = true;
} else if (strcasecmp(value, "off") == 0) {
state = false;
} else {
UTIL_Format(error, maxlength, "Invalid value: must be \"on\" or \"off\"");
return ConfigResult_Reject;
}
if (source == ConfigSource_Console)
{
state ? EnableLogging() : DisableLogging();
} else {
m_InitialState = state;
}
return ConfigResult_Accept;
} else if (strcasecmp(key, "LogMode") == 0) {
if (strcasecmp(value, "daily") == 0)
{
m_Mode = LoggingMode_Daily;
} else if (strcasecmp(value, "map") == 0) {
m_Mode = LoggingMode_PerMap;
} else if (strcasecmp(value, "game") == 0) {
m_Mode = LoggingMode_Game;
} else {
UTIL_Format(error, maxlength, "Invalid value: must be [daily|map|game]");
return ConfigResult_Reject;
}
return ConfigResult_Accept;
}
return ConfigResult_Ignore;
}
void Logger::OnSourceModStartup(bool late)
{
InitLogger(m_Mode);
}
void Logger::OnSourceModAllShutdown()
{
CloseLogger();
}
void Logger::OnSourceModLevelChange(const char *mapName)
{
MapChange(mapName);
}
void Logger::_NewMapFile()
{
if (!m_Active)
{
return;
}
/* Append "Log file closed" to previous log file */
_CloseFile();
char _filename[256];
int i = 0;
time_t t;
GetAdjustedTime(&t);
tm *curtime = localtime(&t);
while (true)
{
g_SourceMod.BuildPath(Path_SM, _filename, sizeof(_filename), "logs/L%02d%02d%03d.log", curtime->tm_mon + 1, curtime->tm_mday, i);
FILE *fp = fopen(_filename, "r");
if (!fp)
{
break;
}
fclose(fp);
i++;
}
m_NrmFileName.assign(_filename);
FILE *fp = fopen(m_NrmFileName.c_str(), "w");
if (!fp)
{
char error[255];
g_LibSys.GetPlatformError(error, sizeof(error));
LogFatal("[SM] Unexpected fatal logging error (file \"%s\")", m_NrmFileName.c_str());
LogFatal("[SM] Platform returned error: \"%s\"", error);
LogFatal("[SM] Logging has been disabled.");
m_Active = false;
return;
} else {
char date[32];
strftime(date, sizeof(date), "%m/%d/%Y - %H:%M:%S", curtime);
fprintf(fp, "L %s: SourceMod log file started (file \"L%02d%02d%03d.log\") (Version \"%s\")\n", date, curtime->tm_mon + 1, curtime->tm_mday, i, SM_FULL_VERSION);
fclose(fp);
}
}
void Logger::_CloseFile()
{
if (!m_Active)
{
return;
}
FILE *fp = NULL;
if (!m_NrmFileName.empty())
{
fp = fopen(m_NrmFileName.c_str(), "r+");
if (fp)
{
fseek(fp, 0, SEEK_END);
LogMessage("Log file closed.");
fclose(fp);
}
m_NrmFileName.clear();
}
if (!m_ErrMapStart)
{
return;
}
fp = fopen(m_ErrFileName.c_str(), "r+");
if (fp)
{
fseek(fp, 0, SEEK_END);
LogError("Error log file session closed.");
fclose(fp);
}
m_ErrFileName.clear();
}
void Logger::InitLogger(LoggingMode mode)
{
m_Mode = mode;
m_Active = m_InitialState;
time_t t;
GetAdjustedTime(&t);
tm *curtime = localtime(&t);
m_CurDay = curtime->tm_mday;
char _filename[256];
g_SourceMod.BuildPath(Path_SM, _filename, sizeof(_filename), "logs/errors_%04d%02d%02d.log", curtime->tm_year + 1900, curtime->tm_mon + 1, curtime->tm_mday);
m_ErrFileName.assign(_filename);
switch (m_Mode)
{
case LoggingMode_PerMap:
{
if (!m_Active)
{
m_DelayedStart = true;
}
break;
}
case LoggingMode_Daily:
{
g_SourceMod.BuildPath(Path_SM, _filename, sizeof(_filename), "logs/L%04d%02d%02d.log", curtime->tm_year + 1900, curtime->tm_mon + 1, curtime->tm_mday);
m_NrmFileName.assign(_filename);
m_DailyPrintHdr = true;
break;
}
default:
{
/* do nothing... */
break;
}
}
}
void Logger::CloseLogger()
{
_CloseFile();
}
void Logger::LogToOpenFile(FILE *fp, const char *msg, ...)
{
if (!m_Active)
{
return;
}
va_list ap;
va_start(ap, msg);
LogToOpenFileEx(fp, msg, ap);
va_end(ap);
}
void Logger::LogToFileOnly(FILE *fp, const char *msg, ...)
{
if (!m_Active)
{
return;
}
va_list ap;
va_start(ap, msg);
LogToFileOnlyEx(fp, msg, ap);
va_end(ap);
}
void Logger::LogToOpenFileEx(FILE *fp, const char *msg, va_list ap)
{
if (!m_Active)
{
return;
}
char buffer[3072];
UTIL_FormatArgs(buffer, sizeof(buffer), msg, ap);
char date[32];
time_t t;
GetAdjustedTime(&t);
tm *curtime = localtime(&t);
strftime(date, sizeof(date), "%m/%d/%Y - %H:%M:%S", curtime);
fprintf(fp, "L %s: %s\n", date, buffer);
g_SMAPI->ConPrintf("L %s: %s\n", date, buffer);
}
void Logger::LogToFileOnlyEx(FILE *fp, const char *msg, va_list ap)
{
if (!m_Active)
{
return;
}
char buffer[3072];
UTIL_FormatArgs(buffer, sizeof(buffer), msg, ap);
char date[32];
time_t t;
GetAdjustedTime(&t);
tm *curtime = localtime(&t);
strftime(date, sizeof(date), "%m/%d/%Y - %H:%M:%S", curtime);
fprintf(fp, "L %s: %s\n", date, buffer);
fflush(fp);
}
void Logger::LogMessage(const char *vafmt, ...)
{
if (!m_Active)
{
return;
}
if (m_Mode == LoggingMode_Game)
{
va_list ap;
va_start(ap, vafmt);
_PrintToGameLog(vafmt, ap);
va_end(ap);
return;
}
if (m_DelayedStart)
{
m_DelayedStart = false;
_NewMapFile();
}
time_t t;
GetAdjustedTime(&t);
tm *curtime = localtime(&t);
FILE *fp = NULL;
if (m_Mode == LoggingMode_PerMap)
{
fp = fopen(m_NrmFileName.c_str(), "a+");
if (!fp)
{
_NewMapFile();
fp = fopen(m_NrmFileName.c_str(), "a+");
if (!fp)
{
goto print_error;
}
}
} else {
if (m_CurDay != curtime->tm_mday)
{
char _filename[256];
g_SourceMod.BuildPath(Path_SM, _filename, sizeof(_filename), "logs/L%04d%02d%02d.log", curtime->tm_year + 1900, curtime->tm_mon + 1, curtime->tm_mday);
m_NrmFileName.assign(_filename);
m_CurDay = curtime->tm_mday;
m_DailyPrintHdr = true;
}
fp = fopen(m_NrmFileName.c_str(), "a+");
}
if (fp)
{
if (m_DailyPrintHdr)
{
char date[32];
m_DailyPrintHdr = false;
strftime(date, sizeof(date), "%m/%d/%Y - %H:%M:%S", curtime);
fprintf(fp, "L %s: SourceMod log file session started (file \"L%04d%02d%02d.log\") (Version \"%s\")\n", date, curtime->tm_year + 1900, curtime->tm_mon + 1, curtime->tm_mday, SM_FULL_VERSION);
}
va_list ap;
va_start(ap, vafmt);
LogToOpenFileEx(fp, vafmt, ap);
va_end(ap);
fclose(fp);
} else {
goto print_error;
}
return;
print_error:
char error[255];
g_LibSys.GetPlatformError(error, sizeof(error));
LogFatal("[SM] Unexpected fatal logging error (file \"%s\")", m_NrmFileName.c_str());
LogFatal("[SM] Platform returned error: \"%s\"", error);
LogFatal("[SM] Logging has been disabled.");
m_Active = false;
}
void Logger::LogError(const char *vafmt, ...)
{
va_list ap;
va_start(ap, vafmt);
LogErrorEx(vafmt, ap);
va_end(ap);
}
void Logger::LogErrorEx(const char *vafmt, va_list ap)
{
if (!m_Active)
{
return;
}
time_t t;
GetAdjustedTime(&t);
tm *curtime = localtime(&t);
if (curtime->tm_mday != m_CurDay)
{
char _filename[256];
g_SourceMod.BuildPath(Path_SM, _filename, sizeof(_filename), "logs/errors_%04d%02d%02d.log", curtime->tm_year + 1900, curtime->tm_mon + 1, curtime->tm_mday);
m_ErrFileName.assign(_filename);
m_CurDay = curtime->tm_mday;
m_ErrMapStart = false;
}
FILE *fp = fopen(m_ErrFileName.c_str(), "a+");
if (fp)
{
if (!m_ErrMapStart)
{
char date[32];
strftime(date, sizeof(date), "%m/%d/%Y - %H:%M:%S", curtime);
fprintf(fp, "L %s: SourceMod error session started\n", date);
fprintf(fp, "L %s: Info (map \"%s\") (file \"errors_%04d%02d%02d.log\")\n", date, m_CurMapName.c_str(), curtime->tm_year + 1900, curtime->tm_mon + 1, curtime->tm_mday);
m_ErrMapStart = true;
}
LogToOpenFileEx(fp, vafmt, ap);
fclose(fp);
}
else
{
char error[255];
g_LibSys.GetPlatformError(error, sizeof(error));
LogFatal("[SM] Unexpected fatal logging error (file \"%s\")", m_NrmFileName.c_str());
LogFatal("[SM] Platform returned error: \"%s\"", error);
LogFatal("[SM] Logging has been disabled.");
m_Active = false;
return;
}
}
void Logger::MapChange(const char *mapname)
{
m_CurMapName.assign(mapname);
switch (m_Mode)
{
case LoggingMode_Daily:
{
LogMessage("-------- Mapchange to %s --------", mapname);
break;
}
case LoggingMode_PerMap:
{
_NewMapFile();
break;
}
default:
{
/* Do nothing... */
break;
}
}
if (m_ErrMapStart)
{
LogError("Error log file session closed.");
}
m_ErrMapStart = false;
}
void Logger::_PrintToGameLog(const char *fmt, va_list ap)
{
char msg[3072];
size_t len;
len = vsnprintf(msg, sizeof(msg)-2, fmt, ap);
len = (len >= sizeof(msg)) ? (sizeof(msg) - 2) : len;
msg[len++] = '\n';
msg[len] = '\0';
Engine_LogPrintWrapper(msg);
}
const char *Logger::GetLogFileName(LogType type) const
{
switch (type)
{
case LogType_Normal:
{
return m_NrmFileName.c_str();
}
case LogType_Error:
{
return m_ErrFileName.c_str();
}
default:
{
return "";
}
}
}
LoggingMode Logger::GetLoggingMode() const
{
return m_Mode;
}
void Logger::EnableLogging()
{
if (m_Active)
{
return;
}
m_Active = true;
LogMessage("[SM] Logging enabled manually by user.");
}
void Logger::DisableLogging()
{
if (!m_Active)
{
return;
}
LogMessage("[SM] Logging disabled manually by user.");
m_Active = false;
}
void Logger::LogFatal(const char *msg, ...)
{
/* :TODO: make this print all pretty-like
* In fact, the pretty log printing function should be abstracted.
* It's already implemented twice which is bad.
*/
va_list ap;
char path[PLATFORM_MAX_PATH];
g_SourceMod.BuildPath(Path_Game, path, sizeof(path), "sourcemod_fatal.log");
FILE *fp = fopen(path, "at");
if (fp)
{
m_Active = true;
va_start(ap, msg);
LogToOpenFileEx(fp, msg, ap);
va_end(ap);
m_Active = false;
fclose(fp);
}
}
bool g_in_game_log_hook = false;
static LoggerCore g_LoggerCore;
SH_DECL_HOOK1_void(IVEngineServer, LogPrint, SH_NOATTRIB, false, const char *);
static void HookLogPrint(const char *message)
{
g_in_game_log_hook = true;
bool stopped = logicore.OnLogPrint(message);
g_in_game_log_hook = false;
if (stopped)
RETURN_META(MRES_SUPERCEDE);
}
void LoggerCore::OnSourceModStartup(bool late)
{
SH_ADD_HOOK(IVEngineServer, LogPrint, engine, SH_STATIC(HookLogPrint), false);
}
void LoggerCore::OnSourceModAllShutdown()
{
SH_REMOVE_HOOK(IVEngineServer, LogPrint, engine, SH_STATIC(HookLogPrint), false);
}
void Engine_LogPrintWrapper(const char *msg)
{
if (g_in_game_log_hook)
+61 -1
View File
@@ -38,13 +38,73 @@
using namespace SourceHook;
class LoggerCore : public SMGlobalClass
enum LogType
{
LogType_Normal,
LogType_Error
};
enum LoggingMode
{
LoggingMode_Daily,
LoggingMode_PerMap,
LoggingMode_Game
};
class Logger : public SMGlobalClass
{
public:
Logger() : m_Mode(LoggingMode_Daily), m_ErrMapStart(false),
m_Active(false), m_DelayedStart(false), m_DailyPrintHdr(false),
m_InitialState(true)
{
}
public: //SMGlobalClass
ConfigResult OnSourceModConfigChanged(const char *key,
const char *value,
ConfigSource source,
char *error,
size_t maxlength);
void OnSourceModStartup(bool late);
void OnSourceModAllShutdown();
void OnSourceModLevelChange(const char *mapName);
public:
void InitLogger(LoggingMode mode);
void CloseLogger();
void EnableLogging();
void DisableLogging();
void LogMessage(const char *msg, ...);
void LogError(const char *msg, ...);
void LogErrorEx(const char *msg, va_list ap);
void LogFatal(const char *msg, ...);
void LogToOpenFile(FILE *fp, const char *msg, ...);
void LogToOpenFileEx(FILE *fp, const char *msg, va_list ap);
/* This version does not print to console, and is thus thread-safe */
void LogToFileOnly(FILE *fp, const char *msg, ...);
void LogToFileOnlyEx(FILE *fp, const char *msg, va_list ap);
void MapChange(const char *mapname);
const char *GetLogFileName(LogType type) const;
LoggingMode GetLoggingMode() const;
private:
void _CloseFile();
void _NewMapFile();
void _PrintToGameLog(const char *fmt, va_list ap);
private:
String m_NrmFileName;
String m_ErrFileName;
String m_CurMapName;
LoggingMode m_Mode;
int m_CurDay;
bool m_ErrMapStart;
bool m_Active;
bool m_DelayedStart;
bool m_DailyPrintHdr;
bool m_InitialState;
};
void Engine_LogPrintWrapper(const char *msg);
extern bool g_in_game_log_hook;
extern Logger g_Logger;
#endif // _INCLUDE_SOURCEMOD_CLOGGER_H_
+54 -89
View File
@@ -2,32 +2,32 @@
# Makefile written by David "BAILOPAN" Anderson
SMSDK = ..
SRCDS_BASE = ~/srcds
HL2SDK_ORIG = ../../hl2sdk
HL2SDK_OB = ../../hl2sdk-ob
HL2SDK_CSS = ../../hl2sdk-css
HL2SDK_OB_VALVE = ../../hl2sdk-ob-valve
HL2SDK_L4D = ../../hl2sdk-l4d
HL2SDK_L4D2 = ../../hl2sdk-l4d2
HL2SDK_CSGO = ../../hl2sdk-csgo
MMSOURCE = ../../mmsource-central
MMSOURCE17 = ../../mmsource-central
#####################################
### EDIT BELOW FOR OTHER PROJECTS ###
#####################################
OBJECTS = AdminCache.cpp CDataPack.cpp ConCmdManager.cpp ConVarManager.cpp CoreConfig.cpp \
Database.cpp DebugReporter.cpp EventManager.cpp HalfLife2.cpp Logger.cpp \
PlayerManager.cpp TimerSys.cpp UserMessages.cpp \
sm_autonatives.cpp sm_srvcmds.cpp sm_stringutil.cpp sm_trie.cpp \
Database.cpp DebugReporter.cpp EventManager.cpp GameConfigs.cpp HalfLife2.cpp Logger.cpp \
MemoryUtils.cpp PlayerManager.cpp TimerSys.cpp Translator.cpp UserMessages.cpp \
sm_autonatives.cpp sm_memtable.cpp sm_srvcmds.cpp sm_stringutil.cpp sm_trie.cpp \
sourcemm_api.cpp sourcemod.cpp MenuStyle_Base.cpp MenuStyle_Valve.cpp MenuManager.cpp \
MenuStyle_Radio.cpp ChatTriggers.cpp ADTFactory.cpp MenuVoting.cpp \
frame_hooks.cpp concmd_cleaner.cpp NextMap.cpp \
MenuStyle_Radio.cpp ChatTriggers.cpp ADTFactory.cpp MenuVoting.cpp sm_crc32.cpp \
frame_hooks.cpp concmd_cleaner.cpp PhraseCollection.cpp NextMap.cpp \
NativeOwner.cpp logic_bridge.cpp ConsoleDetours.cpp
OBJECTS += smn_bitbuffer.cpp smn_console.cpp smn_core.cpp \
smn_database.cpp smn_entities.cpp smn_events.cpp \
smn_fakenatives.cpp smn_filesystem.cpp smn_halflife.cpp \
smn_keyvalues.cpp smn_player.cpp \
smn_usermsgs.cpp smn_menus.cpp smn_vector.cpp \
OBJECTS += smn_admin.cpp smn_bitbuffer.cpp smn_console.cpp smn_core.cpp \
smn_datapacks.cpp smn_entities.cpp smn_events.cpp smn_fakenatives.cpp \
smn_filesystem.cpp smn_gameconfigs.cpp smn_halflife.cpp \
smn_handles.cpp smn_keyvalues.cpp smn_banning.cpp \
smn_lang.cpp smn_player.cpp smn_string.cpp smn_timers.cpp \
smn_usermsgs.cpp smn_menus.cpp smn_database.cpp smn_vector.cpp \
smn_hudtext.cpp smn_nextmap.cpp
OBJECTS += ExtensionSys.cpp \
ForwardSys.cpp \
@@ -49,119 +49,80 @@ CPP_GCC4_FLAGS = -fvisibility-inlines-hidden
CPP = gcc
override ENGSET = false
ifneq (,$(filter original orangebox css orangeboxvalve left4dead left4dead2 csgo,$(ENGINE)))
override ENGSET = true
endif
ifeq "$(ENGINE)" "original"
HL2SDK = $(HL2SDK_ORIG)
HL2PUB = $(HL2SDK)/public
HL2LIB = $(HL2SDK)/linux_sdk
CFLAGS += -DSOURCE_ENGINE=1
METAMOD = $(MMSOURCE)/core-legacy
METAMOD = $(MMSOURCE17)/core-legacy
INCLUDE += -I$(HL2SDK)/public/dlls
SRCDS = $(SRCDS_BASE)
BINARY = sourcemod.1.ep1.so
override ENGSET = true
endif
ifeq "$(ENGINE)" "orangebox"
HL2SDK = $(HL2SDK_OB)
HL2PUB = $(HL2SDK)/public
HL2LIB = $(HL2SDK)/lib/linux
CFLAGS += -DSOURCE_ENGINE=3
METAMOD = $(MMSOURCE)/core
METAMOD = $(MMSOURCE17)/core
INCLUDE += -I$(HL2SDK)/public/game/server
SRCDS = $(SRCDS_BASE)/orangebox
BINARY = sourcemod.2.ep2.so
endif
ifeq "$(ENGINE)" "css"
HL2SDK = $(HL2SDK_CSS)
HL2LIB = $(HL2SDK)/lib/linux
CFLAGS += -DSOURCE_ENGINE=6
METAMOD = $(MMSOURCE)/core
INCLUDE += -I$(HL2SDK)/public/game/server
BINARY = sourcemod.2.css.so
override ENGSET = true
endif
ifeq "$(ENGINE)" "orangeboxvalve"
HL2SDK = $(HL2SDK_OB_VALVE)
HL2PUB = $(HL2SDK)/public
HL2LIB = $(HL2SDK)/lib/linux
CFLAGS += -DSOURCE_ENGINE=7
METAMOD = $(MMSOURCE)/core
INCLUDE += -I$(HL2SDK)/public/game/server
CFLAGS += -DSOURCE_ENGINE=4
METAMOD = $(MMSOURCE17)/core
INCLUDE += -I$(HL2SDK)/public/game/server -I$(HL2SDK)/common
SRCDS = $(SRCDS_BASE)/orangebox
BINARY = sourcemod.2.ep2v.so
override ENGSET = true
endif
ifeq "$(ENGINE)" "left4dead"
HL2SDK = $(HL2SDK_L4D)
HL2PUB = $(HL2SDK)/public
HL2LIB = $(HL2SDK)/lib/linux
CFLAGS += -DSOURCE_ENGINE=8
METAMOD = $(MMSOURCE)/core
CFLAGS += -DSOURCE_ENGINE=5
METAMOD = $(MMSOURCE17)/core
INCLUDE += -I$(HL2SDK)/public/game/server
SRCDS = $(SRCDS_BASE)/l4d
BINARY = sourcemod.2.l4d.so
override ENGSET = true
endif
ifeq "$(ENGINE)" "left4dead2"
HL2SDK = $(HL2SDK_L4D2)
HL2PUB = $(HL2SDK)/public
HL2LIB = $(HL2SDK)/lib/linux
CFLAGS += -DSOURCE_ENGINE=9
METAMOD = $(MMSOURCE)/core
CFLAGS += -DSOURCE_ENGINE=6
METAMOD = $(MMSOURCE17)/core
INCLUDE += -I$(HL2SDK)/public/game/server
SRCDS = $(SRCDS_BASE)/left4dead2
BINARY = sourcemod.2.l4d2.so
endif
ifeq "$(ENGINE)" "csgo"
HL2SDK = $(HL2SDK_CSGO)
HL2LIB = $(HL2SDK)/lib/linux
CFLAGS += -DSOURCE_ENGINE=12
METAMOD = $(MMSOURCE)/core
INCLUDE += -I$(HL2SDK)/public/game/server
BINARY = sourcemod.2.csgo.so
override ENGSET = true
endif
HL2PUB = $(HL2SDK)/public
CFLAGS += -DSE_EPISODEONE=1 -DSE_DARKMESSIAH=2 -DSE_ORANGEBOX=3 -DSE_ORANGEBOXVALVE=4 -DSE_LEFT4DEAD=5 -DSE_LEFT4DEAD2=6
OS := $(shell uname -s)
ifeq "$(OS)" "Darwin"
LIB_EXT = dylib
HL2LIB = $(HL2SDK)/lib/mac
ifeq "$(ENGINE)" "left4dead2"
LINK += $(HL2LIB)/tier1_i486.a $(HL2LIB)/mathlib_i486.a libvstdlib.so \
libtier0.so -static-libgcc
else
LIB_EXT = so
ifeq "$(ENGINE)" "original"
HL2LIB = $(HL2SDK)/linux_sdk
else
HL2LIB = $(HL2SDK)/lib/linux
endif
endif
ifneq (,$(filter original orangebox left4dead,$(ENGINE)))
LIB_SUFFIX = _i486.$(LIB_EXT)
else
LIB_PREFIX = lib
ifneq (,$(filter orangeboxvalve css,$(ENGINE)))
ifneq "$(OS)" "Darwin"
LIB_SUFFIX = _srv.$(LIB_EXT)
else
LIB_SUFFIX = .$(LIB_EXT)
endif
else
LIB_SUFFIX = .$(LIB_EXT)
endif
endif
CFLAGS += -DSE_EPISODEONE=1 -DSE_DARKMESSIAH=2 -DSE_ORANGEBOX=3 -DSE_BLOODYGOODTIME=4 -DSE_EYE=5 \
-DSE_CSS=6 -DSE_ORANGEBOXVALVE=7 -DSE_LEFT4DEAD=8 -DSE_LEFT4DEAD2=9 -DSE_ALIENSWARM=10 \
-DSE_PORTAL2=11 -DSE_CSGO=12
LINK += $(HL2LIB)/tier1_i486.a $(HL2LIB)/mathlib_i486.a $(LIB_PREFIX)vstdlib$(LIB_SUFFIX) \
$(LIB_PREFIX)tier0$(LIB_SUFFIX) -static-libgcc
ifeq "$(ENGINE)" "csgo"
LINK += $(HL2LIB)/interfaces_i486.a
LINK += $(HL2LIB)/tier1_i486.a $(HL2LIB)/mathlib_i486.a vstdlib_i486.so \
tier0_i486.so -static-libgcc
endif
INCLUDE += -I. -I.. -I$(HL2PUB) -I$(HL2PUB)/engine -I$(HL2PUB)/mathlib -I$(HL2PUB)/vstdlib \
-I$(HL2PUB)/tier0 -I$(HL2PUB)/tier1 -I$(METAMOD) -I$(METAMOD)/sourcehook \
-I$(SMSDK)/public -I$(SMSDK)/public/sourcepawn
CFLAGS += -D_LINUX -DPOSIX -Dstricmp=strcasecmp -D_stricmp=strcasecmp -D_strnicmp=strncasecmp -Dstrnicmp=strncasecmp \
CFLAGS += -D_LINUX -Dstricmp=strcasecmp -D_stricmp=strcasecmp -D_strnicmp=strncasecmp -Dstrnicmp=strncasecmp \
-D_snprintf=snprintf -D_vsnprintf=vsnprintf -D_alloca=alloca -Dstrcmpi=strcasecmp -Wall -Werror \
-Wno-uninitialized -Wno-unused -Wno-switch -mfpmath=sse -msse -DSOURCEMOD_BUILD -DHAVE_STDINT_H \
-DSM_DEFAULT_THREADER -m32 -DCOMPILER_GCC
CPPFLAGS += -Wno-non-virtual-dtor -Wno-overloaded-virtual -fno-threadsafe-statics -fno-exceptions -fno-rtti
-Wno-uninitialized -mfpmath=sse -msse -DSOURCEMOD_BUILD -DHAVE_STDINT_H -DSM_DEFAULT_THREADER -m32
CPPFLAGS += -Wno-non-virtual-dtor -fno-exceptions -fno-rtti
################################################
### DO NOT EDIT BELOW HERE FOR MOST PROJECTS ###
@@ -192,14 +153,18 @@ $(BIN_DIR)/%.o: %.c
all: check
mkdir -p $(BIN_DIR)
ln -sf $(HL2LIB)/$(LIB_PREFIX)vstdlib$(LIB_SUFFIX)
ln -sf $(HL2LIB)/$(LIB_PREFIX)tier0$(LIB_SUFFIX)
ifeq "$(ENGINE)" "left4dead2"
ln -sf $(SRCDS)/bin/libvstdlib.so libvstdlib.so;
ln -sf $(SRCDS)/bin/libtier0.so libtier0.so;
else
ln -sf $(SRCDS)/bin/vstdlib_i486.so vstdlib_i486.so;
ln -sf $(SRCDS)/bin/tier0_i486.so tier0_i486.so;
endif
$(MAKE) -f Makefile sourcemod
check:
if [ "$(ENGSET)" = "false" ]; then \
echo "You must supply one of the following values for ENGINE:"; \
echo "csgo, left4dead2, left4dead, orangeboxvalve, css, orangebox, or original"; \
echo "You must supply ENGINE=left4dead or ENGINE=orangebox or ENGINE=original"; \
exit 1; \
fi
@@ -2,7 +2,7 @@
* vim: set ts=4 sw=4 tw=99 noet :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2010 AlliedModders LLC. All rights reserved.
* Copyright (C) 2004-2009 AlliedModders LLC. All rights reserved.
* =============================================================================
*
* This program is free software; you can redistribute it and/or modify it under
@@ -28,39 +28,36 @@
*/
#include "MemoryUtils.h"
#include "ShareSys.h"
#ifdef PLATFORM_LINUX
#include <fcntl.h>
#include <link.h>
#include <sys/mman.h>
#define PAGE_SIZE 4096
#define PAGE_ALIGN_UP(x) ((x + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))
#endif
#ifdef PLATFORM_APPLE
#include <mach-o/dyld_images.h>
#include <mach-o/loader.h>
#include <mach-o/nlist.h>
#endif
//MemoryUtils g_MemUtils;
MemoryUtils g_MemUtils;
#if 0
MemoryUtils::MemoryUtils()
{
#ifdef PLATFORM_APPLE
#ifdef PLATFORM_WINDOWS
/* Get pointer to struct that describes all loaded mach-o images in process */
struct nlist list[2];
memset(list, 0, sizeof(list));
list[0].n_un.n_name = (char *)"_dyld_all_image_infos";
nlist("/usr/lib/dyld", list);
m_ImageList = (struct dyld_all_image_infos *)list[0].n_value;
SYSTEM_INFO info;
GetSystemInfo(&info);
m_PageSize = info.dwPageSize;
#elif defined PLATFORM_POSIX
m_PageSize = sysconf(_SC_PAGE_SIZE);
#endif
}
#endif
MemoryUtils::~MemoryUtils()
{
#if defined PLATFORM_LINUX || defined PLATFORM_APPLE
#ifdef PLATFORM_LINUX
for (size_t i = 0; i < m_SymTables.size(); i++)
{
delete m_SymTables[i];
@@ -69,10 +66,10 @@ MemoryUtils::~MemoryUtils()
#endif
}
/*void MemoryUtils::OnSourceModAllInitialized()
void MemoryUtils::OnSourceModAllInitialized()
{
sharesys->AddInterface(NULL, this);
}*/
g_ShareSys.AddInterface(NULL, this);
}
void *MemoryUtils::FindPattern(const void *libPtr, const char *pattern, size_t len)
{
@@ -116,7 +113,7 @@ void *MemoryUtils::ResolveSymbol(void *handle, const char *symbol)
#ifdef PLATFORM_WINDOWS
return GetProcAddress((HMODULE)handle, symbol);
#elif defined PLATFORM_LINUX
struct link_map *dlmap;
@@ -131,14 +128,12 @@ void *MemoryUtils::ResolveSymbol(void *handle, const char *symbol)
uint32_t symbol_count;
LibSymbolTable *libtable;
SymbolTable *table;
AddrTable *table2;
Symbol *symbol_entry;
dlmap = (struct link_map *)handle;
symtab_hdr = NULL;
strtab_hdr = NULL;
table = NULL;
table2 = NULL;
/* See if we already have a symbol table for this library */
for (size_t i = 0; i < m_SymTables.size(); i++)
@@ -147,7 +142,6 @@ void *MemoryUtils::ResolveSymbol(void *handle, const char *symbol)
if (libtable->lib_base == dlmap->l_addr)
{
table = &libtable->table;
table2 = &libtable->table2;
break;
}
}
@@ -157,11 +151,9 @@ void *MemoryUtils::ResolveSymbol(void *handle, const char *symbol)
{
libtable = new LibSymbolTable();
libtable->table.Initialize();
libtable->table2.Initialize();
libtable->lib_base = dlmap->l_addr;
libtable->last_pos = 0;
table = &libtable->table;
table2 = &libtable->table2;
m_SymTables.push_back(libtable);
}
@@ -245,173 +237,23 @@ void *MemoryUtils::ResolveSymbol(void *handle, const char *symbol)
/* Caching symbols as we go along */
cur_sym = table->InternSymbol(sym_name, strlen(sym_name), (void *)(dlmap->l_addr + sym.st_value));
table2->InternSymbol(sym_name, strlen(sym_name), (void *)(dlmap->l_addr + sym.st_value));
if (strcmp(symbol, sym_name) == 0)
{
symbol_entry = cur_sym;
libtable->last_pos = ++i;
// break;
break;
}
}
libtable->last_pos = symbol_count;
munmap(file_hdr, dlstat.st_size);
return symbol_entry ? symbol_entry->address : NULL;
#elif defined PLATFORM_APPLE
uintptr_t dlbase, linkedit_addr;
uint32_t image_count;
struct mach_header *file_hdr;
struct load_command *loadcmds;
struct segment_command *linkedit_hdr;
struct symtab_command *symtab_hdr;
struct nlist *symtab;
const char *strtab;
uint32_t loadcmd_count;
uint32_t symbol_count;
LibSymbolTable *libtable;
SymbolTable *table;
Symbol *symbol_entry;
dlbase = 0;
image_count = m_ImageList->infoArrayCount;
linkedit_hdr = NULL;
symtab_hdr = NULL;
table = NULL;
/* Loop through mach-o images in process.
* We can skip index 0 since that is just the executable.
*/
for (uint32_t i = 1; i < image_count; i++)
{
const struct dyld_image_info &info = m_ImageList->infoArray[i];
/* "Load" each one until we get a matching handle */
void *h = dlopen(info.imageFilePath, RTLD_NOLOAD);
if (h == handle)
{
dlbase = (uintptr_t)info.imageLoadAddress;
dlclose(h);
break;
}
dlclose(h);
}
if (!dlbase)
{
/* Uh oh, we couldn't find a matching handle */
return NULL;
}
/* See if we already have a symbol table for this library */
for (size_t i = 0; i < m_SymTables.size(); i++)
{
libtable = m_SymTables[i];
if (libtable->lib_base == dlbase)
{
table = &libtable->table;
break;
}
}
/* If we don't have a symbol table for this library, then create one */
if (table == NULL)
{
libtable = new LibSymbolTable();
libtable->table.Initialize();
libtable->lib_base = dlbase;
libtable->last_pos = 0;
table = &libtable->table;
m_SymTables.push_back(libtable);
}
/* See if the symbol is already cached in our table */
symbol_entry = table->FindSymbol(symbol, strlen(symbol));
if (symbol_entry != NULL)
{
return symbol_entry->address;
}
/* If symbol isn't in our table, then we have to locate it in memory */
file_hdr = (struct mach_header *)dlbase;
loadcmds = (struct load_command *)(dlbase + sizeof(struct mach_header));
loadcmd_count = file_hdr->ncmds;
/* Loop through load commands until we find the ones for the symbol table */
for (uint32_t i = 0; i < loadcmd_count; i++)
{
if (loadcmds->cmd == LC_SEGMENT && !linkedit_hdr)
{
struct segment_command *seg = (struct segment_command *)loadcmds;
if (strcmp(seg->segname, "__LINKEDIT") == 0)
{
linkedit_hdr = seg;
if (symtab_hdr)
{
break;
}
}
}
else if (loadcmds->cmd == LC_SYMTAB)
{
symtab_hdr = (struct symtab_command *)loadcmds;
if (linkedit_hdr)
{
break;
}
}
/* Load commands are not of a fixed size which is why we add the size */
loadcmds = (struct load_command *)((uintptr_t)loadcmds + loadcmds->cmdsize);
}
if (!linkedit_hdr || !symtab_hdr || !symtab_hdr->symoff || !symtab_hdr->stroff)
{
/* Uh oh, no symbol table */
return NULL;
}
linkedit_addr = dlbase + linkedit_hdr->vmaddr;
symtab = (struct nlist *)(linkedit_addr + symtab_hdr->symoff - linkedit_hdr->fileoff);
strtab = (const char *)(linkedit_addr + symtab_hdr->stroff - linkedit_hdr->fileoff);
symbol_count = symtab_hdr->nsyms;
/* Iterate symbol table starting from the position we were at last time */
for (uint32_t i = libtable->last_pos; i < symbol_count; i++)
{
struct nlist &sym = symtab[i];
/* Ignore the prepended underscore on all symbols, so +1 here */
const char *sym_name = strtab + sym.n_un.n_strx + 1;
Symbol *cur_sym;
/* Skip symbols that are undefined */
if (sym.n_sect == NO_SECT)
{
continue;
}
/* Caching symbols as we go along */
cur_sym = table->InternSymbol(sym_name, strlen(sym_name), (void *)(dlbase + sym.n_value));
if (strcmp(symbol, sym_name) == 0)
{
symbol_entry = cur_sym;
libtable->last_pos = ++i;
break;
}
}
return symbol_entry ? symbol_entry->address : NULL;
#endif
}
bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
{
uintptr_t baseAddr;
unsigned long baseAddr;
if (libPtr == NULL)
{
@@ -431,7 +273,7 @@ bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
return false;
}
baseAddr = reinterpret_cast<uintptr_t>(info.AllocationBase);
baseAddr = reinterpret_cast<unsigned long>(info.AllocationBase);
/* All this is for our insane sanity checks :o */
dos = reinterpret_cast<IMAGE_DOS_HEADER *>(baseAddr);
@@ -480,7 +322,7 @@ bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
}
/* This is for our insane sanity checks :o */
baseAddr = reinterpret_cast<uintptr_t>(info.dli_fbase);
baseAddr = reinterpret_cast<unsigned long>(info.dli_fbase);
file = reinterpret_cast<Elf32_Ehdr *>(baseAddr);
/* Check ELF magic */
@@ -511,105 +353,21 @@ bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
phdrCount = file->e_phnum;
phdr = reinterpret_cast<Elf32_Phdr *>(baseAddr + file->e_phoff);
/* Add up the memory sizes of segments marked as PT_LOAD as those are the only ones that should be in memory */
for (uint16_t i = 0; i < phdrCount; i++)
{
Elf32_Phdr &hdr = phdr[i];
/* We only really care about the segment with executable code */
if (hdr.p_type == PT_LOAD && hdr.p_flags == (PF_X|PF_R))
if (hdr.p_type == PT_LOAD)
{
/* From glibc, elf/dl-load.c:
* c->mapend = ((ph->p_vaddr + ph->p_filesz + GLRO(dl_pagesize) - 1)
* & ~(GLRO(dl_pagesize) - 1));
*
* In glibc, the segment file size is aligned up to the nearest page size and
* added to the virtual address of the segment. We just want the size here.
*/
lib.memorySize = PAGE_ALIGN_UP(hdr.p_filesz);
break;
lib.memorySize += hdr.p_memsz;
}
}
#elif defined PLATFORM_APPLE
Dl_info info;
struct mach_header *file;
struct segment_command *seg;
uint32_t cmd_count;
if (!dladdr(libPtr, &info))
{
return false;
}
if (!info.dli_fbase || !info.dli_fname)
{
return false;
}
/* This is for our insane sanity checks :o */
baseAddr = (uintptr_t)info.dli_fbase;
file = (struct mach_header *)baseAddr;
/* Check Mach-O magic */
if (file->magic != MH_MAGIC)
{
return false;
}
/* Check architecture (32-bit/x86) */
if (file->cputype != CPU_TYPE_I386 || file->cpusubtype != CPU_SUBTYPE_I386_ALL)
{
return false;
}
/* For our purposes, this must be a dynamic library */
if (file->filetype != MH_DYLIB)
{
return false;
}
cmd_count = file->ncmds;
seg = (struct segment_command *)(baseAddr + sizeof(struct mach_header));
/* Add up memory sizes of mapped segments */
for (uint32_t i = 0; i < cmd_count; i++)
{
if (seg->cmd == LC_SEGMENT)
{
lib.memorySize += seg->vmsize;
}
seg = (struct segment_command *)((uintptr_t)seg + seg->cmdsize);
}
#endif
lib.baseAddress = reinterpret_cast<void *>(baseAddr);
return true;
}
const char* MemoryUtils::ResolveAddr(void *handle, void* addr)
{
struct link_map *dlmap;
dlmap = (struct link_map *)handle;
LibSymbolTable *libtable;
AddrTable *table2;
for (size_t i = 0; i < m_SymTables.size(); i++)
{
libtable = m_SymTables[i];
if (libtable->lib_base == dlmap->l_addr)
{
table2 = &libtable->table2;
break;
}
}
if (table2 == NULL) return NULL;
Symbol *sym = table2->FindAddr(addr);
return sym ? sym->buffer() : NULL;
}
@@ -2,7 +2,7 @@
* vim: set ts=4 sw=4 tw=99 noet :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2011 AlliedModders LLC. All rights reserved.
* Copyright (C) 2004-2000 AlliedModders LLC. All rights reserved.
* =============================================================================
*
* This program is free software; you can redistribute it and/or modify it under
@@ -30,9 +30,9 @@
#ifndef _INCLUDE_SOURCEMOD_MEMORYUTILS_H_
#define _INCLUDE_SOURCEMOD_MEMORYUTILS_H_
#include "common_logic.h"
#include <IMemoryUtils.h>
#if defined PLATFORM_LINUX || defined PLATFORM_APPLE
#include "sm_globals.h"
#ifdef PLATFORM_LINUX
#include <sh_vector.h>
#include "sm_symtable.h"
@@ -41,21 +41,19 @@ using namespace SourceHook;
using namespace SourceMod;
#ifdef PLATFORM_APPLE
#include <CoreServices/CoreServices.h>
#endif
struct DynLibInfo
{
void *baseAddress;
size_t memorySize;
};
#if defined PLATFORM_LINUX || defined PLATFORM_APPLE
#ifdef PLATFORM_LINUX
typedef uint32_t Elf32_Addr;
struct LibSymbolTable
{
SymbolTable table;
uintptr_t lib_base;
Elf32_Addr lib_base;
uint32_t last_pos;
};
#endif
@@ -65,7 +63,6 @@ class MemoryUtils :
public SMGlobalClass
{
public:
MemoryUtils();
~MemoryUtils();
public: // SMGlobalClass
void OnSourceModAllInitialized();
@@ -74,14 +71,9 @@ public: // IMemoryUtils
void *ResolveSymbol(void *handle, const char *symbol);
public:
bool GetLibraryInfo(const void *libPtr, DynLibInfo &lib);
#if defined PLATFORM_LINUX || defined PLATFORM_APPLE
#ifdef PLATFORM_LINUX
private:
CVector<LibSymbolTable *> m_SymTables;
#ifdef PLATFORM_APPLE
struct dyld_all_image_infos *m_ImageList;
SInt32 m_OSXMajor;
SInt32 m_OSXMinor;
#endif
#endif
};
+17 -35
View File
@@ -38,8 +38,10 @@
#include "sourcemm_api.h"
#include "PlayerManager.h"
#include "MenuStyle_Valve.h"
#include "ShareSys.h"
#include "HandleSys.h"
#include "sourcemm_api.h"
#include "logic_bridge.h"
#include "Translator.h"
MenuManager g_Menus;
VoteMenuHandler s_VoteHandler;
@@ -54,24 +56,24 @@ MenuManager::MenuManager()
void MenuManager::OnSourceModAllInitialized()
{
sharesys->AddInterface(NULL, this);
g_ShareSys.AddInterface(NULL, this);
HandleAccess access;
handlesys->InitAccessDefaults(NULL, &access);
g_HandleSys.InitAccessDefaults(NULL, &access);
/* Deny cloning to menus */
access.access[HandleAccess_Clone] = HANDLE_RESTRICT_OWNER|HANDLE_RESTRICT_IDENTITY;
m_MenuType = handlesys->CreateType("IBaseMenu", this, 0, NULL, &access, g_pCoreIdent, NULL);
m_MenuType = g_HandleSys.CreateType("IBaseMenu", this, 0, NULL, &access, g_pCoreIdent, NULL);
/* Also deny deletion to styles */
access.access[HandleAccess_Delete] = HANDLE_RESTRICT_OWNER|HANDLE_RESTRICT_IDENTITY;
m_StyleType = handlesys->CreateType("IMenuStyle", this, 0, NULL, &access, g_pCoreIdent, NULL);
m_StyleType = g_HandleSys.CreateType("IMenuStyle", this, 0, NULL, &access, g_pCoreIdent, NULL);
}
void MenuManager::OnSourceModAllShutdown()
{
handlesys->RemoveType(m_MenuType, g_pCoreIdent);
handlesys->RemoveType(m_StyleType, g_pCoreIdent);
g_HandleSys.RemoveType(m_MenuType, g_pCoreIdent);
g_HandleSys.RemoveType(m_StyleType, g_pCoreIdent);
}
void MenuManager::OnHandleDestroy(HandleType_t type, void *object)
@@ -110,7 +112,7 @@ Handle_t MenuManager::CreateMenuHandle(IBaseMenu *menu, IdentityToken_t *pOwner)
return BAD_HANDLE;
}
return handlesys->CreateHandle(m_MenuType, menu, pOwner, g_pCoreIdent, NULL);
return g_HandleSys.CreateHandle(m_MenuType, menu, pOwner, g_pCoreIdent, NULL);
}
Handle_t MenuManager::CreateStyleHandle(IMenuStyle *style)
@@ -120,7 +122,7 @@ Handle_t MenuManager::CreateStyleHandle(IMenuStyle *style)
return BAD_HANDLE;
}
return handlesys->CreateHandle(m_StyleType, style, g_pCoreIdent, g_pCoreIdent, NULL);
return g_HandleSys.CreateHandle(m_StyleType, style, g_pCoreIdent, g_pCoreIdent, NULL);
}
HandleError MenuManager::ReadMenuHandle(Handle_t handle, IBaseMenu **menu)
@@ -130,7 +132,7 @@ HandleError MenuManager::ReadMenuHandle(Handle_t handle, IBaseMenu **menu)
sec.pIdentity = g_pCoreIdent;
sec.pOwner = NULL;
return handlesys->ReadHandle(handle, m_MenuType, &sec, (void **)menu);
return g_HandleSys.ReadHandle(handle, m_MenuType, &sec, (void **)menu);
}
HandleError MenuManager::ReadStyleHandle(Handle_t handle, IMenuStyle **style)
@@ -140,7 +142,7 @@ HandleError MenuManager::ReadStyleHandle(Handle_t handle, IMenuStyle **style)
sec.pIdentity = g_pCoreIdent;
sec.pOwner = g_pCoreIdent;
return handlesys->ReadHandle(handle, m_StyleType, &sec, (void **)style);
return g_HandleSys.ReadHandle(handle, m_StyleType, &sec, (void **)style);
}
bool MenuManager::SetDefaultStyle(IMenuStyle *style)
@@ -229,7 +231,6 @@ IMenuPanel *MenuManager::RenderMenu(int client, menu_states_t &md, ItemOrder ord
unsigned int pgn = menu->GetPagination();
unsigned int maxItems = style->GetMaxPageItems();
bool exitButton = (menu->GetMenuOptionFlags() & MENUFLAG_BUTTON_EXIT) == MENUFLAG_BUTTON_EXIT;
bool novoteButton = (menu->GetMenuOptionFlags() & MENUFLAG_BUTTON_NOVOTE) == MENUFLAG_BUTTON_NOVOTE;
if (pgn != MENU_NO_PAGINATION)
{
@@ -240,11 +241,6 @@ IMenuPanel *MenuManager::RenderMenu(int client, menu_states_t &md, ItemOrder ord
maxItems--;
}
if (novoteButton)
{
maxItems--;
}
/* This is very not allowed! */
if (maxItems < 2)
{
@@ -440,20 +436,6 @@ skip_search:
/* Draw the item according to the order */
menu_slots_t *slots = md.slots;
unsigned int position = 0; /* Keep track of the last position */
if (novoteButton)
{
char text[50];
if (!logicore.CoreTranslate(text, sizeof(text), "%T", 2, NULL, "No Vote", &client))
{
UTIL_Format(text, sizeof(text), "No Vote");
}
ItemDrawInfo dr(text, 0);
position = panel->DrawItem(dr);
slots[position].type = ItemSel_Exit;
position++;
}
if (order == ItemOrder_Ascending)
{
md.item_on_page = drawItems[0].position;
@@ -604,7 +586,7 @@ skip_search:
{
if (exitBackButton)
{
if (!logicore.CoreTranslate(text, sizeof(text), "%T", 2, NULL, "Back", &client))
if (!CoreTranslate(text, sizeof(text), "%T", 2, NULL, "Back", &client))
{
UTIL_Format(text, sizeof(text), "Back");
}
@@ -614,7 +596,7 @@ skip_search:
}
else
{
if (!logicore.CoreTranslate(text, sizeof(text), "%T", 2, NULL, "Previous", &client))
if (!CoreTranslate(text, sizeof(text), "%T", 2, NULL, "Previous", &client))
{
UTIL_Format(text, sizeof(text), "Previous");
}
@@ -635,7 +617,7 @@ skip_search:
/* NEXT */
if (displayNext || canDrawDisabled)
{
if (!logicore.CoreTranslate(text, sizeof(text), "%T", 2, NULL, "Next", &client))
if (!CoreTranslate(text, sizeof(text), "%T", 2, NULL, "Next", &client))
{
UTIL_Format(text, sizeof(text), "Next");
}
@@ -666,7 +648,7 @@ skip_search:
/* EXIT */
if (exitButton)
{
if (!logicore.CoreTranslate(text, sizeof(text), "%T", 2, NULL, "Exit", &client))
if (!CoreTranslate(text, sizeof(text), "%T", 2, NULL, "Exit", &client))
{
UTIL_Format(text, sizeof(text), "Exit");
}
+1
View File
@@ -37,6 +37,7 @@
#include <sh_stack.h>
#include <sh_list.h>
#include <sh_string.h>
#include "sm_memtable.h"
#include "sm_globals.h"
using namespace SourceMod;
+46 -37
View File
@@ -1,5 +1,5 @@
/**
* vim: set ts=4 sw=4 tw=99 noet :
* vim: set ts=4 :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
@@ -34,12 +34,11 @@
#include "MenuStyle_Base.h"
#include "PlayerManager.h"
#include "MenuManager.h"
#include "HandleSys.h"
#include "CellRecipientFilter.h"
#if defined MENU_DEBUG
#include "Logger.h"
#endif
#include "logic_bridge.h"
#include "AutoHandleRooter.h"
BaseMenuStyle::BaseMenuStyle() : m_WatchList(256), m_hHandle(BAD_HANDLE)
{
@@ -323,24 +322,15 @@ void BaseMenuStyle::ClientPressedKey(int client, unsigned int key_press)
if (pCollideable)
{
const Vector & pos = pCollideable->GetCollisionOrigin();
enginesound->EmitSound(filter,
client,
CHAN_AUTO,
#if SOURCE_ENGINE >= SE_PORTAL2
sound,
-1,
#endif
sound,
VOL_NORM,
ATTN_NORM,
#if SOURCE_ENGINE >= SE_PORTAL2
0,
#endif
0,
PITCH_NORM,
#if SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_SDK2013 || SOURCE_ENGINE == SE_TF2
0,
#endif
&pos);
}
}
@@ -387,9 +377,6 @@ void BaseMenuStyle::ClientPressedKey(int client, unsigned int key_press)
RemoveClientFromWatch(client);
}
Handle_t hndl = menu ? menu->GetHandle() : BAD_HANDLE;
AutoHandleRooter ahr(hndl);
if (cancel)
{
mh->OnMenuCancel(menu, client, reason);
@@ -604,7 +591,7 @@ bool BaseMenuStyle::RedoClientMenu(int client, ItemOrder order)
}
CBaseMenu::CBaseMenu(IMenuHandler *pHandler, IMenuStyle *pStyle, IdentityToken_t *pOwner) :
m_pStyle(pStyle), m_Pagination(7), m_bShouldDelete(false), m_bCancelling(false),
m_pStyle(pStyle), m_Strings(512), m_Pagination(7), m_bShouldDelete(false), m_bCancelling(false),
m_pOwner(pOwner ? pOwner : g_pCoreIdent), m_bDeleting(false), m_bWillFreeHandle(false),
m_hHandle(BAD_HANDLE), m_pHandler(pHandler), m_nFlags(MENUFLAG_BUTTON_EXIT)
{
@@ -627,74 +614,94 @@ Handle_t CBaseMenu::GetHandle()
bool CBaseMenu::AppendItem(const char *info, const ItemDrawInfo &draw)
{
if (m_Pagination == (unsigned)MENU_NO_PAGINATION
&& m_items.length() >= m_pStyle->GetMaxPageItems())
&& m_items.size() >= m_pStyle->GetMaxPageItems())
{
return false;
}
CItem item;
item.info = info;
item.infoString = m_Strings.AddString(info);
if (draw.display)
item.display = new ke::AString(draw.display);
{
item.displayString = m_Strings.AddString(draw.display);
}
item.style = draw.style;
m_items.append(ke::Move(item));
m_items.push_back(item);
return true;
}
bool CBaseMenu::InsertItem(unsigned int position, const char *info, const ItemDrawInfo &draw)
{
if (m_Pagination == (unsigned)MENU_NO_PAGINATION &&
m_items.length() >= m_pStyle->GetMaxPageItems())
if (m_Pagination == (unsigned)MENU_NO_PAGINATION
&& m_items.size() >= m_pStyle->GetMaxPageItems())
{
return false;
}
if (position >= m_items.length())
if (position >= m_items.size())
{
return false;
}
CItem item;
item.info = info;
item.infoString = m_Strings.AddString(info);
if (draw.display)
item.display = new ke::AString(draw.display);
{
item.displayString = m_Strings.AddString(draw.display);
}
item.style = draw.style;
m_items.insert(position, ke::Move(item));
CVector<CItem>::iterator iter = m_items.iterAt(position);
m_items.insert(iter, item);
return true;
}
bool CBaseMenu::RemoveItem(unsigned int position)
{
if (position >= m_items.length())
if (position >= m_items.size())
{
return false;
}
m_items.erase(m_items.iterAt(position));
if (m_items.size() == 0)
{
m_Strings.Reset();
}
m_items.remove(position);
return true;
}
void CBaseMenu::RemoveAllItems()
{
m_items.clear();
m_Strings.Reset();
}
const char *CBaseMenu::GetItemInfo(unsigned int position, ItemDrawInfo *draw/* =NULL */)
{
if (position >= m_items.length())
if (position >= m_items.size())
{
return NULL;
}
if (draw)
{
draw->display = m_items[position].display->chars();
draw->display = m_Strings.GetString(m_items[position].displayString);
draw->style = m_items[position].style;
}
return m_items[position].info.chars();
return m_Strings.GetString(m_items[position].infoString);
}
unsigned int CBaseMenu::GetItemCount()
{
return m_items.length();
return m_items.size();
}
bool CBaseMenu::SetPagination(unsigned int itemsPerPage)
@@ -727,12 +734,12 @@ IMenuStyle *CBaseMenu::GetDrawStyle()
void CBaseMenu::SetDefaultTitle(const char *message)
{
m_Title = message;
m_Title.assign(message);
}
const char *CBaseMenu::GetDefaultTitle()
{
return m_Title.chars();
return m_Title.c_str();
}
void CBaseMenu::Cancel()
@@ -799,7 +806,7 @@ void CBaseMenu::InternalDelete()
m_hHandle = BAD_HANDLE;
m_bDeleting = true;
handlesys->FreeHandle(hndl, &sec);
g_HandleSys.FreeHandle(hndl, &sec);
}
m_pHandler->OnMenuDestroy(this);
@@ -824,5 +831,7 @@ IMenuHandler *CBaseMenu::GetHandler()
unsigned int CBaseMenu::GetBaseMemUsage()
{
return m_Title.length() + (m_items.length() * sizeof(CItem));
return m_Title.size()
+ m_Strings.GetMemTable()->GetMemUsage()
+ (m_items.size() * sizeof(CItem));
}
+12 -27
View File
@@ -1,5 +1,5 @@
/**
* vim: set ts=4 sw=4 tw=99 noet :
* vim: set ts=4 :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
@@ -34,45 +34,29 @@
#include <IMenuManager.h>
#include <IPlayerHelpers.h>
#include <am-string.h>
#include <am-vector.h>
#include <sh_string.h>
#include <sh_vector.h>
#include "sm_memtable.h"
#include "sm_fastlink.h"
using namespace SourceMod;
using namespace SourceHook;
class CItem
{
public:
CItem()
{
infoString = -1;
displayString = -1;
style = 0;
access = 0;
}
CItem(ke::Moveable<CItem> other)
: info(ke::Move(other->info)),
display(ke::Move(other->display))
{
style = other->style;
access = other->access;
}
CItem & operator =(ke::Moveable<CItem> other)
{
info = ke::Move(other->info);
display = ke::Move(other->display);
style = other->style;
access = other->access;
return *this;
}
public:
ke::AString info;
ke::AutoPtr<ke::AString> display;
int infoString;
int displayString;
unsigned int style;
unsigned int access;
private:
CItem(const CItem &other) KE_DELETE;
CItem &operator =(const CItem &other) KE_DELETE;
};
class CBaseMenuPlayer
@@ -155,10 +139,11 @@ public:
private:
void InternalDelete();
protected:
ke::AString m_Title;
String m_Title;
IMenuStyle *m_pStyle;
BaseStringTable m_Strings;
unsigned int m_Pagination;
ke::Vector<CItem> m_items;
CVector<CItem> m_items;
bool m_bShouldDelete;
bool m_bCancelling;
IdentityToken_t *m_pOwner;
+18 -83
View File
@@ -32,20 +32,11 @@
#include "MenuStyle_Radio.h"
#include "sm_stringutil.h"
#include "UserMessages.h"
#include <IGameConfigs.h>
#include "GameConfigs.h"
#include "PlayerManager.h"
#if defined MENU_DEBUG
#include "Logger.h"
#endif
#include "logic_bridge.h"
#ifdef USE_PROTOBUF_USERMESSAGES
#include <google/protobuf/descriptor.h>
#endif
#if SOURCE_ENGINE == SE_CSGO
#include <game/shared/csgo/protobuf/cstrike15_usermessages.pb.h>
#endif
extern const char *g_RadioNumTable[];
CRadioStyle g_RadioMenuStyle;
@@ -53,14 +44,6 @@ int g_ShowMenuId = -1;
bool g_bRadioInit = false;
unsigned int g_RadioMenuTimeout = 0;
// back, next, exit
#define MAX_PAGINATION_OPTIONS 3
#define MAX_MENUSLOT_KEYS 10
static unsigned int s_RadioMaxPageItems = MAX_MENUSLOT_KEYS;
CRadioStyle::CRadioStyle()
{
m_players = new CRadioMenuPlayer[256+1];
@@ -83,10 +66,6 @@ void CRadioStyle::OnSourceModLevelChange(const char *mapName)
}
g_bRadioInit = true;
// Always register the style. Use IsSupported() to check for validity before use.
g_Menus.AddStyle(this);
const char *msg = g_pGameConf->GetKeyValue("HudRadioMenuMsg");
if (!msg || msg[0] == '\0')
{
@@ -110,18 +89,7 @@ void CRadioStyle::OnSourceModLevelChange(const char *mapName)
g_RadioMenuTimeout = 0;
}
const char *items = g_pGameConf->GetKeyValue("RadioMenuMaxPageItems");
if (items != NULL)
{
int value = atoi(items);
// Only override the mostly-safe default if it's a sane value
if (value > MAX_PAGINATION_OPTIONS && value <= MAX_MENUSLOT_KEYS)
{
s_RadioMaxPageItems = value;
}
}
g_Menus.AddStyle(this);
g_Menus.SetDefaultStyle(this);
g_UserMsgs.HookUserMessage(g_ShowMenuId, this, false);
@@ -141,11 +109,7 @@ void CRadioStyle::OnSourceModShutdown()
bool CRadioStyle::IsSupported()
{
#if SOURCE_ENGINE == SE_DOTA
return false;
#else
return (g_ShowMenuId != -1);
#endif
}
bool CRadioStyle::OnClientCommand(int client, const char *cmdname, const CCommand &cmd)
@@ -170,23 +134,13 @@ static unsigned int g_last_holdtime = 0;
static unsigned int g_last_client_count = 0;
static int g_last_clients[256];
#ifdef USE_PROTOBUF_USERMESSAGES
void CRadioStyle::OnUserMessage(int msg_id, protobuf::Message &msg, IRecipientFilter *pFilter)
#else
void CRadioStyle::OnUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter)
#endif
{
#if SOURCE_ENGINE != SE_DOTA
int count = pFilter->GetRecipientCount();
#ifdef USE_PROTOBUF_USERMESSAGES
int c = ((CCSUsrMsg_ShowMenu &)msg).display_time();
#else
bf_read br(bf->GetBasePointer(), 3);
br.ReadWord();
int c = br.ReadChar();
#endif
g_last_holdtime = (c == -1) ? 0 : (unsigned)c;
@@ -194,7 +148,6 @@ void CRadioStyle::OnUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFil
{
g_last_clients[g_last_client_count++] = pFilter->GetRecipientIndex(i);
}
#endif
}
void CRadioStyle::OnUserMessageSent(int msg_id)
@@ -235,7 +188,7 @@ IBaseMenu *CRadioStyle::CreateMenu(IMenuHandler *pHandler, IdentityToken_t *pOwn
unsigned int CRadioStyle::GetMaxPageItems()
{
return s_RadioMaxPageItems;
return 10;
}
const char *CRadioStyle::GetStyleName()
@@ -264,6 +217,15 @@ CRadioDisplay *CRadioStyle::MakeRadioDisplay(CRadioMenu *menu)
return display;
}
IMenuPanel *CRadioStyle::MakeRadioDisplay(const char *str, int keys)
{
CRadioDisplay *pPanel = MakeRadioDisplay(NULL);
pPanel->DirectSet(str, keys);
return pPanel;
}
void CRadioStyle::FreeRadioDisplay(CRadioDisplay *display)
{
m_FreeDisplays.push(display);
@@ -330,12 +292,11 @@ void CRadioDisplay::Reset()
keys = 0;
}
bool CRadioDisplay::DirectSet(const char *str)
void CRadioDisplay::DirectSet(const char *str, int keymap)
{
m_Title.clear();
m_BufferText.assign(str);
return true;
keys = keymap;
}
unsigned int CRadioDisplay::GetCurrentKey()
@@ -345,7 +306,7 @@ unsigned int CRadioDisplay::GetCurrentKey()
bool CRadioDisplay::SetCurrentKey(unsigned int key)
{
if (key < m_NextPos || m_NextPos > s_RadioMaxPageItems)
if (key < m_NextPos || m_NextPos > 10)
{
return false;
}
@@ -381,7 +342,7 @@ void CRadioDisplay::DrawTitle(const char *text, bool onlyIfEmpty/* =false */)
unsigned int CRadioDisplay::DrawItem(const ItemDrawInfo &item)
{
if (m_NextPos > s_RadioMaxPageItems || !CanDrawItem(item.style))
if (m_NextPos > 10 || !CanDrawItem(item.style))
{
return 0;
}
@@ -474,8 +435,7 @@ void CRadioMenuPlayer::Radio_Init(int keys, const char *title, const char *text)
void CRadioMenuPlayer::Radio_Refresh()
{
#if SOURCE_ENGINE != SE_DOTA
cell_t players[1] = { (cell_t)m_index };
cell_t players[1] = {m_index};
char *ptr = display_pkt;
char save = 0;
size_t len = display_len;
@@ -491,15 +451,6 @@ void CRadioMenuPlayer::Radio_Refresh()
time = menuHoldTime - (unsigned int)(gpGlobals->curtime - menuStartTime);
}
#ifdef USE_PROTOBUF_USERMESSAGES
// If or when we need to support multiple games per engine with this, we can switch to reflection
// TODO: find what happens past 240 on CS:GO
CCSUsrMsg_ShowMenu *msg = (CCSUsrMsg_ShowMenu *)g_UserMsgs.StartProtobufMessage(g_ShowMenuId, players, 1, USERMSG_BLOCKHOOKS);
msg->set_bits_valid_slots(display_keys);
msg->set_display_time(time);
msg->set_menu_string(ptr);
g_UserMsgs.EndMessage();
#else
while (true)
{
if (len > 240)
@@ -507,8 +458,7 @@ void CRadioMenuPlayer::Radio_Refresh()
save = ptr[240];
ptr[240] = '\0';
}
bf_write *buffer = g_UserMsgs.StartBitBufMessage(g_ShowMenuId, players, 1, USERMSG_BLOCKHOOKS);
bf_write *buffer = g_UserMsgs.StartMessage(g_ShowMenuId, players, 1, USERMSG_BLOCKHOOKS);
buffer->WriteWord(display_keys);
buffer->WriteChar(time ? time : -1);
buffer->WriteByte( (len > 240) ? 1 : 0 );
@@ -525,10 +475,8 @@ void CRadioMenuPlayer::Radio_Refresh()
break;
}
}
#endif
display_last_refresh = gpGlobals->curtime;
#endif // !DOTA
}
int CRadioDisplay::GetAmountRemaining()
@@ -562,7 +510,6 @@ unsigned int CRadioDisplay::GetApproxMemUsage()
CRadioMenu::CRadioMenu(IMenuHandler *pHandler, IdentityToken_t *pOwner) :
CBaseMenu(pHandler, &g_RadioMenuStyle, pOwner)
{
m_Pagination = s_RadioMaxPageItems - MAX_PAGINATION_OPTIONS;
}
bool CRadioMenu::SetExtOption(MenuOption option, const void *valuePtr)
@@ -596,7 +543,6 @@ bool CRadioMenu::DisplayAtItem(int client,
return false;
}
AutoHandleRooter ahr(this->GetHandle());
return g_RadioMenuStyle.DoClientMenu(client,
this,
start_item,
@@ -604,17 +550,6 @@ bool CRadioMenu::DisplayAtItem(int client,
time);
}
bool CRadioMenu::SetPagination(unsigned int itemsPerPage)
{
const unsigned int maxPerPage = s_RadioMaxPageItems - MAX_PAGINATION_OPTIONS;
if (itemsPerPage > maxPerPage)
{
return false;
}
return CBaseMenu::SetPagination(itemsPerPage);
}
void CRadioMenu::Cancel_Finally()
{
g_RadioMenuStyle.CancelMenu(this);
+5 -14
View File
@@ -37,12 +37,10 @@
#include "MenuStyle_Base.h"
#include "sourcemm_api.h"
#include <IPlayerHelpers.h>
#include "UserMessages.h"
#include <IUserMessages.h>
#include "sm_fastlink.h"
#include <sh_stack.h>
#include <compat_wrappers.h>
#include "logic/common_logic.h"
#include "AutoHandleRooter.h"
using namespace SourceMod;
@@ -67,11 +65,7 @@ private:
class CRadioStyle :
public BaseMenuStyle,
public SMGlobalClass,
#ifdef USE_PROTOBUF_USERMESSAGES
public IProtobufUserMessageListener
#else
public IBitBufUserMessageListener
#endif
public IUserMessageListener
{
public:
CRadioStyle();
@@ -90,11 +84,7 @@ public: //IMenuStyle
unsigned int GetMaxPageItems();
unsigned int GetApproxMemUsage();
public: //IUserMessageListener
#ifdef USE_PROTOBUF_USERMESSAGES
void OnUserMessage(int msg_id, protobuf::Message &msg, IRecipientFilter *pFilter);
#else
void OnUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter);
#endif
void OnUserMessageSent(int msg_id);
public:
bool IsSupported();
@@ -103,6 +93,7 @@ public:
CRadioDisplay *MakeRadioDisplay(CRadioMenu *menu=NULL);
void FreeRadioDisplay(CRadioDisplay *display);
CRadioMenuPlayer *GetRadioMenuPlayer(int client);
IMenuPanel *MakeRadioDisplay(const char *str, int keys);
private:
CRadioMenuPlayer *m_players;
CStack<CRadioDisplay *> m_FreeDisplays;
@@ -130,7 +121,8 @@ public: //IMenuPanel
bool SetCurrentKey(unsigned int key);
int GetAmountRemaining();
unsigned int GetApproxMemUsage();
bool DirectSet(const char *str);
public:
void DirectSet(const char *str, int keymap);
private:
String m_BufferText;
String m_Title;
@@ -150,7 +142,6 @@ public:
unsigned int time,
unsigned int start_item,
IMenuHandler *alt_handler/* =NULL */);
bool SetPagination(unsigned int itemsPerPage);
void Cancel_Finally();
unsigned int GetApproxMemUsage();
};
+3 -7
View File
@@ -32,6 +32,7 @@
#include "sm_stringutil.h"
#include "PlayerManager.h"
#include "MenuStyle_Valve.h"
#include "Translator.h"
#include "PlayerManager.h"
#include "ConCmdManager.h"
@@ -65,20 +66,16 @@ bool ValveMenuStyle::OnClientCommand(int client, const char *cmdname, const CCom
void ValveMenuStyle::OnSourceModAllInitialized()
{
#if SOURCE_ENGINE != SE_DOTA
g_Players.AddClientListener(this);
SH_ADD_HOOK(IServerPluginHelpers, CreateMessage, serverpluginhelpers, SH_MEMBER(this, &ValveMenuStyle::HookCreateMessage), false);
SH_ADD_HOOK_MEMFUNC(IServerPluginHelpers, CreateMessage, serverpluginhelpers, this, &ValveMenuStyle::HookCreateMessage, false);
g_pSPHCC = SH_GET_CALLCLASS(serverpluginhelpers);
#endif
}
void ValveMenuStyle::OnSourceModShutdown()
{
#if SOURCE_ENGINE != SE_DOTA
SH_RELEASE_CALLCLASS(g_pSPHCC);
SH_REMOVE_HOOK(IServerPluginHelpers, CreateMessage, serverpluginhelpers, SH_MEMBER(this, &ValveMenuStyle::HookCreateMessage), false);
SH_REMOVE_HOOK_MEMFUNC(IServerPluginHelpers, CreateMessage, serverpluginhelpers, this, &ValveMenuStyle::HookCreateMessage, false);
g_Players.RemoveClientListener(this);
#endif
}
void ValveMenuStyle::HookCreateMessage(edict_t *pEdict,
@@ -408,7 +405,6 @@ bool CValveMenu::DisplayAtItem(int client,
return false;
}
AutoHandleRooter ahr(this->GetHandle());
return g_ValveMenuStyle.DoClientMenu(client, this, start_item, alt_handler ? alt_handler : m_pHandler, time);
}
-4
View File
@@ -39,8 +39,6 @@
#include "KeyValues.h"
#include "sm_fastlink.h"
#include <compat_wrappers.h>
#include "logic/common_logic.h"
#include "AutoHandleRooter.h"
using namespace SourceMod;
@@ -77,7 +75,6 @@ public: //IMenuStyle
IBaseMenu *CreateMenu(IMenuHandler *pHandler, IdentityToken_t *pOwner);
unsigned int GetMaxPageItems();
unsigned int GetApproxMemUsage();
bool IsSupported() { return true; }
private:
void HookCreateMessage(edict_t *pEdict, DIALOG_TYPE type, KeyValues *kv, IServerPluginCallbacks *plugin);
private:
@@ -108,7 +105,6 @@ public:
bool SetCurrentKey(unsigned int key);
int GetAmountRemaining();
unsigned int GetApproxMemUsage();
bool DirectSet(const char *str) { return false; }
private:
KeyValues *m_pKv;
unsigned int m_NextPos;
+8 -13
View File
@@ -39,8 +39,7 @@
#include <HalfLife2.h>
#include <mathlib.h>
#include <const.h>
#include <ITranslator.h>
#include "logic_bridge.h"
#include <Translator.h>
float g_next_vote = 0.0f;
@@ -518,7 +517,7 @@ void VoteMenuHandler::OnMenuSelect(IBaseMenu *menu, int client, unsigned int ite
m_Votes[item]++;
m_NumVotes++;
if (sm_vote_chat.GetBool() || sm_vote_console.GetBool() || sm_vote_client_console.GetBool())
if (sm_vote_chat.GetBool() || sm_vote_console.GetBool())
{
static char buffer[1024];
ItemDrawInfo dr;
@@ -527,8 +526,7 @@ void VoteMenuHandler::OnMenuSelect(IBaseMenu *menu, int client, unsigned int ite
if (sm_vote_console.GetBool())
{
int target = SOURCEMOD_SERVER_LANGUAGE;
logicore.CoreTranslate(buffer, sizeof(buffer), "[SM] %T", 4, NULL, "Voted For",
&target, g_Players.GetPlayerByIndex(client)->GetName(), dr.display);
CoreTranslate(buffer, sizeof(buffer), "[SM] %T", 4, NULL, "Voted For", &target, g_Players.GetPlayerByIndex(client)->GetName(), dr.display);
Engine_LogPrintWrapper(buffer);
}
@@ -540,17 +538,15 @@ void VoteMenuHandler::OnMenuSelect(IBaseMenu *menu, int client, unsigned int ite
CPlayer *pPlayer = g_Players.GetPlayerByIndex(i);
assert(pPlayer);
if (pPlayer->IsInGame() && !pPlayer->IsFakeClient())
if (pPlayer->IsInGame())
{
if (m_Revoting[client])
{
logicore.CoreTranslate(buffer, sizeof(buffer), "[SM] %T", 4, NULL, "Changed Vote",
&i, g_Players.GetPlayerByIndex(client)->GetName(), dr.display);
CoreTranslate(buffer, sizeof(buffer), "[SM] %T", 4, NULL, "Changed Vote", &i, g_Players.GetPlayerByIndex(client)->GetName(), dr.display);
}
else
{
logicore.CoreTranslate(buffer, sizeof(buffer), "[SM] %T", 4, NULL, "Voted For",
&i, g_Players.GetPlayerByIndex(client)->GetName(), dr.display);
CoreTranslate(buffer, sizeof(buffer), "[SM] %T", 4, NULL, "Voted For", &i, g_Players.GetPlayerByIndex(client)->GetName(), dr.display);
}
if (sm_vote_chat.GetBool())
@@ -560,7 +556,7 @@ void VoteMenuHandler::OnMenuSelect(IBaseMenu *menu, int client, unsigned int ite
if (sm_vote_client_console.GetBool())
{
ClientConsolePrint(pPlayer->GetEdict(), buffer);
engine->ClientPrintf(pPlayer->GetEdict(), buffer);
}
}
}
@@ -638,8 +634,7 @@ void VoteMenuHandler::DrawHintProgress()
{
if (g_Players.GetPlayerByIndex(i)->IsInGame())
{
logicore.CoreTranslate(buffer, sizeof(buffer), "%T%s", 6, NULL, "Vote Count",
&i, &m_NumVotes, &m_TotalClients, &iTimeRemaining, &m_leaderList);
CoreTranslate(buffer, sizeof(buffer), "%T%s", 6, NULL, "Vote Count", &i, &m_NumVotes, &m_TotalClients, &iTimeRemaining, &m_leaderList);
g_HL2.HintTextMsg(i, buffer);
}
}
@@ -1,5 +1,5 @@
/**
* vim: set ts=4 sw=4 tw=99 noet :
* vim: set ts=4 :
* =============================================================================
* SourcePawn
* Copyright (C) 2004-2009 AlliedModders LLC. All rights reserved.
@@ -54,7 +54,7 @@ unsigned int NativeInterface::GetInterfaceVersion()
void NativeInterface::OnSourceModAllInitialized()
{
sharesys->AddInterface(NULL, &g_NInvoke);
g_ShareSys.AddInterface(NULL, &g_NInvoke);
}
IPluginRuntime *NativeInterface::CreateRuntime(const char *name, size_t bytes)
@@ -69,15 +69,30 @@ INativeInvoker *NativeInterface::CreateInvoker()
bool NativeInvoker::Start(IPluginContext *pContext, const char *name)
{
ke::Ref<Native> entry = g_ShareSys.FindNative(name);
if (!entry)
NativeEntry *entry;
entry = g_ShareSys.FindNative(name);
if (entry == NULL)
{
return false;
}
if (!entry->owner)
native = NULL;
if (entry->replacement.owner != NULL)
{
native = entry->replacement.func;
}
else if (entry->owner != NULL)
{
native = entry->func;
}
if (native == NULL)
{
return false;
}
native_ = entry->func();
context_ = pContext;
this->pContext = pContext;
m_curparam = 0;
m_errorstate = SP_ERROR_NONE;
@@ -169,13 +184,15 @@ int NativeInvoker::_PushString(const char *string, int sz_flags, int cp_flags, s
void NativeInvoker::Cancel()
{
if (context_ == NULL)
if (pContext == NULL)
{
return;
}
m_errorstate = SP_ERROR_NONE;
m_curparam = 0;
context_ = NULL;
native_ = NULL;
pContext = NULL;
native = NULL;
}
int NativeInvoker::SetError(int err)
@@ -188,8 +205,10 @@ int NativeInvoker::Invoke(cell_t *result)
{
int err = SP_ERROR_NONE;
if (context_ == NULL)
if (pContext == NULL)
{
return SP_ERROR_INVALID_NATIVE;
}
if (m_errorstate != SP_ERROR_NONE)
{
@@ -206,7 +225,7 @@ int NativeInvoker::Invoke(cell_t *result)
}
//This is for re-entrancy!
IPluginContext *ctx = context_;
IPluginContext *ctx = pContext;
cell_t _temp_params[SP_MAX_EXEC_PARAMS + 1];
cell_t *temp_params = &_temp_params[1];
ParamInfo temp_info[SP_MAX_EXEC_PARAMS];
@@ -220,7 +239,7 @@ int NativeInvoker::Invoke(cell_t *result)
memcpy(temp_info, m_info, numparams * sizeof(ParamInfo));
}
m_curparam = 0;
context_ = NULL;
pContext = NULL;
/* Initialize 0th parameter */
_temp_params[0] = numparams;
@@ -305,7 +324,7 @@ int NativeInvoker::Invoke(cell_t *result)
/* Make the call if we can */
if (err == SP_ERROR_NONE)
{
*result = native_(ctx, _temp_params);
*result = native(ctx, _temp_params);
if (ctx->GetLastNativeError() != SP_ERROR_NONE)
{
docopies = false;
@@ -32,12 +32,8 @@
#ifndef _INCLUDE_SOURCEMOD_NATIVE_INVOKER_H_
#define _INCLUDE_SOURCEMOD_NATIVE_INVOKER_H_
#include <sp_vm_api.h>
#include "sm_globals.h"
#include <INativeInvoker.h>
#include "common_logic.h"
using namespace SourceMod;
using namespace SourcePawn;
struct ParamInfo
{
@@ -75,8 +71,8 @@ private:
int _PushString(const char *string, int sz_flags, int cp_flags, size_t len);
int SetError(int err);
private:
IPluginContext *context_;
SPVM_NATIVE_FUNC native_;
IPluginContext *pContext;
SPVM_NATIVE_FUNC native;
cell_t m_params[SP_MAX_EXEC_PARAMS];
ParamInfo m_info[SP_MAX_EXEC_PARAMS];
unsigned int m_curparam;
+144
View File
@@ -0,0 +1,144 @@
#include "NativeOwner.h"
#include "ShareSys.h"
#include "PluginSys.h"
CNativeOwner::CNativeOwner() : m_nMarkSerial(0)
{
}
void CNativeOwner::SetMarkSerial(unsigned int serial)
{
m_nMarkSerial = serial;
}
unsigned int CNativeOwner::GetMarkSerial()
{
return m_nMarkSerial;
}
void CNativeOwner::AddDependent(CPlugin *pPlugin)
{
m_Dependents.push_back(pPlugin);
}
void CNativeOwner::AddWeakRef(const WeakNative & ref)
{
m_WeakRefs.push_back(ref);
}
void CNativeOwner::AddNatives(const sp_nativeinfo_t *natives)
{
NativeEntry *pEntry;
for (unsigned int i = 0; natives[i].func != NULL && natives[i].name != NULL; i++)
{
if ((pEntry = g_ShareSys.AddNativeToCache(this, &natives[i])) == NULL)
{
continue;
}
m_Natives.push_back(pEntry);
}
}
void CNativeOwner::PropogateMarkSerial(unsigned int serial)
{
CNativeOwner *pOwner;
List<CPlugin *>::iterator iter;
for (iter = m_Dependents.begin();
iter != m_Dependents.end();
iter++)
{
pOwner = (*iter);
pOwner->SetMarkSerial(serial);
}
}
void CNativeOwner::UnbindWeakRef(const WeakNative & ref)
{
sp_native_t *native;
IPluginContext *pContext;
pContext = ref.pl->GetBaseContext();
if ((pContext->GetNativeByIndex(ref.idx, &native)) == SP_ERROR_NONE)
{
/* If there is no reference, the native must be unbound */
if (ref.entry == NULL)
{
native->status = SP_NATIVE_UNBOUND;
native->pfn = NULL;
}
/* If we've cached a reference, it's a core native we can
* rebind back to its original (this was a replacement).
*/
else
{
native->pfn = ref.entry->func;
}
}
}
void CNativeOwner::DropEverything()
{
NativeEntry *pEntry;
List<WeakNative>::iterator iter;
List<NativeEntry *>::iterator ntv_iter;
/* Unbind and remove all weak references to us */
iter = m_WeakRefs.begin();
while (iter != m_WeakRefs.end())
{
UnbindWeakRef((*iter));
iter = m_WeakRefs.erase(iter);
}
/* Unmark our replacement natives */
ntv_iter = m_ReplacedNatives.begin();
while (ntv_iter != m_ReplacedNatives.end())
{
pEntry = (*ntv_iter);
pEntry->replacement.func = NULL;
pEntry->replacement.owner = NULL;
ntv_iter = m_ReplacedNatives.erase(ntv_iter);
}
/* Strip all of our natives from the cache */
ntv_iter = m_Natives.begin();
while (ntv_iter != m_Natives.end())
{
g_ShareSys.ClearNativeFromCache(this, (*ntv_iter)->name);
ntv_iter = m_Natives.erase(ntv_iter);
}
}
void CNativeOwner::DropWeakRefsTo(CPlugin *pPlugin)
{
List<WeakNative>::iterator iter;
iter = m_WeakRefs.begin();
while (iter != m_WeakRefs.end())
{
WeakNative & ref = (*iter);
if (ref.pl == pPlugin)
{
iter = m_WeakRefs.erase(iter);
}
else
{
iter++;
}
}
}
void CNativeOwner::DropRefsTo(CPlugin *pPlugin)
{
m_Dependents.remove(pPlugin);
DropWeakRefsTo(pPlugin);
}
void CNativeOwner::AddReplacedNative(NativeEntry *pEntry)
{
m_ReplacedNatives.push_back(pEntry);
}
+59
View File
@@ -0,0 +1,59 @@
#ifndef _INCLUDE_SOURCEMOD_NATIVE_OWNER_H_
#define _INCLUDE_SOURCEMOD_NATIVE_OWNER_H_
#include <sp_vm_types.h>
#include <sh_list.h>
class CPlugin;
struct NativeEntry;
struct WeakNative
{
WeakNative(CPlugin *plugin, uint32_t index) :
pl(plugin), idx(index), entry(NULL)
{
pl = plugin;
idx = index;
}
WeakNative(CPlugin *plugin, uint32_t index, NativeEntry *pEntry) :
pl(plugin), idx(index), entry(pEntry)
{
pl = plugin;
idx = index;
}
CPlugin *pl;
uint32_t idx;
NativeEntry *entry;
};
using namespace SourceHook;
class CNativeOwner
{
public:
CNativeOwner();
public:
virtual void DropEverything();
public:
void AddNatives(const sp_nativeinfo_t *info);
public:
void SetMarkSerial(unsigned int serial);
unsigned int GetMarkSerial();
void PropogateMarkSerial(unsigned int serial);
public:
void AddDependent(CPlugin *pPlugin);
void AddWeakRef(const WeakNative & ref);
void DropRefsTo(CPlugin *pPlugin);
void AddReplacedNative(NativeEntry *pEntry);
private:
void DropWeakRefsTo(CPlugin *pPlugin);
void UnbindWeakRef(const WeakNative & ref);
protected:
List<CPlugin *> m_Dependents;
unsigned int m_nMarkSerial;
List<WeakNative> m_WeakRefs;
List<NativeEntry *> m_Natives;
List<NativeEntry *> m_ReplacedNatives;
};
#endif //_INCLUDE_SOURCEMOD_NATIVE_OWNER_H_
+13 -20
View File
@@ -31,12 +31,10 @@
#include "NextMap.h"
#include "Logger.h"
#include "HalfLife2.h"
#include "sourcemm_api.h"
#include "sm_stringutil.h"
#include "sourcehook.h"
#include "sm_srvcmds.h"
#include "logic_bridge.h"
NextMapManager g_NextMap;
@@ -46,9 +44,7 @@ SH_DECL_HOOK2_void(IVEngineServer, ChangeLevel, SH_NOATTRIB, 0, const char *, co
SH_DECL_HOOK4_void(IVEngineServer, ChangeLevel, SH_NOATTRIB, 0, const char *, const char *, const char *, bool);
#endif
#if SOURCE_ENGINE == SE_DOTA
SH_DECL_EXTERN2_void(ConCommand, Dispatch, SH_NOATTRIB, false, const CCommandContext &, const CCommand &);
#elif SOURCE_ENGINE >= SE_ORANGEBOX
#if SOURCE_ENGINE >= SE_ORANGEBOX
SH_DECL_EXTERN1_void(ConCommand, Dispatch, SH_NOATTRIB, false, const CCommand &);
#elif SOURCE_ENGINE == SE_DARKMESSIAH
SH_DECL_EXTERN0_void(ConCommand, Dispatch, SH_NOATTRIB, false);
@@ -72,13 +68,13 @@ void NextMapManager::OnSourceModAllInitialized_Post()
#if SOURCE_ENGINE >= SE_ORANGEBOX
SH_ADD_HOOK(IVEngineServer, ChangeLevel, engine, SH_MEMBER(this, &NextMapManager::HookChangeLevel), false);
#else
SH_ADD_HOOK(IVEngineServer, ChangeLevel, engine, SH_MEMBER(this, &NextMapManager::HookChangeLevel), false);
SH_ADD_HOOK_MEMFUNC(IVEngineServer, ChangeLevel, engine, this, &NextMapManager::HookChangeLevel, false);
#endif
ConCommand *pCmd = FindCommand("changelevel");
if (pCmd != NULL)
{
SH_ADD_HOOK(ConCommand, Dispatch, pCmd, SH_STATIC(CmdChangeLevelCallback), false);
SH_ADD_HOOK_STATICFUNC(ConCommand, Dispatch, pCmd, CmdChangeLevelCallback, false);
changeLevelCmd = pCmd;
}
}
@@ -88,12 +84,12 @@ void NextMapManager::OnSourceModShutdown()
#if SOURCE_ENGINE >= SE_ORANGEBOX
SH_REMOVE_HOOK(IVEngineServer, ChangeLevel, engine, SH_MEMBER(this, &NextMapManager::HookChangeLevel), false);
#else
SH_REMOVE_HOOK(IVEngineServer, ChangeLevel, engine, SH_MEMBER(this, &NextMapManager::HookChangeLevel), false);
SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, ChangeLevel, engine, this, &NextMapManager::HookChangeLevel, false);
#endif
if (changeLevelCmd != NULL)
{
SH_REMOVE_HOOK(ConCommand, Dispatch, changeLevelCmd, SH_STATIC(CmdChangeLevelCallback), false);
SH_REMOVE_HOOK_STATICFUNC(ConCommand, Dispatch, changeLevelCmd, CmdChangeLevelCallback, false);
}
SourceHook::List<MapChangeData *>::iterator iter;
@@ -113,7 +109,7 @@ const char *NextMapManager::GetNextMap()
bool NextMapManager::SetNextMap(const char *map)
{
if (!g_HL2.IsMapValid(map))
if (!engine->IsMapValid(map))
{
return false;
}
@@ -131,18 +127,18 @@ void NextMapManager::HookChangeLevel(const char *map, const char *unknown, const
{
if (g_forcedChange)
{
logger->LogMessage("[SM] Changed map to \"%s\"", map);
g_Logger.LogMessage("[SM] Changed map to \"%s\"", map);
RETURN_META(MRES_IGNORED);
}
const char *newmap = sm_nextmap.GetString();
if (newmap[0] == 0 || !g_HL2.IsMapValid(newmap))
if (newmap[0] == 0 || !engine->IsMapValid(newmap))
{
RETURN_META(MRES_IGNORED);
}
logger->LogMessage("[SM] Changed map to \"%s\"", newmap);
g_Logger.LogMessage("[SM] Changed map to \"%s\"", newmap);
UTIL_Format(m_tempChangeInfo.m_mapName, sizeof(m_tempChangeInfo.m_mapName), newmap);
UTIL_Format(m_tempChangeInfo.m_changeReason, sizeof(m_tempChangeInfo.m_changeReason), "Normal level change");
@@ -187,14 +183,14 @@ void NextMapManager::OnSourceModLevelChange( const char *mapName )
m_tempChangeInfo.m_mapName[0] ='\0';
m_tempChangeInfo.m_changeReason[0] = '\0';
m_tempChangeInfo.startTime = time(NULL);
UTIL_Format(lastMap, sizeof(lastMap), "%s", mapName);
UTIL_Format(lastMap, sizeof(lastMap), mapName);
}
void NextMapManager::ForceChangeLevel( const char *mapName, const char* changeReason )
{
/* Store the mapname and reason */
UTIL_Format(m_tempChangeInfo.m_mapName, sizeof(m_tempChangeInfo.m_mapName), "%s", mapName);
UTIL_Format(m_tempChangeInfo.m_changeReason, sizeof(m_tempChangeInfo.m_changeReason), "%s", changeReason);
UTIL_Format(m_tempChangeInfo.m_mapName, sizeof(m_tempChangeInfo.m_mapName), mapName);
UTIL_Format(m_tempChangeInfo.m_changeReason, sizeof(m_tempChangeInfo.m_changeReason), changeReason);
/* Change level and skip our hook */
g_forcedChange = true;
@@ -208,10 +204,7 @@ NextMapManager::NextMapManager()
m_mapHistory = SourceHook::List<MapChangeData *>();
}
#if SOURCE_ENGINE == SE_DOTA
void CmdChangeLevelCallback(const CCommandContext &context, const CCommand &command)
{
#elif SOURCE_ENGINE >= SE_ORANGEBOX
#if SOURCE_ENGINE >= SE_ORANGEBOX
void CmdChangeLevelCallback(const CCommand &command)
{
#else
+3 -7
View File
@@ -53,14 +53,12 @@ struct MapChangeData
startTime = 0;
}
char m_mapName[PLATFORM_MAX_PATH];
char m_mapName[32];
char m_changeReason[100];
time_t startTime;
};
#if SOURCE_ENGINE == SE_DOTA
void CmdChangeLevelCallback(const CCommandContext &context, const CCommand &command);
#elif SOURCE_ENGINE >= SE_ORANGEBOX
#if SOURCE_ENGINE >= SE_ORANGEBOX
void CmdChangeLevelCallback(const CCommand &command);
#else
void CmdChangeLevelCallback();
@@ -71,9 +69,7 @@ class NextMapManager : public SMGlobalClass
public:
NextMapManager();
#if SOURCE_ENGINE == SE_DOTA
friend void CmdChangeLevelCallback(const CCommandContext &context, const CCommand &command);
#elif SOURCE_ENGINE >= SE_ORANGEBOX
#if SOURCE_ENGINE >= SE_ORANGEBOX
friend void CmdChangeLevelCallback(const CCommand &command);
#else
friend void CmdChangeLevelCallback();
@@ -29,9 +29,9 @@
* Version: $Id$
*/
#include "common_logic.h"
#include "PhraseCollection.h"
#include "Translator.h"
#include "sm_stringutil.h"
CPhraseCollection::CPhraseCollection()
{
@@ -54,7 +54,7 @@ IPhraseFile *CPhraseCollection::AddPhraseFile(const char *filename)
char full_name[PLATFORM_MAX_PATH];
/* No compat shim here. The user should have read the doc. */
smcore.Format(full_name, sizeof(full_name), "%s.txt", filename);
UTIL_Format(full_name, sizeof(full_name), "%s.txt", filename);
fid = g_Translator.FindOrAddPhraseFile(full_name);
pFile = g_Translator.GetFileByIndex(fid);
@@ -113,7 +113,7 @@ bool CPhraseCollection::FormatString(char *buffer,
unsigned int arg;
arg = 0;
if (!smcore.gnprintf(buffer, maxlength, format, this, params, numparams, arg, pOutLength, pFailPhrase))
if (!gnprintf(buffer, maxlength, format, this, params, numparams, arg, pOutLength, pFailPhrase))
{
return false;
}
+169 -892
View File
File diff suppressed because it is too large Load Diff
+12 -60
View File
@@ -41,11 +41,8 @@
#include <sh_string.h>
#include <sh_list.h>
#include <sh_vector.h>
#include <am-string.h>
#include "ConVarManager.h"
#include <steam/steamclientpublic.h>
using namespace SourceHook;
#define PLAYER_LIFE_UNKNOWN 0
@@ -59,7 +56,7 @@ union serial_t
uint32_t value;
struct
{
uint32_t index : 8;
uint8_t index;
uint32_t serial : 24;
} bits;
};
@@ -72,34 +69,23 @@ public:
public:
const char *GetName();
const char *GetIPAddress();
const char *GetAuthString(bool validated = true);
unsigned int GetSteamAccountID(bool validated = true);
const CSteamID &GetSteamId(bool validated = true);
uint64_t GetSteamId64(bool validated = true) { return GetSteamId(validated).ConvertToUint64(); }
const char *GetSteam2Id(bool validated = true);
const char *GetSteam3Id(bool validated = true);
const char *GetAuthString();
edict_t *GetEdict();
bool IsInGame();
bool WasCountedAsInGame();
bool IsConnected();
bool IsAuthorized();
bool IsFakeClient();
bool IsSourceTV() const;
bool IsReplay() const;
void SetAdminId(AdminId id, bool temporary);
AdminId GetAdminId();
void Kick(const char *str);
bool IsInKickQueue();
IPlayerInfo *GetPlayerInfo();
unsigned int GetLanguageId();
void SetLanguageId(unsigned int id);
int GetUserId();
bool RunAdminCacheChecks();
void NotifyPostAdminChecks();
unsigned int GetSerial();
int GetIndex() const;
void PrintToConsole(const char *pMsg);
void ClearAdmin();
public:
void DoBasicAdminChecks();
void MarkAsBeingKicked();
@@ -110,11 +96,9 @@ private:
void Disconnect();
void SetName(const char *name);
void DumpAdmin(bool deleting);
void UpdateAuthIds();
void Authorize();
void Authorize(const char *auth);
void Authorize_Post();
void DoPostConnectAuthorization();
bool IsAuthStringValidated();
private:
bool m_IsConnected;
bool m_IsInGame;
@@ -123,9 +107,7 @@ private:
String m_Name;
String m_Ip;
String m_IpNoPort;
ke::AString m_AuthID;
ke::AString m_Steam2Id;
ke::AString m_Steam3Id;
String m_AuthID;
AdminId m_Admin;
bool m_TempAdmin;
edict_t *m_pEdict;
@@ -136,18 +118,13 @@ private:
unsigned int m_LangId;
int m_UserId;
bool m_bFakeClient;
bool m_bIsSourceTV;
bool m_bIsReplay;
serial_t m_Serial;
CSteamID m_SteamId;
#if SOURCE_ENGINE == SE_CSGO
QueryCvarCookie_t m_LanguageCookie;
#endif
};
class PlayerManager :
public SMGlobalClass,
public IPlayerManager
public IPlayerManager,
public IConVarChangeListener
{
friend class CPlayer;
public:
@@ -162,17 +139,9 @@ public: //SMGlobalClass
public:
CPlayer *GetPlayerByIndex(int client) const;
void RunAuthChecks();
void ClearAdminId(AdminId id);
void ClearAllAdmins();
public:
#if SOURCE_ENGINE == SE_DOTA
bool OnClientConnect(CEntityIndex index, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen);
bool OnClientConnect_Post(CEntityIndex index, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen);
void OnClientPutInServer(CEntityIndex index, char const *playername);
void OnClientDisconnect(CEntityIndex index, int reason);
void OnClientDisconnect_Post(CEntityIndex index, int reason);
void OnClientCommand(CEntityIndex index, const CCommand &args);
void OnClientSettingsChanged(CEntityIndex index);
//void OnClientSettingsChanged_Pre(CEntityIndex client);
#else
bool OnClientConnect(edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen);
bool OnClientConnect_Post(edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen);
void OnClientPutInServer(edict_t *pEntity, char const *playername);
@@ -185,8 +154,6 @@ public:
#endif
void OnClientSettingsChanged(edict_t *pEntity);
//void OnClientSettingsChanged_Pre(edict_t *pEntity);
#endif
void OnServerHibernationUpdate(bool bHibernating);
public: //IPlayerManager
void AddClientListener(IClientListener *listener);
void RemoveClientListener(IClientListener *listener);
@@ -202,8 +169,8 @@ public: //IPlayerManager
void UnregisterCommandTargetProcessor(ICommandTargetProcessor *pHandler);
void ProcessCommandTarget(cmd_target_info_t *info);
int GetClientFromSerial(unsigned int serial);
void ClearAdminId(AdminId id);
void RecheckAnyAdmins();
public: // IConVarChangeListener
void OnConVarChanged(ConVar *pConVar, const char *oldValue, float flOldValue);
public:
inline int MaxClients()
{
@@ -220,23 +187,16 @@ public:
bool CheckSetAdmin(int index, CPlayer *pPlayer, AdminId id);
bool CheckSetAdminName(int index, CPlayer *pPlayer, AdminId id);
const char *GetPassInfoVar();
void RecheckAnyAdmins();
unsigned int GetReplyTo();
unsigned int SetReplyTo(unsigned int reply);
void MaxPlayersChanged(int newvalue = -1);
#if SOURCE_ENGINE == SE_CSGO
bool HandleConVarQuery(QueryCvarCookie_t cookie, edict_t *pPlayer, EQueryCvarValueStatus result, const char *cvarName, const char *cvarValue);
#endif
private:
#if SOURCE_ENGINE == SE_DOTA
void OnServerActivate();
#else
void OnServerActivate(edict_t *pEdictList, int edictCount, int clientMax);
#endif
void InvalidatePlayer(CPlayer *pPlayer);
private:
List<IClientListener *> m_hooks;
IForward *m_clconnect;
IForward *m_clconnect_post;
IForward *m_cldisconnect;
IForward *m_cldisconnect_post;
IForward *m_clputinserver;
@@ -249,23 +209,15 @@ private:
int *m_UserIdLookUp;
int m_maxClients;
int m_PlayerCount;
int m_PlayersSinceActive;
bool m_FirstPass;
unsigned int *m_AuthQueue;
String m_PassInfoVar;
bool m_QueryLang;
bool m_bAuthstringValidation; // are we validating admins with steam before authorizing?
bool m_bIsListenServer;
int m_ListenClient;
bool m_bIsSourceTVActive;
bool m_bIsReplayActive;
int m_SourceTVUserId;
int m_ReplayUserId;
};
#if SOURCE_ENGINE == SE_DOTA
void CmdMaxplayersCallback(const CCommandContext &context, const CCommand &command);
#elif SOURCE_ENGINE >= SE_ORANGEBOX
#if SOURCE_ENGINE >= SE_ORANGEBOX
void CmdMaxplayersCallback(const CCommand &command);
#else
void CmdMaxplayersCallback();
+349
View File
@@ -0,0 +1,349 @@
/**
* vim: set ts=4 :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
* =============================================================================
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 3.0, as published by the
* Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
* As a special exception, AlliedModders LLC gives you permission to link the
* code of this program (as well as its derivative works) to "Half-Life 2," the
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
* by the Valve Corporation. You must obey the GNU General Public License in
* all respects for all other code used. Additionally, AlliedModders LLC grants
* this exception to all derivative works. AlliedModders LLC defines further
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
* or <http://www.sourcemod.net/license.php>.
*
* Version: $Id$
*/
#include <stdarg.h>
#include <string.h>
#include "PluginInfoDatabase.h"
#include "PluginSys.h"
void PluginSettings::Init()
{
name = -1;
pause_val = false;
type_val = PluginType_MapUpdated;
optarray = -1;
opts_num = 0;
opts_size = 0;
blockload_val = false;
}
/**
* :TODO: write the logger, make these errors log instead of being static
* NOTE: once we do that, we will have to change some code to ignore sections
*/
CPluginInfoDatabase::CPluginInfoDatabase()
{
m_strtab = NULL;
m_infodb_count = 0;
m_infodb_size = 0;
m_infodb = -1;
}
CPluginInfoDatabase::~CPluginInfoDatabase()
{
delete m_strtab;
}
void CPluginInfoDatabase::ReadSMC_ParseStart()
{
/* Create or reset our string table */
if (m_strtab)
{
m_strtab->Reset();
} else {
m_strtab = new BaseStringTable(1024);
}
/* Set our internal states to the beginning */
in_plugins = false;
cur_plugin = -1;
in_options = false;
m_infodb_size = 0;
m_infodb_count = 0;
m_infodb = -1;
}
SMCResult CPluginInfoDatabase::MakeError(const char *fmt, ...)
{
char buffer[512];
va_list ap;
va_start(ap, fmt);
vsnprintf(buffer, sizeof(buffer), fmt, ap);
va_end(ap);
m_errmsg = m_strtab->AddString(buffer);
return SMCResult_HaltFail;
}
unsigned int CPluginInfoDatabase::GetSettingsNum()
{
return m_infodb_count;
}
PluginSettings *CPluginInfoDatabase::GetSettingsIfMatch(unsigned int index, const char *filename)
{
BaseMemTable *memtab = m_strtab->GetMemTable();
int *table = (int *)memtab->GetAddress(m_infodb);
if (!table || index >= m_infodb_count)
{
return NULL;
}
PluginSettings *plugin = (PluginSettings *)memtab->GetAddress(table[index]);
const char *name = m_strtab->GetString(plugin->name);
if (!name)
{
return NULL;
}
if (!g_PluginSys.TestAliasMatch(name, filename))
{
return NULL;
}
return plugin;
}
void CPluginInfoDatabase::GetOptionsForPlugin(PluginSettings *settings, unsigned int opt_num, const char **key, const char **val)
{
PluginOpts *table = (PluginOpts *)m_strtab->GetMemTable()->GetAddress(settings->optarray);
if (!table)
{
*key = NULL;
*val = NULL;
return;
}
if (opt_num >= settings->opts_num)
{
*key = NULL;
*val = NULL;
return;
}
*key = m_strtab->GetString(table[opt_num].key);
*val = m_strtab->GetString(table[opt_num].val);
}
SMCResult CPluginInfoDatabase::ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value)
{
if (cur_plugin != -1)
{
PluginSettings *plugin = (PluginSettings *)m_strtab->GetMemTable()->GetAddress(cur_plugin);
if (!in_options)
{
if (strcmp(key, "pause") == 0)
{
if (strcasecmp(value, "yes") == 0)
{
plugin->pause_val = true;
}
else
{
plugin->pause_val = false;
}
}
else if (strcmp(key, "lifetime") == 0)
{
if (strcasecmp(value, "private") == 0)
{
plugin->type_val = PluginType_Private;
}
else if (strcasecmp(value, "mapsync") == 0)
{
plugin->type_val = PluginType_MapUpdated;
}
else if (strcasecmp(value, "maponly") == 0)
{
plugin->type_val = PluginType_MapOnly;
}
else if (strcasecmp(value, "global") == 0)
{
plugin->type_val = PluginType_Global;
}
else
{
return MakeError("Unknown value for key \"lifetime\": \"%s\"", value);
}
}
else if (strcmp(key, "blockload") == 0)
{
plugin->blockload_val = true;
}
else
{
return MakeError("Unknown property key: \"%s\"", key);
}
}
else
{
/* Cache every option, valid or not */
int keyidx = m_strtab->AddString(key);
int validx = m_strtab->AddString(value);
PluginOpts *table;
BaseMemTable *memtab = m_strtab->GetMemTable();
plugin = (PluginSettings *)memtab->GetAddress(cur_plugin);
if (plugin->opts_num + 1 > plugin->opts_size)
{
unsigned int oldsize = plugin->opts_size;
if (oldsize == 0)
{
//right now we don't have many
plugin->opts_size = 2;
}
else
{
plugin->opts_size *= 2;
}
int newidx = memtab->CreateMem(plugin->opts_size * sizeof(PluginOpts), (void **)&table);
/* in case it resized */
plugin = (PluginSettings *)memtab->GetAddress(cur_plugin);
if (plugin->optarray != -1)
{
void *oldtable = memtab->GetAddress(plugin->optarray);
memcpy(table, oldtable, oldsize * sizeof(PluginOpts));
}
plugin->optarray = newidx;
}
else
{
table = (PluginOpts *)memtab->GetAddress(plugin->optarray);
}
PluginOpts *opt = &table[plugin->opts_num++];
opt->key = keyidx;
opt->val = validx;
}
}
else if (in_plugins)
{
return MakeError("Unknown property key: \"%s\"", key);
}
else
{
/* Ignore anything we don't know about! */
}
return SMCResult_Continue;
}
SMCResult CPluginInfoDatabase::ReadSMC_LeavingSection(const SMCStates *states)
{
if (in_plugins)
{
if (cur_plugin != -1)
{
if (in_options)
{
in_options = false;
}
else
{
/* If the plugin is ending, add it to the table */
BaseMemTable *memtab = m_strtab->GetMemTable();
int *table;
if (m_infodb_count + 1 > m_infodb_size)
{
unsigned int oldsize = m_infodb_size;
if (!m_infodb_size)
{
m_infodb_size = 8;
}
else
{
m_infodb_size *= 2;
}
int newidx = memtab->CreateMem(m_infodb_size * sizeof(int), (void **)&table);
if (m_infodb != -1)
{
void *oldtable = (int *)memtab->GetAddress(m_infodb);
memcpy(table, oldtable, oldsize * sizeof(int));
}
m_infodb = newidx;
}
else
{
table = (int *)memtab->GetAddress(m_infodb);
}
/* Assign to table and scrap the current plugin */
table[m_infodb_count++] = cur_plugin;
cur_plugin = -1;
}
}
else
{
in_plugins = false;
}
}
return SMCResult_Continue;
}
SMCResult CPluginInfoDatabase::ReadSMC_NewSection(const SMCStates *states, const char *name)
{
if (!in_plugins)
{
/* If we're not in the main Plugins section, and we don't get it for the name, error out */
if (strcmp(name, "Plugins") != 0)
{
return MakeError("Unknown root section: \"%s\"", name);
}
else
{
/* Otherwise set our states */
in_plugins = true;
cur_plugin = -1;
in_options = false;
}
}
else
{
if (cur_plugin == -1)
{
/* If we get a plugin node and we don't have a current plugin, create a new one */
PluginSettings *plugin;
int i_name = m_strtab->AddString(name);
cur_plugin = m_strtab->GetMemTable()->CreateMem(sizeof(PluginSettings), (void **)&plugin);
plugin->Init();
plugin->name = i_name;
in_options = false;
}
else
{
if (!in_options && strcmp(name, "Options") == 0)
{
in_options = true;
}
else
{
return MakeError("Unknown plugin sub-section: \"%s\"", name);
}
}
}
return SMCResult_Continue;
}
+106
View File
@@ -0,0 +1,106 @@
/**
* vim: set ts=4 :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
* =============================================================================
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 3.0, as published by the
* Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
* As a special exception, AlliedModders LLC gives you permission to link the
* code of this program (as well as its derivative works) to "Half-Life 2," the
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
* by the Valve Corporation. You must obey the GNU General Public License in
* all respects for all other code used. Additionally, AlliedModders LLC grants
* this exception to all derivative works. AlliedModders LLC defines further
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
* or <http://www.sourcemod.net/license.php>.
*
* Version: $Id$
*/
#ifndef _INCLUDE_SOURCEMOD_CORE_SYSTEM_PLUGININFODATABASE_H_
#define _INCLUDE_SOURCEMOD_CORE_SYSTEM_PLUGININFODATABASE_H_
/**
* This file parses plugin_settings.cfg and stores the information in cached memory.
* It provides simplistic abstraction to retrieving the info.
* :TODO: currently untested
*/
#include "sm_memtable.h"
#include "ITextParsers.h"
#include "IPluginSys.h"
#include "sm_globals.h"
struct PluginOpts
{
int key;
int val;
};
struct PluginSettings
{
void Init();
int name;
bool pause_val;
PluginType type_val;
int optarray;
size_t opts_num;
size_t opts_size;
bool blockload_val;
};
class CPluginInfoDatabase : public ITextListener_SMC
{
public:
CPluginInfoDatabase();
~CPluginInfoDatabase();
public: //ITextListener_SMC
void ReadSMC_ParseStart();
SMCResult ReadSMC_NewSection(const SMCStates *states, const char *name);
SMCResult ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value);
SMCResult ReadSMC_LeavingSection(const SMCStates *states);
public:
/**
* Returns the number of plugin settings available.
*/
unsigned int GetSettingsNum();
/**
* Given an index, returns the plugin settings block if the filename matches.
* Otherwise, returns NULL.
*/
PluginSettings *GetSettingsIfMatch(unsigned int index, const char *filename);
/**
* Given a plugin settings struct and an index,
* returns the given JIT key/value option pair at that index.
* If the input is invalid, key and val will be set to NULL.
*/
void GetOptionsForPlugin(PluginSettings *settings, unsigned int opt_num, const char **key, const char **val);
private:
SMCResult MakeError(const char *fmt, ...);
private:
BaseStringTable *m_strtab;
int m_errmsg;
bool in_plugins;
bool in_options;
int m_infodb;
size_t m_infodb_count;
size_t m_infodb_size;
int cur_plugin;
};
#endif //_INCLUDE_SOURCEMOD_CORE_SYSTEM_PLUGININFODATABASE_H_
File diff suppressed because it is too large Load Diff
+39 -58
View File
@@ -1,8 +1,8 @@
/**
* vim: set ts=4 sw=4 tw=99 noet :
* vim: set ts=4 :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2010 AlliedModders LLC. All rights reserved.
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
* =============================================================================
*
* This program is free software; you can redistribute it and/or modify it under
@@ -42,12 +42,19 @@
#include <sh_stack.h>
#include <sh_vector.h>
#include <sh_string.h>
#include "common_logic.h"
#include "sm_globals.h"
#include "PluginInfoDatabase.h"
#include "sm_trie.h"
#include "sourcemod.h"
#include <IRootConsoleMenu.h>
#include <sm_stringhashmap.h>
#include <sm_namehashset.h>
#if (SOURCE_ENGINE == SE_LEFT4DEAD) || (SOURCE_ENGINE == SE_LEFT4DEAD2)
#include "convar_sm_l4d.h"
#elif (SOURCE_ENGINE == SE_ORANGEBOX) || (SOURCE_ENGINE == SE_ORANGEBOXVALVE)
#include "convar_sm_ob.h"
#else
#include "convar_sm.h"
#endif
#include "ITranslator.h"
#include "IGameConfigs.h"
#include "NativeOwner.h"
#include "ShareSys.h"
@@ -121,8 +128,17 @@ enum APLRes
APLRes_SilentFailure
};
struct AutoConfig
{
String autocfg;
String folder;
bool create;
};
class CPlugin;
class CPlugin :
public SMPlugin,
public IPlugin,
public CNativeOwner
{
friend class CPluginManager;
@@ -149,9 +165,6 @@ public:
bool GetProperty(const char *prop, void **ptr, bool remove=false);
void DropEverything();
SourcePawn::IPluginRuntime *GetRuntime();
CNativeOwner *ToNativeOwner() {
return this;
}
public:
/**
* Creates a plugin object with default values.
@@ -161,11 +174,6 @@ public:
* a valid (but error-stated) CPlugin will be returned.
*/
static CPlugin *CreatePlugin(const char *file, char *error, size_t maxlength);
static inline bool matches(const char *file, const CPlugin *plugin)
{
return strcmp(plugin->m_filename, file) == 0;
}
public:
/**
@@ -204,11 +212,6 @@ public:
*/
void Call_OnAllPluginsLoaded();
/**
* Calls the OnLibraryAdded function.
*/
void Call_OnLibraryAdded(const char *lib);
/**
* Returns true if a plugin is usable.
*/
@@ -238,13 +241,13 @@ public:
bool AddFakeNative(IPluginFunction *pFunc, const char *name, SPVM_FAKENATIVE_FUNC func);
void AddConfig(bool autoCreate, const char *cfg, const char *folder);
size_t GetConfigCount();
AutoConfig *GetConfig(size_t i);
unsigned int GetConfigCount();
AutoConfig *GetConfig(unsigned int i);
inline void AddLibrary(const char *name)
{
m_Libraries.push_back(name);
}
void LibraryActions(LibraryAction action);
void LibraryActions(bool dropping);
void SyncMaxClients(int max_clients);
protected:
bool UpdateInfo();
@@ -265,7 +268,7 @@ private:
IPhraseCollection *m_pPhrases;
List<String> m_RequiredLibs;
List<String> m_Libraries;
StringHashMap<void *> m_Props;
Trie *m_pProps;
bool m_FakeNativesMissing;
bool m_LibraryMissing;
CVector<AutoConfig *> m_configs;
@@ -278,7 +281,7 @@ private:
};
class CPluginManager :
public IScriptManager,
public IPluginManager,
public SMGlobalClass,
public IHandleTypeDispatch,
public IRootConsoleCommand
@@ -305,7 +308,7 @@ public:
List<CPlugin *>::iterator current;
};
friend class CPluginManager::CPluginIterator;
public: //IScriptManager
public: //IPluginManager
IPlugin *LoadPlugin(const char *path,
bool debug,
PluginType type,
@@ -318,30 +321,9 @@ public: //IScriptManager
IPluginIterator *GetPluginIterator();
void AddPluginsListener(IPluginsListener *listener);
void RemovePluginsListener(IPluginsListener *listener);
void LoadAll(const char *config_path, const char *plugins_path);
void RefreshAll();
SMPlugin *FindPluginByOrder(unsigned num) {
return GetPluginByOrder(num);
}
SMPlugin *FindPluginByIdentity(IdentityToken_t *ident) {
return GetPluginFromIdentity(ident);
}
SMPlugin *FindPluginByContext(IPluginContext *ctx) {
return GetPluginByCtx(ctx->GetContext());
}
SMPlugin *FindPluginByContext(sp_context_t *ctx) {
return GetPluginByCtx(ctx);
}
SMPlugin *FindPluginByConsoleArg(const char *text);
SMPlugin *FindPluginByHandle(Handle_t hndl, HandleError *errp) {
return static_cast<SMPlugin *>(PluginFromHandle(hndl, errp));
}
const CVector<SMPlugin *> *ListPlugins();
void FreePluginList(const CVector<SMPlugin *> *plugins);
public: //SMGlobalClass
void OnSourceModAllInitialized();
void OnSourceModShutdown();
ConfigResult OnSourceModConfigChanged(const char *key, const char *value, ConfigSource source, char *error, size_t maxlength);
void OnSourceModMaxPlayersChanged(int newvalue);
public: //IHandleTypeDispatch
void OnHandleDestroy(HandleType_t type, void *object);
@@ -397,6 +379,11 @@ public:
*/
const char *GetStatusText(PluginStatus status);
/**
* Reload or update plugins on level shutdown.
*/
void ReloadOrUnloadPlugins();
/**
* Add public functions from all running or paused
* plugins to the specified forward if the names match.
@@ -412,7 +399,7 @@ public:
void Shutdown();
void OnLibraryAction(const char *lib, LibraryAction action);
void OnLibraryAction(const char *lib, bool is_a_plugin, bool drop);
bool LibraryExists(const char *lib);
@@ -420,6 +407,8 @@ public:
void UnloadAll();
CPlugin *FindPluginByConsoleArg(const char *arg);
void SyncMaxClients(int max_clients);
void ListPluginsToClient(CPlayer *player, const CCommand &args);
@@ -464,14 +453,14 @@ public:
{
return m_MyIdent;
}
IPluginManager *GetOldAPI();
private:
void TryRefreshDependencies(CPlugin *pOther);
private:
List<IPluginsListener *> m_listeners;
List<CPlugin *> m_plugins;
CStack<CPluginManager::CPluginIterator *> m_iters;
NameHashSet<CPlugin *> m_LoadLookup;
CPluginInfoDatabase m_PluginInfo;
Trie *m_LoadLookup;
bool m_AllPluginsLoaded;
IdentityToken_t *m_MyIdent;
@@ -479,16 +468,8 @@ private:
List<FakeNative *> m_Natives;
bool m_LoadingLocked;
// Config
bool m_bBlockBadPlugins;
// Forwards
IForward *m_pOnLibraryAdded;
IForward *m_pOnLibraryRemoved;
};
extern CPluginManager g_PluginSys;
#endif //_INCLUDE_SOURCEMOD_PLUGINSYSTEM_H_
+230 -114
View File
@@ -1,5 +1,5 @@
/**
* vim: set ts=4 sw=4 tw=99 noet :
* vim: set ts=4 :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
@@ -30,14 +30,11 @@
*/
#include "ShareSys.h"
#include "ExtensionSys.h"
#include <ILibrarySys.h>
#include "common_logic.h"
#include "PluginSys.h"
#include "HandleSys.h"
#include <assert.h>
using namespace ke;
#include "ExtensionSys.h"
#include "LibrarySys.h"
#include "PluginSys.h"
#include "sm_stringutil.h"
ShareSystem g_ShareSys;
static unsigned int g_mark_serial = 0;
@@ -64,36 +61,36 @@ void ShareSystem::Initialize()
{
TypeAccess sec;
handlesys->InitAccessDefaults(&sec, NULL);
g_HandleSys.InitAccessDefaults(&sec, NULL);
sec.ident = GetIdentRoot();
m_TypeRoot = handlesys->CreateType("Identity", this, 0, &sec, NULL, NULL, NULL);
m_IfaceType = handlesys->CreateType("Interface", this, 0, NULL, NULL, GetIdentRoot(), NULL);
m_TypeRoot = g_HandleSys.CreateType("Identity", this, 0, &sec, NULL, NULL, NULL);
m_IfaceType = g_HandleSys.CreateType("Interface", this, 0, NULL, NULL, GetIdentRoot(), NULL);
/* Initialize our static identity handle */
m_IdentRoot.ident = handlesys->CreateHandle(m_TypeRoot, NULL, NULL, GetIdentRoot(), NULL);
m_IdentRoot.ident = g_HandleSys.CreateHandle(m_TypeRoot, NULL, NULL, GetIdentRoot(), NULL);
/* Add the Handle System and others... they are too innocent and pure to do it themselves */
AddInterface(NULL, handlesys);
AddInterface(NULL, libsys);
AddInterface(NULL, &g_HandleSys);
AddInterface(NULL, &g_LibSys);
}
void ShareSystem::OnSourceModShutdown()
{
if (m_CoreType)
{
handlesys->RemoveType(m_CoreType, GetIdentRoot());
g_HandleSys.RemoveType(m_CoreType, GetIdentRoot());
}
handlesys->RemoveType(m_IfaceType, GetIdentRoot());
handlesys->RemoveType(m_TypeRoot, GetIdentRoot());
g_HandleSys.RemoveType(m_IfaceType, GetIdentRoot());
g_HandleSys.RemoveType(m_TypeRoot, GetIdentRoot());
}
IdentityType_t ShareSystem::FindIdentType(const char *name)
{
HandleType_t type;
if (handlesys->FindHandleType(name, &type))
if (g_HandleSys.FindHandleType(name, &type))
{
if (g_HandleSys.TypeCheck(type, m_TypeRoot))
{
@@ -111,7 +108,7 @@ IdentityType_t ShareSystem::CreateIdentType(const char *name)
return 0;
}
return handlesys->CreateType(name, this, m_TypeRoot, NULL, NULL, GetIdentRoot(), NULL);
return g_HandleSys.CreateType(name, this, m_TypeRoot, NULL, NULL, GetIdentRoot(), NULL);
}
void ShareSystem::OnHandleDestroy(HandleType_t type, void *object)
@@ -220,13 +217,13 @@ void ShareSystem::DestroyIdentity(IdentityToken_t *identity)
sec.pOwner = GetIdentRoot();
sec.pIdentity = GetIdentRoot();
handlesys->FreeHandle(identity->ident, &sec);
g_HandleSys.FreeHandle(identity->ident, &sec);
delete identity;
}
void ShareSystem::DestroyIdentType(IdentityType_t type)
{
handlesys->RemoveType(type, GetIdentRoot());
g_HandleSys.RemoveType(type, GetIdentRoot());
}
void ShareSystem::RemoveInterfaces(IExtension *pExtension)
@@ -258,19 +255,51 @@ void ShareSystem::RegisterLibrary(IExtension *myself, const char *name)
void ShareSystem::OverrideNatives(IExtension *myself, const sp_nativeinfo_t *natives)
{
assert(false);
unsigned int i;
NativeEntry *pEntry;
CNativeOwner *pOwner;
pOwner = g_Extensions.GetNativeOwner(myself);
for (i = 0; natives[i].func != NULL && natives[i].name != NULL; i++)
{
if ((pEntry = FindNative(natives[i].name)) == NULL)
{
continue;
}
if (pEntry->owner != g_pCoreNatives)
{
continue;
}
if (pEntry->replacement.owner != NULL)
{
continue;
}
/* Now it's safe to add the override */
pEntry->replacement.func = natives[i].func;
pEntry->replacement.owner = pOwner;
pOwner->AddReplacedNative(pEntry);
}
}
PassRef<Native> ShareSystem::FindNative(const char *name)
NativeEntry *ShareSystem::FindNative(const char *name)
{
NativeCache::Result r = m_NtvCache.find(name);
if (!r.found())
NativeEntry **ppEntry;
if ((ppEntry = m_NtvCache.retrieve(name)) == NULL)
{
return NULL;
return *r;
}
return *ppEntry;
}
void ShareSystem::BindNativesToPlugin(CPlugin *pPlugin, bool bCoreOnly)
{
NativeEntry *pEntry;
sp_native_t *native;
uint32_t i, native_count;
IPluginContext *pContext;
@@ -279,152 +308,230 @@ void ShareSystem::BindNativesToPlugin(CPlugin *pPlugin, bool bCoreOnly)
/* Generate a new serial ID, mark our dependencies with it. */
g_mark_serial++;
pPlugin->PropagateMarkSerial(g_mark_serial);
pPlugin->PropogateMarkSerial(g_mark_serial);
native_count = pContext->GetNativesNum();
for (i = 0; i < native_count; i++)
{
if (pContext->GetNativeByIndex(i, &native) != SP_ERROR_NONE)
{
continue;
}
// If we're already bound, no need to do anything else.
/* If we're bound, check if there is a replacement available.
* If not, this native is totally finalized.
*/
if (native->status == SP_NATIVE_BOUND)
continue;
{
pEntry = (NativeEntry *)native->user;
assert(pEntry != NULL);
if (pEntry->replacement.owner == NULL
|| (pEntry->replacement.owner != NULL
&& pEntry->replacement.func == native->pfn))
{
continue;
}
}
/* Otherwise, the native must be in our cache. */
Ref<Native> pEntry = FindNative(native->name);
if (!pEntry)
else if ((pEntry = FindNative(native->name)) == NULL)
{
continue;
}
if (bCoreOnly && pEntry->owner != &g_CoreNatives)
if (bCoreOnly && pEntry->owner != g_pCoreNatives)
{
continue;
}
BindNativeToPlugin(pPlugin, native, i, pEntry);
}
}
void ShareSystem::BindNativeToPlugin(CPlugin *pPlugin, const Ref<Native> &entry)
void ShareSystem::BindNativeToPlugin(CPlugin *pPlugin, NativeEntry *pEntry)
{
if (!entry->owner)
return;
IPluginContext *pContext = pPlugin->GetBaseContext();
uint32_t i;
if (pContext->FindNativeByName(entry->name(), &i) != SP_ERROR_NONE)
return;
sp_native_t *native;
if (pContext->GetNativeByIndex(i, &native) != SP_ERROR_NONE)
IPluginContext *pContext;
pContext = pPlugin->GetBaseContext();
if (pContext->FindNativeByName(pEntry->name, &i) != SP_ERROR_NONE)
{
return;
}
if (pContext->GetNativeByIndex(i, &native) != SP_ERROR_NONE)
{
return;
}
if (native->status == SP_NATIVE_BOUND)
{
return;
}
BindNativeToPlugin(pPlugin, native, i, entry);
BindNativeToPlugin(pPlugin, native, i, pEntry);
}
void ShareSystem::BindNativeToPlugin(CPlugin *pPlugin, sp_native_t *native, uint32_t index,
const Ref<Native> &pEntry)
void ShareSystem::BindNativeToPlugin(CPlugin *pPlugin,
sp_native_t *native,
uint32_t index,
NativeEntry *pEntry)
{
/* Mark as bound... we do the rest next. */
native->status = SP_NATIVE_BOUND;
native->pfn = pEntry->func();
native->user = pEntry;
if (pEntry->fake)
/* See if a replacement is available. */
if (pEntry->replacement.owner != NULL)
{
/* This native is not necessarily optional, but we don't guarantee
* that its address is long-lived. */
native->flags |= SP_NTVFLAG_EPHEMERAL;
/* Perform a replacement bind. */
native->pfn = pEntry->replacement.func;
pEntry->replacement.owner->AddWeakRef(WeakNative(pPlugin, index, pEntry));
}
/* We don't bother with dependency crap if the owner is Core. */
if (pEntry->owner != &g_CoreNatives)
else
{
/* The native is optional, this is a special case */
if ((native->flags & SP_NTVFLAG_OPTIONAL) == SP_NTVFLAG_OPTIONAL)
/* Perform a normal bind. */
native->pfn = pEntry->func;
/* We don't bother with dependency crap if the owner is Core. */
if (pEntry->owner != g_pCoreNatives)
{
/* Only add if there is a valid owner. */
if (pEntry->owner)
pEntry->owner->AddWeakRef(WeakNative(pPlugin, index));
else
native->status = SP_NATIVE_UNBOUND;
}
/* Otherwise, we're a strong dependent and not a weak one */
else
{
/* See if this has already been marked as a dependent.
* If it has, it means this relationship has already occurred,
* and there is no reason to do it again.
*/
if (pEntry->owner != pPlugin->ToNativeOwner()
&& pEntry->owner->GetMarkSerial() != g_mark_serial)
/* The native is optional, this is a special case */
if ((native->flags & SP_NTVFLAG_OPTIONAL) == SP_NTVFLAG_OPTIONAL)
{
/* This has not been marked as a dependency yet */
//pPlugin->AddDependency(pEntry->owner);
pEntry->owner->AddDependent(pPlugin);
pEntry->owner->SetMarkSerial(g_mark_serial);
/* Only add if there is a valid owner. */
if (pEntry->owner != NULL)
{
pEntry->owner->AddWeakRef(WeakNative(pPlugin, index));
}
else
{
native->status = SP_NATIVE_UNBOUND;
}
}
/* Otherwise, we're a strong dependent and not a weak one */
else
{
/* See if this has already been marked as a dependent.
* If it has, it means this relationship has already occurred,
* and there is no reason to do it again.
*/
if (pEntry->owner != pPlugin
&& pEntry->owner->GetMarkSerial() != g_mark_serial)
{
/* This has not been marked as a dependency yet */
//pPlugin->AddDependency(pEntry->owner);
pEntry->owner->AddDependent(pPlugin);
pEntry->owner->SetMarkSerial(g_mark_serial);
}
}
}
}
}
PassRef<Native> ShareSystem::AddNativeToCache(CNativeOwner *pOwner, const sp_nativeinfo_t *ntv)
NativeEntry *ShareSystem::AddNativeToCache(CNativeOwner *pOwner, const sp_nativeinfo_t *ntv)
{
NativeCache::Insert i = m_NtvCache.findForAdd(ntv->name);
if (i.found())
NativeEntry *pEntry;
if ((pEntry = FindNative(ntv->name)) == NULL)
{
pEntry = new NativeEntry;
pEntry->owner = pOwner;
pEntry->name = ntv->name;
pEntry->func = ntv->func;
pEntry->replacement.func = NULL;
pEntry->replacement.owner = NULL;
pEntry->fake = NULL;
m_NtvCache.insert(ntv->name, pEntry);
return pEntry;
}
if (pEntry->owner != NULL)
{
return NULL;
}
Ref<Native> entry = new Native(pOwner, ntv);
m_NtvCache.insert(ntv->name, entry);
return entry;
}
pEntry->owner = pOwner;
pEntry->func = ntv->func;
pEntry->name = ntv->name;
FakeNative::~FakeNative()
{
g_pSourcePawn2->DestroyFakeNative(gate);
return pEntry;
}
void ShareSystem::ClearNativeFromCache(CNativeOwner *pOwner, const char *name)
{
NativeCache::Result r = m_NtvCache.find(name);
if (!r.found())
NativeEntry *pEntry;
if ((pEntry = FindNative(name)) == NULL)
{
return;
}
Ref<Native> entry(*r);
if (entry->owner != pOwner)
if (pEntry->owner != pOwner)
{
return;
}
// Clear out the owner bit as a sanity measure.
entry->owner = NULL;
if (pEntry->fake != NULL)
{
g_pSourcePawn2->DestroyFakeNative(pEntry->func);
delete pEntry->fake;
pEntry->fake = NULL;
}
m_NtvCache.remove(r);
pEntry->func = NULL;
pEntry->name = NULL;
pEntry->owner = NULL;
pEntry->replacement.func = NULL;
pEntry->replacement.owner = NULL;
}
PassRef<Native> ShareSystem::AddFakeNative(IPluginFunction *pFunc, const char *name, SPVM_FAKENATIVE_FUNC func)
NativeEntry *ShareSystem::AddFakeNative(IPluginFunction *pFunc, const char *name, SPVM_FAKENATIVE_FUNC func)
{
Ref<Native> entry(FindNative(name));
if (entry)
FakeNative *pFake;
NativeEntry *pEntry;
SPVM_NATIVE_FUNC gate;
if ((pEntry = FindNative(name)) != NULL && pEntry->owner != NULL)
{
return NULL;
}
AutoPtr<FakeNative> fake(new FakeNative(name, pFunc));
pFake = new FakeNative;
fake->gate = g_pSourcePawn2->CreateFakeNative(func, fake);
if (!fake->gate)
if ((gate = g_pSourcePawn2->CreateFakeNative(func, pFake)) == NULL)
{
delete pFake;
return NULL;
}
CNativeOwner *owner = g_PluginSys.GetPluginByCtx(fake->ctx->GetContext());
if (pEntry == NULL)
{
pEntry = new NativeEntry;
m_NtvCache.insert(name, pEntry);
}
entry = new Native(owner, fake.take());
m_NtvCache.insert(name, entry);
pFake->call = pFunc;
pFake->ctx = pFunc->GetParentContext();
strncopy(pFake->name, name, sizeof(pFake->name));
pEntry->fake = pFake;
pEntry->func = gate;
pEntry->name = pFake->name;
pEntry->owner = g_PluginSys.GetPluginByCtx(pFake->ctx->GetContext());
pEntry->replacement.func = NULL;
pEntry->replacement.owner = NULL;
return entry;
return pEntry;
}
void ShareSystem::AddCapabilityProvider(IExtension *myself, IFeatureProvider *provider,
const char *name)
{
if (m_caps.contains(name))
if (m_caps.retrieve(name) != NULL)
return;
Capability cap;
@@ -437,13 +544,14 @@ void ShareSystem::AddCapabilityProvider(IExtension *myself, IFeatureProvider *pr
void ShareSystem::DropCapabilityProvider(IExtension *myself, IFeatureProvider *provider,
const char *name)
{
StringHashMap<Capability>::Result r = m_caps.find(name);
if (!r.found())
return;
if (r->value.ext != myself || r->value.provider != provider)
Capability *pCap = m_caps.retrieve(name);
if (pCap == NULL)
return;
m_caps.remove(r);
if (pCap->ext != myself || pCap->provider != provider)
return;
m_caps.remove(name);
}
FeatureStatus ShareSystem::TestFeature(IPluginRuntime *pRuntime, FeatureType feature,
@@ -478,18 +586,26 @@ FeatureStatus ShareSystem::TestNative(IPluginRuntime *pRuntime, const char *name
}
}
Ref<Native> entry = FindNative(name);
if (!entry)
NativeEntry *entry = FindNative(name);
if (entry == NULL)
return FeatureStatus_Unknown;
return FeatureStatus_Unavailable;
if ((entry->replacement.owner != NULL || entry->owner != NULL) &&
(entry->replacement.func != NULL || entry->func != NULL))
{
return FeatureStatus_Available;
}
else
{
return FeatureStatus_Unavailable;
}
}
FeatureStatus ShareSystem::TestCap(const char *name)
{
StringHashMap<Capability>::Result r = m_caps.find(name);
if (!r.found())
Capability *cap = m_caps.retrieve(name);
if (cap == NULL)
return FeatureStatus_Unknown;
return r->value.provider->GetFeatureStatus(FeatureType_Capability, name);
return cap->provider->GetFeatureStatus(FeatureType_Capability, name);
}
+37 -17
View File
@@ -1,5 +1,5 @@
/**
* vim: set ts=4 sw=4 tw=99 noet :
* vim: set ts=4 :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
@@ -34,14 +34,10 @@
#include <IShareSys.h>
#include <IHandleSys.h>
#include <am-string.h>
#include <am-utility.h>
#include <am-refcounting.h>
#include <sh_list.h>
#include <sm_stringhashmap.h>
#include <sm_namehashset.h>
#include "common_logic.h"
#include "Native.h"
#include <sm_trie_tpl.h>
#include "sm_globals.h"
#include "sourcemod.h"
using namespace SourceHook;
@@ -67,6 +63,29 @@ struct IfaceInfo
class CNativeOwner;
class CPlugin;
struct NativeEntry;
struct ReplaceNative
{
CNativeOwner *owner;
SPVM_NATIVE_FUNC func;
};
struct FakeNative
{
char name[64];
IPluginContext *ctx;
IPluginFunction *call;
};
struct NativeEntry
{
CNativeOwner *owner;
SPVM_NATIVE_FUNC func;
const char *name;
ReplaceNative replacement;
FakeNative *fake;
};
struct Capability
{
@@ -120,23 +139,24 @@ public:
}
public:
void BindNativesToPlugin(CPlugin *pPlugin, bool bCoreOnly);
void BindNativeToPlugin(CPlugin *pPlugin, const ke::Ref<Native> &pEntry);
ke::PassRef<Native> AddFakeNative(IPluginFunction *pFunc, const char *name, SPVM_FAKENATIVE_FUNC func);
ke::PassRef<Native> FindNative(const char *name);
void BindNativeToPlugin(CPlugin *pPlugin, NativeEntry *pEntry);
NativeEntry *AddFakeNative(IPluginFunction *pFunc, const char *name, SPVM_FAKENATIVE_FUNC func);
NativeEntry *FindNative(const char *name);
private:
ke::PassRef<Native> AddNativeToCache(CNativeOwner *pOwner, const sp_nativeinfo_t *ntv);
NativeEntry *AddNativeToCache(CNativeOwner *pOwner, const sp_nativeinfo_t *ntv);
void ClearNativeFromCache(CNativeOwner *pOwner, const char *name);
void BindNativeToPlugin(CPlugin *pPlugin, sp_native_t *ntv, uint32_t index, const ke::Ref<Native> &pEntry);
void BindNativeToPlugin(CPlugin *pPlugin,
sp_native_t *ntv,
uint32_t index,
NativeEntry *pEntry);
private:
typedef NameHashSet<ke::Ref<Native>, Native> NativeCache;
List<IfaceInfo> m_Interfaces;
HandleType_t m_TypeRoot;
IdentityToken_t m_IdentRoot;
HandleType_t m_IfaceType;
IdentityType_t m_CoreType;
NativeCache m_NtvCache;
StringHashMap<Capability> m_caps;
KTrie<NativeEntry *> m_NtvCache;
KTrie<Capability> m_caps;
};
extern ShareSystem g_ShareSys;
+6 -6
View File
@@ -31,10 +31,10 @@
#include <time.h>
#include "TimerSys.h"
#include "ForwardSys.h"
#include "sourcemm_api.h"
#include "frame_hooks.h"
#include "ConVarManager.h"
#include "logic_bridge.h"
#define TIMER_MIN_ACCURACY 0.1
@@ -180,9 +180,9 @@ TimerSystem::~TimerSystem()
void TimerSystem::OnSourceModAllInitialized()
{
sharesys->AddInterface(NULL, this);
m_pOnGameFrame = forwardsys->CreateForward("OnGameFrame", ET_Ignore, 0, NULL);
m_pOnMapTimeLeftChanged = forwardsys->CreateForward("OnMapTimeLeftChanged", ET_Ignore, 0, NULL);
g_ShareSys.AddInterface(NULL, this);
m_pOnGameFrame = g_Forwards.CreateForward("OnGameFrame", ET_Ignore, 0, NULL);
m_pOnMapTimeLeftChanged = g_Forwards.CreateForward("OnMapTimeLeftChanged", ET_Ignore, 0, NULL);
}
void TimerSystem::OnSourceModGameInitialized()
@@ -198,8 +198,8 @@ void TimerSystem::OnSourceModGameInitialized()
void TimerSystem::OnSourceModShutdown()
{
SetMapTimer(NULL);
forwardsys->ReleaseForward(m_pOnGameFrame);
forwardsys->ReleaseForward(m_pOnMapTimeLeftChanged);
g_Forwards.ReleaseForward(m_pOnGameFrame);
g_Forwards.ReleaseForward(m_pOnMapTimeLeftChanged);
}
void TimerSystem::OnSourceModLevelEnd()
+2 -2
View File
@@ -32,11 +32,11 @@
#ifndef _INCLUDE_SOURCEMOD_CTIMERSYS_H_
#define _INCLUDE_SOURCEMOD_CTIMERSYS_H_
#include "ShareSys.h"
#include <ITimerSystem.h>
#include <sh_stack.h>
#include <sh_list.h>
#include "sourcemm_api.h"
#include "sm_globals.h"
using namespace SourceHook;
using namespace SourceMod;
@@ -78,11 +78,11 @@ public: //ITimerSystem
float GetTickedTime();
void NotifyOfGameStart(float offset /* = 0.0f */);
bool GetMapTimeLeft(float *pTime);
IMapTimer *GetMapTimer();
public:
void RunFrame();
void RemoveMapChangeTimers();
void GameFrame(bool simulating);
IMapTimer *GetMapTimer();
private:
List<ITimer *> m_SingleTimers;
List<ITimer *> m_LoopTimers;
+143 -108
View File
@@ -1,5 +1,5 @@
/**
* vim: set ts=4 sw=4 tw=99 noet:
* vim: set ts=4 :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
@@ -29,24 +29,22 @@
* Version: $Id$
*/
#include "common_logic.h"
#include <stdarg.h>
#include <stdlib.h>
#include <ctype.h>
#include <sm_platform.h>
#include "Translator.h"
#include <IPlayerHelpers.h>
#include <ISourceMod.h>
#include <ILibrarySys.h>
#include "Logger.h"
#include "LibrarySys.h"
#include "sm_stringutil.h"
#include "sourcemod.h"
#include "PlayerManager.h"
#include "PhraseCollection.h"
#include "stringutil.h"
#include "ShareSys.h"
Translator g_Translator;
IPhraseCollection *g_pCorePhrases = NULL;
unsigned int g_pCorePhraseID = 0;
using namespace SourceMod;
struct trans_t
{
int stridx;
@@ -69,10 +67,15 @@ CPhraseFile::CPhraseFile(Translator *pTranslator, const char *file)
m_LangCount = pTranslator->GetLanguageCount();
m_File.assign(file);
m_pTranslator = pTranslator;
m_pPhraseLookup = NULL;
}
CPhraseFile::~CPhraseFile()
{
if (m_pPhraseLookup)
{
sm_trie_destroy(m_pPhraseLookup);
}
}
void CPhraseFile::ParseError(const char *message, ...)
@@ -96,16 +99,20 @@ void CPhraseFile::ParseWarning(const char *message, ...)
if (!m_FileLogged)
{
logger->LogError("[SM] Warning(s) encountered in translation file \"%s\"", m_File.c_str());
g_Logger.LogError("[SM] Warning(s) encountered in translation file \"%s\"", m_File.c_str());
m_FileLogged = true;
}
logger->LogError("[SM] %s", buffer);
g_Logger.LogError("[SM] %s", buffer);
}
void CPhraseFile::ReparseFile()
{
m_PhraseLookup.clear();
if (m_pPhraseLookup)
{
sm_trie_destroy(m_pPhraseLookup);
}
m_pPhraseLookup = sm_trie_create();
m_LangCount = m_pTranslator->GetLanguageCount();
@@ -116,19 +123,19 @@ void CPhraseFile::ReparseFile()
SMCError err;
char path[PLATFORM_MAX_PATH];
g_pSM->BuildPath(Path_SM, path, PLATFORM_MAX_PATH, "translations/%s", m_File.c_str());
g_SourceMod.BuildPath(Path_SM, path, PLATFORM_MAX_PATH, "translations/%s", m_File.c_str());
//backwards compatibility shim
/* :HACKHACK: Change .cfg/.txt and vice versa for compatibility */
if (!libsys->PathExists(path))
if (!g_LibSys.PathExists(path))
{
if (m_File.compare("common.cfg") == 0)
{
UTIL_ReplaceAll(path, sizeof(path), "common.cfg", "common.phrases.txt", true);
UTIL_ReplaceAll(path, sizeof(path), "common.cfg", "common.phrases.txt");
} else if (strstr(path, ".cfg")) {
UTIL_ReplaceAll(path, sizeof(path), ".cfg", ".txt", true);
UTIL_ReplaceAll(path, sizeof(path), ".cfg", ".txt");
} else if (strstr(path, ".txt")) {
UTIL_ReplaceAll(path, sizeof(path), ".txt", ".cfg", true);
UTIL_ReplaceAll(path, sizeof(path), ".txt", ".cfg");
}
}
@@ -142,8 +149,8 @@ void CPhraseFile::ReparseFile()
msg = m_ParseError.c_str();
}
logger->LogError("[SM] Fatal error encountered parsing translation file \"%s\"", m_File.c_str());
logger->LogError("[SM] Error (line %d, column %d): %s", states.line, states.col, msg);
g_Logger.LogError("[SM] Fatal error encountered parsing translation file \"%s\"", m_File.c_str());
g_Logger.LogError("[SM] Error (line %d, column %d): %s", states.line, states.col, msg);
}
const char *code;
@@ -154,7 +161,7 @@ void CPhraseFile::ReparseFile()
continue;
}
g_pSM->BuildPath(Path_SM,
g_SourceMod.BuildPath(Path_SM,
path,
PLATFORM_MAX_PATH,
"translations/%s/%s",
@@ -162,7 +169,7 @@ void CPhraseFile::ReparseFile()
m_File.c_str());
/* Speculatively load these. */
if (!libsys->PathExists(path))
if (!g_LibSys.PathExists(path))
{
continue;
}
@@ -175,10 +182,10 @@ void CPhraseFile::ReparseFile()
msg = m_ParseError.c_str();
}
logger->LogError("[SM] Fatal error encountered parsing translation file \"%s/%s\"",
g_Logger.LogError("[SM] Fatal error encountered parsing translation file \"%s/%s\"",
code,
m_File.c_str());
logger->LogError("[SM] Error (line %d, column %d): %s",
g_Logger.LogError("[SM] Error (line %d, column %d): %s",
states.line,
states.col,
msg);
@@ -210,12 +217,17 @@ SMCResult CPhraseFile::ReadSMC_NewSection(const SMCStates *states, const char *n
m_ParseState = PPS_InPhrase;
recognized = true;
if (!m_PhraseLookup.retrieve(name, &m_CurPhrase))
void *value;
if (sm_trie_retrieve(m_pPhraseLookup, name, &value))
{
m_CurPhrase = reinterpret_cast<int>(value);
}
else
{
phrase_t *pPhrase;
m_CurPhrase = m_pMemory->CreateMem(sizeof(phrase_t), (void **)&pPhrase);
m_PhraseLookup.insert(name, m_CurPhrase);
sm_trie_insert(m_pPhraseLookup, name, reinterpret_cast<void *>(m_CurPhrase));
/* Initialize new phrase */
trans_t *pTrans;
@@ -474,6 +486,13 @@ SMCResult CPhraseFile::ReadSMC_KeyValue(const SMCStates *states, const char *key
}
else
{
size_t len = strlen(key);
if (len < 2 || len > 3)
{
ParseWarning("Ignoring translation to invalid language \"%s\" on line %d.", key, states->line);
return SMCResult_Continue;
}
unsigned int lang;
if (!m_pTranslator->GetLanguageByCode(key, &lang))
{
@@ -486,7 +505,7 @@ SMCResult CPhraseFile::ReadSMC_KeyValue(const SMCStates *states, const char *key
/* See how many bytes we need for this string, then allocate.
* NOTE: THIS SHOULD GUARANTEE THAT WE DO NOT NEED TO NEED TO SIZE CHECK
*/
size_t len = strlen(value) + pPhrase->fmt_bytes + 1;
len = strlen(value) + pPhrase->fmt_bytes + 1;
char *out_buf;
int out_idx;
@@ -620,7 +639,9 @@ SMCResult CPhraseFile::ReadSMC_LeavingSection(const SMCStates *states)
if (m_ParseState == PPS_InPhrase)
{
if (m_CurPhrase == -1 && m_LastPhraseString.size())
m_PhraseLookup.remove(m_LastPhraseString.c_str());
{
sm_trie_delete(m_pPhraseLookup, m_LastPhraseString.c_str());
}
m_CurPhrase = -1;
m_ParseState = PPS_Phrases;
m_LastPhraseString.assign("");
@@ -637,7 +658,9 @@ void CPhraseFile::ReadSMC_ParseEnd(bool halted, bool failed)
{
/* Check to see if we have any dangling phrases that weren't completed, and scrap them */
if ((halted || failed) && m_LastPhraseString.size())
m_PhraseLookup.remove(m_LastPhraseString.c_str());
{
sm_trie_delete(m_pPhraseLookup, m_LastPhraseString.c_str());
}
}
TransError CPhraseFile::GetTranslation(const char *szPhrase, unsigned int lang_id, Translation *pTrans)
@@ -647,11 +670,13 @@ TransError CPhraseFile::GetTranslation(const char *szPhrase, unsigned int lang_i
return Trans_BadLanguage;
}
int address;
if (!m_PhraseLookup.retrieve(szPhrase, &address))
void *object;
if (!sm_trie_retrieve(m_pPhraseLookup, szPhrase, &object))
{
return Trans_BadPhrase;
}
phrase_t *pPhrase = (phrase_t *)m_pMemory->GetAddress(address);
phrase_t *pPhrase = (phrase_t *)m_pMemory->GetAddress(reinterpret_cast<int>(object));
trans_t *trans = (trans_t *)m_pMemory->GetAddress(pPhrase->trans_tbl);
trans = &trans[lang_id];
@@ -680,6 +705,7 @@ const char *CPhraseFile::GetFilename()
Translator::Translator() : m_ServerLang(SOURCEMOD_LANGUAGE_ENGLISH)
{
m_pStringTab = new BaseStringTable(2048);
m_pLCodeLookup = sm_trie_create();
strncopy(m_InitialLang, "en", sizeof(m_InitialLang));
}
@@ -695,6 +721,8 @@ Translator::~Translator()
delete m_Languages[i];
}
sm_trie_destroy(m_pLCodeLookup);
delete m_pStringTab;
}
@@ -711,13 +739,13 @@ ConfigResult Translator::OnSourceModConfigChanged(const char *key,
unsigned int index;
if (!GetLanguageByCode(value, &index))
{
smcore.Format(error, maxlength, "Language code \"%s\" is not registered", value);
UTIL_Format(error, maxlength, "Language code \"%s\" is not registered", value);
return ConfigResult_Reject;
}
m_ServerLang = index;
} else {
smcore.strncopy(m_InitialLang, value, sizeof(m_InitialLang));
strncopy(m_InitialLang, value, sizeof(m_InitialLang));
}
return ConfigResult_Accept;
@@ -728,23 +756,20 @@ ConfigResult Translator::OnSourceModConfigChanged(const char *key,
void Translator::OnSourceModLevelChange(const char *mapName)
{
RebuildLanguageDatabase();
/* Refresh language stuff */
char path[PLATFORM_MAX_PATH];
g_SourceMod.BuildPath(Path_SM, path, sizeof(path), "configs/languages.cfg");
RebuildLanguageDatabase(path);
}
void Translator::OnSourceModAllInitialized()
{
AddLanguage("en", "English");
const char* lang = smcore.GetCoreConfigValue("ServerLang");
if (lang)
{
strncpy(m_InitialLang, lang, sizeof(m_InitialLang));
}
g_pCorePhrases = CreatePhraseCollection();
g_pCorePhrases->AddPhraseFile("core.phrases");
sharesys->AddInterface(NULL, this);
g_ShareSys.AddInterface(NULL, this);
}
void Translator::OnSourceModShutdown()
@@ -754,24 +779,45 @@ void Translator::OnSourceModShutdown()
bool Translator::GetLanguageByCode(const char *code, unsigned int *index)
{
return m_LCodeLookup.retrieve(code, index);
void *_index;
if (!sm_trie_retrieve(m_pLCodeLookup, code, &_index))
{
return false;
}
if (index)
{
*index = reinterpret_cast<unsigned int>(_index);
}
return true;
}
bool Translator::GetLanguageByName(const char *name, unsigned int *index)
{
char lower[256];
size_t len = strlen(name);
if (len > 255) len = 255;
for (size_t i = 0; i < len; i++)
{
if (name[i] >= 'A' && name[i] <= 'Z')
lower[i] = tolower(name[i]);
else
lower[i] = name[i];
}
lower[len] = '\0';
CVector<Language *>::iterator iter;
unsigned int id = 0;
return m_LAliases.retrieve(lower, index);
for (iter=m_Languages.begin(); iter!=m_Languages.end(); iter++, id++)
{
if (strcasecmp(m_pStringTab->GetString((*iter)->m_FullName), name) == 0)
{
break;
}
}
if (iter == m_Languages.end())
{
return false;
}
if (index)
{
*index = id;
}
return true;
}
unsigned int Translator::GetLanguageCount()
@@ -804,11 +850,11 @@ unsigned int Translator::FindOrAddPhraseFile(const char *phrase_file)
return idx;
}
void Translator::RebuildLanguageDatabase()
void Translator::RebuildLanguageDatabase(const char *lang_header_file)
{
/* Erase everything we have */
m_LCodeLookup.clear();
m_LAliases.clear();
sm_trie_destroy(m_pLCodeLookup);
m_pLCodeLookup = sm_trie_create();
m_pStringTab->Reset();
for (size_t i=0; i<m_Languages.size(); i++)
@@ -818,12 +864,9 @@ void Translator::RebuildLanguageDatabase()
m_Languages.clear();
/* Start anew */
char path[PLATFORM_MAX_PATH];
g_pSM->BuildPath(Path_SM, path, sizeof(path), "configs/languages.cfg");
SMCError err;
SMCStates states;
if ((err=textparsers->ParseFile_SMC(path, this, &states)) != SMCError_Okay)
if ((err=textparsers->ParseFile_SMC(lang_header_file, this, &states)) != SMCError_Okay)
{
const char *str_err = textparsers->GetSMCErrorString(err);
if (!str_err)
@@ -831,21 +874,25 @@ void Translator::RebuildLanguageDatabase()
str_err = m_CustomError.c_str();
}
logger->LogError("[SM] Failed to parse language header file: \"%s\"", path);
logger->LogError("[SM] Parse error (line %d, column %d): %s", states.line, states.col, str_err);
g_Logger.LogError("[SM] Failed to parse language header file: \"%s\"", lang_header_file);
g_Logger.LogError("[SM] Parse error (line %d, column %d): %s", states.line, states.col, str_err);
}
if (!m_LCodeLookup.retrieve(m_InitialLang, &m_ServerLang))
{
logger->LogError("Server language was set to bad language \"%s\" -- reverting to English", m_InitialLang);
void *serverLang;
smcore.strncopy(m_InitialLang, "en", sizeof(m_InitialLang));
if (!sm_trie_retrieve(m_pLCodeLookup, m_InitialLang, &serverLang))
{
g_Logger.LogError("Server language was set to bad language \"%s\" -- reverting to English", m_InitialLang);
strncopy(m_InitialLang, "en", sizeof(m_InitialLang));
m_ServerLang = SOURCEMOD_LANGUAGE_ENGLISH;
}
m_ServerLang = reinterpret_cast<unsigned int>(serverLang);
if (!m_Languages.size())
{
logger->LogError("[SM] Fatal error, no languages found! Translation will not work.");
g_Logger.LogError("[SM] Fatal error, no languages found! Translation will not work.");
}
for (size_t i=0; i<m_Files.size(); i++)
@@ -872,7 +919,7 @@ SMCResult Translator::ReadSMC_NewSection(const SMCStates *states, const char *na
if (!m_InLanguageSection)
{
logger->LogError("[SM] Warning: Unrecognized section \"%s\" in languages.cfg", name);
g_Logger.LogError("[SM] Warning: Unrecognized section \"%s\" in languages.cfg", name);
}
return SMCResult_Continue;
@@ -889,10 +936,10 @@ SMCResult Translator::ReadSMC_KeyValue(const SMCStates *states, const char *key,
{
size_t len = strlen(key);
if (len >= sizeof(((Language *)0)->m_code2))
if (len < 2 || len > 3)
{
logger->LogError("[SM] Warning encountered parsing languages.cfg file.");
logger->LogError("[SM] Invalid language code \"%s\" is too long.", key);
g_Logger.LogError("[SM] Warning encountered parsing languages.cfg file.");
g_Logger.LogError("[SM] Invalid language code \"%s\" is being ignored.", key);
}
AddLanguage(key, value);
@@ -902,36 +949,20 @@ SMCResult Translator::ReadSMC_KeyValue(const SMCStates *states, const char *key,
bool Translator::AddLanguage(const char *langcode, const char *description)
{
char lower[256];
size_t len = strlen(description);
if (len > 255) len = 255;
for (size_t i = 0; i < len; i++)
if (sm_trie_retrieve(m_pLCodeLookup, langcode, NULL))
{
if (description[i] >= 'A' && description[i] <= 'Z')
lower[i] = tolower(description[i]);
else
lower[i] = description[i];
}
lower[len] = '\0';
if (m_LAliases.contains(lower))
return false;
unsigned int idx;
if (!m_LCodeLookup.retrieve(langcode, &idx))
{
Language *pLanguage = new Language;
idx = m_Languages.size();
smcore.Format(pLanguage->m_code2, sizeof(pLanguage->m_code2), "%s", langcode);
pLanguage->m_CanonicalName = m_pStringTab->AddString(lower);
m_LCodeLookup.insert(langcode, idx);
m_Languages.push_back(pLanguage);
}
m_LAliases.insert(lower, idx);
Language *pLanguage = new Language;
unsigned int idx = m_Languages.size();
UTIL_Format(pLanguage->m_code2, sizeof(pLanguage->m_code2), "%s", langcode);
pLanguage->m_FullName = m_pStringTab->AddString(description);
sm_trie_insert(m_pLCodeLookup, langcode, reinterpret_cast<void *>(idx));
m_Languages.push_back(pLanguage);
return true;
}
@@ -953,7 +984,7 @@ unsigned int Translator::GetServerLanguage()
unsigned int Translator::GetClientLanguage(int client)
{
IGamePlayer *pPlayer = playerhelpers->GetGamePlayer(client);
CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
return pPlayer->GetLanguageId();
}
@@ -971,7 +1002,7 @@ bool Translator::GetLanguageInfo(unsigned int number, const char **code, const c
}
if (name)
{
*name = m_pStringTab->GetString(l->m_CanonicalName);
*name = m_pStringTab->GetString(l->m_FullName);
}
return true;
@@ -994,16 +1025,20 @@ IPhraseCollection *Translator::CreatePhraseCollection()
int Translator::SetGlobalTarget(int index)
{
return g_pSM->SetGlobalTarget(index);
return g_SourceMod.SetGlobalTarget(index);
}
int Translator::GetGlobalTarget() const
{
return g_pSM->GetGlobalTarget();
return g_SourceMod.GetGlobalTarget();
}
bool CoreTranslate(char *buffer, size_t maxlength, const char *format, unsigned int numparams,
size_t *pOutLength, ...)
bool CoreTranslate(char *buffer,
size_t maxlength,
const char *format,
unsigned int numparams,
size_t *pOutLength,
...)
{
va_list ap;
unsigned int i;
@@ -1033,11 +1068,11 @@ bool CoreTranslate(char *buffer, size_t maxlength, const char *format, unsigned
{
if (fail_phrase != NULL)
{
logger->LogError("[SM] Could not find core phrase: %s", fail_phrase);
g_Logger.LogError("[SM] Could not find core phrase: %s", fail_phrase);
}
else
{
logger->LogError("[SM] Unknown fatal error while translating a core phrase.");
g_Logger.LogError("[SM] Unknown fatal error while translating a core phrase.");
}
return false;
@@ -1058,7 +1093,7 @@ bool Translator::FormatString(char *buffer,
unsigned int arg;
arg = 0;
if (!smcore.gnprintf(buffer, maxlength, format, pPhrases, params, numparams, arg, pOutLength, pFailPhrase))
if (!gnprintf(buffer, maxlength, format, pPhrases, params, numparams, arg, pOutLength, pFailPhrase))
{
return false;
}
+11 -10
View File
@@ -32,14 +32,17 @@
#ifndef _INCLUDE_SOURCEMOD_TRANSLATOR_H_
#define _INCLUDE_SOURCEMOD_TRANSLATOR_H_
#include "common_logic.h"
#include <sm_stringhashmap.h>
#include "sm_trie.h"
#include <sh_string.h>
#include <sh_vector.h>
#include "sm_globals.h"
#include "sm_memtable.h"
#include "ITextParsers.h"
#include <ITranslator.h>
#define MAX_TRANSLATE_PARAMS 32
#define CORELANG_ENGLISH 0
/* :TODO: write a templatized version of tries? */
using namespace SourceHook;
@@ -54,8 +57,8 @@ enum PhraseParseState
struct Language
{
char m_code2[32];
int m_CanonicalName;
char m_code2[4];
int m_FullName;
};
class CPhraseFile :
@@ -79,7 +82,7 @@ private:
void ParseError(const char *message, ...);
void ParseWarning(const char *message, ...);
private:
StringHashMap<int> m_PhraseLookup;
Trie *m_pPhraseLookup;
String m_File;
Translator *m_pTranslator;
PhraseParseState m_ParseState;
@@ -115,9 +118,11 @@ public: // ITextListener_SMC
SMCResult ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value);
SMCResult ReadSMC_LeavingSection(const SMCStates *states);
public:
void RebuildLanguageDatabase(const char *lang_header_file);
unsigned int FindOrAddPhraseFile(const char *phrase_file);
BaseStringTable *GetStringTable();
unsigned int GetLanguageCount();
bool GetLanguageInfo(unsigned int number, const char **code, const char **name);
bool GetLanguageByCode(const char *code, unsigned int *index);
bool GetLanguageByName(const char *name, unsigned int *index);
CPhraseFile *GetFileByIndex(unsigned int index);
@@ -144,16 +149,13 @@ public: //ITranslator
unsigned int numparams,
size_t *pOutLength,
const char **pFailPhrase);
bool GetLanguageInfo(unsigned int number, const char **code, const char **name);
void RebuildLanguageDatabase();
private:
bool AddLanguage(const char *langcode, const char *description);
private:
CVector<Language *> m_Languages;
CVector<CPhraseFile *> m_Files;
BaseStringTable *m_pStringTab;
StringHashMap<unsigned int> m_LCodeLookup;
StringHashMap<unsigned int> m_LAliases;
Trie *m_pLCodeLookup;
bool m_InLanguageSection;
String m_CustomError;
unsigned int m_ServerLang;
@@ -173,4 +175,3 @@ extern unsigned int g_pCorePhraseID;
extern Translator g_Translator;
#endif //_INCLUDE_SOURCEMOD_TRANSLATOR_H_
File diff suppressed because it is too large Load Diff
+60 -350
View File
@@ -1,8 +1,8 @@
/**
* vim: set ts=4 sw=4 tw=99 noet :
* vim: set ts=4 :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2010 AlliedModders LLC. All rights reserved.
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
* =============================================================================
*
* This program is free software; you can redistribute it and/or modify it under
@@ -31,35 +31,19 @@
#include "UserMessages.h"
#include "sm_stringutil.h"
#include "logic_bridge.h"
#if SOURCE_ENGINE == SE_DOTA
#include <dota_usermessage_helpers.h>
#elif SOURCE_ENGINE == SE_CSGO
#include <cstrike15_usermessage_helpers.h>
#endif
UserMessages g_UserMsgs;
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
SH_DECL_HOOK3_void(IVEngineServer, SendUserMessage, SH_NOATTRIB, 0, IRecipientFilter &, int, const protobuf::Message &);
#else
#if SOURCE_ENGINE >= SE_LEFT4DEAD
#if (SOURCE_ENGINE == SE_LEFT4DEAD) || (SOURCE_ENGINE == SE_LEFT4DEAD2)
SH_DECL_HOOK3(IVEngineServer, UserMessageBegin, SH_NOATTRIB, 0, bf_write *, IRecipientFilter *, int, const char *);
#else
SH_DECL_HOOK2(IVEngineServer, UserMessageBegin, SH_NOATTRIB, 0, bf_write *, IRecipientFilter *, int);
#endif
SH_DECL_HOOK0_void(IVEngineServer, MessageEnd, SH_NOATTRIB, 0);
#endif // ==SE_CSGO
UserMessages::UserMessages()
#ifndef USE_PROTOBUF_USERMESSAGES
: m_InterceptBuffer(m_pBase, 2500)
UserMessages::UserMessages() : m_InterceptBuffer(m_pBase, 2500)
{
#else
: m_InterceptBuffer(NULL)
{
#endif
m_Names = sm_trie_create();
m_HookCount = 0;
m_InExec = false;
m_InHook = false;
@@ -69,6 +53,8 @@ UserMessages::UserMessages()
UserMessages::~UserMessages()
{
sm_trie_destroy(m_Names);
CStack<ListenerInfo *>::iterator iter;
for (iter=m_FreeListeners.begin(); iter!=m_FreeListeners.end(); iter++)
{
@@ -79,46 +65,32 @@ UserMessages::~UserMessages()
void UserMessages::OnSourceModStartup(bool late)
{
#ifndef USE_PROTOBUF_USERMESSAGES
/* -1 means SourceMM was unable to get the user message list */
m_FallbackSearch = (g_SMAPI->GetUserMessageCount() == -1);
#endif
}
void UserMessages::OnSourceModAllInitialized()
{
sharesys->AddInterface(NULL, this);
g_ShareSys.AddInterface(NULL, this);
}
void UserMessages::OnSourceModAllShutdown()
{
if (m_HookCount)
{
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
SH_REMOVE_HOOK(IVEngineServer, SendUserMessage, engine, SH_MEMBER(this, &UserMessages::OnSendUserMessage_Pre), false);
SH_REMOVE_HOOK(IVEngineServer, SendUserMessage, engine, SH_MEMBER(this, &UserMessages::OnSendUserMessage_Post), true);
#else
SH_REMOVE_HOOK(IVEngineServer, UserMessageBegin, engine, SH_MEMBER(this, &UserMessages::OnStartMessage_Pre), false);
SH_REMOVE_HOOK(IVEngineServer, UserMessageBegin, engine, SH_MEMBER(this, &UserMessages::OnStartMessage_Post), true);
SH_REMOVE_HOOK(IVEngineServer, MessageEnd, engine, SH_MEMBER(this, &UserMessages::OnMessageEnd_Pre), false);
SH_REMOVE_HOOK(IVEngineServer, MessageEnd, engine, SH_MEMBER(this, &UserMessages::OnMessageEnd_Post), true);
#endif
SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &UserMessages::OnStartMessage_Pre, false);
SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &UserMessages::OnStartMessage_Post, true);
SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &UserMessages::OnMessageEnd_Pre, false);
SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &UserMessages::OnMessageEnd_Post, true);
}
m_HookCount = 0;
}
int UserMessages::GetMessageIndex(const char *msg)
{
#if SOURCE_ENGINE == SE_DOTA
// Can split this per engine and/or game later
return g_DotaUsermessageHelpers.GetIndex(msg);
#elif SOURCE_ENGINE == SE_CSGO
// Can split this per engine and/or game later
return g_Cstrike15UsermessageHelpers.GetIndex(msg);
#else
int msgid;
if (!m_Names.retrieve(msg, &msgid))
if (!sm_trie_retrieve(m_Names, msg, reinterpret_cast<void **>(&msgid)))
{
if (m_FallbackSearch)
{
@@ -130,7 +102,7 @@ int UserMessages::GetMessageIndex(const char *msg)
{
if (strcmp(msgbuf, msg) == 0)
{
m_Names.insert(msg, msgid);
sm_trie_insert(m_Names, msg, reinterpret_cast<void *>(msgid));
return msgid;
}
msgid++;
@@ -140,27 +112,16 @@ int UserMessages::GetMessageIndex(const char *msg)
msgid = g_SMAPI->FindUserMessage(msg);
if (msgid != INVALID_MESSAGE_ID)
m_Names.insert(msg, msgid);
{
sm_trie_insert(m_Names, msg, reinterpret_cast<void *>(msgid));
}
}
return msgid;
#endif
}
bool UserMessages::GetMessageName(int msgid, char *buffer, size_t maxlength) const
{
#ifdef USE_PROTOBUF_USERMESSAGES
#if SOURCE_ENGINE == SE_DOTA
const char *pszName = g_DotaUsermessageHelpers.GetName(msgid);
#elif SOURCE_ENGINE == SE_CSGO
const char *pszName = g_Cstrike15UsermessageHelpers.GetName(msgid);
#endif
if (!pszName)
return false;
strncopy(buffer, pszName, maxlength);
return true;
#else
if (m_FallbackSearch)
{
int size;
@@ -176,14 +137,10 @@ bool UserMessages::GetMessageName(int msgid, char *buffer, size_t maxlength) con
}
return false;
#endif
}
bf_write *UserMessages::StartBitBufMessage(int msg_id, const cell_t players[], unsigned int playersNum, int flags)
bf_write *UserMessages::StartMessage(int msg_id, const cell_t players[], unsigned int playersNum, int flags)
{
#ifdef USE_PROTOBUF_USERMESSAGES
return NULL;
#else
bf_write *buffer;
if (m_InExec || m_InHook)
@@ -211,13 +168,13 @@ bf_write *UserMessages::StartBitBufMessage(int msg_id, const cell_t players[], u
if (m_CurFlags & USERMSG_BLOCKHOOKS)
{
#if SOURCE_ENGINE >= SE_LEFT4DEAD
#if (SOURCE_ENGINE == SE_LEFT4DEAD) || (SOURCE_ENGINE == SE_LEFT4DEAD2)
buffer = ENGINE_CALL(UserMessageBegin)(static_cast<IRecipientFilter *>(&m_CellRecFilter), msg_id, g_SMAPI->GetUserMessage(msg_id));
#else
buffer = ENGINE_CALL(UserMessageBegin)(static_cast<IRecipientFilter *>(&m_CellRecFilter), msg_id);
#endif
} else {
#if SOURCE_ENGINE >= SE_LEFT4DEAD
#if (SOURCE_ENGINE == SE_LEFT4DEAD) || (SOURCE_ENGINE == SE_LEFT4DEAD2)
buffer = engine->UserMessageBegin(static_cast<IRecipientFilter *>(&m_CellRecFilter), msg_id, g_SMAPI->GetUserMessage(msg_id));
#else
buffer = engine->UserMessageBegin(static_cast<IRecipientFilter *>(&m_CellRecFilter), msg_id);
@@ -225,75 +182,6 @@ bf_write *UserMessages::StartBitBufMessage(int msg_id, const cell_t players[], u
}
return buffer;
#endif // USE_PROTOBUF_USERMESSAGES
}
google::protobuf::Message *UserMessages::StartProtobufMessage(int msg_id, const cell_t players[], unsigned int playersNum, int flags)
{
#ifndef USE_PROTOBUF_USERMESSAGES
return NULL;
#else
protobuf::Message *buffer;
if (m_InExec || m_InHook)
{
return NULL;
}
if (msg_id < 0 || msg_id >= 255)
{
return NULL;
}
m_CurId = msg_id;
m_CellRecFilter.Initialize(players, playersNum);
m_CurFlags = flags;
if (m_CurFlags & USERMSG_INITMSG)
{
m_CellRecFilter.SetToInit(true);
}
if (m_CurFlags & USERMSG_RELIABLE)
{
m_CellRecFilter.SetToReliable(true);
}
m_InExec = true;
if (m_CurFlags & USERMSG_BLOCKHOOKS)
{
// direct message creation, return buffer "from engine". keep track
m_FakeEngineBuffer = GetMessagePrototype(msg_id)->New();
buffer = m_FakeEngineBuffer;
} else {
char messageName[32];
if (!GetMessageName(msg_id, messageName, sizeof(messageName)))
{
m_InExec = false;
return NULL;
}
protobuf::Message *msg = OnStartMessage_Pre(static_cast<IRecipientFilter *>(&m_CellRecFilter), msg_id, messageName);
switch (m_FakeMetaRes)
{
case MRES_IGNORED:
case MRES_HANDLED:
m_FakeEngineBuffer = GetMessagePrototype(msg_id)->New();
buffer = m_FakeEngineBuffer;
break;
case MRES_OVERRIDE:
m_FakeEngineBuffer = GetMessagePrototype(msg_id)->New();
// fallthrough
case MRES_SUPERCEDE:
buffer = msg;
break;
}
OnStartMessage_Post(static_cast<IRecipientFilter *>(&m_CellRecFilter), msg_id, messageName);
}
return buffer;
#endif // USE_PROTOBUF_USERMESSAGES
}
bool UserMessages::EndMessage()
@@ -303,37 +191,12 @@ bool UserMessages::EndMessage()
return false;
}
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
if (m_CurFlags & USERMSG_BLOCKHOOKS)
{
ENGINE_CALL(SendUserMessage)(static_cast<IRecipientFilter &>(m_CellRecFilter), m_CurId, *m_FakeEngineBuffer);
delete m_FakeEngineBuffer;
m_FakeEngineBuffer = NULL;
} else {
OnMessageEnd_Pre();
switch (m_FakeMetaRes)
{
case MRES_IGNORED:
case MRES_HANDLED:
case MRES_OVERRIDE:
engine->SendUserMessage(static_cast<IRecipientFilter &>(m_CellRecFilter), m_CurId, *m_FakeEngineBuffer);
delete m_FakeEngineBuffer;
m_FakeEngineBuffer = NULL;
break;
//case MRES_SUPERCEDE:
}
OnMessageEnd_Post();
}
#else
if (m_CurFlags & USERMSG_BLOCKHOOKS)
{
ENGINE_CALL(MessageEnd)();
} else {
engine->MessageEnd();
}
#endif // SE_CSGO || SE_DOTA
m_InExec = false;
m_CurFlags = 0;
@@ -342,60 +205,31 @@ bool UserMessages::EndMessage()
return true;
}
UserMessageType UserMessages::GetUserMessageType() const
{
#ifdef USE_PROTOBUF_USERMESSAGES
return UM_Protobuf;
#else
return UM_BitBuf;
#endif
}
bool UserMessages::HookUserMessage2(int msg_id,
IUserMessageListener *pListener,
bool intercept)
{
#ifdef USE_PROTOBUF_USERMESSAGES
return InternalHook(msg_id, (IProtobufUserMessageListener *)pListener, intercept, true);
#else
return InternalHook(msg_id, (IBitBufUserMessageListener *)pListener, intercept, true);
#endif
return InternalHook(msg_id, pListener, intercept, true);
}
bool UserMessages::UnhookUserMessage2(int msg_id,
IUserMessageListener *pListener,
bool intercept)
{
#ifdef USE_PROTOBUF_USERMESSAGES
return InternalUnhook(msg_id, (IProtobufUserMessageListener *)pListener, intercept, true);
#else
return InternalUnhook(msg_id, (IBitBufUserMessageListener *)pListener, intercept, true);
#endif
return InternalUnhook(msg_id, pListener, intercept, true);
}
bool UserMessages::HookUserMessage(int msg_id, IUserMessageListener *pListener, bool intercept)
{
#ifdef USE_PROTOBUF_USERMESSAGES
return InternalHook(msg_id, (IProtobufUserMessageListener *)pListener, intercept, false);
#else
return InternalHook(msg_id, (IBitBufUserMessageListener *)pListener, intercept, false);
#endif
return InternalHook(msg_id, pListener, intercept, false);
}
bool UserMessages::UnhookUserMessage(int msg_id, IUserMessageListener *pListener, bool intercept)
{
#ifdef USE_PROTOBUF_USERMESSAGES
return InternalUnhook(msg_id, (IProtobufUserMessageListener *)pListener, intercept, false);
#else
return InternalUnhook(msg_id, (IBitBufUserMessageListener *)pListener, intercept, false);
#endif
return InternalUnhook(msg_id, pListener, intercept, false);
}
#ifdef USE_PROTOBUF_USERMESSAGES
bool UserMessages::InternalHook(int msg_id, IProtobufUserMessageListener *pListener, bool intercept, bool isNew)
#else
bool UserMessages::InternalHook(int msg_id, IBitBufUserMessageListener *pListener, bool intercept, bool isNew)
#endif
bool UserMessages::InternalHook(int msg_id, IUserMessageListener *pListener, bool intercept, bool isNew)
{
if (msg_id < 0 || msg_id >= 255)
{
@@ -418,15 +252,10 @@ bool UserMessages::InternalHook(int msg_id, IBitBufUserMessageListener *pListene
if (!m_HookCount++)
{
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
SH_ADD_HOOK(IVEngineServer, SendUserMessage, engine, SH_MEMBER(this, &UserMessages::OnSendUserMessage_Pre), false);
SH_ADD_HOOK(IVEngineServer, SendUserMessage, engine, SH_MEMBER(this, &UserMessages::OnSendUserMessage_Post), true);
#else
SH_ADD_HOOK(IVEngineServer, UserMessageBegin, engine, SH_MEMBER(this, &UserMessages::OnStartMessage_Pre), false);
SH_ADD_HOOK(IVEngineServer, UserMessageBegin, engine, SH_MEMBER(this, &UserMessages::OnStartMessage_Post), true);
SH_ADD_HOOK(IVEngineServer, MessageEnd, engine, SH_MEMBER(this, &UserMessages::OnMessageEnd_Pre), false);
SH_ADD_HOOK(IVEngineServer, MessageEnd, engine, SH_MEMBER(this, &UserMessages::OnMessageEnd_Post), true);
#endif
SH_ADD_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &UserMessages::OnStartMessage_Pre, false);
SH_ADD_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &UserMessages::OnStartMessage_Post, true);
SH_ADD_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &UserMessages::OnMessageEnd_Pre, false);
SH_ADD_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &UserMessages::OnMessageEnd_Post, true);
}
if (intercept)
@@ -439,22 +268,7 @@ bool UserMessages::InternalHook(int msg_id, IBitBufUserMessageListener *pListene
return true;
}
#ifdef USE_PROTOBUF_USERMESSAGES
const protobuf::Message *UserMessages::GetMessagePrototype(int msg_type)
{
#if SOURCE_ENGINE == SE_DOTA
return g_DotaUsermessageHelpers.GetPrototype(msg_type);
#elif SOURCE_ENGINE == SE_CSGO
return g_Cstrike15UsermessageHelpers.GetPrototype(msg_type);
#endif
}
#endif
#ifdef USE_PROTOBUF_USERMESSAGES
bool UserMessages::InternalUnhook(int msg_id, IProtobufUserMessageListener *pListener, bool intercept, bool isNew)
#else
bool UserMessages::InternalUnhook(int msg_id, IBitBufUserMessageListener *pListener, bool intercept, bool isNew)
#endif
bool UserMessages::InternalUnhook(int msg_id, IUserMessageListener *pListener, bool intercept, bool isNew)
{
MsgList *pList;
MsgIter iter;
@@ -495,77 +309,14 @@ void UserMessages::_DecRefCounter()
{
if (--m_HookCount == 0)
{
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
SH_REMOVE_HOOK(IVEngineServer, SendUserMessage, engine, SH_MEMBER(this, &UserMessages::OnSendUserMessage_Pre), false);
SH_REMOVE_HOOK(IVEngineServer, SendUserMessage, engine, SH_MEMBER(this, &UserMessages::OnSendUserMessage_Post), true);
#else
SH_REMOVE_HOOK(IVEngineServer, UserMessageBegin, engine, SH_MEMBER(this, &UserMessages::OnStartMessage_Pre), false);
SH_REMOVE_HOOK(IVEngineServer, UserMessageBegin, engine, SH_MEMBER(this, &UserMessages::OnStartMessage_Post), true);
SH_REMOVE_HOOK(IVEngineServer, MessageEnd, engine, SH_MEMBER(this, &UserMessages::OnMessageEnd_Pre), false);
SH_REMOVE_HOOK(IVEngineServer, MessageEnd, engine, SH_MEMBER(this, &UserMessages::OnMessageEnd_Post), true);
#endif
SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &UserMessages::OnStartMessage_Pre, false);
SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &UserMessages::OnStartMessage_Post, true);
SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &UserMessages::OnMessageEnd_Pre, false);
SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &UserMessages::OnMessageEnd_Post, true);
}
}
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
void UserMessages::OnSendUserMessage_Pre(IRecipientFilter &filter, int msg_type, const protobuf::Message &msg)
{
#if SOURCE_ENGINE == SE_DOTA
OnStartMessage_Pre(&filter, msg_type, g_DotaUsermessageHelpers.GetName(msg_type));
#elif SOURCE_ENGINE == SE_CSGO
OnStartMessage_Pre(&filter, msg_type, g_Cstrike15UsermessageHelpers.GetName(msg_type));
#endif
if (m_FakeMetaRes == MRES_SUPERCEDE)
{
int size = msg.ByteSize();
uint8 *data = (uint8 *)stackalloc(size);
msg.SerializePartialToArray(data, size);
m_InterceptBuffer->ParsePartialFromArray(data, size);
}
else
{
m_FakeEngineBuffer = &const_cast<protobuf::Message &>(msg);
}
#if SOURCE_ENGINE == SE_DOTA
OnStartMessage_Post(&filter, msg_type, g_DotaUsermessageHelpers.GetName(msg_type));
#elif SOURCE_ENGINE == SE_CSGO
OnStartMessage_Post(&filter, msg_type, g_Cstrike15UsermessageHelpers.GetName(msg_type));
#endif
OnMessageEnd_Pre();
if (m_FakeMetaRes == MRES_SUPERCEDE)
RETURN_META(MRES_SUPERCEDE);
RETURN_META(MRES_IGNORED);
}
void UserMessages::OnSendUserMessage_Post(IRecipientFilter &filter, int msg_type, const protobuf::Message &msg)
{
OnMessageEnd_Post();
RETURN_META(MRES_IGNORED);
}
#endif
#ifdef USE_PROTOBUF_USERMESSAGES
#define UM_RETURN_META_VALUE(res, val) \
m_FakeMetaRes = res; \
return val;
#define UM_RETURN_META(res) \
m_FakeMetaRes = res; \
return;
#else
#define UM_RETURN_META_VALUE(res, val) \
RETURN_META_VALUE(res, val)
#define UM_RETURN_META(res) \
RETURN_META(res)
#endif
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
protobuf::Message *UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_type, const char *msg_name)
#elif SOURCE_ENGINE >= SE_LEFT4DEAD
#if (SOURCE_ENGINE == SE_LEFT4DEAD) || (SOURCE_ENGINE == SE_LEFT4DEAD2)
bf_write *UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_type, const char *msg_name)
#else
bf_write *UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_type)
@@ -578,7 +329,7 @@ bf_write *UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_typ
|| (m_InExec && (m_CurFlags & USERMSG_BLOCKHOOKS)))
{
m_InHook = false;
UM_RETURN_META_VALUE(MRES_IGNORED, NULL);
RETURN_META_VALUE(MRES_IGNORED, NULL);
}
m_CurId = msg_type;
@@ -588,24 +339,14 @@ bf_write *UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_typ
if (!is_intercept_empty)
{
#ifdef USE_PROTOBUF_USERMESSAGES
if (m_InterceptBuffer)
delete m_InterceptBuffer;
m_InterceptBuffer = GetMessagePrototype(msg_type)->New();
UM_RETURN_META_VALUE(MRES_SUPERCEDE, m_InterceptBuffer);
#else
m_InterceptBuffer.Reset();
UM_RETURN_META_VALUE(MRES_SUPERCEDE, &m_InterceptBuffer);
#endif
RETURN_META_VALUE(MRES_SUPERCEDE, &m_InterceptBuffer);
}
UM_RETURN_META_VALUE(MRES_IGNORED, NULL);
RETURN_META_VALUE(MRES_IGNORED, NULL);
}
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
protobuf::Message *UserMessages::OnStartMessage_Post(IRecipientFilter *filter, int msg_type, const char *msg_name)
#elif SOURCE_ENGINE >= SE_LEFT4DEAD
#if (SOURCE_ENGINE == SE_LEFT4DEAD) || (SOURCE_ENGINE == SE_LEFT4DEAD2)
bf_write *UserMessages::OnStartMessage_Post(IRecipientFilter *filter, int msg_type, const char *msg_name)
#else
bf_write *UserMessages::OnStartMessage_Post(IRecipientFilter *filter, int msg_type)
@@ -613,26 +354,19 @@ bf_write *UserMessages::OnStartMessage_Post(IRecipientFilter *filter, int msg_ty
{
if (!m_InHook)
{
UM_RETURN_META_VALUE(MRES_IGNORED, NULL);
RETURN_META_VALUE(MRES_IGNORED, NULL);
}
#ifdef USE_PROTOBUF_USERMESSAGES
if (m_FakeMetaRes == MRES_SUPERCEDE)
m_OrigBuffer = m_InterceptBuffer;
else
m_OrigBuffer = m_FakeEngineBuffer;
#else
m_OrigBuffer = META_RESULT_ORIG_RET(bf_write *);
#endif
UM_RETURN_META_VALUE(MRES_IGNORED, NULL);
RETURN_META_VALUE(MRES_IGNORED, NULL);
}
void UserMessages::OnMessageEnd_Post()
{
if (!m_InHook)
{
UM_RETURN_META(MRES_IGNORED);
RETURN_META(MRES_IGNORED);
}
MsgList *pList;
@@ -700,7 +434,7 @@ void UserMessages::OnMessageEnd_Pre()
{
if (!m_InHook)
{
UM_RETURN_META(MRES_IGNORED);
RETURN_META(MRES_IGNORED);
}
MsgList *pList;
@@ -716,11 +450,7 @@ void UserMessages::OnMessageEnd_Pre()
{
pInfo = (*iter);
pInfo->IsHooked = true;
#ifdef USE_PROTOBUF_USERMESSAGES
res = pInfo->Callback->InterceptUserMessage(m_CurId, m_InterceptBuffer, m_CurRecFilter);
#else
res = pInfo->Callback->InterceptUserMessage(m_CurId, &m_InterceptBuffer, m_CurRecFilter);
#endif
intercepted = true;
@@ -768,11 +498,9 @@ void UserMessages::OnMessageEnd_Pre()
if (!handled && intercepted)
{
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
ENGINE_CALL(SendUserMessage)(static_cast<IRecipientFilter &>(*m_CurRecFilter), m_CurId, *m_InterceptBuffer);
#else
bf_write *engine_bfw;
#if SOURCE_ENGINE >= SE_LEFT4DEAD
#if (SOURCE_ENGINE == SE_LEFT4DEAD) || (SOURCE_ENGINE == SE_LEFT4DEAD2)
engine_bfw = ENGINE_CALL(UserMessageBegin)(m_CurRecFilter, m_CurId, g_SMAPI->GetUserMessage(m_CurId));
#else
engine_bfw = ENGINE_CALL(UserMessageBegin)(m_CurRecFilter, m_CurId);
@@ -780,47 +508,29 @@ void UserMessages::OnMessageEnd_Pre()
m_ReadBuffer.StartReading(m_InterceptBuffer.GetBasePointer(), m_InterceptBuffer.GetNumBytesWritten());
engine_bfw->WriteBitsFromBuffer(&m_ReadBuffer, m_InterceptBuffer.GetNumBitsWritten());
ENGINE_CALL(MessageEnd)();
#endif // SE_CSGO || SE_DOTA
}
pList = &m_msgHooks[m_CurId];
for (iter=pList->begin(); iter!=pList->end(); )
{
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
int size = m_OrigBuffer->ByteSize();
uint8 *data = (uint8 *)stackalloc(size);
m_OrigBuffer->SerializePartialToArray(data, size);
pInfo = (*iter);
pInfo->IsHooked = true;
pInfo->Callback->OnUserMessage(m_CurId, m_OrigBuffer, m_CurRecFilter);
protobuf::Message *pTempMsg = GetMessagePrototype(m_CurId)->New();
pTempMsg->ParsePartialFromArray(data, size);
#else
bf_write *pTempMsg = m_OrigBuffer;
#endif
pList = &m_msgHooks[m_CurId];
for (iter=pList->begin(); iter!=pList->end(); )
if (pInfo->KillMe)
{
pInfo = (*iter);
pInfo->IsHooked = true;
pInfo->Callback->OnUserMessage(m_CurId, pTempMsg, m_CurRecFilter);
if (pInfo->KillMe)
{
iter = pList->erase(iter);
m_FreeListeners.push(pInfo);
_DecRefCounter();
continue;
}
pInfo->IsHooked = false;
iter++;
iter = pList->erase(iter);
m_FreeListeners.push(pInfo);
_DecRefCounter();
continue;
}
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
delete pTempMsg;
#endif
pInfo->IsHooked = false;
iter++;
}
UM_RETURN_META((intercepted) ? MRES_SUPERCEDE : MRES_IGNORED);
RETURN_META((intercepted) ? MRES_SUPERCEDE : MRES_IGNORED);
supercede:
m_BlockEndPost = true;
UM_RETURN_META(MRES_SUPERCEDE);
RETURN_META(MRES_SUPERCEDE);
}
+11 -59
View File
@@ -1,8 +1,8 @@
/**
* vim: set ts=4 sw=4 tw=99 noet :
* vim: set ts=4 :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2010 AlliedModders LLC. All rights reserved.
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
* =============================================================================
*
* This program is free software; you can redistribute it and/or modify it under
@@ -32,41 +32,20 @@
#ifndef _INCLUDE_SOURCEMOD_CUSERMESSAGES_H_
#define _INCLUDE_SOURCEMOD_CUSERMESSAGES_H_
#include "ShareSys.h"
#include <IUserMessages.h>
#include "sourcemm_api.h"
#include <sm_stringhashmap.h>
#include "sm_stringutil.h"
#include "sm_trie.h"
#include "CellRecipientFilter.h"
#include "sm_globals.h"
#include <sh_list.h>
#include <sh_stack.h>
using namespace SourceHook;
using namespace SourceMod;
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
#define USE_PROTOBUF_USERMESSAGES
#endif
#ifdef USE_PROTOBUF_USERMESSAGES
#include <google/protobuf/message.h>
#include <google/protobuf/descriptor.h>
#include <netmessages.pb.h>
using namespace google;
#else
#include <bitbuf.h>
#endif
#define INVALID_MESSAGE_ID -1
struct ListenerInfo
{
#ifdef USE_PROTOBUF_USERMESSAGES
IProtobufUserMessageListener *Callback;
#else
IBitBufUserMessageListener *Callback;
#endif
IUserMessageListener *Callback;
bool IsHooked;
bool KillMe;
bool IsNew;
@@ -91,8 +70,7 @@ public: //IUserMessages
bool GetMessageName(int msgid, char *buffer, size_t maxlength) const;
bool HookUserMessage(int msg_id, IUserMessageListener *pListener, bool intercept=false);
bool UnhookUserMessage(int msg_id, IUserMessageListener *pListener, bool intercept=false);
bf_write *StartBitBufMessage(int msg_id, const cell_t players[], unsigned int playersNum, int flags);
google::protobuf::Message *StartProtobufMessage(int msg_id, const cell_t players[], unsigned int playersNum, int flags);
bf_write *StartMessage(int msg_id, const cell_t players[], unsigned int playersNum, int flags);
bool EndMessage();
bool HookUserMessage2(int msg_id,
IUserMessageListener *pListener,
@@ -100,17 +78,8 @@ public: //IUserMessages
bool UnhookUserMessage2(int msg_id,
IUserMessageListener *pListener,
bool intercept=false);
UserMessageType GetUserMessageType() const;
public:
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
void OnSendUserMessage_Pre(IRecipientFilter &filter, int msg_type, const protobuf::Message &msg);
void OnSendUserMessage_Post(IRecipientFilter &filter, int msg_type, const protobuf::Message &msg);
#endif
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
protobuf::Message *OnStartMessage_Pre(IRecipientFilter *filter, int msg_type, const char *msg_name);
protobuf::Message *OnStartMessage_Post(IRecipientFilter *filter, int msg_type, const char *msg_name);
#elif SOURCE_ENGINE >= SE_LEFT4DEAD
#if (SOURCE_ENGINE == SE_LEFT4DEAD) || (SOURCE_ENGINE == SE_LEFT4DEAD2)
bf_write *OnStartMessage_Pre(IRecipientFilter *filter, int msg_type, const char *msg_name);
bf_write *OnStartMessage_Post(IRecipientFilter *filter, int msg_type, const char *msg_name);
#else
@@ -120,41 +89,24 @@ public:
void OnMessageEnd_Pre();
void OnMessageEnd_Post();
private:
#ifdef USE_PROTOBUF_USERMESSAGES
const protobuf::Message *GetMessagePrototype(int msg_type);
bool InternalHook(int msg_id, IProtobufUserMessageListener *pListener, bool intercept, bool isNew);
bool InternalUnhook(int msg_id, IProtobufUserMessageListener *pListener, bool intercept, bool isNew);
#else
bool InternalHook(int msg_id, IBitBufUserMessageListener *pListener, bool intercept, bool isNew);
bool InternalUnhook(int msg_id, IBitBufUserMessageListener *pListener, bool intercept, bool isNew);
#endif
bool InternalHook(int msg_id, IUserMessageListener *pListener, bool intercept, bool isNew);
bool InternalUnhook(int msg_id, IUserMessageListener *pListener, bool intercept, bool isNew);
void _DecRefCounter();
private:
List<ListenerInfo *> m_msgHooks[255];
List<ListenerInfo *> m_msgIntercepts[255];
CStack<ListenerInfo *> m_FreeListeners;
IRecipientFilter *m_CurRecFilter;
#ifndef USE_PROTOBUF_USERMESSAGES
unsigned char m_pBase[2500];
IRecipientFilter *m_CurRecFilter;
bf_write m_InterceptBuffer;
bf_write *m_OrigBuffer;
bf_read m_ReadBuffer;
#else
// The engine used to provide this. Now we track it.
protobuf::Message *m_OrigBuffer;
protobuf::Message *m_FakeEngineBuffer;
META_RES m_FakeMetaRes;
protobuf::Message *m_InterceptBuffer;
#endif
size_t m_HookCount;
bool m_InHook;
bool m_BlockEndPost;
#ifndef USE_PROTOBUF_USERMESSAGES
bool m_FallbackSearch;
StringHashMap<int> m_Names;
#endif
Trie *m_Names;
CellRecipientFilter m_CellRecFilter;
bool m_InExec;
int m_CurFlags;
+6 -6
View File
@@ -64,20 +64,20 @@ public:
void OnSourceModAllInitialized()
{
#if SOURCE_ENGINE >= SE_ORANGEBOX
SH_ADD_HOOK(ICvar, UnregisterConCommand, icvar, SH_MEMBER(this, &ConCommandCleaner::UnlinkConCommandBase), false);
SH_ADD_HOOK(ICvar, RegisterConCommand, icvar, SH_MEMBER(this, &ConCommandCleaner::LinkConCommandBase), false);
SH_ADD_HOOK_MEMFUNC(ICvar, UnregisterConCommand, icvar, this, &ConCommandCleaner::UnlinkConCommandBase, false);
SH_ADD_HOOK_MEMFUNC(ICvar, RegisterConCommand, icvar, this, &ConCommandCleaner::LinkConCommandBase, false);
#else
SH_ADD_HOOK(ICvar, RegisterConCommandBase, icvar, SH_MEMBER(this, &ConCommandCleaner::LinkConCommandBase), false);
SH_ADD_HOOK_MEMFUNC(ICvar, RegisterConCommandBase, icvar, this, &ConCommandCleaner::LinkConCommandBase, false);
#endif
}
void OnSourceModShutdown()
{
#if SOURCE_ENGINE >= SE_ORANGEBOX
SH_REMOVE_HOOK(ICvar, UnregisterConCommand, icvar, SH_MEMBER(this, &ConCommandCleaner::UnlinkConCommandBase), false);
SH_REMOVE_HOOK(ICvar, RegisterConCommand, icvar, SH_MEMBER(this, &ConCommandCleaner::LinkConCommandBase), false);
SH_REMOVE_HOOK_MEMFUNC(ICvar, UnregisterConCommand, icvar, this, &ConCommandCleaner::UnlinkConCommandBase, false);
SH_REMOVE_HOOK_MEMFUNC(ICvar, RegisterConCommand, icvar, this, &ConCommandCleaner::LinkConCommandBase, false);
#else
SH_REMOVE_HOOK(ICvar, RegisterConCommandBase, icvar, SH_MEMBER(this, &ConCommandCleaner::LinkConCommandBase), false);
SH_REMOVE_HOOK_MEMFUNC(ICvar, RegisterConCommandBase, icvar, this, &ConCommandCleaner::LinkConCommandBase, false);
#endif
}
File diff suppressed because it is too large Load Diff
+2 -5
View File
@@ -24,7 +24,7 @@
#ifdef _WIN32
#define FORCEINLINE_CVAR FORCEINLINE
#elif defined _LINUX || defined __APPLE__
#elif _LINUX
#define FORCEINLINE_CVAR inline
#else
#error "implement me"
@@ -386,7 +386,7 @@ public:
virtual void SetValue( const char *value );
virtual void SetValue( float value );
virtual void SetValue( int value );
#if SOURCE_ENGINE >= SE_NUCLEARDAWN
#if SOURCE_ENGINE == SE_LEFT4DEAD2
virtual void SetValue( Color value );
#endif
@@ -404,9 +404,6 @@ private:
// For CVARs marked FCVAR_NEVER_AS_STRING
virtual void InternalSetFloatValue( float fNewValue );
virtual void InternalSetIntValue( int nValue );
#if SOURCE_ENGINE >= SE_LEFT4DEAD2
virtual void InternalSetColorValue( Color value );
#endif
virtual bool ClampValue( float& value );
virtual void ChangeStringValue( const char *tempVal, float flOldValue );
+1 -1
View File
@@ -24,7 +24,7 @@
#ifdef _WIN32
#define FORCEINLINE_CVAR FORCEINLINE
#elif defined _LINUX || defined __APPLE__
#elif _LINUX
#define FORCEINLINE_CVAR inline
#else
#error "implement me"
File diff suppressed because it is too large Load Diff
+2 -1
View File
@@ -30,6 +30,7 @@
*/
#include "frame_hooks.h"
#include "TimerSys.h"
#include "Database.h"
#include "HalfLife2.h"
#include "MenuStyle_Valve.h"
#include "MenuStyle_Radio.h"
@@ -37,7 +38,6 @@
#include "CoreConfig.h"
#include <sm_queue.h>
#include <IThreader.h>
#include "sourcemod.h"
static IMutex *frame_mutex;
static Queue<FrameAction> *frame_queue;
@@ -95,6 +95,7 @@ void RunFrameHooks(bool simulating)
}
/* Frame based hooks */
g_DBMan.RunFrame();
g_HL2.ProcessFakeCliCmdQueue();
g_HL2.ProcessDelayedKicks();
+35 -78
View File
@@ -1,84 +1,41 @@
# vim: set sts=2 ts=8 sw=2 tw=99 et ft=python:
# vim: set ts=2 sw=2 tw=99 noet ft=python:
import os
binary = SM.Library(builder, 'sourcemod.logic')
binary.compiler.cxxincludes += [
os.path.join(builder.sourcePath, 'core', 'logic'),
os.path.join(builder.sourcePath, 'public'),
os.path.join(builder.sourcePath, 'public', 'sourcepawn'),
os.path.join(builder.sourcePath, 'public', 'amtl'),
os.path.join(SM.mms_root, 'core', 'sourcehook')
]
binary.compiler.defines += [
'SM_DEFAULT_THREADER',
'SM_LOGIC'
]
if builder.target_platform == 'linux':
binary.compiler.postlink += ['-lpthread', '-lrt']
elif builder.target_platform == 'mac':
binary.compiler.cflags += ['-Wno-deprecated-declarations']
binary.compiler.postlink += ['-framework', 'CoreServices']
compiler = SM.DefaultCompiler()
base = AMBuild.sourceFolder
compiler['CXXINCLUDES'].append(os.path.join(SM.mmsPath, 'core', 'sourcehook'))
compiler['CXXINCLUDES'].append(os.path.join(base, 'core', 'logic'))
compiler['CXXINCLUDES'].append(os.path.join(base, 'public'))
compiler['CXXINCLUDES'].append(os.path.join(base, 'public', 'sourcepawn'))
compiler['CDEFINES'].append('SM_DEFAULT_THREADER')
compiler['CDEFINES'].append('SM_LOGIC')
if binary.compiler.vendor == 'gcc' or binary.compiler.vendor == 'clang':
binary.compiler.cxxflags += ['-fno-rtti']
elif binary.compiler.vendor == 'msvc':
binary.compiler.cxxflags += ['/GR-']
if AMBuild.target['platform'] == 'linux':
compiler['POSTLINKFLAGS'].append('-lpthread')
binary.sources += [
'common_logic.cpp',
'smn_adt_array.cpp',
'smn_sorting.cpp',
'smn_maplists.cpp',
'ADTFactory.cpp',
'smn_adt_stack.cpp',
'thread/ThreadWorker.cpp',
'thread/BaseWorker.cpp',
'ThreadSupport.cpp',
'smn_float.cpp',
'TextParsers.cpp',
'smn_textparse.cpp',
'smn_adt_trie.cpp',
'smn_functions.cpp',
'smn_timers.cpp',
'smn_players.cpp',
'MemoryUtils.cpp',
'smn_admin.cpp',
'smn_banning.cpp',
'smn_filesystem.cpp',
'stringutil.cpp',
'Translator.cpp',
'PhraseCollection.cpp',
'smn_lang.cpp',
'smn_string.cpp',
'smn_handles.cpp',
'smn_datapacks.cpp',
'smn_gameconfigs.cpp',
'smn_fakenatives.cpp',
'GameConfigs.cpp',
'sm_crc32.cpp',
'smn_profiler.cpp',
'ShareSys.cpp',
'PluginSys.cpp',
'HandleSys.cpp',
'NativeOwner.cpp',
'NativeInvoker.cpp',
'ExtensionSys.cpp',
'DebugReporter.cpp',
'Database.cpp',
'smn_database.cpp',
'ForwardSys.cpp',
'AdminCache.cpp',
'sm_trie.cpp',
'smn_console.cpp',
'ProfileTools.cpp',
'Logger.cpp',
'smn_core.cpp',
'smn_menus.cpp',
]
if builder.target_platform == 'windows':
binary.sources += ['thread/WinThreads.cpp']
extension = AMBuild.AddJob('sourcemod.logic')
binary = Cpp.LibraryBuilder('sourcemod.logic', AMBuild, extension, compiler)
files = [
'common_logic.cpp',
'smn_adt_array.cpp',
'smn_sorting.cpp',
'smn_maplists.cpp',
'smn_adt_stack.cpp',
'thread/ThreadWorker.cpp',
'thread/BaseWorker.cpp',
'ThreadSupport.cpp',
'smn_float.cpp',
'TextParsers.cpp',
'smn_textparse.cpp',
'smn_adt_trie.cpp',
'Profiler.cpp',
'smn_functions.cpp'
]
if AMBuild.target['platform'] == 'windows':
files.append('thread/WinThreads.cpp')
else:
binary.sources += ['thread/PosixThreads.cpp']
files.append('thread/PosixThreads.cpp')
binary.AddSourceFiles('core/logic', files)
SM.AutoVersion('core/logic', binary)
binary.SendToJob()
SM.binaries += [builder.Add(binary)]
File diff suppressed because it is too large Load Diff
-551
View File
@@ -1,551 +0,0 @@
/**
* vim: set ts=4 sw=4 :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2009 AlliedModders LLC. All rights reserved.
* =============================================================================
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 3.0, as published by the
* Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
* As a special exception, AlliedModders LLC gives you permission to link the
* code of this program (as well as its derivative works) to "Half-Life 2," the
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
* by the Valve Corporation. You must obey the GNU General Public License in
* all respects for all other code used. Additionally, AlliedModders LLC grants
* this exception to all derivative works. AlliedModders LLC defines further
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
* or <http://www.sourcemod.net/license.php>.
*
* Version: $Id$
*/
#include <time.h>
#include <cstdarg>
#include "Logger.h"
#include <sourcemod_version.h>
#include <ISourceMod.h>
Logger g_Logger;
/**
* :TODO: This should be creating the log folder if it doesn't exist
*/
ConfigResult Logger::OnSourceModConfigChanged(const char *key,
const char *value,
ConfigSource source,
char *error,
size_t maxlength)
{
if (strcasecmp(key, "Logging") == 0)
{
bool state;
if (strcasecmp(value, "on") == 0)
{
state = true;
} else if (strcasecmp(value, "off") == 0) {
state = false;
} else {
smcore.Format(error, maxlength, "Invalid value: must be \"on\" or \"off\"");
return ConfigResult_Reject;
}
if (source == ConfigSource_Console)
{
state ? EnableLogging() : DisableLogging();
} else {
m_InitialState = state;
}
return ConfigResult_Accept;
} else if (strcasecmp(key, "LogMode") == 0) {
if (strcasecmp(value, "daily") == 0)
{
m_Mode = LoggingMode_Daily;
} else if (strcasecmp(value, "map") == 0) {
m_Mode = LoggingMode_PerMap;
} else if (strcasecmp(value, "game") == 0) {
m_Mode = LoggingMode_Game;
} else {
smcore.Format(error, maxlength, "Invalid value: must be [daily|map|game]");
return ConfigResult_Reject;
}
return ConfigResult_Accept;
}
return ConfigResult_Ignore;
}
void Logger::OnSourceModStartup(bool late)
{
InitLogger(m_Mode);
}
void Logger::OnSourceModAllShutdown()
{
CloseLogger();
}
void Logger::OnSourceModLevelChange(const char *mapName)
{
MapChange(mapName);
}
void Logger::_NewMapFile()
{
if (!m_Active)
{
return;
}
/* Append "Log file closed" to previous log file */
_CloseFile();
char _filename[256];
int i = 0;
time_t t = g_pSM->GetAdjustedTime();
tm *curtime = localtime(&t);
while (true)
{
g_pSM->BuildPath(Path_SM, _filename, sizeof(_filename), "logs/L%02d%02d%03d.log", curtime->tm_mon + 1, curtime->tm_mday, i);
FILE *fp = fopen(_filename, "r");
if (!fp)
{
break;
}
fclose(fp);
i++;
}
m_NrmFileName.assign(_filename);
FILE *fp = fopen(m_NrmFileName.c_str(), "w");
if (!fp)
{
char error[255];
libsys->GetPlatformError(error, sizeof(error));
LogFatal("[SM] Unexpected fatal logging error (file \"%s\")", m_NrmFileName.c_str());
LogFatal("[SM] Platform returned error: \"%s\"", error);
LogFatal("[SM] Logging has been disabled.");
m_Active = false;
return;
} else {
char date[32];
strftime(date, sizeof(date), "%m/%d/%Y - %H:%M:%S", curtime);
fprintf(fp, "L %s: SourceMod log file started (file \"L%02d%02d%03d.log\") (Version \"%s\")\n", date, curtime->tm_mon + 1, curtime->tm_mday, i, SOURCEMOD_VERSION);
fclose(fp);
}
}
void Logger::_CloseFile()
{
if (!m_Active)
{
return;
}
FILE *fp = NULL;
if (!m_NrmFileName.empty())
{
fp = fopen(m_NrmFileName.c_str(), "r+");
if (fp)
{
fseek(fp, 0, SEEK_END);
LogMessage("Log file closed.");
fclose(fp);
}
m_NrmFileName.clear();
}
if (!m_ErrMapStart)
{
return;
}
fp = fopen(m_ErrFileName.c_str(), "r+");
if (fp)
{
fseek(fp, 0, SEEK_END);
LogError("Error log file session closed.");
fclose(fp);
}
m_ErrFileName.clear();
}
void Logger::InitLogger(LoggingMode mode)
{
m_Mode = mode;
m_Active = m_InitialState;
time_t t = g_pSM->GetAdjustedTime();
tm *curtime = localtime(&t);
m_NrmCurDay = curtime->tm_mday;
m_ErrCurDay = curtime->tm_mday;
char _filename[256];
g_pSM->BuildPath(Path_SM, _filename, sizeof(_filename), "logs/errors_%04d%02d%02d.log", curtime->tm_year + 1900, curtime->tm_mon + 1, curtime->tm_mday);
m_ErrFileName.assign(_filename);
switch (m_Mode)
{
case LoggingMode_PerMap:
{
if (!m_Active)
{
m_DelayedStart = true;
}
break;
}
case LoggingMode_Daily:
{
g_pSM->BuildPath(Path_SM, _filename, sizeof(_filename), "logs/L%04d%02d%02d.log", curtime->tm_year + 1900, curtime->tm_mon + 1, curtime->tm_mday);
m_NrmFileName.assign(_filename);
m_DailyPrintHdr = true;
break;
}
default:
{
/* do nothing... */
break;
}
}
}
void Logger::CloseLogger()
{
_CloseFile();
}
void Logger::LogToOpenFile(FILE *fp, const char *msg, ...)
{
if (!m_Active)
{
return;
}
va_list ap;
va_start(ap, msg);
LogToOpenFileEx(fp, msg, ap);
va_end(ap);
}
void Logger::LogToFileOnly(FILE *fp, const char *msg, ...)
{
if (!m_Active)
{
return;
}
va_list ap;
va_start(ap, msg);
LogToFileOnlyEx(fp, msg, ap);
va_end(ap);
}
void Logger::LogToOpenFileEx(FILE *fp, const char *msg, va_list ap)
{
if (!m_Active)
{
return;
}
static ConVar *sv_logecho = smcore.FindConVar("sv_logecho");
char buffer[3072];
smcore.FormatArgs(buffer, sizeof(buffer), msg, ap);
char date[32];
time_t t = g_pSM->GetAdjustedTime();
tm *curtime = localtime(&t);
strftime(date, sizeof(date), "%m/%d/%Y - %H:%M:%S", curtime);
fprintf(fp, "L %s: %s\n", date, buffer);
if (!sv_logecho || smcore.GetCvarBool(sv_logecho))
{
static char conBuffer[4096];
smcore.Format(conBuffer, sizeof(conBuffer), "L %s: %s\n", date, buffer);
smcore.ConPrint(conBuffer);
}
}
void Logger::LogToFileOnlyEx(FILE *fp, const char *msg, va_list ap)
{
if (!m_Active)
{
return;
}
char buffer[3072];
smcore.FormatArgs(buffer, sizeof(buffer), msg, ap);
char date[32];
time_t t = g_pSM->GetAdjustedTime();
tm *curtime = localtime(&t);
strftime(date, sizeof(date), "%m/%d/%Y - %H:%M:%S", curtime);
fprintf(fp, "L %s: %s\n", date, buffer);
fflush(fp);
}
void Logger::LogMessage(const char *vafmt, ...)
{
va_list ap;
va_start(ap, vafmt);
LogMessageEx(vafmt, ap);
va_end(ap);
}
void Logger::LogMessageEx(const char *vafmt, va_list ap)
{
if (!m_Active)
{
return;
}
if (m_Mode == LoggingMode_Game)
{
_PrintToGameLog(vafmt, ap);
return;
}
if (m_DelayedStart)
{
m_DelayedStart = false;
_NewMapFile();
}
time_t t = g_pSM->GetAdjustedTime();
tm *curtime = localtime(&t);
FILE *fp = NULL;
if (m_Mode == LoggingMode_PerMap)
{
fp = fopen(m_NrmFileName.c_str(), "a+");
if (!fp)
{
_NewMapFile();
fp = fopen(m_NrmFileName.c_str(), "a+");
if (!fp)
{
goto print_error;
}
}
} else {
if (m_NrmCurDay != curtime->tm_mday)
{
char _filename[256];
g_pSM->BuildPath(Path_SM, _filename, sizeof(_filename), "logs/L%04d%02d%02d.log", curtime->tm_year + 1900, curtime->tm_mon + 1, curtime->tm_mday);
m_NrmFileName.assign(_filename);
m_NrmCurDay = curtime->tm_mday;
m_DailyPrintHdr = true;
}
fp = fopen(m_NrmFileName.c_str(), "a+");
}
if (fp)
{
if (m_DailyPrintHdr)
{
char date[32];
m_DailyPrintHdr = false;
strftime(date, sizeof(date), "%m/%d/%Y - %H:%M:%S", curtime);
fprintf(fp, "L %s: SourceMod log file session started (file \"L%04d%02d%02d.log\") (Version \"%s\")\n", date, curtime->tm_year + 1900, curtime->tm_mon + 1, curtime->tm_mday, SOURCEMOD_VERSION);
}
LogToOpenFileEx(fp, vafmt, ap);
fclose(fp);
} else {
goto print_error;
}
return;
print_error:
char error[255];
libsys->GetPlatformError(error, sizeof(error));
LogFatal("[SM] Unexpected fatal logging error (file \"%s\")", m_NrmFileName.c_str());
LogFatal("[SM] Platform returned error: \"%s\"", error);
LogFatal("[SM] Logging has been disabled.");
m_Active = false;
}
void Logger::LogError(const char *vafmt, ...)
{
va_list ap;
va_start(ap, vafmt);
LogErrorEx(vafmt, ap);
va_end(ap);
}
void Logger::LogErrorEx(const char *vafmt, va_list ap)
{
if (!m_Active)
{
return;
}
time_t t = g_pSM->GetAdjustedTime();
tm *curtime = localtime(&t);
if (curtime->tm_mday != m_ErrCurDay)
{
char _filename[256];
g_pSM->BuildPath(Path_SM, _filename, sizeof(_filename), "logs/errors_%04d%02d%02d.log", curtime->tm_year + 1900, curtime->tm_mon + 1, curtime->tm_mday);
m_ErrFileName.assign(_filename);
m_ErrCurDay = curtime->tm_mday;
m_ErrMapStart = false;
}
FILE *fp = fopen(m_ErrFileName.c_str(), "a+");
if (fp)
{
if (!m_ErrMapStart)
{
char date[32];
strftime(date, sizeof(date), "%m/%d/%Y - %H:%M:%S", curtime);
fprintf(fp, "L %s: SourceMod error session started\n", date);
fprintf(fp, "L %s: Info (map \"%s\") (file \"errors_%04d%02d%02d.log\")\n", date, m_CurMapName.c_str(), curtime->tm_year + 1900, curtime->tm_mon + 1, curtime->tm_mday);
m_ErrMapStart = true;
}
LogToOpenFileEx(fp, vafmt, ap);
fclose(fp);
}
else
{
char error[255];
libsys->GetPlatformError(error, sizeof(error));
LogFatal("[SM] Unexpected fatal logging error (file \"%s\")", m_NrmFileName.c_str());
LogFatal("[SM] Platform returned error: \"%s\"", error);
LogFatal("[SM] Logging has been disabled.");
m_Active = false;
return;
}
}
void Logger::MapChange(const char *mapname)
{
m_CurMapName.assign(mapname);
switch (m_Mode)
{
case LoggingMode_Daily:
{
LogMessage("-------- Mapchange to %s --------", mapname);
break;
}
case LoggingMode_PerMap:
{
_NewMapFile();
break;
}
default:
{
/* Do nothing... */
break;
}
}
if (m_ErrMapStart)
{
LogError("Error log file session closed.");
}
m_ErrMapStart = false;
}
void Logger::_PrintToGameLog(const char *fmt, va_list ap)
{
char msg[3072];
size_t len;
len = vsnprintf(msg, sizeof(msg)-2, fmt, ap);
len = (len >= sizeof(msg)) ? (sizeof(msg) - 2) : len;
msg[len++] = '\n';
msg[len] = '\0';
smcore.LogToGame(msg);
}
const char *Logger::GetLogFileName(LogType type) const
{
switch (type)
{
case LogType_Normal:
{
return m_NrmFileName.c_str();
}
case LogType_Error:
{
return m_ErrFileName.c_str();
}
default:
{
return "";
}
}
}
LoggingMode Logger::GetLoggingMode() const
{
return m_Mode;
}
void Logger::EnableLogging()
{
if (m_Active)
{
return;
}
m_Active = true;
LogMessage("[SM] Logging enabled manually by user.");
}
void Logger::DisableLogging()
{
if (!m_Active)
{
return;
}
LogMessage("[SM] Logging disabled manually by user.");
m_Active = false;
}
void Logger::LogFatal(const char *msg, ...)
{
va_list ap;
va_start(ap, msg);
LogFatalEx(msg, ap);
va_end(ap);
}
void Logger::LogFatalEx(const char *msg, va_list ap)
{
/* :TODO: make this print all pretty-like
* In fact, the pretty log printing function should be abstracted.
* It's already implemented twice which is bad.
*/
char path[PLATFORM_MAX_PATH];
g_pSM->BuildPath(Path_Game, path, sizeof(path), "sourcemod_fatal.log");
FILE *fp = fopen(path, "at");
if (fp)
{
m_Active = true;
LogToOpenFileEx(fp, msg, ap);
m_Active = false;
fclose(fp);
}
}
-111
View File
@@ -1,111 +0,0 @@
/**
* vim: set ts=4 :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
* =============================================================================
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 3.0, as published by the
* Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
* As a special exception, AlliedModders LLC gives you permission to link the
* code of this program (as well as its derivative works) to "Half-Life 2," the
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
* by the Valve Corporation. You must obey the GNU General Public License in
* all respects for all other code used. Additionally, AlliedModders LLC grants
* this exception to all derivative works. AlliedModders LLC defines further
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
* or <http://www.sourcemod.net/license.php>.
*
* Version: $Id$
*/
#ifndef _INCLUDE_SOURCEMOD_CLOGGER_H_
#define _INCLUDE_SOURCEMOD_CLOGGER_H_
#include <stdio.h>
#include <sh_string.h>
#include "common_logic.h"
using namespace SourceHook;
enum LogType
{
LogType_Normal,
LogType_Error
};
enum LoggingMode
{
LoggingMode_Daily,
LoggingMode_PerMap,
LoggingMode_Game
};
class Logger : public SMGlobalClass, public ILogger
{
public:
Logger() : m_Mode(LoggingMode_Daily), m_ErrMapStart(false),
m_Active(false), m_DelayedStart(false), m_DailyPrintHdr(false),
m_InitialState(true)
{
}
public: //SMGlobalClass
ConfigResult OnSourceModConfigChanged(const char *key,
const char *value,
ConfigSource source,
char *error,
size_t maxlength);
void OnSourceModStartup(bool late);
void OnSourceModAllShutdown();
void OnSourceModLevelChange(const char *mapName);
public:
void InitLogger(LoggingMode mode);
void CloseLogger();
void EnableLogging();
void DisableLogging();
void LogMessage(const char *msg, ...);
void LogMessageEx(const char *msg, va_list ap);
void LogError(const char *msg, ...);
void LogErrorEx(const char *msg, va_list ap);
void LogFatal(const char *msg, ...);
void LogFatalEx(const char *msg, va_list ap);
void LogToOpenFile(FILE *fp, const char *msg, ...);
void LogToOpenFileEx(FILE *fp, const char *msg, va_list ap);
/* This version does not print to console, and is thus thread-safe */
void LogToFileOnly(FILE *fp, const char *msg, ...);
void LogToFileOnlyEx(FILE *fp, const char *msg, va_list ap);
void MapChange(const char *mapname);
const char *GetLogFileName(LogType type) const;
LoggingMode GetLoggingMode() const;
private:
void _CloseFile();
void _NewMapFile();
void _PrintToGameLog(const char *fmt, va_list ap);
private:
String m_NrmFileName;
String m_ErrFileName;
String m_CurMapName;
LoggingMode m_Mode;
int m_NrmCurDay;
int m_ErrCurDay;
bool m_ErrMapStart;
bool m_Active;
bool m_DelayedStart;
bool m_DailyPrintHdr;
bool m_InitialState;
};
extern Logger g_Logger;
#endif // _INCLUDE_SOURCEMOD_CLOGGER_H_
+1 -17
View File
@@ -25,23 +25,7 @@ OBJECTS = \
smn_textparse.cpp \
smn_adt_trie.cpp \
Profiler.cpp \
smn_functions.cpp \
sm_crc32.cpp \
smn_timers.cpp \
MemoryUtils.cpp \
smn_admin.cpp \
smn_banning.cpp \
stringutil.cpp \
Translator.cpp \
PhraseCollection.cpp \
smn_lang.cpp \
smn_string.cpp \
smn_handles.cpp \
smn_datapacks.cpp \
smn_gameconfigs.cpp \
GameConfigs.cpp \
smn_players.cpp \
smn_profiler.cpp
smn_functions.cpp
##############################################
### CONFIGURE ANY OTHER FLAGS/OPTIONS HERE ###
-612
View File
@@ -1,612 +0,0 @@
/**
* vim: set ts=4 sw=4 tw=99 noet :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2011 AlliedModders LLC. All rights reserved.
* =============================================================================
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 3.0, as published by the
* Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
* As a special exception, AlliedModders LLC gives you permission to link the
* code of this program (as well as its derivative works) to "Half-Life 2," the
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
* by the Valve Corporation. You must obey the GNU General Public License in
* all respects for all other code used. Additionally, AlliedModders LLC grants
* this exception to all derivative works. AlliedModders LLC defines further
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
* or <http://www.sourcemod.net/license.php>.
*/
#include "MemoryUtils.h"
#ifdef PLATFORM_LINUX
#include <fcntl.h>
#include <link.h>
#include <sys/mman.h>
#define PAGE_SIZE 4096
#define PAGE_ALIGN_UP(x) ((x + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))
#endif
#ifdef PLATFORM_APPLE
#include <AvailabilityMacros.h>
#include <mach/task.h>
#include <mach-o/dyld_images.h>
#include <mach-o/loader.h>
#include <mach-o/nlist.h>
/* Define things from 10.6 SDK for older SDKs */
#ifndef MAC_OS_X_VERSION_10_6
struct task_dyld_info
{
mach_vm_address_t all_image_info_addr;
mach_vm_size_t all_image_info_size;
};
typedef struct task_dyld_info task_dyld_info_data_t;
#define TASK_DYLD_INFO 17
#define TASK_DYLD_INFO_COUNT (sizeof(task_dyld_info_data_t) / sizeof(natural_t))
#endif // MAC_OS_X_VERSION_10_6
#endif // PLATFORM_APPLE
MemoryUtils g_MemUtils;
MemoryUtils::MemoryUtils()
{
#ifdef PLATFORM_APPLE
Gestalt(gestaltSystemVersionMajor, &m_OSXMajor);
Gestalt(gestaltSystemVersionMinor, &m_OSXMinor);
/* Get pointer to struct that describes all loaded mach-o images in process */
if ((m_OSXMajor == 10 && m_OSXMinor >= 6) || m_OSXMajor > 10)
{
task_dyld_info_data_t dyld_info;
mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
task_info(mach_task_self(), TASK_DYLD_INFO, (task_info_t)&dyld_info, &count);
m_ImageList = (struct dyld_all_image_infos *)dyld_info.all_image_info_addr;
}
else
{
struct nlist list[2];
memset(list, 0, sizeof(list));
list[0].n_un.n_name = (char *)"_dyld_all_image_infos";
nlist("/usr/lib/dyld", list);
m_ImageList = (struct dyld_all_image_infos *)list[0].n_value;
}
#endif
}
MemoryUtils::~MemoryUtils()
{
#if defined PLATFORM_LINUX || defined PLATFORM_APPLE
for (size_t i = 0; i < m_SymTables.size(); i++)
{
delete m_SymTables[i];
}
m_SymTables.clear();
#endif
}
void MemoryUtils::OnSourceModAllInitialized()
{
sharesys->AddInterface(NULL, this);
}
void *MemoryUtils::FindPattern(const void *libPtr, const char *pattern, size_t len)
{
DynLibInfo lib;
bool found;
char *ptr, *end;
memset(&lib, 0, sizeof(DynLibInfo));
if (!GetLibraryInfo(libPtr, lib))
{
return NULL;
}
ptr = reinterpret_cast<char *>(lib.baseAddress);
end = ptr + lib.memorySize - len;
while (ptr < end)
{
found = true;
for (register size_t i = 0; i < len; i++)
{
if (pattern[i] != '\x2A' && pattern[i] != ptr[i])
{
found = false;
break;
}
}
if (found)
return ptr;
ptr++;
}
return NULL;
}
void *MemoryUtils::ResolveSymbol(void *handle, const char *symbol)
{
#ifdef PLATFORM_WINDOWS
return GetProcAddress((HMODULE)handle, symbol);
#elif defined PLATFORM_LINUX
struct link_map *dlmap;
struct stat dlstat;
int dlfile;
uintptr_t map_base;
Elf32_Ehdr *file_hdr;
Elf32_Shdr *sections, *shstrtab_hdr, *symtab_hdr, *strtab_hdr;
Elf32_Sym *symtab;
const char *shstrtab, *strtab;
uint16_t section_count;
uint32_t symbol_count;
LibSymbolTable *libtable;
SymbolTable *table;
Symbol *symbol_entry;
dlmap = (struct link_map *)handle;
symtab_hdr = NULL;
strtab_hdr = NULL;
table = NULL;
/* See if we already have a symbol table for this library */
for (size_t i = 0; i < m_SymTables.size(); i++)
{
libtable = m_SymTables[i];
if (libtable->lib_base == dlmap->l_addr)
{
table = &libtable->table;
break;
}
}
/* If we don't have a symbol table for this library, then create one */
if (table == NULL)
{
libtable = new LibSymbolTable();
libtable->table.Initialize();
libtable->lib_base = dlmap->l_addr;
libtable->last_pos = 0;
table = &libtable->table;
m_SymTables.push_back(libtable);
}
/* See if the symbol is already cached in our table */
symbol_entry = table->FindSymbol(symbol, strlen(symbol));
if (symbol_entry != NULL)
{
return symbol_entry->address;
}
/* If symbol isn't in our table, then we have open the actual library */
dlfile = open(dlmap->l_name, O_RDONLY);
if (dlfile == -1 || fstat(dlfile, &dlstat) == -1)
{
close(dlfile);
return NULL;
}
/* Map library file into memory */
file_hdr = (Elf32_Ehdr *)mmap(NULL, dlstat.st_size, PROT_READ, MAP_PRIVATE, dlfile, 0);
map_base = (uintptr_t)file_hdr;
if (file_hdr == MAP_FAILED)
{
close(dlfile);
return NULL;
}
close(dlfile);
if (file_hdr->e_shoff == 0 || file_hdr->e_shstrndx == SHN_UNDEF)
{
munmap(file_hdr, dlstat.st_size);
return NULL;
}
sections = (Elf32_Shdr *)(map_base + file_hdr->e_shoff);
section_count = file_hdr->e_shnum;
/* Get ELF section header string table */
shstrtab_hdr = &sections[file_hdr->e_shstrndx];
shstrtab = (const char *)(map_base + shstrtab_hdr->sh_offset);
/* Iterate sections while looking for ELF symbol table and string table */
for (uint16_t i = 0; i < section_count; i++)
{
Elf32_Shdr &hdr = sections[i];
const char *section_name = shstrtab + hdr.sh_name;
if (strcmp(section_name, ".symtab") == 0)
{
symtab_hdr = &hdr;
}
else if (strcmp(section_name, ".strtab") == 0)
{
strtab_hdr = &hdr;
}
}
/* Uh oh, we don't have a symbol table or a string table */
if (symtab_hdr == NULL || strtab_hdr == NULL)
{
munmap(file_hdr, dlstat.st_size);
return NULL;
}
symtab = (Elf32_Sym *)(map_base + symtab_hdr->sh_offset);
strtab = (const char *)(map_base + strtab_hdr->sh_offset);
symbol_count = symtab_hdr->sh_size / symtab_hdr->sh_entsize;
/* Iterate symbol table starting from the position we were at last time */
for (uint32_t i = libtable->last_pos; i < symbol_count; i++)
{
Elf32_Sym &sym = symtab[i];
unsigned char sym_type = ELF32_ST_TYPE(sym.st_info);
const char *sym_name = strtab + sym.st_name;
Symbol *cur_sym;
/* Skip symbols that are undefined or do not refer to functions or objects */
if (sym.st_shndx == SHN_UNDEF || (sym_type != STT_FUNC && sym_type != STT_OBJECT))
{
continue;
}
/* Caching symbols as we go along */
cur_sym = table->InternSymbol(sym_name, strlen(sym_name), (void *)(dlmap->l_addr + sym.st_value));
if (strcmp(symbol, sym_name) == 0)
{
symbol_entry = cur_sym;
libtable->last_pos = ++i;
break;
}
}
munmap(file_hdr, dlstat.st_size);
return symbol_entry ? symbol_entry->address : NULL;
#elif defined PLATFORM_APPLE
uintptr_t dlbase, linkedit_addr;
uint32_t image_count;
struct mach_header *file_hdr;
struct load_command *loadcmds;
struct segment_command *linkedit_hdr;
struct symtab_command *symtab_hdr;
struct nlist *symtab;
const char *strtab;
uint32_t loadcmd_count;
uint32_t symbol_count;
LibSymbolTable *libtable;
SymbolTable *table;
Symbol *symbol_entry;
dlbase = 0;
image_count = m_ImageList->infoArrayCount;
linkedit_hdr = NULL;
symtab_hdr = NULL;
table = NULL;
/* Loop through mach-o images in process.
* We can skip index 0 since that is just the executable.
*/
for (uint32_t i = 1; i < image_count; i++)
{
const struct dyld_image_info &info = m_ImageList->infoArray[i];
/* "Load" each one until we get a matching handle */
void *h = dlopen(info.imageFilePath, RTLD_NOLOAD);
if (h == handle)
{
dlbase = (uintptr_t)info.imageLoadAddress;
dlclose(h);
break;
}
dlclose(h);
}
if (!dlbase)
{
/* Uh oh, we couldn't find a matching handle */
return NULL;
}
/* See if we already have a symbol table for this library */
for (size_t i = 0; i < m_SymTables.size(); i++)
{
libtable = m_SymTables[i];
if (libtable->lib_base == dlbase)
{
table = &libtable->table;
break;
}
}
/* If we don't have a symbol table for this library, then create one */
if (table == NULL)
{
libtable = new LibSymbolTable();
libtable->table.Initialize();
libtable->lib_base = dlbase;
libtable->last_pos = 0;
table = &libtable->table;
m_SymTables.push_back(libtable);
}
/* See if the symbol is already cached in our table */
symbol_entry = table->FindSymbol(symbol, strlen(symbol));
if (symbol_entry != NULL)
{
return symbol_entry->address;
}
/* If symbol isn't in our table, then we have to locate it in memory */
file_hdr = (struct mach_header *)dlbase;
loadcmds = (struct load_command *)(dlbase + sizeof(struct mach_header));
loadcmd_count = file_hdr->ncmds;
/* Loop through load commands until we find the ones for the symbol table */
for (uint32_t i = 0; i < loadcmd_count; i++)
{
if (loadcmds->cmd == LC_SEGMENT && !linkedit_hdr)
{
struct segment_command *seg = (struct segment_command *)loadcmds;
if (strcmp(seg->segname, "__LINKEDIT") == 0)
{
linkedit_hdr = seg;
if (symtab_hdr)
{
break;
}
}
}
else if (loadcmds->cmd == LC_SYMTAB)
{
symtab_hdr = (struct symtab_command *)loadcmds;
if (linkedit_hdr)
{
break;
}
}
/* Load commands are not of a fixed size which is why we add the size */
loadcmds = (struct load_command *)((uintptr_t)loadcmds + loadcmds->cmdsize);
}
if (!linkedit_hdr || !symtab_hdr || !symtab_hdr->symoff || !symtab_hdr->stroff)
{
/* Uh oh, no symbol table */
return NULL;
}
linkedit_addr = dlbase + linkedit_hdr->vmaddr;
symtab = (struct nlist *)(linkedit_addr + symtab_hdr->symoff - linkedit_hdr->fileoff);
strtab = (const char *)(linkedit_addr + symtab_hdr->stroff - linkedit_hdr->fileoff);
symbol_count = symtab_hdr->nsyms;
/* Iterate symbol table starting from the position we were at last time */
for (uint32_t i = libtable->last_pos; i < symbol_count; i++)
{
struct nlist &sym = symtab[i];
/* Ignore the prepended underscore on all symbols, so +1 here */
const char *sym_name = strtab + sym.n_un.n_strx + 1;
Symbol *cur_sym;
/* Skip symbols that are undefined */
if (sym.n_sect == NO_SECT)
{
continue;
}
/* Caching symbols as we go along */
cur_sym = table->InternSymbol(sym_name, strlen(sym_name), (void *)(dlbase + sym.n_value));
if (strcmp(symbol, sym_name) == 0)
{
symbol_entry = cur_sym;
libtable->last_pos = ++i;
break;
}
}
return symbol_entry ? symbol_entry->address : NULL;
#endif
}
bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
{
uintptr_t baseAddr;
if (libPtr == NULL)
{
return false;
}
#ifdef PLATFORM_WINDOWS
MEMORY_BASIC_INFORMATION info;
IMAGE_DOS_HEADER *dos;
IMAGE_NT_HEADERS *pe;
IMAGE_FILE_HEADER *file;
IMAGE_OPTIONAL_HEADER *opt;
if (!VirtualQuery(libPtr, &info, sizeof(MEMORY_BASIC_INFORMATION)))
{
return false;
}
baseAddr = reinterpret_cast<uintptr_t>(info.AllocationBase);
/* All this is for our insane sanity checks :o */
dos = reinterpret_cast<IMAGE_DOS_HEADER *>(baseAddr);
pe = reinterpret_cast<IMAGE_NT_HEADERS *>(baseAddr + dos->e_lfanew);
file = &pe->FileHeader;
opt = &pe->OptionalHeader;
/* Check PE magic and signature */
if (dos->e_magic != IMAGE_DOS_SIGNATURE || pe->Signature != IMAGE_NT_SIGNATURE || opt->Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC)
{
return false;
}
/* Check architecture, which is 32-bit/x86 right now
* Should change this for 64-bit if Valve gets their act together
*/
if (file->Machine != IMAGE_FILE_MACHINE_I386)
{
return false;
}
/* For our purposes, this must be a dynamic library */
if ((file->Characteristics & IMAGE_FILE_DLL) == 0)
{
return false;
}
/* Finally, we can do this */
lib.memorySize = opt->SizeOfImage;
#elif defined PLATFORM_LINUX
Dl_info info;
Elf32_Ehdr *file;
Elf32_Phdr *phdr;
uint16_t phdrCount;
if (!dladdr(libPtr, &info))
{
return false;
}
if (!info.dli_fbase || !info.dli_fname)
{
return false;
}
/* This is for our insane sanity checks :o */
baseAddr = reinterpret_cast<uintptr_t>(info.dli_fbase);
file = reinterpret_cast<Elf32_Ehdr *>(baseAddr);
/* Check ELF magic */
if (memcmp(ELFMAG, file->e_ident, SELFMAG) != 0)
{
return false;
}
/* Check ELF version */
if (file->e_ident[EI_VERSION] != EV_CURRENT)
{
return false;
}
/* Check ELF architecture, which is 32-bit/x86 right now
* Should change this for 64-bit if Valve gets their act together
*/
if (file->e_ident[EI_CLASS] != ELFCLASS32 || file->e_machine != EM_386 || file->e_ident[EI_DATA] != ELFDATA2LSB)
{
return false;
}
/* For our purposes, this must be a dynamic library/shared object */
if (file->e_type != ET_DYN)
{
return false;
}
phdrCount = file->e_phnum;
phdr = reinterpret_cast<Elf32_Phdr *>(baseAddr + file->e_phoff);
for (uint16_t i = 0; i < phdrCount; i++)
{
Elf32_Phdr &hdr = phdr[i];
/* We only really care about the segment with executable code */
if (hdr.p_type == PT_LOAD && hdr.p_flags == (PF_X|PF_R))
{
/* From glibc, elf/dl-load.c:
* c->mapend = ((ph->p_vaddr + ph->p_filesz + GLRO(dl_pagesize) - 1)
* & ~(GLRO(dl_pagesize) - 1));
*
* In glibc, the segment file size is aligned up to the nearest page size and
* added to the virtual address of the segment. We just want the size here.
*/
lib.memorySize = PAGE_ALIGN_UP(hdr.p_filesz);
break;
}
}
#elif defined PLATFORM_APPLE
Dl_info info;
struct mach_header *file;
struct segment_command *seg;
uint32_t cmd_count;
if (!dladdr(libPtr, &info))
{
return false;
}
if (!info.dli_fbase || !info.dli_fname)
{
return false;
}
/* This is for our insane sanity checks :o */
baseAddr = (uintptr_t)info.dli_fbase;
file = (struct mach_header *)baseAddr;
/* Check Mach-O magic */
if (file->magic != MH_MAGIC)
{
return false;
}
/* Check architecture (32-bit/x86) */
if (file->cputype != CPU_TYPE_I386 || file->cpusubtype != CPU_SUBTYPE_I386_ALL)
{
return false;
}
/* For our purposes, this must be a dynamic library */
if (file->filetype != MH_DYLIB)
{
return false;
}
cmd_count = file->ncmds;
seg = (struct segment_command *)(baseAddr + sizeof(struct mach_header));
/* Add up memory sizes of mapped segments */
for (uint32_t i = 0; i < cmd_count; i++)
{
if (seg->cmd == LC_SEGMENT)
{
lib.memorySize += seg->vmsize;
}
seg = (struct segment_command *)((uintptr_t)seg + seg->cmdsize);
}
#endif
lib.baseAddress = reinterpret_cast<void *>(baseAddr);
return true;
}
-143
View File
@@ -1,143 +0,0 @@
/**
* vim: set ts=4 sw=4 tw=99 noet :
* =============================================================================
* SourcePawn
* Copyright (C) 2004-2009 AlliedModders LLC. All rights reserved.
* =============================================================================
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 3.0, as published by the
* Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
* As a special exception, AlliedModders LLC gives you permission to link the
* code of this program (as well as its derivative works) to "Half-Life 2," the
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
* by the Valve Corporation. You must obey the GNU General Public License in
* all respects for all other code used. Additionally, AlliedModders LLC grants
* this exception to all derivative works. AlliedModders LLC defines further
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
* or <http://www.sourcemod.net/license.php>.
*
* Version: $Id$
*/
#include "NativeOwner.h"
#include "ShareSys.h"
#include "PluginSys.h"
CNativeOwner::CNativeOwner() : m_nMarkSerial(0)
{
}
void CNativeOwner::SetMarkSerial(unsigned int serial)
{
m_nMarkSerial = serial;
}
unsigned int CNativeOwner::GetMarkSerial()
{
return m_nMarkSerial;
}
void CNativeOwner::AddDependent(CPlugin *pPlugin)
{
m_Dependents.push_back(pPlugin);
}
void CNativeOwner::AddWeakRef(const WeakNative & ref)
{
m_WeakRefs.push_back(ref);
}
void CNativeOwner::AddNatives(const sp_nativeinfo_t *natives)
{
for (const sp_nativeinfo_t *native = natives; native->func && native->name; native++)
g_ShareSys.AddNativeToCache(this, native);
m_natives.append(natives);
}
void CNativeOwner::PropagateMarkSerial(unsigned int serial)
{
CNativeOwner *pOwner;
List<CPlugin *>::iterator iter;
for (iter = m_Dependents.begin();
iter != m_Dependents.end();
iter++)
{
pOwner = (*iter);
pOwner->SetMarkSerial(serial);
}
}
void CNativeOwner::UnbindWeakRef(const WeakNative &ref)
{
sp_native_t *native;
IPluginContext *pContext;
pContext = ref.pl->GetBaseContext();
if ((pContext->GetNativeByIndex(ref.idx, &native)) == SP_ERROR_NONE)
{
native->status = SP_NATIVE_UNBOUND;
native->pfn = NULL;
}
}
void CNativeOwner::DropEverything()
{
List<WeakNative>::iterator iter;
/* Unbind and remove all weak references to us */
iter = m_WeakRefs.begin();
while (iter != m_WeakRefs.end())
{
UnbindWeakRef((*iter));
iter = m_WeakRefs.erase(iter);
}
/* Strip all of our natives from the cache */
for (size_t i = 0; i < m_natives.length(); i++) {
const sp_nativeinfo_t *natives = m_natives[i];
for (const sp_nativeinfo_t *native = natives; native->func && native->name; native++)
g_ShareSys.ClearNativeFromCache(this, native->name);
}
m_natives.clear();
for (size_t i = 0; i < m_fakes.length(); i++)
g_ShareSys.ClearNativeFromCache(this, m_fakes[i]->name());
m_fakes.clear();
}
void CNativeOwner::DropWeakRefsTo(CPlugin *pPlugin)
{
List<WeakNative>::iterator iter;
iter = m_WeakRefs.begin();
while (iter != m_WeakRefs.end())
{
WeakNative & ref = (*iter);
if (ref.pl == pPlugin)
{
iter = m_WeakRefs.erase(iter);
}
else
{
iter++;
}
}
}
void CNativeOwner::DropRefsTo(CPlugin *pPlugin)
{
m_Dependents.remove(pPlugin);
DropWeakRefsTo(pPlugin);
}

Some files were not shown because too many files have changed in this diff Show More