Removed files for dead branch: refac-jit

--HG--
branch : refac-jit
This commit is contained in:
Scott Ehlert 2008-09-14 02:55:49 -05:00
parent 5668f23b50
commit 56b77a536f
884 changed files with 0 additions and 297368 deletions

View File

@ -1,36 +0,0 @@
We now use svn:keywords "Id" on all .c/.cpp/.h/.inc/.sp/ files.
Please make sure your client is configured properly.
WINDOWS:
- Open your Application Data directory.
Windows XP/2000: C:\Documents and Settings\<user>\Application Data
Windows Vista: C:\Users\<user>\AppData\Roaming
- Now go to the Subversion directory.
- Open the "config" file with a text editor.
LINUX:
- Open ~/.subversion/config with your favorite text editor.
Under [miscellany], uncomment this line:
# enable-auto-props = yes
Under [auto-props], add these lines:
*.c = svn:keywords=Id
*.cpp = svn:keywords=Id
*.h = svn:keywords=Id
*.inc = svn:keywords=Id
*.sp = svn:keywords=Id
If you find a file with one of the above extensions that does not have the svn:keywords property...
TORTOISE SVN:
- Right click on the file(s) that do not have the property.
- In the context menu that appears, select TortoiseSVN -> Properties.
- A properties window should appear. Click the Add button.
- Select "svn:keywords" from the "Property name" combo box and type "Id" in the "Property value" text area.
- Click OK on both windows and commit the change(s).
CLI SVN CLIENT:
- Execute the following command: svn propset svn:keywords Id <files>

View File

@ -1,75 +0,0 @@
SourceMod Changelog
----------------------------
SourceMod 1.0.3 [2008-06-21]
Changes:
- Fixed SDKTools compatibility for latest TF2 update.
- Fixed amb1750: OnAutoConfigsBuffered() inserted before "exec server.cfg".
- Fixed a logic bug where OnConfigsExecuted() could be executed before "exec server.cfg" finished.
- Fixed a rare crash in the event manager that manifested on Zombie Panic! Source.
----------------------------
SourceMod 1.0.2 [2008-05-31]
Changes:
- The admin menu is now user-modifiable (the "Dynamic Admin Menu").
- Added a TF2 extension with Team Fortress functions.
- Added a RegEx extension with regular expression functions.
- Added functions to SDKTools for hooking entity outputs.
- Added preliminary support for the DoD:S Orange Box beta.
- Added a forward for map config plugins for preventing race conditions.
- Added a %b format specifier for binary printing.
- Added sm_dump_datamaps command (SDKTools) for enumerating datamap properties.
- Added sm_dump_admcache command for debugging the admin cache.
- Added amb1715 - TraceHull functions to SDKTools (complementing TraceRay).
- Added amb1694 - FindCharInString() function.
- Added amb1685 - GetTickInterval() function.
- Added amb1620 - ActivateEntity() function to SDKTools (for Orange Box particle system).
- Added amb1610 - StripQuotes() function.
- Added amb1558 - Compiler now has __BINARY_PATH__ and __BINARY_FILE__ macros.
- Fixed amb1686 - ReplaceString* with an empty search string crashed; it now throws an error.
- Fixed amb1684 - Blank passwords required an empty but set password.
- Fixed amb1595 - Extension load failures did not show a platform error message.
- Fixed amb1583 - MySQL string fetch from prepared queries returned corrupted data.
- Fixed amb1358 - Timeleft did not reset on TF2 restarts.
- Fixed cases where the JIT was too cautious in space optimizations.
- Fixed TF2/Cstrike extensions being loadable on incompatible games.
- Fixed various documentation inconsistencies and typos.
- Fixed internal bugs with file extension handling.
Notes:
There is a possible compatibility regression from amb1684. SetAdminPassword()
has been modified to remove any set password when given an empty string. Previously,
a blank password ("") would force an admin to use "setinfo" to set an empty password,
but this functionality was deemed unuseful and unintended. Blank passwords now
remove any set password.
----------------------------
SourceMod 1.0.1 [2008-05-20]
Changes:
- Fixed SDKTools compatibility for latest TF2 update.
- Removed GivePlayerItem from TF2 (TF2 update broke functionality).
- Fixed amb1688: GivePlayerItem offset was wrong for DoD:S Linux.
- Fixed amb1657: Server console did not see admin version of sm_who.
- Fixed amb1648: Stack corruption from GetClientEyeAngles() on Windows.
- Fixed amb1646: NetFlow_Both did not work for client network statistics.
- Fixed amb1601: Vote FF menu reading from sv_alltalk cvar instead of mp_friendlyfire.
- Fixed amb1591: Fixed listen server crashes on mods like IOS:S which pre-add more than one bot.
- Fixed amb1586: GetTeamName() could crash the server if called on load.
- Fixed mapchooser's round counting for TF2.
- Fixed a bug where an RTE on plugin load would throw a message referring to the plugin as "-1".
- Symbols are no longer stripped on Linux.
- Minor SourceMod SDK fixes.
Notes:
The extension interface version has been bumped. Any extensions compiled against 1.0.1 will require 1.0.1 or higher to run. Extensions against 1.0.0 will continue to run normally.

View File

@ -1,36 +0,0 @@
Groups
{
/**
* Allowed properties for a group:
*
* "flags" - Flag string.
* "immunity" - Immunity level number, or a group name.
* If the group name is a number, prepend it with an
* '@' symbol similar to admins_simple.ini. Users
* will only inherit the level number if it's higher
* than their current value.
*/
"Default"
{
"immunity" "1"
}
"Full Admins"
{
/**
* You can override commands and command groups here.
* Specify a command name or group and either "allow" or "deny"
* Examples:
* ":CSDM" "allow"
* "csdm_enable" "deny"
*/
Overrides
{
}
"flags" "abcdefghiz"
/* Largish number for lots of in-between values. */
"immunity" "99"
}
}

View File

@ -1,49 +0,0 @@
/**
* There is no reason to edit this file. Core uses this to map each named
* access type to a given ASCII character. The names are all pre-defined.
*/
Levels
{
/**
* These are the default role flag mappings.
* You can assign new letters for custom purposes, however you should
* not change the default names, as SourceMod hardcodes these.
*/
Flags
{
"reservation" "a" //Reserved slots
"generic" "b" //Generic admin, required for admins
"kick" "c" //Kick other players
"ban" "d" //Banning other players
"unban" "e" //Removing bans
"slay" "f" //Slaying other players
"changemap" "g" //Changing the map
"cvars" "h" //Changing cvars
"config" "i" //Changing configs
"chat" "j" //Special chat privileges
"vote" "k" //Voting
"password" "l" //Password the server
"rcon" "m" //Remote console
"cheats" "n" //Change sv_cheats and related commands
/**
* Custom flags can be used by plugins, but they can also be used to
* for you to expand on the previous groups, using Overrides.
*/
"custom1" "o"
"custom2" "p"
"custom3" "q"
"custom4" "r"
"custom5" "s"
"custom6" "t"
/**
* Root is a magic access flag that grants all permissions.
* This should only be given to trusted administrators.
* Root users can target anyone regardless of immunity,
* however, they themselves are not automatically immune.
*/
"root" "z"
}
}

View File

@ -1,21 +0,0 @@
Overrides
{
/**
* By default, commands are registered with three pieces of information:
* 1)Command Name (for example, "csdm_enable")
* 2)Command Group Name (for example, "CSDM")
* 3)Command Level (for example, "changemap")
*
* You can override the default flags assigned to individual commands or command groups in this way.
* To override a group, use the "@" character before the name. Example:
* Examples:
* "@CSDM" "b" // Override the CSDM group to 'b' flag
* "csdm_enable" "bgi" // Override the csdm_enable command to 'bgi' flags
*
* Note that for overrides, order is important. In the above example, csdm_enable overwrites
* any setting that csdm_enable previously had.
*
* You can make a command completely public by using an empty flag string.
*/
}

View File

@ -1,10 +0,0 @@
/**
* List config files here (relative to moddir) to have them added to the exec config menu list
* Left side is the filename, right side is the text to be added to the menu
*/
Configs
{
"cfg/server.cfg" "Standard Server Setup"
"cfg/sourcemod/sm_warmode_on.cfg" "War Mode On"
"cfg/sourcemod/sm_warmode_off.cfg" "War Mode Off"
}

View File

@ -1,12 +0,0 @@
// Custom admin menu commands.
// For more information:
//
// http://wiki.alliedmods.net/Custom_Admin_Menu_%28SourceMod%29
//
// Note: This file must be in Valve KeyValues format (no multiline comments)
//
"Commands"
{
}

View File

@ -1,20 +0,0 @@
/* Add group options to be added to 'group' or 'groupplayer' type submenus
* The left side is the name that will show in the menu, right is the command that will be fired
*
* For more information: http://wiki.alliedmods.net/Custom_Admin_Menu_%28SourceMod%29
*/
Groups
{
"All" "@all"
"Bots" "@bots"
"Alive" "@alive"
"Dead" "@dead"
"Humans" "@humans"
"Current aim" "@aim"
/* You can enable these if you are using Counter-Strike Source and running the cstrike extension */
// "Terrorists" "@t"
// "Counter-Terrorists" "@ct"
}

View File

@ -1,39 +0,0 @@
/**
* The default sorting is designed to look familiar to Mani's admin menu.
* You may re-order items here for your own menu. Any items not explicitly
* sorted will be sorted by their final translated phrases for each given client.
*/
"Menu"
{
"PlayerCommands"
{
"item" "sm_slay"
"item" "sm_slap"
"item" "sm_kick"
"item" "sm_ban"
"item" "sm_gag"
"item" "sm_burn"
"item" "sm_beacon"
"item" "sm_freeze"
"item" "sm_timebomb"
"item" "sm_firebomb"
"item" "sm_freezebomb"
}
"ServerCommands"
{
"item" "sm_map"
"item" "sm_execcfg"
"item" "sm_reloadadmins"
}
"VotingCommands"
{
"item" "sm_cancelvote"
"item" "sm_votemap"
"item" "sm_votekick"
"item" "sm_voteban"
}
}

View File

@ -1,39 +0,0 @@
/**
* USE THIS SECTION TO DECLARE DETAILED ADMIN PROPERTIES.
*
* Each admin should have its own "Admin" section, followed by a name.
* The name does not have to be unique.
*
* Available properties: (Anything else is filtered as custom)
* "auth" - REQUIRED - Auth method to use. Built-in methods are:
* "steam" - Steam based authentication
* "name" - Name based authentication
* "ip" - IP based authentication
* Anything else is treated as custom.
* Note: Only one auth method is allowed per entry.
*
* "identity" - REQUIRED - Identification string, for example, a steamid or name.
* Note: Only one identity is allowed per entry.
*
* "password" - Optional password to require.
* "group" - Adds one group to the user's group table.
* "flags" - Adds one or more flags to the user's permissions.
* "immunity" - Sets the user's immunity level (0 = no immunity).
* Immunity can be any value. Admins with higher
* values cannot be targetted. See sm_immunity_mode
* to tweak the rules. Default value is 0.
*
* Example:
"BAILOPAN"
{
"auth" "steam"
"identity" "STEAM_0:1:16"
"flags" "abcdef"
}
*
*/
Admins
{
}

View File

@ -1,46 +0,0 @@
//
// READ THIS CAREFULLY! SEE BOTTOM FOR EXAMPLES
//
// For each admin, you need three settings:
// "identity" "permissions" "password"
//
// For the Identity, you can use a SteamID or Name. To use an IP address, prepend a ! character.
// For the Permissions, you can use a flag string and an optional password.
//
// PERMISSIONS:
// Flag definitions are in "admin_levels.cfg"
// You can combine flags into a string like this:
// "abcdefgh"
//
// If you want to specify a group instead of a flag, use an @ symbol. Example:
// "@Full Admins"
//
// You can also specify immunity values. Two examples:
// "83:abcdefg" //Immunity is 83, flags are abcefgh
// "6:@Full Admins" //Immunity is 6, group is "Full Admins"
//
// Immunity values can be any number. An admin cannot target an admin with
// a higher access value (see sm_immunity_mode to tweak the rules). Default
// immunity value is 0 (no immunity).
//
// PASSWORDS:
// Passwords are generally not needed unless you have name-based authentication.
// In this case, admins must type this in their console:
//
// setinfo "KEY" "PASSWORD"
//
// Where KEY is the "PassInfoVar" setting in your core.cfg file, and "PASSWORD"
// is their password. With name based authentication, this must be done before
// changing names or connecting. Otherwise, SourceMod will automatically detect
// the password being set.
//
////////////////////////////////
// Examples: (do not put // in front of real lines, as // means 'comment')
//
// "STEAM_0:1:16" "bce" //kick, ban, slay for this steam ID, no immunity
// "!127.0.0.1" "99:z" //all permissions for this ip, immunity value is 99
// "BAILOPAN" "abc" "Gab3n" //name BAILOPAN, password "Gab3n": gets reservation, kick, ban
//
////////////////////////////////

View File

@ -1,4 +0,0 @@
//This file re-enables a server from "war mode" by unlocking plugin loading
//and refreshing the plugins list.
sm plugins load_unlock
sm plugins refresh

View File

@ -1,9 +0,0 @@
//This file unloads all plugins, re-loads a few "safe" ones, and then prevents
//any more plugins from being loaded.
sm plugins unload_all
sm plugins load basebans.smx
sm plugins load basecommands.smx
sm plugins load admin-flatfile.smx
sm plugins load adminhelp.smx
sm plugins load adminmenu.smx
sm plugins load_lock

View File

@ -1,109 +0,0 @@
// SourceMod Configuration File
// This file is automatically executed by SourceMod every mapchange.
// Specifies how admin activity should be relayed to users. Add up the values
// below to get the functionality you want.
// 1: Show admin activity to non-admins anonymously.
// 2: If 1 is specified, admin names will be shown.
// 4: Show admin activity to admins anonymously.
// 8: If 4 is specified, admin names will be shown.
// 16: Always show admin names to root users.
// --
// Default: 13 (1+4+8)
sm_show_activity 13
// Specifies whether menu sounds are enabled for menus created by SourceMod.
// Menu sounds can be further configured in addons/sourcemod/configs/core.cfg.
// --
// Default: 1
sm_menu_sounds 1
// Specifies how long of a delay, in seconds, should be used in between votes
// that are "public" or can be spammed. Whether or not this delay is obeyed
// is dependent on the menu/command.
// --
// Default: 30
sm_vote_delay 30
// Default datetime formatting rules when displaying to clients.
// For full options, see: http://www.opengroup.org/onlinepubs/007908799/xsh/strftime.html
// --
// Default: %m/%d/%Y - %H:%M:%S
// 12 hour format: %m/%d/%Y - %I:%M:%S %p
sm_datetime_format "%m/%d/%Y - %H:%M:%S"
// Sets how SourceMod should check immunity levels when administrators target
// each other.
// 0: Ignore immunity levels (except for specific group immunities).
// 1: Protect from admins of lower access only.
// 2: Protect from admins of equal to or lower access.
// 3: Same as 2, except admins with no immunity can affect each other.
// --
// Default: 1
sm_immunity_mode 1
// Sets how many seconds SourceMod should adjust time values for incorrect
// server clocks. This can be positive or negative and will affect every
// system time in SourceMod, including logging stamps.
// --
// Default: 0
sm_time_adjustment 0
// Specifies the amount of time that is allowed between chat messages. This
// includes the say and say_team commands. If a client sends a message faster
// than this time, they receive a flood token. When the client has accumulated
// 3 or more tokens, a warning message is shown instead of the chat message.
// --
// Requires: antiflood.smx
// Default: 0.75
sm_flood_time 0.75
// Specifies how the reserved slots plugin operates. Valid values are:
// 0 : Public slots are used in preference to reserved slots. Reserved slots are freed before public slots.
// 1 : If someone with reserve access joins into a reserved slot, the player with the highest latency and
// no reserved slot access (spectator players are selected first) is kicked to make room. Thus, the reserved
// slots always remains free. The only situation where the reserved slot(s) can become properly occupied is
// if the server is full with reserve slot access clients.
// --
// Requires: reservedslots.smx
// Default: 0
sm_reserve_type 0
// Specifies the number of reserved player slots. Users with the reservation
// admin flag set will be able to join the server when there are no public slots
// remaining. If someone does not have this flag, they will be kicked.
// (Public slots are defined as: maxplayers - number of reserved slots)
// --
// Requires: reservedslots.smx
// Default: 0
sm_reserved_slots 0
// Specifies whether or not reserved slots will be hidden (subtracted from max
// slot count). Valid values are 0 (visible) or 1 (hidden).
// --
// Requires: reservedslots.smx
// Default: 0
sm_hide_slots 0
// Specifies whether or not non-admins can send messages to admins using
// say_team @<message>. Valid values are 0 (disabled) or 1 (enabled)
// --
// Requires: basechat.smx
// Default: 1
sm_chat_mode 1
// Specifies whether or not "timeleft" will automaticly be triggered every
// x seconds. Valid values are 0 (disabled) to 1800 seconds.
// --
// Requires: basetriggers.smx
// Default: 0
sm_timeleft_interval 0
// Specifies whether or not chat triggers are broadcast to the server or just
// the player who requested the info trigger. Valid values are 0 (Disabled) or
// 1 (Enabled)
// --
// Requires: basetriggers.smx
// Default: 1
sm_trigger_show 1

View File

@ -1,105 +0,0 @@
/**
* This file is used to set various options that are important to SourceMod's core.
* If this file is missing or an option in this file is missing, then the default values will be used.
*/
"Core"
{
/**
* Relative path to SourceMod's base directory. This is relative to the game/mod directory.
* Only change this if you have installed SourceMod in a non-default location.
*
* The default value is "addons/sourcemod"
*/
"BasePath" "addons/sourcemod"
/**
* This option determines if SourceMod logging is enabled.
*
* "on" - Logging is enabled (default)
* "off" - Logging is disabled
*/
"Logging" "on"
/**
* This option determines how SourceMod logging should be handled.
*
* "daily" - New log file is created for each day (default)
* "map" - New log file is created for each map change
* "game" - Use game's log files
*/
"LogMode" "daily"
/**
* Language that multilingual enabled plugins and extensions will use to print messages.
* Only languages listed in languages.cfg are valid.
*
* The default value is "en"
*/
"ServerLang" "en"
/**
* String to use as the public chat trigger. Set an empty string to disable.
*/
"PublicChatTrigger" "!"
/**
* String to use as the silent chat trigger. Set an empty string to disable.
*/
"SilentChatTrigger" "/"
/**
* If a say command is a silent chat trigger, and is used by an admin,
* but it does not evaluate to an actual command, it will be displayed
* publicly. This setting allows you to suppress accidental typings.
*
* The default value is "no". A value of "yes" will supress.
*/
"SilentFailSuppress" "no"
/**
* Password setinfo key that clients must set. You must change this in order for
* passwords to work, for security reasons.
*/
"PassInfoVar" "_password"
/**
* Specifies the sound that gets played when an item is selected from a menu.
*/
"MenuItemSound" "buttons/button14.wav"
/**
* Specifies the sound that gets played when an "Exit" button is selected
* from a menu.
*/
"MenuExitSound" "buttons/combine_button7.wav"
/**
* Specifies the sound that gets played when an "Exit Back" button is selected
* from a menu. This is the special "Back" button that is intended to roll back
* to a previous menu.
*/
"MenuExitBackSound" "buttons/combine_button7.wav"
/**
* Enables or disables whether SourceMod reads a client's cl_language cvar to set
* their language for server-side phrase translation.
*
* "on" - Translate using the client's language (default)
* "off" - Translate using default server's language
*/
"AllowClLanguageVar" "On"
/**
* Enables or Disables SourceMod's automatic gamedata updating.
*
* The default value is "no". A value of "yes" will block the Auto Updater.
*/
"DisableAutoUpdate" "no"
/**
* Enables or disables automatic restarting of the server after a successful update.
*
* The default value is "no". A value of "yes" will let the server automatically restart.
*/
"ForceRestartAfterUpdate" "no"
}

View File

@ -1,32 +0,0 @@
"Databases"
{
"driver_default" "mysql"
"default"
{
"driver" "default"
"host" "localhost"
"database" "sourcemod"
"user" "root"
"pass" ""
//"timeout" "0"
//"port" "0"
}
"storage-local"
{
"driver" "sqlite"
"database" "sourcemod-local"
}
"clientprefs"
{
"driver" "sqlite"
"host" "localhost"
"database" "clientprefs-sqlite"
"user" "root"
"pass" ""
//"timeout" "0"
//"port" "0"
}
}

Binary file not shown.

View File

@ -1,6 +0,0 @@
"Languages"
{
"en" "English"
"es" "Español"
}

View File

@ -1,59 +0,0 @@
/**
* Use this file to configure map lists.
*
* Each section is a map list that plugins can use. For example, the Admin Menu
* requests an "admin menu" map list, and you can control which maps appear via
* this file.
*
* Each section must have a property that explains where to read the maps from.
* There are two properties:
*
* target - Redirect the request to another section.
* file - Read a file of map names, in mapcycle.txt format.
*
* There is one section by default, called "mapcyclefile" - it is mapped to the
* mapcycle.txt file, or whatever the contents of your mapcyclefile cvar is.
*
* If a plugin requests a map list file which doesn't exist, or is empty, SourceMod
* tries the "default" section, and then the "mapcyclefile" section.
*/
"MapLists"
{
/**
* Default requests go right to the mapcyclefile.
*/
"default"
{
"target" "mapcyclefile"
}
/* Admin menu, map menu */
"sm_map menu"
{
"file" "addons/sourcemod/configs/adminmenu_maplist.ini"
}
/* Admin menu, map voting menu */
"sm_votemap menu"
{
"file" "addons/sourcemod/configs/adminmenu_maplist.ini"
}
/* For the "randomcycle" plugin */
"randomcycle"
{
"target" "default"
}
/* For the "mapchooser" plugin */
"mapchooser"
{
"target" "default"
}
/* For the "rockthevote" plugin */
"rockthevote"
{
"target" "default"
}
}

View File

@ -1,5 +0,0 @@
"Metamod Plugin"
{
"alias" "sourcemod"
"file" "addons/sourcemod/bin/sourcemod_mm"
}

View File

@ -1,38 +0,0 @@
/**
* 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:
* "debug" - Whether or not to load the plugin in debug mode
* "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"
{
"debug" "no"
}
}
}

View File

@ -1,17 +0,0 @@
CREATE TABLE sm_cookies
(
id INTEGER unsigned NOT NULL auto_increment,
name varchar(30) NOT NULL UNIQUE,
description varchar(255),
access INTEGER,
PRIMARY KEY (id)
);
CREATE TABLE sm_cookie_cache
(
player varchar(65) NOT NULL,
cookie_id int(10) NOT NULL,
value varchar(100),
timestamp int NOT NULL,
PRIMARY KEY (player, cookie_id)
);

View File

@ -1,56 +0,0 @@
CREATE TABLE sm_admins (
id int(10) unsigned NOT NULL auto_increment,
authtype enum('steam','name','ip') NOT NULL,
identity varchar(65) NOT NULL,
password varchar(65),
flags varchar(30) NOT NULL,
name varchar(65) NOT NULL,
immunity int(10) unsigned NOT NULL,
PRIMARY KEY (id)
);
CREATE TABLE sm_groups (
id int(10) unsigned NOT NULL auto_increment,
flags varchar(30) NOT NULL,
name varchar(120) NOT NULL,
immunity_level int(1) unsigned NOT NULL,
PRIMARY KEY (id)
);
CREATE TABLE sm_group_immunity (
group_id int(10) unsigned NOT NULL,
other_id int(10) unsigned NOT NULL,
PRIMARY KEY (group_id, other_id)
);
CREATE TABLE sm_group_overrides (
group_id int(10) unsigned NOT NULL,
type enum('command','group') NOT NULL,
name varchar(32) NOT NULL,
access enum('allow','deny') NOT NULL,
PRIMARY KEY (group_id, type, name)
);
CREATE TABLE sm_overrides (
type enum('command','group') NOT NULL,
name varchar(32) NOT NULL,
flags varchar(30) NOT NULL,
PRIMARY KEY (type,name)
);
CREATE TABLE sm_admins_groups (
admin_id int(10) unsigned NOT NULL,
group_id int(10) unsigned NOT NULL,
inherit_order int(10) NOT NULL,
PRIMARY KEY (admin_id, group_id)
);
CREATE TABLE IF NOT EXISTS sm_config (
cfg_key varchar(32) NOT NULL,
cfg_value varchar(255) NOT NULL,
PRIMARY KEY (cfg_key)
);
INSERT INTO sm_config (cfg_key, cfg_value) VALUES ('admin_version', '1.0.0.1409') ON DUPLICATE KEY UPDATE cfg_value = '1.0.0.1409';

View File

@ -1,15 +0,0 @@
ALTER TABLE sm_admins ADD immunity INT UNSIGNED NOT NULL;
ALTER TABLE sm_groups ADD immunity_level INT UNSIGNED NOT NULL;
UPDATE sm_groups SET immunity_level = 2 WHERE immunity = 'default';
UPDATE sm_groups SET immunity_level = 1 WHERE immunity = 'global';
ALTER TABLE sm_groups DROP immunity;
CREATE TABLE sm_config (
cfg_key varchar(32) NOT NULL,
cfg_value varchar(255) NOT NULL,
PRIMARY KEY (cfg_key)
);
INSERT INTO sm_config (cfg_key, cfg_value) VALUES ('admin_version', '1.0.0.1409') ON DUPLICATE KEY UPDATE cfg_value = '1.0.0.1409';

View File

@ -1,16 +0,0 @@
CREATE TABLE sm_cookies
(
id INTEGER PRIMARY KEY AUTOINCREMENT,
name varchar(30) NOT NULL UNIQUE,
description varchar(255),
access INTEGER
);
CREATE TABLE sm_cookie_cache
(
player varchar(65) NOT NULL,
cookie_id int(10) NOT NULL,
value varchar(100),
timestamp int,
PRIMARY KEY (player, cookie_id)
);

View File

@ -1,54 +0,0 @@
CREATE TABLE sm_admins (
id INTEGER PRIMARY KEY AUTOINCREMENT,
authtype varchar(16) NOT NULL CHECK(authtype IN ('steam', 'ip', 'name')),
identity varchar(65) NOT NULL,
password varchar(65),
flags varchar(30) NOT NULL,
name varchar(65) NOT NULL,
immunity INTEGER NOT NULL
);
CREATE TABLE sm_groups (
id INTEGER PRIMARY KEY AUTOINCREMENT,
flags varchar(30) NOT NULL,
name varchar(120) NOT NULL,
immunity_level INTEGER NOT NULL
);
CREATE TABLE sm_group_immunity (
group_id INTEGER NOT NULL,
other_id INTEGER NOT NULL,
PRIMARY KEY (group_id, other_id)
);
CREATE TABLE sm_group_overrides (
group_id INTEGER NOT NULL,
type varchar(16) NOT NULL CHECK (type IN ('command', 'group')),
name varchar(32) NOT NULL,
access varchar(16) NOT NULL CHECK (access IN ('allow', 'deny')),
PRIMARY KEY (group_id, type, name)
);
CREATE TABLE sm_overrides (
type varchar(16) NOT NULL CHECK (type IN ('command', 'group')),
name varchar(32) NOT NULL,
flags varchar(30) NOT NULL,
PRIMARY KEY (type,name)
);
CREATE TABLE sm_admins_groups (
admin_id INTEGER NOT NULL,
group_id INTEGER NOT NULL,
inherit_order int(10) NOT NULL,
PRIMARY KEY (admin_id, group_id)
);
CREATE TABLE IF NOT EXISTS sm_config (
cfg_key varchar(32) NOT NULL,
cfg_value varchar(255) NOT NULL,
PRIMARY KEY (cfg_key)
);
REPLACE INTO sm_config (cfg_key, cfg_value) VALUES ('admin_version', '1.0.0.1409');

View File

@ -1,23 +0,0 @@
ALTER TABLE sm_admins ADD immunity INTEGER DEFAULT 0 NOT NULL;
CREATE TABLE _sm_groups_temp (
id INTEGER PRIMARY KEY AUTOINCREMENT,
flags varchar(30) NOT NULL,
name varchar(120) NOT NULL,
immunity_level INTEGER DEFAULT 0 NOT NULL
);
INSERT INTO _sm_groups_temp (id, flags, name) SELECT id, flags, name FROM sm_groups;
UPDATE _sm_groups_temp SET immunity_level = 2 WHERE id IN (SELECT g.id FROM sm_groups g WHERE g.immunity = 'global');
UPDATE _sm_groups_temp SET immunity_level = 1 WHERE id IN (SELECT g.id FROM sm_groups g WHERE g.immunity = 'default');
DROP TABLE sm_groups;
ALTER TABLE _sm_groups_temp RENAME TO sm_groups;
CREATE TABLE IF NOT EXISTS sm_config (
cfg_key varchar(32) NOT NULL,
cfg_value varchar(255) NOT NULL,
PRIMARY KEY (cfg_key)
);
REPLACE INTO sm_config (cfg_key, cfg_value) VALUES ('admin_version', '1.0.0.1409');

View File

@ -1,96 +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$
*/
#include "ADTFactory.h"
#include "sm_globals.h"
#include "ShareSys.h"
ADTFactory g_AdtFactory;
const char *ADTFactory::GetInterfaceName()
{
return SMINTERFACE_ADTFACTORY_NAME;
}
unsigned int ADTFactory::GetInterfaceVersion()
{
return SMINTERFACE_ADTFACTORY_VERSION;
}
void ADTFactory::OnSourceModAllInitialized()
{
g_ShareSys.AddInterface(NULL, this);
}
IBasicTrie *ADTFactory::CreateBasicTrie()
{
return new BaseTrie();
}
BaseTrie::BaseTrie()
{
m_pTrie = sm_trie_create();
}
BaseTrie::~BaseTrie()
{
sm_trie_destroy(m_pTrie);
}
bool BaseTrie::Insert(const char *key, void *value)
{
return sm_trie_insert(m_pTrie, key, value);
}
bool BaseTrie::Retrieve(const char *key, void **value)
{
return sm_trie_retrieve(m_pTrie, key, value);
}
bool BaseTrie::Delete(const char *key)
{
return sm_trie_delete(m_pTrie, key);
}
void BaseTrie::Clear()
{
sm_trie_clear(m_pTrie);
}
void BaseTrie::Destroy()
{
delete this;
}
bool BaseTrie::Replace(const char *key, void *value)
{
return sm_trie_replace(m_pTrie, key, value);
}

View File

@ -1,70 +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_ADTFACTORY_H_
#define _INCLUDE_SOURCEMOD_ADTFACTORY_H_
#include <IADTFactory.h>
#include "sm_globals.h"
#include "sm_trie.h"
using namespace SourceMod;
class BaseTrie : public IBasicTrie
{
public:
BaseTrie();
virtual ~BaseTrie();
virtual bool Insert(const char *key, void *value);
virtual bool Replace(const char *key, void *value);
virtual bool Retrieve(const char *key, void **value);
virtual bool Delete(const char *key);
virtual void Clear();
virtual void Destroy();
private:
Trie *m_pTrie;
};
class ADTFactory :
public SMGlobalClass,
public IADTFactory
{
public: //SMInterface
const char *GetInterfaceName();
unsigned int GetInterfaceVersion();
public: //SMGlobalClass
void OnSourceModAllInitialized();
public: //IADTFactory
IBasicTrie *CreateBasicTrie();
};
#endif //_INCLUDE_SOURCEMOD_ADTFACTORY_H_

File diff suppressed because it is too large Load Diff

View File

@ -1,208 +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_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_

View File

@ -1,259 +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$
*/
#include <malloc.h>
#include <string.h>
#include "CDataPack.h"
#define DATAPACK_INITIAL_SIZE 512
CDataPack::CDataPack()
{
m_pBase = (char *)malloc(DATAPACK_INITIAL_SIZE);
m_capacity = DATAPACK_INITIAL_SIZE;
Initialize();
}
CDataPack::~CDataPack()
{
free(m_pBase);
}
void CDataPack::Initialize()
{
m_curptr = m_pBase;
m_size = 0;
}
void CDataPack::CheckSize(size_t typesize)
{
if (m_curptr - m_pBase + typesize <= m_capacity)
{
return;
}
size_t pos = m_curptr - m_pBase;
do
{
m_capacity *= 2;
m_pBase = (char *)realloc(m_pBase, m_capacity);
m_curptr = m_pBase + pos;
} while (m_curptr - m_pBase + typesize > m_capacity);
}
void CDataPack::ResetSize()
{
m_size = 0;
}
size_t CDataPack::CreateMemory(size_t size, void **addr)
{
CheckSize(sizeof(size_t) + size);
size_t pos = m_curptr - m_pBase;
*(size_t *)m_curptr = size;
m_curptr += sizeof(size_t);
if (addr)
{
*addr = m_curptr;
}
m_curptr += size;
m_size += sizeof(size_t) + size;
return pos;
}
void CDataPack::PackCell(cell_t cell)
{
CheckSize(sizeof(size_t) + sizeof(cell_t));
*(size_t *)m_curptr = sizeof(cell_t);
m_curptr += sizeof(size_t);
*(cell_t *)m_curptr = cell;
m_curptr += sizeof(cell_t);
m_size += sizeof(size_t) + sizeof(cell_t);
}
void CDataPack::PackFloat(float val)
{
CheckSize(sizeof(size_t) + sizeof(float));
*(size_t *)m_curptr = sizeof(float);
m_curptr += sizeof(size_t);
*(float *)m_curptr = val;
m_curptr += sizeof(float);
m_size += sizeof(size_t) + sizeof(float);
}
void CDataPack::PackString(const char *string)
{
size_t len = strlen(string);
size_t maxsize = sizeof(size_t) + len + 1;
CheckSize(maxsize);
// Pack the string length first for buffer overrun checking.
*(size_t *)m_curptr = len;
m_curptr += sizeof(size_t);
// Now pack the string.
memcpy(m_curptr, string, len);
m_curptr[len] = '\0';
m_curptr += len + 1;
m_size += maxsize;
}
void CDataPack::Reset() const
{
m_curptr = m_pBase;
}
size_t CDataPack::GetPosition() const
{
return static_cast<size_t>(m_curptr - m_pBase);
}
bool CDataPack::SetPosition(size_t pos) const
{
if (pos > m_size-1)
{
return false;
}
m_curptr = m_pBase + pos;
return true;
}
cell_t CDataPack::ReadCell() const
{
if (!IsReadable(sizeof(size_t) + sizeof(cell_t)))
{
return 0;
}
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;
}
float CDataPack::ReadFloat() const
{
if (!IsReadable(sizeof(size_t) + sizeof(float)))
{
return 0;
}
if (*reinterpret_cast<size_t *>(m_curptr) != sizeof(float))
{
return 0;
}
m_curptr += sizeof(size_t);
float val = *reinterpret_cast<float *>(m_curptr);
m_curptr += sizeof(float);
return val;
}
bool CDataPack::IsReadable(size_t bytes) const
{
return (bytes + (m_curptr - m_pBase) > m_size) ? false : true;
}
const char *CDataPack::ReadString(size_t *len) const
{
if (!IsReadable(sizeof(size_t)))
{
return NULL;
}
size_t real_len = *(size_t *)m_curptr;
m_curptr += sizeof(size_t);
char *str = (char *)m_curptr;
if ((strlen(str) != real_len) || !(IsReadable(real_len+1)))
{
return NULL;
}
if (len)
{
*len = real_len;
}
m_curptr += real_len + 1;
return str;
}
void *CDataPack::GetMemory() const
{
return m_curptr;
}
void *CDataPack::ReadMemory(size_t *size) const
{
if (!IsReadable(sizeof(size_t)))
{
return NULL;
}
size_t bytecount = *(size_t *)m_curptr;
m_curptr += sizeof(size_t);
if (!IsReadable(bytecount))
{
return NULL;
}
void *ptr = m_curptr;
if (size)
{
*size = bytecount;
}
m_curptr += bytecount;
return ptr;
}

View File

@ -1,71 +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_CDATAPACK_H_
#define _INCLUDE_SOURCEMOD_CDATAPACK_H_
#include <IDataPack.h>
using namespace SourceMod;
class CDataPack : public IDataPack
{
public:
CDataPack();
~CDataPack();
public: //IDataReader
void Reset() const;
size_t GetPosition() const;
bool SetPosition(size_t pos) const;
cell_t ReadCell() const;
float ReadFloat() const;
bool IsReadable(size_t bytes) const;
const char *ReadString(size_t *len) const;
void *GetMemory() const;
void *ReadMemory(size_t *size) 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);
public:
void Initialize();
private:
void CheckSize(size_t sizetype);
private:
char *m_pBase;
mutable char *m_curptr;
size_t m_capacity;
size_t m_size;
};
#endif //_INCLUDE_SOURCEMOD_CDATAPACK_H_

View File

@ -1,206 +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$
*/
#include <malloc.h>
#include <string.h>
extern HandleType_t htCellArray;
class CellArray
{
public:
CellArray(size_t blocksize) : m_Data(NULL), m_BlockSize(blocksize), m_AllocSize(0), m_Size(0)
{
}
~CellArray()
{
free(m_Data);
}
size_t size() const
{
return m_Size;
}
cell_t *push()
{
if (!GrowIfNeeded(1))
{
return NULL;
}
cell_t *arr = &m_Data[m_Size * m_BlockSize];
m_Size++;
return arr;
}
cell_t *at(size_t b) const
{
return &m_Data[b * m_BlockSize];
}
size_t blocksize() const
{
return m_BlockSize;
}
void clear()
{
m_Size = 0;
}
bool swap(size_t item1, size_t item2)
{
/* Make sure there is extra space available */
if (!GrowIfNeeded(1))
{
return false;
}
cell_t *pri = at(item1);
cell_t *alt = at(item2);
/* Get our temporary array 1 after the limit */
cell_t *temp = &m_Data[m_Size * m_BlockSize];
memcpy(temp, pri, sizeof(cell_t) * m_BlockSize);
memcpy(pri, alt, sizeof(cell_t) * m_BlockSize);
memcpy(alt, temp, sizeof(cell_t) * m_BlockSize);
return true;
}
void remove(size_t index)
{
/* If we're at the end, take the easy way out */
if (index == m_Size - 1)
{
m_Size--;
return;
}
/* Otherwise, it's time to move stuff! */
size_t remaining_indexes = (m_Size - 1) - index;
cell_t *src = at(index + 1);
cell_t *dest = at(index);
memmove(dest, src, sizeof(cell_t) * m_BlockSize * remaining_indexes);
m_Size--;
}
cell_t *insert_at(size_t index)
{
/* Make sure it'll fit */
if (!GrowIfNeeded(1))
{
return NULL;
}
/* move everything up */
cell_t *src = at(index);
cell_t *dst = at(index + 1);
memmove(dst, src, sizeof(cell_t) * m_BlockSize * (m_Size-index));
m_Size++;
return src;
}
bool resize(size_t count)
{
if (count <= m_Size)
{
m_Size = count;
return true;
}
if (!GrowIfNeeded(count - m_Size))
{
return false;
}
m_Size = count;
return true;
}
CellArray *clone()
{
CellArray *array = new CellArray(m_BlockSize);
array->m_AllocSize = m_AllocSize;
array->m_Size = m_Size;
array->m_Data = (cell_t *)malloc(sizeof(cell_t) * m_BlockSize * m_AllocSize);
memcpy(array->m_Data, m_Data, sizeof(cell_t) * m_BlockSize * m_Size);
return array;
}
cell_t *base()
{
return m_Data;
}
size_t mem_usage()
{
return m_AllocSize * m_BlockSize * sizeof(cell_t);
}
private:
bool GrowIfNeeded(size_t count)
{
/* Shortcut out if we can store this */
if (m_Size + count <= m_AllocSize)
{
return true;
}
/* Set a base allocation size of 8 items */
if (!m_AllocSize)
{
m_AllocSize = 8;
}
/* If it's not enough, keep doubling */
while (m_Size + count > m_AllocSize)
{
m_AllocSize *= 2;
}
/* finally, allocate the new block */
if (m_Data)
{
m_Data = (cell_t *)realloc(m_Data, sizeof(cell_t) * m_BlockSize * m_AllocSize);
} else {
m_Data = (cell_t *)malloc(sizeof(cell_t) * m_BlockSize * m_AllocSize);
}
return (m_Data != NULL);
}
private:
cell_t *m_Data;
size_t m_BlockSize;
size_t m_AllocSize;
size_t m_Size;
};

View File

@ -1,107 +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_CELLRECIPIENTFILTER_H_
#define _INCLUDE_SOURCEMOD_CELLRECIPIENTFILTER_H_
#include <irecipientfilter.h>
#include <sp_vm_types.h>
class CellRecipientFilter : public IRecipientFilter
{
public:
CellRecipientFilter() : m_IsReliable(false), m_IsInitMessage(false), m_Size(0) {}
~CellRecipientFilter() {}
public: //IRecipientFilter
bool IsReliable() const;
bool IsInitMessage() const;
int GetRecipientCount() const;
int GetRecipientIndex(int slot) const;
public:
void Initialize(const cell_t *ptr, size_t count);
void SetToReliable(bool isreliable);
void SetToInit(bool isinitmsg);
void Reset();
private:
cell_t m_Players[255];
bool m_IsReliable;
bool m_IsInitMessage;
size_t m_Size;
};
inline void CellRecipientFilter::Reset()
{
m_IsReliable = false;
m_IsInitMessage = false;
m_Size = 0;
}
inline bool CellRecipientFilter::IsReliable() const
{
return m_IsReliable;
}
inline bool CellRecipientFilter::IsInitMessage() const
{
return m_IsInitMessage;
}
inline int CellRecipientFilter::GetRecipientCount() const
{
return m_Size;
}
inline int CellRecipientFilter::GetRecipientIndex(int slot) const
{
if ((slot < 0) || (slot >= GetRecipientCount()))
{
return -1;
}
return static_cast<int>(m_Players[slot]);
}
inline void CellRecipientFilter::SetToInit(bool isinitmsg)
{
m_IsInitMessage = isinitmsg;
}
inline void CellRecipientFilter::SetToReliable(bool isreliable)
{
m_IsReliable = isreliable;
}
inline void CellRecipientFilter::Initialize(const cell_t *ptr, size_t count)
{
memcpy(m_Players, ptr, count * sizeof(cell_t));
m_Size = count;
}
#endif //_INCLUDE_SOURCEMOD_CELLRECIPIENTFILTER_H_

View File

@ -1,450 +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$
*/
#include <ITextParsers.h>
#include "ChatTriggers.h"
#include "sm_stringutil.h"
#include "ConCmdManager.h"
#include "PlayerManager.h"
#include "Translator.h"
#include "HalfLife2.h"
/* :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 defined ORANGEBOX_BUILD
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
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 //ORANGEBOX_BUILD
ChatTriggers g_ChatTriggers;
bool g_bSupressSilentFails = false;
CPhraseFile *g_pFloodPhrases = NULL;
ChatTriggers::ChatTriggers() : m_pSayCmd(NULL), m_bWillProcessInPost(false),
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;
}
ChatTriggers::~ChatTriggers()
{
delete [] m_PubTrigger;
m_PubTrigger = NULL;
delete [] m_PrivTrigger;
m_PrivTrigger = NULL;
}
ConfigResult ChatTriggers::OnSourceModConfigChanged(const char *key,
const char *value,
ConfigSource source,
char *error,
size_t maxlength)
{
if (strcmp(key, "PublicChatTrigger") == 0)
{
delete [] m_PubTrigger;
m_PubTrigger = sm_strdup(value);
m_PubTriggerSize = strlen(m_PubTrigger);
return ConfigResult_Accept;
}
else if (strcmp(key, "SilentChatTrigger") == 0)
{
delete [] m_PrivTrigger;
m_PrivTrigger = sm_strdup(value);
m_PrivTriggerSize = strlen(m_PrivTrigger);
return ConfigResult_Accept;
}
else if (strcmp(key, "SilentFailSuppress") == 0)
{
g_bSupressSilentFails = strcmp(value, "yes") == 0;
return ConfigResult_Accept;
}
return ConfigResult_Ignore;
}
void ChatTriggers::OnSourceModAllInitialized()
{
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()
{
unsigned int file_id;
file_id = g_Translator.FindOrAddPhraseFile("antiflood.phrases.txt");
g_pFloodPhrases = g_Translator.GetFileByIndex(file_id);
}
void ChatTriggers::OnSourceModGameInitialized()
{
unsigned int total = 2;
ConCommandBase *pCmd = icvar->GetCommands();
const char *name;
while (pCmd)
{
if (pCmd->IsCommand())
{
name = pCmd->GetName();
if (!m_pSayCmd && strcmp(name, "say") == 0)
{
m_pSayCmd = (ConCommand *)pCmd;
if (--total == 0)
{
break;
}
} else if (!m_pSayTeamCmd && strcmp(name, "say_team") == 0) {
m_pSayTeamCmd = (ConCommand *)pCmd;
if (--total == 0)
{
break;
}
}
}
pCmd = const_cast<ConCommandBase *>(pCmd->GetNext());
}
if (m_pSayCmd)
{
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_MEMFUNC(ConCommand, Dispatch, m_pSayTeamCmd, this, &ChatTriggers::OnSayCommand_Pre, false);
SH_ADD_HOOK_MEMFUNC(ConCommand, Dispatch, m_pSayTeamCmd, this, &ChatTriggers::OnSayCommand_Post, true);
}
}
void ChatTriggers::OnSourceModShutdown()
{
if (m_pSayTeamCmd)
{
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);
}
g_Forwards.ReleaseForward(m_pShouldFloodBlock);
g_Forwards.ReleaseForward(m_pDidFloodBlock);
}
#if defined ORANGEBOX_BUILD
void ChatTriggers::OnSayCommand_Pre(const CCommand &command)
{
#else
void ChatTriggers::OnSayCommand_Pre()
{
CCommand command;
#endif
int client;
CPlayer *pPlayer;
client = g_ConCmds.GetCommandClient();
m_bIsChatTrigger = false;
m_bWasFloodedMessage = false;
/* The server console cannot do this */
if (client == 0 || (pPlayer = g_Players.GetPlayerByIndex(client)) == NULL)
{
RETURN_META(MRES_IGNORED);
}
/* We guarantee the client is connected */
if (!pPlayer->IsConnected())
{
RETURN_META(MRES_IGNORED);
}
const char *args = command.ArgS();
if (!args)
{
RETURN_META(MRES_IGNORED);
}
/* Check if we need to block this message from being sent */
if (ClientIsFlooding(client))
{
char buffer[128];
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. */
char fullbuffer[192];
UTIL_Format(fullbuffer, sizeof(fullbuffer), "[SM] %s", buffer);
g_HL2.TextMsg(client, HUD_PRINTTALK, fullbuffer);
m_bWasFloodedMessage = true;
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(args, m_PubTrigger, m_PubTriggerSize) == 0)
{
is_trigger = true;
args = &args[m_PubTriggerSize];
}
else if (m_PrivTriggerSize && strncmp(args, m_PrivTrigger, m_PrivTriggerSize) == 0)
{
is_trigger = true;
is_silent = true;
args = &args[m_PrivTriggerSize];
}
if (!is_trigger)
{
RETURN_META(MRES_IGNORED);
}
/**
* Test if this is actually a command!
*/
if (!PreProcessTrigger(engine->PEntityOfEntIndex(client), args, is_quoted))
{
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);
}
m_bIsChatTrigger = true;
/**
* 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);
}
/* Otherwise, let the command continue */
RETURN_META(MRES_IGNORED);
}
#if defined ORANGEBOX_BUILD
void ChatTriggers::OnSayCommand_Post(const CCommand &command)
#else
void ChatTriggers::OnSayCommand_Post()
#endif
{
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);
serverpluginhelpers->ClientCommand(engine->PEntityOfEntIndex(client), m_ToExecute);
SetReplyTo(old);
}
}
bool ChatTriggers::PreProcessTrigger(edict_t *pEdict, const char *args, bool is_quoted)
{
/* Extract a command. This is kind of sloppy. */
char cmd_buf[64];
size_t cmd_len = 0;
const char *inptr = args;
while (*inptr != '\0'
&& !textparsers->IsWhitespace(inptr)
&& *inptr != '"'
&& cmd_len < sizeof(cmd_buf) - 1)
{
cmd_buf[cmd_len++] = *inptr++;
}
cmd_buf[cmd_len] = '\0';
if (cmd_len == 0)
{
return false;
}
/* See if we have this registered */
bool prepended = false;
if (!g_ConCmds.LookForSourceModCommand(cmd_buf))
{
/* Check if we had an "sm_" prefix */
if (strncmp(cmd_buf, "sm_", 3) == 0)
{
return false;
}
/* Now, prepend. Don't worry about the buffers. This will
* work because the sizes are limited from earlier.
*/
char new_buf[80];
strcpy(new_buf, "sm_");
strncopy(&new_buf[3], cmd_buf, sizeof(new_buf)-3);
/* Recheck */
if (!g_ConCmds.LookForSourceModCommand(new_buf))
{
return false;
}
prepended = true;
}
/* See if we need to do extra string manipulation */
if (is_quoted || prepended)
{
size_t len;
/* Check if we need to prepend sm_ */
if (prepended)
{
len = UTIL_Format(m_ToExecute, sizeof(m_ToExecute), "sm_%s", 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));
}
return true;
}
unsigned int ChatTriggers::SetReplyTo(unsigned int reply)
{
unsigned int old = m_ReplyTo;
m_ReplyTo = reply;
return old;
}
unsigned int ChatTriggers::GetReplyTo()
{
return m_ReplyTo;
}
bool ChatTriggers::IsChatTrigger()
{
return m_bIsChatTrigger;
}
bool ChatTriggers::ClientIsFlooding(int client)
{
bool is_flooding = false;
if (m_pShouldFloodBlock->GetFunctionCount() != 0)
{
cell_t res = 0;
m_pShouldFloodBlock->PushCell(client);
m_pShouldFloodBlock->Execute(&res);
if (res != 0)
{
is_flooding = true;
}
}
if (m_pDidFloodBlock->GetFunctionCount() != 0)
{
m_pDidFloodBlock->PushCell(client);
m_pDidFloodBlock->PushCell(is_flooding ? 1 : 0);
m_pDidFloodBlock->Execute(NULL);
}
return is_flooding;
}
bool ChatTriggers::WasFloodedMessage()
{
return m_bWasFloodedMessage;
}

View File

@ -1,91 +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_CHAT_TRIGGERS_H_
#define _INCLUDE_SOURCEMOD_CHAT_TRIGGERS_H_
#include "sm_globals.h"
#include "sourcemm_api.h"
#include <IGameHelpers.h>
#include <compat_wrappers.h>
#include <IForwardSys.h>
class ChatTriggers : public SMGlobalClass
{
public:
ChatTriggers();
~ChatTriggers();
public: //SMGlobalClass
void OnSourceModAllInitialized();
void OnSourceModAllInitialized_Post();
void OnSourceModGameInitialized();
void OnSourceModShutdown();
ConfigResult OnSourceModConfigChanged(const char *key,
const char *value,
ConfigSource source,
char *error,
size_t maxlength);
private: //ConCommand
#if defined ORANGEBOX_BUILD
void OnSayCommand_Pre(const CCommand &command);
void OnSayCommand_Post(const CCommand &command);
#else
void OnSayCommand_Pre();
void OnSayCommand_Post();
#endif
public:
unsigned int GetReplyTo();
unsigned int SetReplyTo(unsigned int reply);
bool IsChatTrigger();
bool WasFloodedMessage();
private:
bool PreProcessTrigger(edict_t *pEdict, const char *args, bool is_quoted);
bool ClientIsFlooding(int client);
private:
ConCommand *m_pSayCmd;
ConCommand *m_pSayTeamCmd;
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;
unsigned int m_ReplyTo;
char m_ToExecute[300];
IForward *m_pShouldFloodBlock;
IForward *m_pDidFloodBlock;
};
extern ChatTriggers g_ChatTriggers;
#endif //_INCLUDE_SOURCEMOD_CHAT_TRIGGERS_H_

View File

@ -1,991 +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$
*/
#include "ConCmdManager.h"
#include "sm_srvcmds.h"
#include "AdminCache.h"
#include "sm_stringutil.h"
#include "PlayerManager.h"
#include "Translator.h"
#include "HalfLife2.h"
#include "ChatTriggers.h"
ConCmdManager g_ConCmds;
#if defined ORANGEBOX_BUILD
SH_DECL_HOOK1_void(ConCommand, Dispatch, SH_NOATTRIB, false, const CCommand &);
#else
SH_DECL_HOOK0_void(ConCommand, Dispatch, SH_NOATTRIB, false);
#endif
SH_DECL_HOOK1_void(IServerGameClients, SetCommandClient, SH_NOATTRIB, false, int);
struct PlCmdInfo
{
ConCmdInfo *pInfo;
CmdHook *pHook;
CmdType type;
};
typedef List<PlCmdInfo> CmdList;
void AddToPlCmdList(CmdList *pList, const PlCmdInfo &info);
ConCmdManager::ConCmdManager() : m_Strings(1024)
{
m_pCmds = sm_trie_create();
m_pCmdGrps = sm_trie_create();
m_CmdClient = 0;
}
ConCmdManager::~ConCmdManager()
{
sm_trie_destroy(m_pCmds);
sm_trie_destroy(m_pCmdGrps);
}
void ConCmdManager::OnSourceModAllInitialized()
{
g_PluginSys.AddPluginsListener(this);
g_RootMenu.AddRootConsoleCommand("cmds", "List console commands", this);
SH_ADD_HOOK_MEMFUNC(IServerGameClients, SetCommandClient, serverClients, this, &ConCmdManager::SetCommandClient, false);
}
void ConCmdManager::OnSourceModShutdown()
{
/* All commands should already be removed by the time we're done */
SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, SetCommandClient, serverClients, this, &ConCmdManager::SetCommandClient, false);
g_RootMenu.RemoveRootConsoleCommand("cmds", this);
}
void ConCmdManager::OnUnlinkConCommandBase(ConCommandBase *pBase, const char *name, bool is_read_safe)
{
/* Whoa, first get its information struct */
ConCmdInfo *pInfo;
if (!sm_trie_retrieve(m_pCmds, name, (void **)&pInfo))
{
return;
}
RemoveConCmds(pInfo->srvhooks);
RemoveConCmds(pInfo->conhooks);
RemoveConCmd(pInfo, name, is_read_safe, false);
}
void ConCmdManager::RemoveConCmds(List<CmdHook *> &cmdlist)
{
List<CmdHook *>::iterator iter = cmdlist.begin();
while (iter != cmdlist.end())
{
CmdHook *pHook = (*iter);
IPluginContext *pContext = pHook->pf->GetParentContext();
IPlugin *pPlugin = g_PluginSys.GetPluginByCtx(pContext->GetContext());
CmdList *pList = NULL;
//gaben
if (!pPlugin->GetProperty("CommandList", (void **)&pList, false) || !pList)
{
continue;
}
CmdList::iterator p_iter = pList->begin();
while (p_iter != pList->end())
{
PlCmdInfo &cmd = (*p_iter);
if (cmd.pHook == pHook)
{
p_iter = pList->erase(p_iter);
}
else
{
p_iter++;
}
}
delete pHook->pAdmin;
delete pHook;
iter = cmdlist.erase(iter);
}
}
void ConCmdManager::RemoveConCmds(List<CmdHook *> &cmdlist, IPluginContext *pContext)
{
List<CmdHook *>::iterator iter = cmdlist.begin();
CmdHook *pHook;
while (iter != cmdlist.end())
{
pHook = (*iter);
if (pHook->pf->GetParentContext() == pContext)
{
delete pHook->pAdmin;
delete pHook;
iter = cmdlist.erase(iter);
}
else
{
iter++;
}
}
}
void ConCmdManager::OnPluginDestroyed(IPlugin *plugin)
{
CmdList *pList;
List<ConCmdInfo *> removed;
if (plugin->GetProperty("CommandList", (void **)&pList, true))
{
IPluginContext *pContext = plugin->GetBaseContext();
CmdList::iterator iter;
/* First pass!
* Only bother if there's an actual command list on this plugin...
*/
for (iter=pList->begin();
iter!=pList->end();
iter++)
{
PlCmdInfo &cmd = (*iter);
ConCmdInfo *pInfo = cmd.pInfo;
/* Has this chain already been fully cleaned/removed? */
if (removed.find(pInfo) != removed.end())
{
continue;
}
/* Remove any hooks from us on this command */
RemoveConCmds(pInfo->conhooks, pContext);
RemoveConCmds(pInfo->srvhooks, pContext);
/* See if there are still hooks */
if (pInfo->srvhooks.size())
{
continue;
}
if (pInfo->conhooks.size())
{
continue;
}
/* Remove the command, it should be safe now */
RemoveConCmd(pInfo, pInfo->pCmd->GetName(), true, true);
removed.push_back(pInfo);
}
delete pList;
}
}
#if defined ORANGEBOX_BUILD
void CommandCallback(const CCommand &command)
{
#else
void CommandCallback()
{
CCommand command;
#endif
g_HL2.PushCommandStack(&command);
g_ConCmds.InternalDispatch(command);
g_HL2.PopCommandStack();
}
void ConCmdManager::SetCommandClient(int client)
{
m_CmdClient = client + 1;
}
ResultType ConCmdManager::DispatchClientCommand(int client, const char *cmd, int args, ResultType type)
{
ConCmdInfo *pInfo;
if (sm_trie_retrieve(m_pCmds, cmd, (void **)&pInfo))
{
cell_t result = type;
cell_t tempres = result;
List<CmdHook *>::iterator iter;
CmdHook *pHook;
for (iter=pInfo->conhooks.begin();
iter!=pInfo->conhooks.end();
iter++)
{
pHook = (*iter);
if (!pHook->pf->IsRunnable())
{
continue;
}
if (pHook->pAdmin && !CheckAccess(client, cmd, pHook->pAdmin))
{
if (result < Pl_Handled)
{
result = Pl_Handled;
}
continue;
}
pHook->pf->PushCell(client);
pHook->pf->PushCell(args);
if (pHook->pf->Execute(&tempres) == SP_ERROR_NONE)
{
if (tempres > result)
{
result = tempres;
}
if (result == Pl_Stop)
{
break;
}
}
}
type = (ResultType)result;
}
return type;
}
void ConCmdManager::InternalDispatch(const CCommand &command)
{
int client = m_CmdClient;
if (client)
{
CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
if (!pPlayer || !pPlayer->IsConnected())
{
return;
}
}
/**
* Note: Console commands will EITHER go through IServerGameDLL::ClientCommand,
* OR this dispatch. They will NEVER go through both.
* --
* Whether or not it goes through the callback is determined by FCVAR_GAMEDLL
*/
const char *cmd = g_HL2.CurrentCommandName();
ConCmdInfo *pInfo;
if (!sm_trie_retrieve(m_pCmds, cmd, (void **)&pInfo))
{
return;
}
/* This is a hack to prevent say triggers from firing on messages that were
* blocked because of flooding. We won't remove this, but the hack will get
* "nicer" when we expose explicit say hooks.
*/
if (g_ChatTriggers.WasFloodedMessage())
{
return;
}
cell_t result = Pl_Continue;
int args = command.ArgC() - 1;
List<CmdHook *>::iterator iter;
CmdHook *pHook;
/* Execute server-only commands if viable */
if (client == 0 && pInfo->srvhooks.size())
{
cell_t tempres = result;
for (iter=pInfo->srvhooks.begin();
iter!=pInfo->srvhooks.end();
iter++)
{
pHook = (*iter);
if (!pHook->pf->IsRunnable())
{
continue;
}
pHook->pf->PushCell(args);
if (pHook->pf->Execute(&tempres) == SP_ERROR_NONE)
{
if (tempres > result)
{
result = tempres;
}
if (result == Pl_Stop)
{
break;
}
}
}
/* Check if there's an early stop */
if (result >= Pl_Stop)
{
if (!pInfo->sourceMod)
{
RETURN_META(MRES_SUPERCEDE);
}
return;
}
}
/* Execute console commands */
if (pInfo->conhooks.size())
{
cell_t tempres = result;
for (iter=pInfo->conhooks.begin();
iter!=pInfo->conhooks.end();
iter++)
{
pHook = (*iter);
if (!pHook->pf->IsRunnable())
{
continue;
}
if (client
&& pHook->pAdmin
&& !CheckAccess(client, cmd, pHook->pAdmin))
{
if (result < Pl_Handled)
{
result = Pl_Handled;
}
continue;
}
/* On a listen server, sometimes the server host's client index can be set as 0.
* So index 1 is passed to the command callback to correct this potential problem.
*/
if (!engine->IsDedicatedServer())
{
client = g_Players.ListenClient();
}
pHook->pf->PushCell(client);
pHook->pf->PushCell(args);
if (pHook->pf->Execute(&tempres) == SP_ERROR_NONE)
{
if (tempres > result)
{
result = tempres;
}
if (result == Pl_Stop)
{
break;
}
}
}
}
if (result >= Pl_Handled)
{
if (!pInfo->sourceMod)
{
RETURN_META(MRES_SUPERCEDE);
}
return;
}
}
bool ConCmdManager::CheckCommandAccess(int client, const char *cmd, FlagBits cmdflags)
{
if (cmdflags == 0 || client == 0)
{
return true;
}
/* If running listen server, then client 1 is the server host and should have 'root' access */
if (client == 1 && !engine->IsDedicatedServer())
{
return true;
}
CPlayer *player = g_Players.GetPlayerByIndex(client);
if (!player
|| player->GetEdict() == NULL
|| player->IsFakeClient())
{
return false;
}
AdminId adm = player->GetAdminId();
if (adm != INVALID_ADMIN_ID)
{
FlagBits bits = g_Admins.GetAdminFlags(adm, Access_Effective);
/* root knows all, WHOA */
if ((bits & ADMFLAG_ROOT) == ADMFLAG_ROOT)
{
return true;
}
/* Check for overrides
* :TODO: is it worth optimizing this?
*/
unsigned int groups = g_Admins.GetAdminGroupCount(adm);
GroupId gid;
OverrideRule rule;
bool override = false;
for (unsigned int i=0; i<groups; i++)
{
gid = g_Admins.GetAdminGroup(adm, i, NULL);
/* First get group-level override */
override = g_Admins.GetGroupCommandOverride(gid, cmd, Override_CommandGroup, &rule);
/* Now get the specific command override */
if (g_Admins.GetGroupCommandOverride(gid, cmd, Override_Command, &rule))
{
override = true;
}
if (override)
{
if (rule == Command_Allow)
{
return true;
}
else if (rule == Command_Deny)
{
return false;
}
}
}
/* See if our other flags match */
if ((bits & cmdflags) == cmdflags)
{
return true;
}
}
return false;
}
bool ConCmdManager::CheckAccess(int client, const char *cmd, AdminCmdInfo *pAdmin)
{
if (CheckCommandAccess(client, cmd, pAdmin->eflags))
{
return true;
}
edict_t *pEdict = engine->PEntityOfEntIndex(client);
/* If we got here, the command failed... */
char buffer[128];
if (!CoreTranslate(buffer, sizeof(buffer), "%T", 2, NULL, "No Access", &client))
{
UTIL_Format(buffer, sizeof(buffer), "You do not have access to this command");
}
unsigned int replyto = g_ChatTriggers.GetReplyTo();
if (replyto == SM_REPLY_CONSOLE)
{
char fullbuffer[192];
UTIL_Format(fullbuffer, sizeof(fullbuffer), "[SM] %s.\n", buffer);
engine->ClientPrintf(pEdict, fullbuffer);
}
else if (replyto == SM_REPLY_CHAT)
{
char fullbuffer[192];
UTIL_Format(fullbuffer, sizeof(fullbuffer), "[SM] %s.", buffer);
g_HL2.TextMsg(client, HUD_PRINTTALK, fullbuffer);
}
return false;
}
bool ConCmdManager::AddConsoleCommand(IPluginFunction *pFunction,
const char *name,
const char *description,
int flags)
{
ConCmdInfo *pInfo = AddOrFindCommand(name, description, flags);
if (!pInfo)
{
return false;
}
CmdHook *pHook = new CmdHook();
pHook->pf = pFunction;
if (description && description[0])
{
pHook->helptext.assign(description);
}
pInfo->conhooks.push_back(pHook);
/* Add to the plugin */
CmdList *pList;
IPlugin *pPlugin = g_PluginSys.GetPluginByCtx(pFunction->GetParentContext()->GetContext());
if (!pPlugin->GetProperty("CommandList", (void **)&pList))
{
pList = new CmdList();
pPlugin->SetProperty("CommandList", pList);
}
PlCmdInfo info;
info.pInfo = pInfo;
info.type = Cmd_Console;
info.pHook = pHook;
AddToPlCmdList(pList, info);
return true;
}
bool ConCmdManager::AddAdminCommand(IPluginFunction *pFunction,
const char *name,
const char *group,
int adminflags,
const char *description,
int flags)
{
ConCmdInfo *pInfo = AddOrFindCommand(name, description, flags);
if (!pInfo)
{
return false;
}
CmdHook *pHook = new CmdHook();
AdminCmdInfo *pAdmin = new AdminCmdInfo();
pHook->pf = pFunction;
if (description && description[0])
{
pHook->helptext.assign(description);
}
pHook->pAdmin = pAdmin;
void *object;
int grpid;
if (!sm_trie_retrieve(m_pCmdGrps, group, (void **)&object))
{
grpid = m_Strings.AddString(group);
sm_trie_insert(m_pCmdGrps, group, (void *)grpid);
}
else
{
grpid = (int)object;
}
pAdmin->cmdGrpId = grpid;
pAdmin->flags = adminflags;
/* First get the command group override, if any */
bool override = g_Admins.GetCommandOverride(group,
Override_CommandGroup,
&(pAdmin->eflags));
/* Next get the command override, if any */
if (g_Admins.GetCommandOverride(name,
Override_Command,
&(pAdmin->eflags)))
{
override = true;
}
/* Assign normal flags if there were no overrides */
if (!override)
{
pAdmin->eflags = pAdmin->flags;
}
/* Finally, add the hook */
pInfo->conhooks.push_back(pHook);
pInfo->admin = *(pHook->pAdmin);
pInfo->is_admin_set = true;
/* Now add to the plugin */
CmdList *pList;
IPlugin *pPlugin = g_PluginSys.GetPluginByCtx(pFunction->GetParentContext()->GetContext());
if (!pPlugin->GetProperty("CommandList", (void **)&pList))
{
pList = new CmdList();
pPlugin->SetProperty("CommandList", pList);
}
PlCmdInfo info;
info.pInfo = pInfo;
info.type = Cmd_Admin;
info.pHook = pHook;
AddToPlCmdList(pList, info);
return true;
}
bool ConCmdManager::AddServerCommand(IPluginFunction *pFunction,
const char *name,
const char *description,
int flags)
{
ConCmdInfo *pInfo = AddOrFindCommand(name, description, flags);
if (!pInfo)
{
return false;
}
CmdHook *pHook = new CmdHook();
pHook->pf = pFunction;
if (description && description[0])
{
pHook->helptext.assign(description);
}
pInfo->srvhooks.push_back(pHook);
/* Add to the plugin */
CmdList *pList;
IPlugin *pPlugin = g_PluginSys.GetPluginByCtx(pFunction->GetParentContext()->GetContext());
if (!pPlugin->GetProperty("CommandList", (void **)&pList))
{
pList = new CmdList();
pPlugin->SetProperty("CommandList", pList);
}
PlCmdInfo info;
info.pInfo = pInfo;
info.type = Cmd_Server;
info.pHook = pHook;
AddToPlCmdList(pList, info);
return true;
}
void AddToPlCmdList(CmdList *pList, const PlCmdInfo &info)
{
CmdList::iterator iter = pList->begin();
bool inserted = false;
const char *orig = NULL;
orig = info.pInfo->pCmd->GetName();
/* Insert this into the help list, SORTED alphabetically. */
while (iter != pList->end())
{
PlCmdInfo &obj = (*iter);
const char *cmd = obj.pInfo->pCmd->GetName();
if (strcmp(orig, cmd) < 0)
{
pList->insert(iter, info);
inserted = true;
break;
}
iter++;
}
if (!inserted)
{
pList->push_back(info);
}
}
void ConCmdManager::AddToCmdList(ConCmdInfo *info)
{
List<ConCmdInfo *>::iterator iter = m_CmdList.begin();
ConCmdInfo *pInfo;
bool inserted = false;
const char *orig = NULL;
orig = info->pCmd->GetName();
/* Insert this into the help list, SORTED alphabetically. */
while (iter != m_CmdList.end())
{
const char *cmd = NULL;
pInfo = (*iter);
cmd = pInfo->pCmd->GetName();
if (strcmp(orig, cmd) < 0)
{
m_CmdList.insert(iter, info);
inserted = true;
break;
}
iter++;
}
if (!inserted)
{
m_CmdList.push_back(info);
}
}
void ConCmdManager::UpdateAdminCmdFlags(const char *cmd, OverrideType type, FlagBits bits, bool remove)
{
ConCmdInfo *pInfo;
if (type == Override_Command)
{
if (!sm_trie_retrieve(m_pCmds, cmd, (void **)&pInfo))
{
return;
}
List<CmdHook *>::iterator iter;
CmdHook *pHook;
for (iter=pInfo->conhooks.begin(); iter!=pInfo->conhooks.end(); iter++)
{
pHook = (*iter);
if (pHook->pAdmin)
{
if (!remove)
{
pHook->pAdmin->eflags = bits;
} else {
pHook->pAdmin->eflags = pHook->pAdmin->flags;
}
pInfo->admin = *(pHook->pAdmin);
}
}
pInfo->is_admin_set = true;
}
else if (type == Override_CommandGroup)
{
void *object;
if (!sm_trie_retrieve(m_pCmdGrps, cmd, &object))
{
return;
}
int grpid = (int)object;
/* This is bad :( loop through all commands */
List<ConCmdInfo *>::iterator iter;
CmdHook *pHook;
for (iter=m_CmdList.begin(); iter!=m_CmdList.end(); iter++)
{
pInfo = (*iter);
for (List<CmdHook *>::iterator citer=pInfo->conhooks.begin();
citer!=pInfo->conhooks.end();
citer++)
{
pHook = (*citer);
if (pHook->pAdmin && pHook->pAdmin->cmdGrpId == grpid)
{
if (remove)
{
pHook->pAdmin->eflags = bits;
} else {
pHook->pAdmin->eflags = pHook->pAdmin->flags;
}
pInfo->admin = *(pHook->pAdmin);
}
}
}
pInfo->is_admin_set = true;
}
}
void ConCmdManager::RemoveConCmd(ConCmdInfo *info, const char *name, bool is_read_safe, bool untrack)
{
/* Remove from the trie */
sm_trie_delete(m_pCmds, name);
/* Remove console-specific information
* This should always be true as of right now
*/
if (info->pCmd)
{
if (info->sourceMod)
{
/* Unlink from SourceMM */
g_SMAPI->UnregisterConCommandBase(g_PLAPI, info->pCmd);
/* Delete the command's memory */
char *new_help = const_cast<char *>(info->pCmd->GetHelpText());
char *new_name = const_cast<char *>(info->pCmd->GetName());
delete [] new_help;
delete [] new_name;
delete info->pCmd;
}
else
{
if (is_read_safe)
{
/* Remove the external hook */
SH_REMOVE_HOOK_STATICFUNC(ConCommand, Dispatch, info->pCmd, CommandCallback, false);
}
if (untrack)
{
UntrackConCommandBase(info->pCmd, this);
}
}
}
/* Remove from list */
m_CmdList.remove(info);
delete info;
}
bool ConCmdManager::LookForSourceModCommand(const char *cmd)
{
ConCmdInfo *pInfo;
if (!sm_trie_retrieve(m_pCmds, cmd, (void **)&pInfo))
{
return false;
}
return pInfo->sourceMod && (pInfo->conhooks.size() > 0);
}
bool ConCmdManager::LookForCommandAdminFlags(const char *cmd, FlagBits *pFlags)
{
ConCmdInfo *pInfo;
if (!sm_trie_retrieve(m_pCmds, cmd, (void **)&pInfo))
{
return false;
}
*pFlags = pInfo->admin.eflags;
return pInfo->is_admin_set;
}
ConCmdInfo *ConCmdManager::AddOrFindCommand(const char *name, const char *description, int flags)
{
ConCmdInfo *pInfo;
if (!sm_trie_retrieve(m_pCmds, name, (void **)&pInfo))
{
pInfo = new ConCmdInfo();
/* Find the commandopan */
ConCommandBase *pBase = icvar->GetCommands();
ConCommand *pCmd = NULL;
while (pBase)
{
if (strcmp(pBase->GetName(), name) == 0)
{
/* Don't want to return convar with same name */
if (!pBase->IsCommand())
{
return NULL;
}
pCmd = (ConCommand *)pBase;
break;
}
pBase = const_cast<ConCommandBase *>(pBase->GetNext());
}
if (!pCmd)
{
/* Note that we have to duplicate because the source might not be
* a static string, and these expect static memory.
*/
if (!description)
{
description = "";
}
char *new_name = sm_strdup(name);
char *new_help = sm_strdup(description);
pCmd = new ConCommand(new_name, CommandCallback, new_help, flags);
pInfo->sourceMod = true;
}
else
{
TrackConCommandBase(pCmd, this);
SH_ADD_HOOK_STATICFUNC(ConCommand, Dispatch, pCmd, CommandCallback, false);
}
pInfo->pCmd = pCmd;
pInfo->is_admin_set = false;
sm_trie_insert(m_pCmds, name, pInfo);
AddToCmdList(pInfo);
}
return pInfo;
}
void ConCmdManager::OnRootConsoleCommand(const char *cmdname, const CCommand &command)
{
if (command.ArgC() >= 3)
{
const char *text = command.Arg(2);
CPlugin *pPlugin = g_PluginSys.FindPluginByConsoleArg(text);
if (!pPlugin)
{
g_RootMenu.ConsolePrint("[SM] Plugin \"%s\" was not found.", text);
return;
}
const sm_plugininfo_t *plinfo = pPlugin->GetPublicInfo();
const char *plname = IS_STR_FILLED(plinfo->name) ? plinfo->name : pPlugin->GetFilename();
CmdList *pList;
if (!pPlugin->GetProperty("CommandList", (void **)&pList))
{
g_RootMenu.ConsolePrint("[SM] No commands found for: %s", plname);
return;
}
if (!pList->size())
{
g_RootMenu.ConsolePrint("[SM] No commands found for: %s", plname);
return;
}
CmdList::iterator iter;
const char *type = NULL;
const char *name;
const char *help;
g_RootMenu.ConsolePrint("[SM] Listing %d commands for: %s", pList->size(), plname);
g_RootMenu.ConsolePrint(" %-17.16s %-8.7s %s", "[Name]", "[Type]", "[Help]");
for (iter=pList->begin();
iter!=pList->end();
iter++)
{
PlCmdInfo &cmd = (*iter);
if (cmd.type == Cmd_Server)
{
type = "server";
}
else if (cmd.type == Cmd_Console)
{
type = "console";
}
else if (cmd.type == Cmd_Admin)
{
type = "admin";
}
name = cmd.pInfo->pCmd->GetName();
if (cmd.pHook->helptext.size())
{
help = cmd.pHook->helptext.c_str();
}
else
{
help = cmd.pInfo->pCmd->GetHelpText();
}
g_RootMenu.ConsolePrint(" %-17.16s %-12.11s %s", name, type, help);
}
return;
}
g_RootMenu.ConsolePrint("[SM] Usage: sm cmds <plugin #>");
}

View File

@ -1,161 +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_CONCMDMANAGER_H_
#define _INCLUDE_SOURCEMOD_CONCMDMANAGER_H_
#include "sm_globals.h"
#include "sourcemm_api.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"
using namespace SourceHook;
enum CmdType
{
Cmd_Server,
Cmd_Console,
Cmd_Admin,
};
struct AdminCmdInfo
{
AdminCmdInfo()
{
cmdGrpId = -1;
flags = 0;
eflags = 0;
}
int cmdGrpId; /* index into cmdgroup string table */
FlagBits flags; /* default flags */
FlagBits eflags; /* effective flags */
};
struct CmdHook
{
CmdHook()
{
pf = NULL;
pAdmin = NULL;
}
IPluginFunction *pf; /* function hook */
String helptext; /* help text */
AdminCmdInfo *pAdmin; /* admin requirements, if any */
};
struct ConCmdInfo
{
ConCmdInfo()
{
sourceMod = false;
pCmd = NULL;
}
bool sourceMod; /**< Determines whether or not concmd was created by a SourceMod plugin */
ConCommand *pCmd; /**< Pointer to the command itself */
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 */
};
class ConCmdManager :
public SMGlobalClass,
public IRootConsoleCommand,
public IPluginsListener,
public IConCommandTracker
{
#if defined ORANGEBOX_BUILD
friend void CommandCallback(const CCommand &command);
#else
friend void CommandCallback();
#endif
public:
ConCmdManager();
~ConCmdManager();
public: //SMGlobalClass
void OnSourceModAllInitialized();
void OnSourceModShutdown();
public: //IPluginsListener
void OnPluginDestroyed(IPlugin *plugin);
public: //IRootConsoleCommand
void OnRootConsoleCommand(const char *cmdname, const CCommand &command);
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,
int adminflags,
const char *description,
int flags);
ResultType DispatchClientCommand(int client, const char *cmd, int args, ResultType type);
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);
ConCmdInfo *AddOrFindCommand(const char *name, const char *description, int flags);
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);
public:
inline int GetCommandClient()
{
return m_CmdClient;
}
inline const List<ConCmdInfo *> & GetCommandList()
{
return m_CmdList;
}
private:
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;
#endif // _INCLUDE_SOURCEMOD_CONCMDMANAGER_H_

View File

@ -1,707 +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$
*/
#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_trie_tpl.h>
ConVarManager g_ConVarManager;
#if !defined ORANGEBOX_BUILD
#define CallGlobalChangeCallbacks CallGlobalChangeCallback
#endif
#if defined ORANGEBOX_BUILD
SH_DECL_HOOK3_void(ICvar, CallGlobalChangeCallbacks, SH_NOATTRIB, false, ConVar *, const char *, float);
#else
SH_DECL_HOOK2_void(ICvar, CallGlobalChangeCallbacks, SH_NOATTRIB, false, ConVar *, const char *);
#endif
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 *);
const ParamType CONVARCHANGE_PARAMS[] = {Param_Cell, Param_String, Param_String};
typedef List<const ConVar *> ConVarList;
KTrie<ConVarInfo *> convar_cache;
ConVarManager::ConVarManager() : m_ConVarType(0), m_bIsDLLQueryHooked(false), m_bIsVSPQueryHooked(false)
{
}
ConVarManager::~ConVarManager()
{
}
void ConVarManager::OnSourceModStartup(bool late)
{
HandleAccess sec;
/* Set up access rights for the 'ConVar' handle type */
sec.access[HandleAccess_Read] = 0;
sec.access[HandleAccess_Delete] = HANDLE_RESTRICT_IDENTITY | HANDLE_RESTRICT_OWNER;
sec.access[HandleAccess_Clone] = HANDLE_RESTRICT_IDENTITY | HANDLE_RESTRICT_OWNER;
/* Create the 'ConVar' handle type */
m_ConVarType = g_HandleSys.CreateType("ConVar", this, 0, NULL, &sec, g_pCoreIdent, NULL);
}
void ConVarManager::OnSourceModAllInitialized()
{
/**
* Episode 2 has this function by default, but the older versions do not.
*/
#if !defined ORANGEBOX_BUILD
if (g_SMAPI->GetGameDLLVersion() >= 6)
{
SH_ADD_HOOK_MEMFUNC(IServerGameDLL, OnQueryCvarValueFinished, gamedll, this, &ConVarManager::OnQueryCvarValueFinished, false);
m_bIsDLLQueryHooked = true;
}
#endif
SH_ADD_HOOK_STATICFUNC(ICvar, CallGlobalChangeCallbacks, icvar, OnConVarChanged, false);
/* Add the 'convars' option to the 'sm' console command */
g_RootMenu.AddRootConsoleCommand("cvars", "View convars created by a plugin", this);
}
void ConVarManager::OnSourceModShutdown()
{
List<ConVarInfo *>::iterator iter = m_ConVars.begin();
HandleSecurity sec(NULL, g_pCoreIdent);
/* Iterate list of ConVarInfo structures, remove every one of them */
while (iter != m_ConVars.end())
{
ConVarInfo *pInfo = (*iter);
iter = m_ConVars.erase(iter);
g_HandleSys.FreeHandle(pInfo->handle, &sec);
if (pInfo->pChangeForward != NULL)
{
g_Forwards.ReleaseForward(pInfo->pChangeForward);
}
if (pInfo->sourceMod)
{
/* If we created it, we won't be tracking it, therefore it is
* safe to remove everything in one go.
*/
META_UNREGCVAR(pInfo->pVar);
delete [] pInfo->pVar->GetName();
delete [] pInfo->pVar->GetHelpText();
delete [] pInfo->pVar->GetDefault();
delete pInfo->pVar;
}
else
{
/* If we didn't create it, we might be tracking it. Also,
* it could be unreadable.
*/
UntrackConCommandBase(pInfo->pVar, this);
}
/* It's not safe to read the name here, so we simply delete the
* the info struct and clear the lookup cache at the end.
*/
delete pInfo;
}
convar_cache.clear();
/* Unhook things */
if (m_bIsDLLQueryHooked)
{
SH_REMOVE_HOOK_MEMFUNC(IServerGameDLL, OnQueryCvarValueFinished, gamedll, this, &ConVarManager::OnQueryCvarValueFinished, false);
m_bIsDLLQueryHooked = false;
}
else if (m_bIsVSPQueryHooked)
{
SH_REMOVE_HOOK_MEMFUNC(IServerPluginCallbacks, OnQueryCvarValueFinished, vsp_interface, this, &ConVarManager::OnQueryCvarValueFinished, false);
m_bIsVSPQueryHooked = false;
}
SH_REMOVE_HOOK_STATICFUNC(ICvar, CallGlobalChangeCallbacks, icvar, OnConVarChanged, false);
/* Remove the 'convars' option from the 'sm' console command */
g_RootMenu.RemoveRootConsoleCommand("cvars", this);
/* Remove the 'ConVar' handle type */
g_HandleSys.RemoveType(m_ConVarType, g_pCoreIdent);
}
/**
* Orange Box will never use this.
*/
void ConVarManager::OnSourceModVSPReceived()
{
/**
* Don't bother if the DLL is already hooked.
*/
if (m_bIsDLLQueryHooked)
{
return;
}
/* For later MM:S versions, use the updated API, since it's cleaner. */
#if defined METAMOD_PLAPI_VERSION
int engine = g_SMAPI->GetSourceEngineBuild();
if (engine == SOURCE_ENGINE_ORIGINAL || vsp_version < 2)
{
return;
}
#else
if (g_HL2.IsOriginalEngine() || vsp_version < 2)
{
return;
}
#endif
SH_ADD_HOOK_MEMFUNC(IServerPluginCallbacks, OnQueryCvarValueFinished, vsp_interface, this, &ConVarManager::OnQueryCvarValueFinished, false);
m_bIsVSPQueryHooked = true;
}
bool convar_cache_lookup(const char *name, ConVarInfo **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)
{
/* Only check convars that have not been created by SourceMod's core */
ConVarInfo *pInfo;
if (!convar_cache_lookup(name, &pInfo))
{
return;
}
HandleSecurity sec(NULL, g_pCoreIdent);
/* Remove it from our cache */
m_ConVars.remove(pInfo);
convar_cache.remove(name);
/* Now make sure no plugins are referring to this pointer */
IPluginIterator *pl_iter = g_PluginSys.GetPluginIterator();
while (pl_iter->MorePlugins())
{
IPlugin *pl = pl_iter->GetPlugin();
ConVarList *pConVarList;
if (pl->GetProperty("ConVarList", (void **)&pConVarList, true)
&& pConVarList != NULL)
{
pConVarList->remove(pInfo->pVar);
}
pl_iter->NextPlugin();
}
/* Free resources */
g_HandleSys.FreeHandle(pInfo->handle, &sec);
delete pInfo;
}
void ConVarManager::OnPluginUnloaded(IPlugin *plugin)
{
ConVarList *pConVarList;
/* If plugin has a convar list, free its memory */
if (plugin->GetProperty("ConVarList", (void **)&pConVarList, true))
{
delete pConVarList;
}
}
void ConVarManager::OnHandleDestroy(HandleType_t type, void *object)
{
}
bool ConVarManager::GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize)
{
*pSize = sizeof(ConVar) + sizeof(ConVarInfo);
return true;
}
void ConVarManager::OnRootConsoleCommand(const char *cmdname, const CCommand &command)
{
int argcount = command.ArgC();
if (argcount >= 3)
{
/* Get plugin index that was passed */
const char *arg = command.Arg(2);
/* Get plugin object */
CPlugin *plugin = g_PluginSys.FindPluginByConsoleArg(arg);
if (!plugin)
{
g_RootMenu.ConsolePrint("[SM] Plugin \"%s\" was not found.", arg);
return;
}
/* Get plugin name */
const sm_plugininfo_t *plinfo = plugin->GetPublicInfo();
const char *plname = IS_STR_FILLED(plinfo->name) ? plinfo->name : plugin->GetFilename();
ConVarList *pConVarList;
ConVarList::iterator iter;
/* If no convar list... */
if (!plugin->GetProperty("ConVarList", (void **)&pConVarList))
{
g_RootMenu.ConsolePrint("[SM] No convars found for: %s", plname);
return;
}
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 = (*iter);
g_RootMenu.ConsolePrint(" %-32.31s %s", pConVar->GetName(), pConVar->GetString());
}
return;
}
/* Display usage of subcommand */
g_RootMenu.ConsolePrint("[SM] Usage: sm convars <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)
{
ConVar *pConVar = NULL;
ConVarInfo *pInfo = NULL;
Handle_t hndl = 0;
/* Find out if the convar exists already */
pConVar = icvar->FindVar(name);
/* If the convar already exists... */
if (pConVar)
{
/* Add convar to plugin's list */
AddConVarToPluginList(pContext, pConVar);
/* First find out if we already have a handle to it */
if (convar_cache_lookup(name, &pInfo))
{
return pInfo->handle;
}
else
{
/* Create and initialize ConVarInfo structure */
pInfo = new ConVarInfo();
pInfo->sourceMod = false;
pInfo->pChangeForward = NULL;
pInfo->pVar = pConVar;
/* If we don't, then create a new handle from the convar */
hndl = g_HandleSys.CreateHandle(m_ConVarType, pInfo, NULL, g_pCoreIdent, NULL);
if (hndl == BAD_HANDLE)
{
delete pInfo;
return BAD_HANDLE;
}
pInfo->handle = hndl;
/* Insert struct into caches */
m_ConVars.push_back(pInfo);
convar_cache.insert(name, pInfo);
TrackConCommandBase(pConVar, this);
return hndl;
}
}
/* To prevent creating a convar that has the same name as a console command... ugh */
ConCommandBase *pBase = icvar->GetCommands();
while (pBase)
{
if (pBase->IsCommand() && strcmp(pBase->GetName(), name) == 0)
{
return BAD_HANDLE;
}
pBase = const_cast<ConCommandBase *>(pBase->GetNext());
}
/* Create and initialize ConVarInfo structure */
pInfo = new ConVarInfo();
pInfo->handle = hndl;
pInfo->sourceMod = true;
pInfo->pChangeForward = NULL;
/* Create a handle from the new convar */
hndl = g_HandleSys.CreateHandle(m_ConVarType, pInfo, NULL, g_pCoreIdent, NULL);
if (hndl == BAD_HANDLE)
{
delete pInfo;
return BAD_HANDLE;
}
pInfo->handle = hndl;
/* Since an existing convar (or concmd with the same name) was not found , now we can finally create it */
pConVar = new ConVar(sm_strdup(name), sm_strdup(defaultVal), flags, sm_strdup(description), hasMin, min, hasMax, max);
pInfo->pVar = pConVar;
/* Add convar to plugin's list */
AddConVarToPluginList(pContext, pConVar);
/* Insert struct into caches */
m_ConVars.push_back(pInfo);
convar_cache.insert(name, pInfo);
return hndl;
}
Handle_t ConVarManager::FindConVar(const char *name)
{
ConVar *pConVar = NULL;
ConVarInfo *pInfo;
Handle_t hndl;
/* Search for convar */
pConVar = icvar->FindVar(name);
/* If it doesn't exist, then return an invalid handle */
if (!pConVar)
{
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;
pInfo->pChangeForward = NULL;
pInfo->pVar = pConVar;
/* If we don't have a handle, then create a new one */
hndl = g_HandleSys.CreateHandle(m_ConVarType, pInfo, NULL, g_pCoreIdent, NULL);
if (hndl == BAD_HANDLE)
{
delete pInfo;
return BAD_HANDLE;
}
pInfo->handle = hndl;
/* Insert struct into our caches */
m_ConVars.push_back(pInfo);
convar_cache.insert(name, pInfo);
TrackConCommandBase(pConVar, this);
return hndl;
}
void ConVarManager::AddConVarChangeListener(const char *name, IConVarChangeListener *pListener)
{
ConVarInfo *pInfo;
if (FindConVar(name) == BAD_HANDLE)
{
return;
}
/* Find the convar in the lookup trie */
if (convar_cache_lookup(name, &pInfo))
{
pInfo->changeListeners.push_back(pListener);
}
}
void ConVarManager::RemoveConVarChangeListener(const char *name, IConVarChangeListener *pListener)
{
ConVarInfo *pInfo;
/* Find the convar in the lookup trie */
if (convar_cache_lookup(name, &pInfo))
{
pInfo->changeListeners.remove(pListener);
}
}
void ConVarManager::HookConVarChange(ConVar *pConVar, IPluginFunction *pFunction)
{
ConVarInfo *pInfo;
IChangeableForward *pForward;
/* Find the convar in the lookup trie */
if (convar_cache_lookup(pConVar->GetName(), &pInfo))
{
/* Get the forward */
pForward = pInfo->pChangeForward;
/* If forward does not exist, create it */
if (!pForward)
{
pForward = g_Forwards.CreateForwardEx(NULL, ET_Ignore, 3, CONVARCHANGE_PARAMS);
pInfo->pChangeForward = pForward;
}
/* Add function to forward's list */
pForward->AddFunction(pFunction);
}
}
void ConVarManager::UnhookConVarChange(ConVar *pConVar, IPluginFunction *pFunction)
{
ConVarInfo *pInfo;
IChangeableForward *pForward;
IPluginContext *pContext = pFunction->GetParentContext();
/* Find the convar in the lookup trie */
if (convar_cache_lookup(pConVar->GetName(), &pInfo))
{
/* Get the forward */
pForward = pInfo->pChangeForward;
/* If the forward doesn't exist, we can't unhook anything */
if (!pForward)
{
pContext->ThrowNativeError("Convar \"%s\" has no active hook", pConVar->GetName());
return;
}
/* Remove the function from the forward's list */
if (!pForward->RemoveFunction(pFunction))
{
pContext->ThrowNativeError("Invalid hook callback specified for convar \"%s\"", pConVar->GetName());
return;
}
/* If the forward now has 0 functions in it... */
if (pForward->GetFunctionCount() == 0)
{
/* Free this forward */
g_Forwards.ReleaseForward(pForward);
pInfo->pChangeForward = NULL;
}
}
}
QueryCvarCookie_t ConVarManager::QueryClientConVar(edict_t *pPlayer, const char *name, IPluginFunction *pCallback, Handle_t hndl)
{
QueryCvarCookie_t cookie;
/* Call StartQueryCvarValue() in either the IVEngineServer or IServerPluginHelpers depending on situation */
if (m_bIsDLLQueryHooked)
{
cookie = engine->StartQueryCvarValue(pPlayer, name);
}
else if (m_bIsVSPQueryHooked)
{
cookie = serverpluginhelpers->StartQueryCvarValue(pPlayer, name);
}
else
{
return InvalidQueryCvarCookie;
}
ConVarQuery query = {cookie, pCallback, hndl};
m_ConVarQueries.push_back(query);
return cookie;
}
void ConVarManager::AddConVarToPluginList(IPluginContext *pContext, const ConVar *pConVar)
{
ConVarList *pConVarList;
ConVarList::iterator iter;
bool inserted = false;
const char *orig = pConVar->GetName();
IPlugin *plugin = g_PluginSys.FindPluginByContext(pContext->GetContext());
/* Check plugin for an existing convar list */
if (!plugin->GetProperty("ConVarList", (void **)&pConVarList))
{
pConVarList = new ConVarList();
plugin->SetProperty("ConVarList", pConVarList);
}
else if (pConVarList->find(pConVar) != pConVarList->end())
{
/* If convar is already in list, then don't add it */
return;
}
/* Insert convar into list which is sorted alphabetically */
for (iter = pConVarList->begin(); iter != pConVarList->end(); iter++)
{
if (strcmp(orig, (*iter)->GetName()) < 0)
{
pConVarList->insert(iter, pConVar);
inserted = true;
break;
}
}
if (!inserted)
{
pConVarList->push_back(pConVar);
}
}
#if defined ORANGEBOX_BUILD
void ConVarManager::OnConVarChanged(ConVar *pConVar, const char *oldValue, float flOldValue)
#else
void ConVarManager::OnConVarChanged(ConVar *pConVar, const char *oldValue)
#endif
{
/* If the values are the same, exit early in order to not trigger callbacks */
if (strcmp(pConVar->GetString(), oldValue) == 0)
{
return;
}
ConVarInfo *pInfo;
/* Find the convar in the lookup trie */
if (!convar_cache_lookup(pConVar->GetName(), &pInfo))
{
return;
}
IChangeableForward *pForward = pInfo->pChangeForward;
if (pInfo->changeListeners.size() != 0)
{
for (List<IConVarChangeListener *>::iterator i = pInfo->changeListeners.begin();
i != pInfo->changeListeners.end();
i++)
{
#if defined ORANGEBOX_BUILD
(*i)->OnConVarChanged(pConVar, oldValue, flOldValue);
#else
(*i)->OnConVarChanged(pConVar, oldValue, atof(oldValue));
#endif
}
}
if (pForward != NULL)
{
/* Now call forwards in plugins that have hooked this */
pForward->PushCell(pInfo->handle);
pForward->PushString(oldValue);
pForward->PushString(pConVar->GetString());
pForward->Execute(NULL);
}
}
bool ConVarManager::IsQueryingSupported()
{
return (m_bIsDLLQueryHooked || m_bIsVSPQueryHooked);
}
void ConVarManager::OnQueryCvarValueFinished(QueryCvarCookie_t cookie, edict_t *pPlayer, EQueryCvarValueStatus result, const char *cvarName, const char *cvarValue)
{
IPluginFunction *pCallback = NULL;
cell_t value = 0;
List<ConVarQuery>::iterator iter;
for (iter = m_ConVarQueries.begin(); iter != m_ConVarQueries.end(); iter++)
{
ConVarQuery &query = (*iter);
if (query.cookie == cookie)
{
pCallback = query.pCallback;
value = query.value;
break;
}
}
if (pCallback)
{
cell_t ret;
pCallback->PushCell(cookie);
pCallback->PushCell(engine->IndexOfEdict(pPlayer));
pCallback->PushCell(result);
pCallback->PushString(cvarName);
if (result == eQueryCvarValueStatus_ValueIntact)
{
pCallback->PushString(cvarValue);
}
else
{
pCallback->PushString("\0");
}
pCallback->PushCell(value);
pCallback->Execute(&ret);
m_ConVarQueries.erase(iter);
}
}
HandleError ConVarManager::ReadConVarHandle(Handle_t hndl, ConVar **pVar)
{
ConVarInfo *pInfo;
HandleError error;
if ((error = g_HandleSys.ReadHandle(hndl, m_ConVarType, NULL, (void **)&pInfo)) != HandleError_None)
{
return error;
}
if (pVar)
{
*pVar = pInfo->pVar;
}
return error;
}

View File

@ -1,165 +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_CONVARMANAGER_H_
#define _INCLUDE_SOURCEMOD_CONVARMANAGER_H_
#include "sm_globals.h"
#include "sourcemm_api.h"
#include <sh_list.h>
#include <IPluginSys.h>
#include <IForwardSys.h>
#include <IHandleSys.h>
#include <IRootConsoleMenu.h>
#include <compat_wrappers.h>
#include "concmd_cleaner.h"
using namespace SourceHook;
class IConVarChangeListener
{
public:
virtual void OnConVarChanged(ConVar *pConVar, const char *oldValue, float flOldValue) =0;
};
/**
* Holds SourceMod-specific information about a convar
*/
struct ConVarInfo
{
Handle_t handle; /**< Handle to self */
bool sourceMod; /**< Determines whether or not convar was created by a SourceMod plugin */
IChangeableForward *pChangeForward; /**< Forward associated with convar */
ConVar *pVar; /**< The actual convar */
List<IConVarChangeListener *> changeListeners;
};
/**
* Holds information about a client convar query
*/
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 */
};
class ConVarManager :
public SMGlobalClass,
public IHandleTypeDispatch,
public IPluginsListener,
public IRootConsoleCommand,
public IConCommandTracker
{
public:
ConVarManager();
~ConVarManager();
public: // SMGlobalClass
void OnSourceModStartup(bool late);
void OnSourceModAllInitialized();
void OnSourceModShutdown();
void OnSourceModVSPReceived();
public: // IHandleTypeDispatch
void OnHandleDestroy(HandleType_t type, void *object);
bool GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize);
public: // IPluginsListener
void OnPluginUnloaded(IPlugin *plugin);
public: //IRootConsoleCommand
void OnRootConsoleCommand(const char *cmdname, const CCommand &command);
public: //IConCommandTracker
void OnUnlinkConCommandBase(ConCommandBase *pBase, const char *name, bool is_read_safe);
public:
/**
* Create a convar and return a handle to it.
*/
Handle_t CreateConVar(IPluginContext *pContext, const char *name, const char *defaultVal,
const char *description, int flags, bool hasMin, float min, bool hasMax, float max);
/**
* Searches for a convar and returns a handle to it
*/
Handle_t FindConVar(const char* name);
/**
* Add a function to call when the specified convar changes.
*/
void HookConVarChange(ConVar *pConVar, IPluginFunction *pFunction);
/**
* Remove a function from the forward that will be called when the specified convar changes.
*/
void UnhookConVarChange(ConVar *pConVar, IPluginFunction *pFunction);
void AddConVarChangeListener(const char *name, IConVarChangeListener *pListener);
void RemoveConVarChangeListener(const char *name, IConVarChangeListener *pListener);
/**
* Starts a query to find the value of a client convar.
*/
QueryCvarCookie_t QueryClientConVar(edict_t *pPlayer, const char *name, IPluginFunction *pCallback,
Handle_t hndl);
bool IsQueryingSupported();
HandleError ReadConVarHandle(Handle_t hndl, ConVar **pVar);
private:
/**
* Adds a convar to a plugin's list.
*/
static void AddConVarToPluginList(IPluginContext *pContext, const ConVar *pConVar);
/**
* Static callback that Valve's ConVar object executes when the convar's value changes.
*/
#if defined ORANGEBOX_BUILD
static void OnConVarChanged(ConVar *pConVar, const char *oldValue, float flOldValue);
#else
static void OnConVarChanged(ConVar *pConVar, const char *oldValue);
#endif
/**
* Callback for when StartQueryCvarValue() has finished.
*/
void OnQueryCvarValueFinished(QueryCvarCookie_t cookie, edict_t *pPlayer, EQueryCvarValueStatus result,
const char *cvarName, const char *cvarValue);
private:
HandleType_t m_ConVarType;
List<ConVarInfo *> m_ConVars;
List<ConVarQuery> m_ConVarQueries;
bool m_bIsDLLQueryHooked;
bool m_bIsVSPQueryHooked;
};
extern ConVarManager g_ConVarManager;
#endif // _INCLUDE_SOURCEMOD_CONVARMANAGER_H_

View File

@ -1,524 +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$
*/
#include <ITextParsers.h>
#include "CoreConfig.h"
#include "sourcemod.h"
#include "sourcemm_api.h"
#include "sm_srvcmds.h"
#include "sm_version.h"
#include "sm_stringutil.h"
#include "LibrarySys.h"
#include "Logger.h"
#include "PluginSys.h"
#include "ForwardSys.h"
#ifdef PLATFORM_WINDOWS
ConVar sm_corecfgfile("sm_corecfgfile", "addons\\sourcemod\\configs\\core.cfg", 0, "SourceMod core configuration file");
#elif defined PLATFORM_LINUX
ConVar sm_corecfgfile("sm_corecfgfile", "addons/sourcemod/configs/core.cfg", 0, "SourceMod core configuration file");
#endif
IForward *g_pOnServerCfg = NULL;
IForward *g_pOnConfigsExecuted = NULL;
IForward *g_pOnAutoConfigsBuffered = NULL;
CoreConfig g_CoreConfig;
bool g_bConfigsExecd = false;
bool g_bServerExecd = false;
bool g_bGotServerStart = false;
bool g_bGotTrigger = false;
ConCommand *g_pExecPtr = NULL;
ConVar *g_ServerCfgFile = NULL;
void CheckAndFinalizeConfigs();
#if defined ORANGEBOX_BUILD
SH_DECL_EXTERN1_void(ConCommand, Dispatch, SH_NOATTRIB, false, const CCommand &);
void Hook_ExecDispatchPre(const CCommand &cmd)
#else
extern bool __SourceHook_FHAddConCommandDispatch(void *,bool,class fastdelegate::FastDelegate0<void>);
extern bool __SourceHook_FHRemoveConCommandDispatch(void *,bool,class fastdelegate::FastDelegate0<void>);
void Hook_ExecDispatchPre()
#endif
{
#if !defined ORANGEBOX_BUILD
CCommand cmd;
#endif
const char *arg = cmd.Arg(1);
if (!g_bServerExecd
&& arg != NULL
&& strcmp(arg, g_ServerCfgFile->GetString()) == 0)
{
g_bGotTrigger = true;
}
}
#if defined ORANGEBOX_BUILD
void Hook_ExecDispatchPost(const CCommand &cmd)
#else
void Hook_ExecDispatchPost()
#endif
{
if (g_bGotTrigger)
{
g_bGotTrigger = false;
g_bServerExecd = true;
CheckAndFinalizeConfigs();
}
}
void CheckAndFinalizeConfigs()
{
if ((g_bServerExecd || g_ServerCfgFile == NULL)
&& g_bGotServerStart)
{
/* Order is important here. We need to buffer things before we send the command out. */
g_pOnAutoConfigsBuffered->Execute(NULL);
engine->ServerCommand("sm internal 1\n");
}
}
void CoreConfig::OnSourceModAllInitialized()
{
g_RootMenu.AddRootConsoleCommand("config", "Set core configuration options", this);
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);
}
void CoreConfig::OnSourceModShutdown()
{
g_RootMenu.RemoveRootConsoleCommand("config", this);
g_Forwards.ReleaseForward(g_pOnServerCfg);
g_Forwards.ReleaseForward(g_pOnConfigsExecuted);
g_Forwards.ReleaseForward(g_pOnAutoConfigsBuffered);
if (g_pExecPtr != NULL)
{
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;
}
}
void CoreConfig::OnSourceModLevelChange(const char *mapName)
{
static bool already_checked = false;
if (!already_checked)
{
g_ServerCfgFile = icvar->FindVar("servercfgfile");
if (g_ServerCfgFile != NULL)
{
ConCommandBase *pBase = icvar->GetCommands();
while (pBase != NULL)
{
if (pBase->IsCommand() && strcmp(pBase->GetName(), "exec") == 0)
{
break;
}
pBase = const_cast<ConCommandBase *>(pBase->GetNext());
}
g_pExecPtr = (ConCommand *)pBase;
if (g_pExecPtr != NULL)
{
SH_ADD_HOOK_STATICFUNC(ConCommand, Dispatch, g_pExecPtr, Hook_ExecDispatchPre, false);
SH_ADD_HOOK_STATICFUNC(ConCommand, Dispatch, g_pExecPtr, Hook_ExecDispatchPost, true);
}
else
{
g_ServerCfgFile = NULL;
}
}
already_checked = true;
}
g_bConfigsExecd = false;
g_bServerExecd = false;
g_bGotServerStart = false;
g_bGotTrigger = false;
}
void CoreConfig::OnRootConsoleCommand(const char *cmdname, const CCommand &command)
{
int argcount = command.ArgC();
if (argcount >= 4)
{
const char *option = command.Arg(2);
const char *value = command.Arg(3);
char error[255];
ConfigResult res = SetConfigOption(option, value, ConfigSource_Console, error, sizeof(error));
if (res == ConfigResult_Reject)
{
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("Config option \"%s\" successfully set to \"%s.\"", option, value);
}
return;
}
g_RootMenu.ConsolePrint("[SM] Usage: sm config <option> <value>");
}
void CoreConfig::Initialize()
{
SMCError err;
char filePath[PLATFORM_MAX_PATH];
/* Try to get command line value of core config convar */
const char *corecfg = icvar->GetCommandLineValue("sm_corecfgfile");
/* If sm_corecfgfile not specified on command line, use default value */
if (!corecfg)
{
corecfg = sm_corecfgfile.GetDefault();
}
/* Format path to config file */
g_LibSys.PathFormat(filePath, sizeof(filePath), "%s/%s", g_SourceMod.GetGamePath(), corecfg);
/* 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);
g_Logger.LogFatal("[SM] Error encountered parsing core config file: %s", error ? error : "");
}
}
SMCResult CoreConfig::ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value)
{
char error[255];
ConfigResult err = SetConfigOption(key, value, ConfigSource_File, error, sizeof(error));
if (err == ConfigResult_Reject)
{
/* This is a fatal error */
g_Logger.LogFatal("Config error (key: %s) (value: %s) %s", key, value, error);
}
return SMCResult_Continue;
}
ConfigResult CoreConfig::SetConfigOption(const char *option, const char *value, ConfigSource source, char *error, size_t maxlength)
{
ConfigResult result;
/* Notify! */
SMGlobalClass *pBase = SMGlobalClass::head;
while (pBase)
{
if ((result = pBase->OnSourceModConfigChanged(option, value, source, error, maxlength)) != ConfigResult_Ignore)
{
return result;
}
pBase = pBase->m_pGlobalClassNext;
}
return ConfigResult_Ignore;
}
bool SM_AreConfigsExecuted()
{
return g_bConfigsExecd;
}
inline bool IsPathSepChar(char c)
{
#if defined PLATFORM_WINDOWS
return (c == '\\' || c == '/');
#elif defined PLATFORM_LINUX
return (c == '/');
#endif
}
bool SM_ExecuteConfig(CPlugin *pl, AutoConfig *cfg, bool can_create)
{
bool will_create = false;
/* See if we should be creating */
if (can_create && cfg->create)
{
will_create = true;
/* If the folder does not exist, attempt to create it.
* We're awfully nice.
*/
const char *folder = cfg->folder.c_str();
char path[PLATFORM_MAX_PATH];
char build[PLATFORM_MAX_PATH];
g_SourceMod.BuildPath(Path_Game, path, sizeof(path), "cfg/%s", folder);
if (!g_LibSys.IsPathDirectory(path))
{
char *cur_ptr = path;
size_t len;
g_LibSys.PathFormat(path, sizeof(path), "%s", folder);
len = g_SourceMod.BuildPath(Path_Game, build, sizeof(build), "cfg");
do
{
/* Find next suitable path */
char *next_ptr = cur_ptr;
while (*next_ptr != '\0')
{
if (IsPathSepChar(*next_ptr))
{
*next_ptr = '\0';
next_ptr++;
break;
}
next_ptr++;
}
if (*next_ptr == '\0')
{
next_ptr = NULL;
}
len += g_LibSys.PathFormat(&build[len],
sizeof(build)-len,
"/%s",
cur_ptr);
if (!g_LibSys.CreateFolder(build))
{
break;
}
cur_ptr = next_ptr;
} while (cur_ptr);
}
}
/* Check if the file exists. */
char file[PLATFORM_MAX_PATH];
char local[PLATFORM_MAX_PATH];
if (cfg->folder.size())
{
g_LibSys.PathFormat(local,
sizeof(local),
"%s/%s.cfg",
cfg->folder.c_str(),
cfg->autocfg.c_str());
} else {
g_LibSys.PathFormat(local,
sizeof(local),
"%s.cfg",
cfg->autocfg.c_str());
}
g_SourceMod.BuildPath(Path_Game, file, sizeof(file), "cfg/%s", local);
bool file_exists = g_LibSys.IsPathFile(file);
if (!file_exists && will_create)
{
List<const ConVar *> *convars = NULL;
if (pl->GetProperty("ConVarList", (void **)&convars, false) && convars)
{
/* Attempt to create it */
FILE *fp = fopen(file, "wt");
if (fp)
{
fprintf(fp, "// This file was auto-generated by SourceMod (v%s)\n", SVN_FULL_VERSION);
fprintf(fp, "// ConVars for plugin \"%s\"\n", pl->GetFilename());
fprintf(fp, "\n\n");
List<const ConVar *>::iterator iter;
float x;
for (iter = convars->begin(); iter != convars->end(); iter++)
{
const ConVar *cvar = (*iter);
if ((cvar->GetFlags() & FCVAR_DONTRECORD) == FCVAR_DONTRECORD)
{
continue;
}
char descr[255];
char *dptr = descr;
/* Print comments until there is no more */
strncopy(descr, cvar->GetHelpText(), sizeof(descr));
while (*dptr != '\0')
{
/* Find the next line */
char *next_ptr = dptr;
while (*next_ptr != '\0')
{
if (*next_ptr == '\n')
{
*next_ptr = '\0';
next_ptr++;
break;
}
next_ptr++;
}
fprintf(fp, "// %s\n", dptr);
dptr = next_ptr;
}
fprintf(fp, "// -\n");
fprintf(fp, "// Default: \"%s\"\n", cvar->GetDefault());
if (cvar->GetMin(x))
{
fprintf(fp, "// Minimum: \"%02f\"\n", x);
}
if (cvar->GetMax(x))
{
fprintf(fp, "// Maximum: \"%02f\"\n", x);
}
fprintf(fp, "%s \"%s\"\n", cvar->GetName(), cvar->GetDefault());
fprintf(fp, "\n");
}
fprintf(fp, "\n");
file_exists = true;
can_create = false;
fclose(fp);
}
}
}
if (file_exists)
{
char cmd[255];
UTIL_Format(cmd, sizeof(cmd), "exec %s\n", local);
engine->ServerCommand(cmd);
}
return can_create;
}
void SM_DoSingleExecFwds(IPluginContext *ctx)
{
IPluginFunction *pf;
if ((pf = ctx->GetFunctionByName("OnServerCfg")) != NULL)
{
pf->Execute(NULL);
}
if ((pf = ctx->GetFunctionByName("OnConfigsExecuted")) != NULL)
{
pf->Execute(NULL);
}
}
void SM_ConfigsExecuted_Plugin(unsigned int serial)
{
IPluginIterator *iter = g_PluginSys.GetPluginIterator();
while (iter->MorePlugins())
{
CPlugin *plugin = (CPlugin *)(iter->GetPlugin());
if (plugin->GetSerial() == serial)
{
SM_DoSingleExecFwds(plugin->GetBaseContext());
break;
}
iter->NextPlugin();
}
iter->Release();
}
void SM_ExecuteForPlugin(IPluginContext *ctx)
{
CPlugin *plugin = (CPlugin *)g_PluginSys.GetPluginByCtx(ctx->GetContext());
unsigned int num = plugin->GetConfigCount();
if (!num)
{
SM_DoSingleExecFwds(ctx);
}
else
{
bool can_create = true;
for (unsigned int i=0; i<num; i++)
{
can_create = SM_ExecuteConfig(plugin, plugin->GetConfig(i), can_create);
}
char cmd[255];
UTIL_Format(cmd, sizeof(cmd), "sm internal 2 %d\n", plugin->GetSerial());
engine->ServerCommand(cmd);
}
}
void SM_ExecuteAllConfigs()
{
if (g_bGotServerStart)
{
return;
}
engine->ServerCommand("exec sourcemod/sourcemod.cfg\n");
IPluginIterator *iter = g_PluginSys.GetPluginIterator();
while (iter->MorePlugins())
{
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();
#if defined ORANGEBOX_BUILD
engine->ServerExecute();
#endif
g_bGotServerStart = true;
CheckAndFinalizeConfigs();
}
void SM_ConfigsExecuted_Global()
{
if (g_bConfigsExecd)
{
return;
}
g_bConfigsExecd = true;
g_pOnServerCfg->Execute(NULL);
g_pOnConfigsExecuted->Execute(NULL);
}

View File

@ -1,74 +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_CORECONFIG_H_
#define _INCLUDE_SOURCEMOD_CORECONFIG_H_
#include "sm_globals.h"
#include <ITextParsers.h>
#include <IRootConsoleMenu.h>
using namespace SourceMod;
class CoreConfig :
public SMGlobalClass,
public ITextListener_SMC,
public IRootConsoleCommand
{
public: // SMGlobalClass
void OnSourceModAllInitialized();
void OnSourceModShutdown();
void OnSourceModLevelChange(const char *mapName);
public: // ITextListener_SMC
SMCResult ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value);
public: // IRootConsoleCommand
void OnRootConsoleCommand(const char *cmdname, const CCommand &command);
public:
/**
* Initializes CoreConfig by reading from core.cfg file
*/
void Initialize();
private:
/**
* Sets configuration option by notifying SourceMod components that rely on core.cfg
*/
ConfigResult SetConfigOption(const char *option, const char *value, ConfigSource, char *Error, size_t maxlength);
};
extern bool SM_AreConfigsExecuted();
extern void SM_ExecuteAllConfigs();
extern void SM_ExecuteForPlugin(IPluginContext *ctx);
extern void SM_ConfigsExecuted_Global();
extern void SM_ConfigsExecuted_Plugin(unsigned int serial);
extern CoreConfig g_CoreConfig;
#endif // _INCLUDE_SOURCEMOD_CORECONFIG_H_

View File

@ -1,199 +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$
*/
#include "sm_globals.h"
#include "sourcemm_api.h"
#include "Tlhelp32.h"
#include "LibrarySys.h"
#include "minidump.h"
#include "sm_stringutil.h"
bool HookImportAddrTable(BYTE *base, const char *func, DWORD hookfunc, char *err, size_t maxlength)
{
IMAGE_DOS_HEADER *dos = (IMAGE_DOS_HEADER *)base;
if (dos->e_magic != IMAGE_DOS_SIGNATURE)
{
UTIL_Format(err, maxlength, "%s", "Could not detect valid DOS signature");
return false;
}
IMAGE_NT_HEADERS *nt = (IMAGE_NT_HEADERS *)(base + dos->e_lfanew);
if (nt->Signature != IMAGE_NT_SIGNATURE)
{
UTIL_Format(err, maxlength, "%s", "Could not detect valid NT signature");
return false;
}
IMAGE_IMPORT_DESCRIPTOR *desc =
(IMAGE_IMPORT_DESCRIPTOR *)
(base + nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
if (base == (BYTE *)desc)
{
UTIL_Format(err, maxlength, "%s", "Could not find IAT");
return false;
}
bool entryFound = false;
while (desc->Name)
{
if (desc->FirstThunk != 0)
{
IMAGE_THUNK_DATA *data = (IMAGE_THUNK_DATA *)(base + desc->OriginalFirstThunk);
DWORD *iat = (DWORD *)(base + desc->FirstThunk);
while (data->u1.Function)
{
if ((data->u1.Ordinal & IMAGE_ORDINAL_FLAG32) != IMAGE_ORDINAL_FLAG32)
{
IMAGE_IMPORT_BY_NAME *import = (IMAGE_IMPORT_BY_NAME *)(base + data->u1.AddressOfData);
if (strcmp((char *)import->Name, func) == 0)
{
DWORD oldprot, oldprot2;
VirtualProtect(iat, 4, PAGE_READWRITE, &oldprot);
*iat = hookfunc;
VirtualProtect(iat, 4, oldprot, &oldprot2);
entryFound = true;
}
}
data++;
iat++;
}
}
desc++;
}
if (!entryFound)
{
UTIL_Format(err, maxlength, "Could not find IAT entry for %s", func);
return false;
}
return true;
}
BOOL
WINAPI
MiniDumpWriteDump2(
IN HANDLE hProcess,
IN DWORD ProcessId,
IN HANDLE hFile,
IN MINIDUMP_TYPE DumpType,
IN CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, OPTIONAL
IN CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, OPTIONAL
IN CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam OPTIONAL
)
{
DumpType = (MINIDUMP_TYPE)((int)DumpType|MiniDumpWithFullMemory|MiniDumpWithHandleData);
return MiniDumpWriteDump(hProcess, ProcessId, hFile, DumpType, ExceptionParam, UserStreamParam, CallbackParam);
}
FARPROC WINAPI GetProcAddress2(HMODULE hModule, LPCSTR lpProcName)
{
if (strcmp(lpProcName, "MiniDumpWriteDump") == 0)
{
return (FARPROC)MiniDumpWriteDump2;
}
return GetProcAddress(hModule, lpProcName);
}
HMODULE WINAPI LoadLibraryEx2(LPCTSTR lpFileName, HANDLE hFile, DWORD dwFlags)
{
HMODULE lib = LoadLibraryEx(lpFileName, hFile, dwFlags);
/* Steam.dll seems to get loaded using an abs path, thus the use of stristr() */
if (stristr(lpFileName, "steam.dll"))
{
char err[64];
if (!HookImportAddrTable((BYTE *)lib, "GetProcAddress", (DWORD)GetProcAddress2, err, sizeof(err)))
{
Error("[SM] %s in steam.dll\n", err);
return NULL;
}
}
return lib;
}
class CrazyWindowsDebugger : public SMGlobalClass
{
public:
void OnSourceModAllInitialized()
{
HANDLE hModuleList = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetCurrentProcessId());
MODULEENTRY32 me32;
BYTE *engine = NULL;
BYTE *steam = NULL;
char err[64];
me32.dwSize = sizeof(MODULEENTRY32);
if (!Module32First(hModuleList, &me32))
{
Error("Could not initialize crazy debugger!");
}
do
{
if (strcasecmp(me32.szModule, "engine.dll") == 0)
{
engine = me32.modBaseAddr;
}
else if (strcasecmp(me32.szModule, "steam.dll") == 0)
{
steam = me32.modBaseAddr;
}
} while (Module32Next(hModuleList, &me32));
CloseHandle(hModuleList);
/* This really should not happen, but ... */
if (!engine)
{
Error("[SM] Could not find engine.dll\n");
}
/* Steam.dll isn't loaded yet */
if (!steam)
{
if (!HookImportAddrTable(engine, "LoadLibraryExA", (DWORD)LoadLibraryEx2, err, sizeof(err)))
{
Error("[SM] %s in engine.dll)\n", err);
}
}
else
{
if (!HookImportAddrTable(steam, "GetProcAddress", (DWORD)GetProcAddress2, err, sizeof(err)))
{
Error("[SM] %s in steam.dll)\n", err);
}
}
}
} s_CrazyDebugger;

View File

@ -1,725 +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$
*/
#include "Database.h"
#include "HandleSys.h"
#include "ShareSys.h"
#include "sourcemod.h"
#include "sm_stringutil.h"
#include "Logger.h"
#include "ExtensionSys.h"
#include <stdlib.h>
#include "ThreadSupport.h"
#define DBPARSE_LEVEL_NONE 0
#define DBPARSE_LEVEL_MAIN 1
#define DBPARSE_LEVEL_DATABASE 2
DBManager g_DBMan;
static bool s_OneTimeThreaderErrorMsg = false;
DBManager::DBManager()
: m_StrTab(512), m_ParseLevel(0), m_ParseState(0), m_pDefault(NULL)
{
}
void DBManager::OnSourceModAllInitialized()
{
HandleAccess sec;
g_HandleSys.InitAccessDefaults(NULL, &sec);
sec.access[HandleAccess_Delete] |= HANDLE_RESTRICT_IDENTITY;
sec.access[HandleAccess_Clone] |= HANDLE_RESTRICT_IDENTITY;
m_DriverType = g_HandleSys.CreateType("IDriver", this, 0, NULL, &sec, g_pCoreIdent, NULL);
m_DatabaseType = g_HandleSys.CreateType("IDatabase", this, 0, NULL, NULL, g_pCoreIdent, NULL);
g_ShareSys.AddInterface(NULL, this);
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);
}
void DBManager::OnSourceModLevelChange(const char *mapName)
{
SMCError err;
SMCStates states = {0, 0};
/* We lock and don't give up the lock until we're done.
* This way the thread's search won't be searching through a
* potentially empty/corrupt list, which would be very bad.
*/
m_pConfigLock->Lock();
if ((err = textparsers->ParseFile_SMC(m_Filename, this, &states)) != SMCError_Okay)
{
g_Logger.LogError("[SM] Detected parse error(s) in file \"%s\"", m_Filename);
if (err != SMCError_Custom)
{
const char *txt = textparsers->GetSMCErrorString(err);
g_Logger.LogError("[SM] Line %d: %s", states.line, txt);
}
}
m_pConfigLock->Unlock();
}
void DBManager::OnSourceModShutdown()
{
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);
}
unsigned int DBManager::GetInterfaceVersion()
{
return SMINTERFACE_DBI_VERSION;
}
const char *DBManager::GetInterfaceName()
{
return SMINTERFACE_DBI_NAME;
}
void DBManager::OnHandleDestroy(HandleType_t type, void *object)
{
if (type == m_DriverType)
{
/* Ignore */
return;
}
if (g_HandleSys.TypeCheck(type, m_DatabaseType))
{
IDatabase *pdb = (IDatabase *)object;
pdb->Close();
}
}
void DBManager::ReadSMC_ParseStart()
{
m_confs.clear();
m_ParseLevel = 0;
m_ParseState = DBPARSE_LEVEL_NONE;
m_StrTab.Reset();
m_DefDriver.clear();
}
ConfDbInfo s_CurInfo;
SMCResult DBManager::ReadSMC_NewSection(const SMCStates *states, const char *name)
{
if (m_ParseLevel)
{
m_ParseLevel++;
return SMCResult_Continue;
}
if (m_ParseState == DBPARSE_LEVEL_NONE)
{
if (strcmp(name, "Databases") == 0)
{
m_ParseState = DBPARSE_LEVEL_MAIN;
} else {
m_ParseLevel++;
}
} else if (m_ParseState == DBPARSE_LEVEL_MAIN) {
s_CurInfo = ConfDbInfo();
s_CurInfo.name = m_StrTab.AddString(name);
m_ParseState = DBPARSE_LEVEL_DATABASE;
} else if (m_ParseState == DBPARSE_LEVEL_DATABASE) {
m_ParseLevel++;
}
return SMCResult_Continue;
}
SMCResult DBManager::ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value)
{
if (m_ParseLevel)
{
return SMCResult_Continue;
}
if (m_ParseState == DBPARSE_LEVEL_MAIN)
{
if (strcmp(key, "driver_default") == 0)
{
m_DefDriver.assign(value);
}
} else if (m_ParseState == DBPARSE_LEVEL_DATABASE) {
if (strcmp(key, "driver") == 0)
{
if (strcmp(value, "default") != 0)
{
s_CurInfo.driver = m_StrTab.AddString(value);
}
} else if (strcmp(key, "database") == 0) {
s_CurInfo.database = m_StrTab.AddString(value);
} else if (strcmp(key, "host") == 0) {
s_CurInfo.host = m_StrTab.AddString(value);
} else if (strcmp(key, "user") == 0) {
s_CurInfo.user = m_StrTab.AddString(value);
} else if (strcmp(key, "pass") == 0) {
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) {
s_CurInfo.info.port = atoi(value);
}
}
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)
{
m_ParseLevel--;
return SMCResult_Continue;
}
if (m_ParseState == DBPARSE_LEVEL_DATABASE)
{
/* 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(s_CurInfo);
/* Go up one level */
m_ParseState = DBPARSE_LEVEL_MAIN;
} else if (m_ParseState == DBPARSE_LEVEL_MAIN) {
m_ParseState = DBPARSE_LEVEL_NONE;
return SMCResult_Halt;
}
return SMCResult_Continue;
}
#undef ASSIGN_VAR
void DBManager::ReadSMC_ParseEnd(bool halted, bool failed)
{
}
bool DBManager::Connect(const char *name, IDBDriver **pdr, IDatabase **pdb, bool persistent, char *error, size_t maxlength)
{
ConfDbInfo *pInfo = GetDatabaseConf(name);
if (!pInfo)
{
if (pdr)
{
*pdr = NULL;
}
*pdb = NULL;
UTIL_Format(error, maxlength, "Configuration \"%s\" not found", name);
return false;
}
const char *dname = pInfo->info.driver;
if (!pInfo->realDriver)
{
/* Try to assign a real driver pointer */
if (pInfo->info.driver[0] == '\0')
{
if (!m_pDefault && m_DefDriver.size() > 0)
{
m_pDefault = FindOrLoadDriver(m_DefDriver.c_str());
}
dname = m_DefDriver.size() ? m_DefDriver.c_str() : "default";
pInfo->realDriver = m_pDefault;
} else {
pInfo->realDriver = FindOrLoadDriver(pInfo->info.driver);
}
}
if (pInfo->realDriver)
{
if (pdr)
{
*pdr = pInfo->realDriver;
}
*pdb = pInfo->realDriver->Connect(&pInfo->info, persistent, error, maxlength);
return (*pdb != NULL);
}
if (pdr)
{
*pdr = NULL;
}
*pdb = NULL;
UTIL_Format(error, maxlength, "Driver \"%s\" not found", dname);
return false;
}
void DBManager::AddDriver(IDBDriver *pDriver)
{
/* Let's kill the worker. Join the thread and let the queries flush.
* This is kind of stupid but we just want to unload safely.
* Rather than recreate the worker, we'll wait until someone throws
* another query through.
*/
KillWorkerThread();
m_drivers.push_back(pDriver);
}
void DBManager::RemoveDriver(IDBDriver *pDriver)
{
/* Again, we're forced to kill the worker. How rude!
* Doing this flushes the queue, and thus we don't need to
* clean anything else.
*/
KillWorkerThread();
for (size_t i=0; i<m_drivers.size(); i++)
{
if (m_drivers[i] == pDriver)
{
m_drivers.erase(m_drivers.iterAt(i));
break;
}
}
/* Make sure NOTHING references this! */
List<ConfDbInfo>::iterator iter;
for (iter=m_confs.begin(); iter!=m_confs.end(); iter++)
{
ConfDbInfo &db = (*iter);
if (db.realDriver == pDriver)
{
db.realDriver = NULL;
}
}
/* Now that the driver is gone, we have to test the think queue.
* Whatever happens therein is up to the db op!
*/
Queue<IDBThreadOperation *>::iterator qiter = m_ThinkQueue.begin();
Queue<IDBThreadOperation *> templist;
while (qiter != m_ThinkQueue.end())
{
IDBThreadOperation *op = (*qiter);
if (op->GetDriver() == pDriver)
{
templist.push(op);
qiter = m_ThinkQueue.erase(qiter);
} else {
qiter++;
}
}
for (qiter = templist.begin();
qiter != templist.end();
qiter++)
{
IDBThreadOperation *op = (*qiter);
op->CancelThinkPart();
op->Destroy();
}
}
IDBDriver *DBManager::GetDefaultDriver()
{
if (!m_pDefault && m_DefDriver.size() > 0)
{
m_pDefault = FindOrLoadDriver(m_DefDriver.c_str());
}
return m_pDefault;
}
Handle_t DBManager::CreateHandle(DBHandleType dtype, void *ptr, IdentityToken_t *pToken)
{
HandleType_t type = 0;
if (dtype == DBHandle_Driver)
{
type = m_DriverType;
} else if (dtype == DBHandle_Database) {
type = m_DatabaseType;
} else {
return BAD_HANDLE;
}
return g_HandleSys.CreateHandle(type, ptr, pToken, g_pCoreIdent, NULL);
}
HandleError DBManager::ReadHandle(Handle_t hndl, DBHandleType dtype, void **ptr)
{
HandleType_t type = 0;
if (dtype == DBHandle_Driver)
{
type = m_DriverType;
} else if (dtype == DBHandle_Database) {
type = m_DatabaseType;
} else {
return HandleError_Type;
}
HandleSecurity sec(NULL, g_pCoreIdent);
return g_HandleSys.ReadHandle(hndl, type, &sec, ptr);
}
HandleError DBManager::ReleaseHandle(Handle_t hndl, DBHandleType type, IdentityToken_t *token)
{
HandleSecurity sec(token, g_pCoreIdent);
return g_HandleSys.FreeHandle(hndl, &sec);
}
unsigned int DBManager::GetDriverCount()
{
return (unsigned int)m_drivers.size();
}
IDBDriver *DBManager::GetDriver(unsigned int index)
{
if (index >= m_drivers.size())
{
return NULL;
}
return m_drivers[index];
}
const DatabaseInfo *DBManager::FindDatabaseConf(const char *name)
{
ConfDbInfo *info = GetDatabaseConf(name);
if (!info)
{
return NULL;
}
return &info->info;
}
ConfDbInfo *DBManager::GetDatabaseConf(const char *name)
{
List<ConfDbInfo>::iterator iter;
for (iter=m_confs.begin(); iter!=m_confs.end(); iter++)
{
ConfDbInfo &conf = (*iter);
if (strcmp(m_StrTab.GetString(conf.name), name) == 0)
{
return &conf;
}
}
return NULL;
}
IDBDriver *DBManager::FindOrLoadDriver(const char *name)
{
size_t last_size = m_drivers.size();
for (size_t i=0; i<last_size; i++)
{
if (strcmp(m_drivers[i]->GetIdentifier(), name) == 0)
{
return m_drivers[i];
}
}
char filename[PLATFORM_MAX_PATH];
UTIL_Format(filename, sizeof(filename), "dbi.%s.ext", name);
IExtension *pExt = g_Extensions.LoadAutoExtension(filename);
if (!pExt || !pExt->IsLoaded() || m_drivers.size() <= last_size)
{
return NULL;
}
/* last_size is now gauranteed to be a valid index.
* The identifier must match the name.
*/
if (strcmp(m_drivers[last_size]->GetIdentifier(), name) == 0)
{
return m_drivers[last_size];
}
return NULL;
}
void DBManager::KillWorkerThread()
{
if (m_pWorker)
{
m_pWorker->Stop(false);
g_pThreader->DestroyWorker(m_pWorker);
m_pWorker = NULL;
s_OneTimeThreaderErrorMsg = false;
}
}
static IdentityToken_t *s_pAddBlock = NULL;
bool DBManager::AddToThreadQueue(IDBThreadOperation *op, PrioQueueLevel prio)
{
if (s_pAddBlock && op->GetOwner() == s_pAddBlock)
{
return false;
}
if (!m_pWorker)
{
m_pWorker = g_pThreader->MakeWorker(this, true);
if (!m_pWorker)
{
if (!s_OneTimeThreaderErrorMsg)
{
g_Logger.LogError("[SM] Unable to create db threader (error unknown)");
s_OneTimeThreaderErrorMsg = true;
}
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 */
{
m_pQueueLock->Lock();
Queue<IDBThreadOperation *> &queue = m_OpQueue.GetQueue(prio);
queue.push(op);
m_pQueueLock->Unlock();
}
/* Make the thread */
m_pWorker->MakeThread(this);
return true;
}
void DBManager::OnWorkerStart(IThreadWorker *pWorker)
{
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 {
m_drSafety.push_back(false);
}
}
}
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::RunThread(IThreadHandle *pThread)
{
IDBThreadOperation *op = NULL;
/* Get something from the queue */
{
m_pQueueLock->Lock();
Queue<IDBThreadOperation *> &queue = m_OpQueue.GetLikelyQueue();
if (!queue.empty())
{
op = queue.first();
queue.pop();
}
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()
{
/* Don't bother if we're empty */
if (!m_ThinkQueue.size())
{
return;
}
/* Dump one thing per-frame so the server stays sane. */
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;
/* Kill the thread so we can flush everything into the think queue... */
KillWorkerThread();
/* Run all of the think operations.
* Unlike the driver unloading example, we'll let these calls go through,
* since a plugin unloading is far more normal.
*/
Queue<IDBThreadOperation *>::iterator iter = m_ThinkQueue.begin();
Queue<IDBThreadOperation *> templist;
while (iter != m_ThinkQueue.end())
{
IDBThreadOperation *op = (*iter);
if (op->GetOwner() == pToken)
{
templist.push(op);
iter = m_ThinkQueue.erase(iter);
} else {
iter++;
}
}
for (iter = templist.begin();
iter != templist.end();
iter++)
{
IDBThreadOperation *op = (*iter);
op->RunThinkPart();
op->Destroy();
}
s_pAddBlock = NULL;
}
void DBManager::OnPluginUnloaded(IPlugin *plugin)
{
/* Kill the thread so we can flush everything into the think queue... */
KillWorkerThread();
/* Mark the plugin as being unloaded so future database calls will ignore threading... */
plugin->SetProperty("DisallowDBThreads", NULL);
/* Run all of the think operations.
* Unlike the driver unloading example, we'll let these calls go through,
* since a plugin unloading is far more normal.
*/
Queue<IDBThreadOperation *>::iterator iter = m_ThinkQueue.begin();
Queue<IDBThreadOperation *> templist;
while (iter != m_ThinkQueue.end())
{
IDBThreadOperation *op = (*iter);
if (op->GetOwner() == plugin->GetIdentity())
{
templist.push(op);
iter = m_ThinkQueue.erase(iter);
} else {
iter++;
}
}
for (iter = templist.begin();
iter != templist.end();
iter++)
{
IDBThreadOperation *op = (*iter);
op->RunThinkPart();
op->Destroy();
}
}
void DBManager::LockConfig()
{
m_pConfigLock->Lock();
}
void DBManager::UnlockConfig()
{
m_pConfigLock->Unlock();
}
const char *DBManager::GetDefaultDriverName()
{
return m_DefDriver.c_str();
}
void DBManager::AddDependency(IExtension *myself, IDBDriver *driver)
{
g_Extensions.AddRawDependency(myself, driver->GetIdentity(), driver);
}

View File

@ -1,150 +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_DATABASE_MANAGER_H_
#define _INCLUDE_DATABASE_MANAGER_H_
#include <IDBDriver.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 "sm_simple_prioqueue.h"
#include "PluginSys.h"
using namespace SourceHook;
struct ConfDbInfo
{
ConfDbInfo() : name(-1), driver(-1), host(-1), user(-1), pass(-1),
database(-1), realDriver(NULL)
{
}
int name;
int driver;
int host;
int user;
int pass;
int database;
IDBDriver *realDriver;
DatabaseInfo info;
};
class DBManager :
public IDBManager,
public SMGlobalClass,
public IHandleTypeDispatch,
public ITextListener_SMC,
public IThread,
public IThreadWorkerCallbacks,
public IPluginsListener
{
public:
DBManager();
public:
const char *GetInterfaceName();
unsigned int GetInterfaceVersion();
public: //SMGlobalClass
void OnSourceModAllInitialized();
void OnSourceModLevelChange(const char *mapName);
void OnSourceModIdentityDropped(IdentityToken_t *pToken);
void OnSourceModShutdown();
public: //IHandleTypeDispatch
void OnHandleDestroy(HandleType_t type, void *object);
public: //IDBManager
void AddDriver(IDBDriver *pDrivera);
void RemoveDriver(IDBDriver *pDriver);
const DatabaseInfo *FindDatabaseConf(const char *name);
bool Connect(const char *name, IDBDriver **pdr, IDatabase **pdb, bool persistent, char *error, size_t maxlength);
unsigned int GetDriverCount();
IDBDriver *GetDriver(unsigned int index);
Handle_t CreateHandle(DBHandleType type, void *ptr, IdentityToken_t *pToken);
HandleError ReadHandle(Handle_t hndl, DBHandleType type, void **ptr);
HandleError ReleaseHandle(Handle_t hndl, DBHandleType type, IdentityToken_t *token);
void AddDependency(IExtension *myself, IDBDriver *driver);
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);
void ReadSMC_ParseEnd(bool halted, bool failed);
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:
ConfDbInfo *GetDatabaseConf(const char *name);
IDBDriver *FindOrLoadDriver(const char *name);
IDBDriver *GetDefaultDriver();
const char *GetDefaultDriverName();
bool AddToThreadQueue(IDBThreadOperation *op, PrioQueueLevel prio);
void LockConfig();
void UnlockConfig();
void RunFrame();
inline HandleType_t GetDatabaseType()
{
return m_DatabaseType;
}
private:
void KillWorkerThread();
private:
CVector<IDBDriver *> m_drivers;
/* Threading stuff */
PrioQueue<IDBThreadOperation *> m_OpQueue;
Queue<IDBThreadOperation *> m_ThinkQueue;
CVector<bool> m_drSafety; /* which drivers are safe? */
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;
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;
IDBDriver *m_pDefault;
};
extern DBManager g_DBMan;
#endif //_INCLUDE_DATABASE_MANAGER_H_

View File

@ -1,184 +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$
*/
#include "DebugReporter.h"
#include "Logger.h"
#include "PluginSys.h"
#include "sm_stringutil.h"
DebugReport g_DbgReporter;
void DebugReport::OnSourceModAllInitialized()
{
g_pSourcePawn->SetDebugListener(this);
}
void DebugReport::GenerateError(IPluginContext *ctx, cell_t func_idx, int err, const char *message, ...)
{
va_list ap;
char buffer[512];
va_start(ap, message);
UTIL_FormatArgs(buffer, sizeof(buffer), message, ap);
va_end(ap);
const char *plname = g_PluginSys.FindPluginByContext(ctx->GetContext())->GetFilename();
const char *error = g_pSourcePawn2->GetErrorString(err);
if (error)
{
g_Logger.LogError("[SM] Plugin \"%s\" encountered error %d: %s", plname, err, error);
} else {
g_Logger.LogError("[SM] Plugin \"%s\" encountered unknown error %d", plname, err);
}
g_Logger.LogError("[SM] %s", buffer);
if (func_idx != -1)
{
if (func_idx & 1)
{
func_idx >>= 1;
sp_public_t *function;
if (ctx->GetPublicByIndex(func_idx, &function) == SP_ERROR_NONE)
{
g_Logger.LogError("[SM] Unable to call function \"%s\" due to above error(s).", function->name);
}
}
}
}
void DebugReport::GenerateCodeError(IPluginContext *pContext, uint32_t code_addr, int err, const char *message, ...)
{
va_list ap;
char buffer[512];
va_start(ap, message);
UTIL_FormatArgs(buffer, sizeof(buffer), message, ap);
va_end(ap);
const char *plname = g_PluginSys.FindPluginByContext(pContext->GetContext())->GetFilename();
const char *error = g_pSourcePawn2->GetErrorString(err);
if (error)
{
g_Logger.LogError("[SM] Plugin \"%s\" encountered error %d: %s", plname, err, error);
} else {
g_Logger.LogError("[SM] Plugin \"%s\" encountered unknown error %d", plname, err);
}
g_Logger.LogError("[SM] %s", buffer);
IPluginDebugInfo *pDebug;
if ((pDebug = pContext->GetDebugInfo()) == NULL)
{
g_Logger.LogError("[SM] Debug mode is not enabled for \"%s\"", plname);
g_Logger.LogError("[SM] To enable debug mode, edit plugin_settings.cfg, or type: sm plugins debug %d on",
_GetPluginIndex(pContext));
return;
}
const char *name;
if (pDebug->LookupFunction(code_addr, &name) == SP_ERROR_NONE)
{
g_Logger.LogError("[SM] Unable to call function \"%s\" due to above error(s).", name);
} else {
g_Logger.LogError("[SM] Unable to call function (name unknown, address \"%x\").", code_addr);
}
}
void DebugReport::OnContextExecuteError(IPluginContext *ctx, IContextTrace *error)
{
const char *lastname;
const char *plname = g_PluginSys.FindPluginByContext(ctx->GetContext())->GetFilename();
int n_err = error->GetErrorCode();
if (n_err != SP_ERROR_NATIVE)
{
g_Logger.LogError("[SM] Plugin encountered error %d: %s",
n_err,
error->GetErrorString());
}
if ((lastname=error->GetLastNative(NULL)) != NULL)
{
const char *custerr;
if ((custerr=error->GetCustomErrorString()) != NULL)
{
g_Logger.LogError("[SM] Native \"%s\" reported: %s", lastname, custerr);
} else {
g_Logger.LogError("[SM] Native \"%s\" encountered a generic error.", lastname);
}
}
if (!error->DebugInfoAvailable())
{
g_Logger.LogError("[SM] Debug mode is not enabled for \"%s\"", plname);
g_Logger.LogError("[SM] To enable debug mode, edit plugin_settings.cfg, or type: sm plugins debug %d on",
_GetPluginIndex(ctx));
return;
}
CallStackInfo stk_info;
int i = 0;
g_Logger.LogError("[SM] Displaying call stack trace for plugin \"%s\":", plname);
while (error->GetTraceInfo(&stk_info))
{
g_Logger.LogError("[SM] [%d] Line %d, %s::%s()",
i++,
stk_info.line,
stk_info.filename,
stk_info.function);
}
}
int DebugReport::_GetPluginIndex(IPluginContext *ctx)
{
int id = 1;
IPluginIterator *iter = g_PluginSys.GetPluginIterator();
for (; iter->MorePlugins(); iter->NextPlugin(), id++)
{
IPlugin *pl = iter->GetPlugin();
if (pl->GetBaseContext() == ctx)
{
iter->Release();
return id;
}
}
iter->Release();
/* If we don't know which plugin this is, it's one being loaded. Fake its index for now. */
return g_PluginSys.GetPluginCount() + 1;
}

View File

@ -1,55 +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_CDBGREPORTER_H_
#define _INCLUDE_SOURCEMOD_CDBGREPORTER_H_
#include "sp_vm_api.h"
#include "sm_globals.h"
class DebugReport :
public SMGlobalClass,
public IDebugListener
{
public: // SMGlobalClass
void OnSourceModAllInitialized();
public: // IDebugListener
void OnContextExecuteError(IPluginContext *ctx, IContextTrace *error);
void GenerateError(IPluginContext *ctx, cell_t func_idx, int err, const char *message, ...);
void GenerateCodeError(IPluginContext *ctx, uint32_t code_addr, int err, const char *message, ...);
private:
int _GetPluginIndex(IPluginContext *ctx);
};
extern DebugReport g_DbgReporter;
#endif // _INCLUDE_SOURCEMOD_CDBGREPORTER_H_

View File

@ -1,461 +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$
*/
#include "EventManager.h"
#include "ForwardSys.h"
#include "HandleSys.h"
#include "PluginSys.h"
#include "sm_stringutil.h"
EventManager g_EventManager;
SH_DECL_HOOK2(IGameEventManager2, FireEvent, SH_NOATTRIB, 0, bool, IGameEvent *, bool);
const ParamType GAMEEVENT_PARAMS[] = {Param_Cell, Param_String, Param_Cell};
typedef List<EventHook *> EventHookList;
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++)
{
delete (*iter);
}
m_FreeEvents.popall();
}
void EventManager::OnSourceModAllInitialized()
{
/* Add a hook for IGameEventManager2::FireEvent() */
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;
/* Handle access security for 'GameEvent' handle type */
sec.access[HandleAccess_Read] = 0;
sec.access[HandleAccess_Delete] = HANDLE_RESTRICT_IDENTITY | HANDLE_RESTRICT_OWNER;
sec.access[HandleAccess_Clone] = HANDLE_RESTRICT_IDENTITY | HANDLE_RESTRICT_OWNER;
/* Create the 'GameEvent' handle type */
m_EventType = g_HandleSys.CreateType("GameEvent", this, 0, NULL, &sec, g_pCoreIdent, NULL);
}
void EventManager::OnSourceModShutdown()
{
/* Remove hook for IGameEventManager2::FireEvent() */
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 */
g_HandleSys.RemoveType(m_EventType, g_pCoreIdent);
/* Remove ourselves as listener for events */
gameevents->RemoveListener(this);
}
void EventManager::OnHandleDestroy(HandleType_t type, void *object)
{
EventInfo *pInfo = static_cast<EventInfo *>(object);
/* Should only free event when created by a plugin */
if (pInfo->pOwner)
{
/* Free IGameEvent */
gameevents->FreeEvent(pInfo->pEvent);
/* Add EventInfo struct to free event stack */
m_FreeEvents.push(pInfo);
}
}
void EventManager::OnPluginUnloaded(IPlugin *plugin)
{
EventHookList *pHookList;
EventHookList::iterator iter;
EventHook *pHook;
// If plugin has an event hook list...
if (plugin->GetProperty("EventHooks", reinterpret_cast<void **>(&pHookList), true))
{
for (iter = pHookList->begin(); iter != pHookList->end(); iter++)
{
pHook = (*iter);
if (--pHook->refCount == 0)
{
if (pHook->pPreHook)
{
g_Forwards.ReleaseForward(pHook->pPreHook);
}
if (pHook->pPostHook)
{
g_Forwards.ReleaseForward(pHook->pPostHook);
}
delete pHook;
}
}
delete pHookList;
}
}
/* IGameEventListener2::FireGameEvent */
void EventManager::FireGameEvent(IGameEvent *pEvent)
{
/* Not going to do anything here.
Just need to add ourselves as a listener to make our hook on IGameEventManager2::FireEvent work */
}
EventHookError EventManager::HookEvent(const char *name, IPluginFunction *pFunction, EventHookMode mode)
{
EventHook *pHook;
/* If we aren't listening to this event... */
if (!gameevents->FindListener(this, name))
{
/* Then add ourselves */
if (!gameevents->AddListener(this, name, true))
{
/* If event doesn't exist... */
return EventHookErr_InvalidEvent;
}
}
/* If a hook structure does not exist... */
if (!sm_trie_retrieve(m_EventHooks, name, (void **)&pHook))
{
EventHookList *pHookList;
IPlugin *plugin = g_PluginSys.GetPluginByCtx(pFunction->GetParentContext()->GetContext());
/* Check plugin for an existing EventHook list */
if (!plugin->GetProperty("EventHooks", (void **)&pHookList))
{
pHookList = new EventHookList();
plugin->SetProperty("EventHooks", pHookList);
}
/* Create new GameEventHook structure */
pHook = new EventHook();
if (mode == EventHookMode_Pre)
{
/* Create forward for a pre hook */
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 = 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 */
pHook->pPostHook->AddFunction(pFunction);
}
/* Increase reference count */
pHook->refCount++;
/* Add hook structure to hook lists */
pHookList->push_back(pHook);
sm_trie_insert(m_EventHooks, name, pHook);
return EventHookErr_Okay;
}
/* Hook structure already exists at this point */
if (mode == EventHookMode_Pre)
{
/* Create pre hook forward if necessary */
if (!pHook->pPreHook)
{
pHook->pPreHook = g_Forwards.CreateForwardEx(NULL, ET_Event, 3, GAMEEVENT_PARAMS);
}
/* Add plugin function to forward list */
pHook->pPreHook->AddFunction(pFunction);
} else {
/* Create post hook forward if necessary */
if (!pHook->pPostHook)
{
pHook->pPostHook = g_Forwards.CreateForwardEx(NULL, ET_Ignore, 3, GAMEEVENT_PARAMS);
}
/* If postCopy is false, then we may want to set it to true */
if (!pHook->postCopy)
{
pHook->postCopy = (mode == EventHookMode_Post);
}
/* Add plugin function to forward list */
pHook->pPostHook->AddFunction(pFunction);
}
/* Increase reference count */
pHook->refCount++;
return EventHookErr_Okay;
}
EventHookError EventManager::UnhookEvent(const char *name, IPluginFunction *pFunction, EventHookMode mode)
{
EventHook *pHook;
IChangeableForward **pEventForward;
/* If hook does not exist at all */
if (!sm_trie_retrieve(m_EventHooks, name, (void **)&pHook))
{
return EventHookErr_NotActive;
}
/* One forward to rule them all */
if (mode == EventHookMode_Pre)
{
pEventForward = &pHook->pPreHook;
} else {
pEventForward = &pHook->pPostHook;
}
/* Remove function from forward's list */
if (*pEventForward == NULL || !(*pEventForward)->RemoveFunction(pFunction))
{
return EventHookErr_InvalidCallback;
}
/* If forward's list contains 0 functions now, free it */
if ((*pEventForward)->GetFunctionCount() == 0)
{
g_Forwards.ReleaseForward(*pEventForward);
*pEventForward = NULL;
}
/* Decrement reference count */
if (--pHook->refCount == 0)
{
/* If reference count is now 0, free hook structure */
EventHookList *pHookList;
IPlugin *plugin = g_PluginSys.GetPluginByCtx(pFunction->GetParentContext()->GetContext());
/* Get plugin's event hook list */
if (!plugin->GetProperty("EventHooks", (void**)&pHookList))
{
return EventHookErr_NotActive;
}
/* Make sure the event was actually being hooked */
if (pHookList->find(pHook) == pHookList->end())
{
return EventHookErr_NotActive;
}
/* Remove current structure from plugin's list */
pHookList->remove(pHook);
/* Delete entry in trie */
sm_trie_delete(m_EventHooks, name);
/* And finally free structure memory */
delete pHook;
}
return EventHookErr_Okay;
}
EventInfo *EventManager::CreateEvent(IPluginContext *pContext, const char *name, bool force)
{
EventInfo *pInfo;
IGameEvent *pEvent = gameevents->CreateEvent(name, force);
if (pEvent)
{
if (m_FreeEvents.empty())
{
pInfo = new EventInfo();
} else {
pInfo = m_FreeEvents.front();
m_FreeEvents.pop();
}
pInfo->pEvent = pEvent;
pInfo->pOwner = pContext->GetIdentity();
return pInfo;
}
return NULL;
}
void EventManager::FireEvent(EventInfo *pInfo, bool bDontBroadcast)
{
/* Actually fire event now */
gameevents->FireEvent(pInfo->pEvent, bDontBroadcast);
/* IGameEvent is free at this point, so no one owns this */
pInfo->pOwner = NULL;
/* Add EventInfo struct to free event stack */
m_FreeEvents.push(pInfo);
}
void EventManager::CancelCreatedEvent(EventInfo *pInfo)
{
/* Free event from IGameEventManager2 */
gameevents->FreeEvent(pInfo->pEvent);
/* IGameEvent is free at this point, so no one owns this */
pInfo->pOwner = NULL;
/* Add EventInfo struct to free event stack */
m_FreeEvents.push(pInfo);
}
/* IGameEventManager2::FireEvent hook */
bool EventManager::OnFireEvent(IGameEvent *pEvent, bool bDontBroadcast)
{
EventHook *pHook;
IChangeableForward *pForward;
const char *name;
cell_t res = Pl_Continue;
/* The engine accepts NULL without crashing, so to prevent a crash in SM we ignore these */
if (!pEvent)
{
RETURN_META_VALUE(MRES_IGNORED, false);
}
/* Get the event name, we're going to need this for passing to post hooks */
name = pEvent->GetName();
m_EventNames.push(name);
if (sm_trie_retrieve(m_EventHooks, name, reinterpret_cast<void **>(&pHook)))
{
pForward = pHook->pPreHook;
if (pForward)
{
EventInfo info = { pEvent, NULL };
Handle_t hndl = g_HandleSys.CreateHandle(m_EventType, &info, NULL, g_pCoreIdent, NULL);
pForward->PushCell(hndl);
pForward->PushString(name);
pForward->PushCell(bDontBroadcast);
pForward->Execute(&res, NULL);
HandleSecurity sec(NULL, g_pCoreIdent);
g_HandleSys.FreeHandle(hndl, &sec);
}
if (pHook->postCopy)
{
pHook->pEventCopy = gameevents->DuplicateEvent(pEvent);
}
if (res)
{
gameevents->FreeEvent(pEvent);
RETURN_META_VALUE(MRES_SUPERCEDE, false);
}
}
RETURN_META_VALUE(MRES_IGNORED, true);
}
/* IGameEventManager2::FireEvent post hook */
bool EventManager::OnFireEvent_Post(IGameEvent *pEvent, bool bDontBroadcast)
{
IGameEvent *pEventCopy = NULL;
EventHook *pHook;
IChangeableForward *pForward;
const char *name;
Handle_t hndl = 0;
/* The engine accepts NULL without crashing, so to prevent a crash in SM we ignore these */
if (!pEvent)
{
RETURN_META_VALUE(MRES_IGNORED, false);
}
name = m_EventNames.front();
if (sm_trie_retrieve(m_EventHooks, name, reinterpret_cast<void **>(&pHook)))
{
pForward = pHook->pPostHook;
if (pForward)
{
EventInfo info = { pHook->pEventCopy, NULL };
if (pHook->postCopy)
{
hndl = g_HandleSys.CreateHandle(m_EventType, &info, NULL, g_pCoreIdent, NULL);
pForward->PushCell(hndl);
} else {
pForward->PushCell(BAD_HANDLE);
}
pForward->PushString(name);
pForward->PushCell(bDontBroadcast);
pForward->Execute(NULL);
if (pHook->postCopy)
{
/* Free handle */
HandleSecurity sec(NULL, g_pCoreIdent);
g_HandleSys.FreeHandle(hndl, &sec);
/* Free event structure */
gameevents->FreeEvent(pEventCopy);
pHook->pEventCopy = NULL;
}
}
}
m_EventNames.pop();
RETURN_META_VALUE(MRES_IGNORED, true);
}

View File

@ -1,128 +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_EVENTMANAGER_H_
#define _INCLUDE_SOURCEMOD_EVENTMANAGER_H_
#include "sm_globals.h"
#include "sourcemm_api.h"
#include "sm_trie.h"
#include <sh_list.h>
#include <sh_stack.h>
#include <IHandleSys.h>
#include <IForwardSys.h>
#include <IPluginSys.h>
using namespace SourceHook;
struct EventInfo
{
IGameEvent *pEvent;
IdentityToken_t *pOwner;
};
struct EventHook
{
EventHook()
{
pPreHook = NULL;
pPostHook = NULL;
postCopy = false;
pEventCopy = NULL;
refCount = 0;
}
IChangeableForward *pPreHook;
IChangeableForward *pPostHook;
bool postCopy;
IGameEvent *pEventCopy;
unsigned int refCount;
};
enum EventHookMode
{
EventHookMode_Pre,
EventHookMode_Post,
EventHookMode_PostNoCopy
};
enum EventHookError
{
EventHookErr_Okay = 0, /**< No error */
EventHookErr_InvalidEvent, /**< Specified event does not exist */
EventHookErr_NotActive, /**< Specified event has no active hook */
EventHookErr_InvalidCallback, /**< Specified event does not fire specified callback */
};
class EventManager :
public SMGlobalClass,
public IHandleTypeDispatch,
public IPluginsListener,
public IGameEventListener2
{
public:
EventManager();
~EventManager();
public: // SMGlobalClass
void OnSourceModAllInitialized();
void OnSourceModShutdown();
public: // IHandleTypeDispatch
void OnHandleDestroy(HandleType_t type, void *object);
public: // IPluginsListener
void OnPluginUnloaded(IPlugin *plugin);
public: // IGameEventListener2
void FireGameEvent(IGameEvent *pEvent);
public:
/**
* Get the 'GameEvent' handle type ID.
*/
inline HandleType_t GetHandleType()
{
return m_EventType;
}
public:
EventHookError HookEvent(const char *name, IPluginFunction *pFunction, EventHookMode mode=EventHookMode_Post);
EventHookError UnhookEvent(const char *name, IPluginFunction *pFunction, EventHookMode mode=EventHookMode_Post);
EventInfo *CreateEvent(IPluginContext *pContext, const char *name, bool force=false);
void FireEvent(EventInfo *pInfo, bool bDontBroadcast=false);
void CancelCreatedEvent(EventInfo *pInfo);
private: // IGameEventManager2 hooks
bool OnFireEvent(IGameEvent *pEvent, bool bDontBroadcast);
bool OnFireEvent_Post(IGameEvent *pEvent, bool bDontBroadcast);
private:
HandleType_t m_EventType;
Trie *m_EventHooks;
CStack<EventInfo *> m_FreeEvents;
CStack<const char *> m_EventNames;
};
extern EventManager g_EventManager;
#endif // _INCLUDE_SOURCEMOD_EVENTMANAGER_H_

View File

@ -1,694 +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$
*/
#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 "GameDataFetcher.h"
#if defined PLATFORM_LINUX
#include <dlfcn.h>
#endif
GameConfigManager g_GameConfigs;
IGameConfig *g_pGameConf = NULL;
char g_Game[256];
char g_GameDesc[256] = {'!', '\0'};
char g_GameName[256] = {'$', '\0'};
#define PSTATE_NONE 0
#define PSTATE_GAMES 1
#define PSTATE_GAMEDEFS 2
#define PSTATE_GAMEDEFS_OFFSETS 3
#define PSTATE_GAMEDEFS_OFFSETS_OFFSET 4
#define PSTATE_GAMEDEFS_KEYS 5
#define PSTATE_GAMEDEFS_SUPPORTED 6
#define PSTATE_GAMEDEFS_SIGNATURES 7
#define PSTATE_GAMEDEFS_SIGNATURES_SIG 8
#define PSTATE_GAMEDEFS_CRC 9
#define PSTATE_GAMEDEFS_CRC_BINARY 10
#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"
#endif
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;
CGameConfig::CGameConfig(const char *file)
{
m_pFile = sm_strdup(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;
}
CGameConfig::~CGameConfig()
{
sm_trie_destroy(m_pOffsets);
sm_trie_destroy(m_pProps);
sm_trie_destroy(m_pKeys);
sm_trie_destroy(m_pSigs);
delete [] m_pFile;
delete m_pStrings;
}
SMCResult CGameConfig::ReadSMC_NewSection(const SMCStates *states, const char *name)
{
if (m_IgnoreLevel)
{
m_IgnoreLevel++;
return SMCResult_Continue;
}
switch (m_ParseState)
{
case PSTATE_NONE:
{
if (strcmp(name, "Games") == 0)
{
m_ParseState = PSTATE_GAMES;
} else {
m_IgnoreLevel++;
}
break;
}
case PSTATE_GAMES:
{
if ((strcmp(name, "*") == 0)
|| (strcmp(name, "#default") == 0)
|| (strcasecmp(name, g_Game) == 0)
|| (strcasecmp(name, g_GameDesc) == 0)
|| (strcasecmp(name, g_GameName) == 0))
{
bShouldBeReadingDefault = true;
m_ParseState = PSTATE_GAMEDEFS;
strncopy(m_Game, name, sizeof(m_Game));
} else {
m_IgnoreLevel++;
}
break;
}
case PSTATE_GAMEDEFS:
{
if (strcmp(name, "Offsets") == 0)
{
m_ParseState = PSTATE_GAMEDEFS_OFFSETS;
}
else if (strcmp(name, "Keys") == 0)
{
m_ParseState = PSTATE_GAMEDEFS_KEYS;
}
else if ((strcmp(name, "#supported") == 0)
&& (strcmp(m_Game, "#default") == 0))
{
m_ParseState = PSTATE_GAMEDEFS_SUPPORTED;
/* Ignore this section unless we get a game. */
bShouldBeReadingDefault = false;
}
else if (strcmp(name, "Signatures") == 0)
{
m_ParseState = PSTATE_GAMEDEFS_SIGNATURES;
}
else if (strcmp(name, "CRC") == 0)
{
m_ParseState = PSTATE_GAMEDEFS_CRC;
bShouldBeReadingDefault = false;
}
else
{
m_IgnoreLevel++;
}
break;
}
case PSTATE_GAMEDEFS_OFFSETS:
{
m_Prop[0] = '\0';
m_Class[0] = '\0';
strncopy(m_offset, name, sizeof(m_offset));
m_ParseState = PSTATE_GAMEDEFS_OFFSETS_OFFSET;
break;
}
case PSTATE_GAMEDEFS_SIGNATURES:
{
strncopy(m_offset, name, sizeof(m_offset));
s_TempSig.Reset();
m_ParseState = PSTATE_GAMEDEFS_SIGNATURES_SIG;
break;
}
case PSTATE_GAMEDEFS_CRC:
{
char error[255];
error[0] = '\0';
if (strcmp(name, "server") != 0)
{
UTIL_Format(error, sizeof(error), "Unrecognized library \"%s\"", name);
}
else if (!s_ServerBinCRC_Ok)
{
FILE *fp;
char path[PLATFORM_MAX_PATH];
g_SourceMod.BuildPath(Path_Game, path, sizeof(path), "bin/" PLATFORM_SERVER_BINARY);
if ((fp = fopen(path, "rb")) == NULL)
{
UTIL_Format(error, sizeof(error), "Could not open binary: %s", path);
} else {
size_t size;
void *buffer;
fseek(fp, 0, SEEK_END);
size = ftell(fp);
fseek(fp, 0, SEEK_SET);
buffer = malloc(size);
fread(buffer, size, 1, fp);
s_ServerBinCRC = UTIL_CRC32(buffer, size);
free(buffer);
s_ServerBinCRC_Ok = true;
}
}
if (error[0] != '\0')
{
m_IgnoreLevel = 1;
g_Logger.LogError("[SM] Error while parsing CRC section for \"%s\" (%s):", m_Game, m_pFile);
g_Logger.LogError("[SM] %s", error);
} else {
m_ParseState = PSTATE_GAMEDEFS_CRC_BINARY;
}
break;
}
/* No sub-sections allowed:
case PSTATE_GAMEDEFS_OFFSETS_OFFSET:
case PSTATE_GAMEDEFS_KEYS:
case PSTATE_GAMEDEFS_SUPPORTED:
case PSTATE_GAMEDEFS_SIGNATURES_SIG:
case PSTATE_GAMEDEFS_CRC_BINARY:
*/
default:
{
/* If we don't know what we got, start ignoring */
m_IgnoreLevel++;
break;
}
}
return SMCResult_Continue;
}
SMCResult CGameConfig::ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value)
{
if (m_IgnoreLevel)
{
return SMCResult_Continue;
}
if (m_ParseState == PSTATE_GAMEDEFS_OFFSETS_OFFSET)
{
if (strcmp(key, "class") == 0)
{
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) {
int val = atoi(value);
sm_trie_replace(m_pOffsets, m_offset, (void *)val);
}
} else if (m_ParseState == PSTATE_GAMEDEFS_KEYS) {
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
&& (strcasecmp(value, g_Game) == 0
|| strcasecmp(value, g_GameDesc) == 0
|| strcasecmp(value, g_GameName) == 0)
)
{
bShouldBeReadingDefault = true;
}
} else if (m_ParseState == PSTATE_GAMEDEFS_SIGNATURES_SIG) {
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
&& !bShouldBeReadingDefault)
{
unsigned int crc = 0;
sscanf(value, "%08X", &crc);
if (s_ServerBinCRC == crc)
{
bShouldBeReadingDefault = true;
}
}
}
return SMCResult_Continue;
}
SMCResult CGameConfig::ReadSMC_LeavingSection(const SMCStates *states)
{
if (m_IgnoreLevel)
{
m_IgnoreLevel--;
return SMCResult_Continue;
}
switch (m_ParseState)
{
case PSTATE_GAMES:
{
m_ParseState = PSTATE_NONE;
break;
}
case PSTATE_GAMEDEFS:
{
m_ParseState = PSTATE_GAMES;
break;
}
case PSTATE_GAMEDEFS_KEYS:
case PSTATE_GAMEDEFS_OFFSETS:
{
m_ParseState = PSTATE_GAMEDEFS;
break;
}
case PSTATE_GAMEDEFS_OFFSETS_OFFSET:
{
/* Parse the offset... */
if (m_Class[0] != '\0'
&& m_Prop[0] != '\0')
{
SendProp *pProp = g_HL2.FindInSendTable(m_Class, m_Prop);
if (pProp)
{
int val = pProp->GetOffset();
sm_trie_replace(m_pOffsets, m_offset, (void *)val);
sm_trie_replace(m_pProps, m_offset, pProp);
} else {
/* Check if it's a non-default game and no offsets exist */
if (((strcmp(m_Game, "*") != 0) && strcmp(m_Game, "#default") != 0)
&& (!sm_trie_retrieve(m_pOffsets, m_offset, NULL)))
{
g_Logger.LogError("[SM] Unable to find property %s.%s (file \"%s\") (mod \"%s\")",
m_Class,
m_Prop,
m_pFile,
m_Game);
}
}
}
m_ParseState = PSTATE_GAMEDEFS_OFFSETS;
break;
}
case PSTATE_GAMEDEFS_CRC:
case PSTATE_GAMEDEFS_SUPPORTED:
{
if (!bShouldBeReadingDefault)
{
/* If we shouldn't read the rest of this section, set the ignore level. */
m_IgnoreLevel = 1;
m_ParseState = PSTATE_GAMES;
} else {
m_ParseState = PSTATE_GAMEDEFS;
}
break;
}
case PSTATE_GAMEDEFS_CRC_BINARY:
{
m_ParseState = PSTATE_GAMEDEFS_CRC;
break;
}
case PSTATE_GAMEDEFS_SIGNATURES:
{
m_ParseState = PSTATE_GAMEDEFS;
break;
}
case PSTATE_GAMEDEFS_SIGNATURES_SIG:
{
if (s_TempSig.library[0] == '\0')
{
/* assume server */
strncopy(s_TempSig.library, "server", sizeof(s_TempSig.library));
}
void *addrInBase = NULL;
if (strcmp(s_TempSig.library, "server") == 0)
{
addrInBase = (void *)g_SMAPI->GetServerFactory(false);
} else if (strcmp(s_TempSig.library, "engine") == 0) {
addrInBase = (void *)g_SMAPI->GetEngineFactory(false);
}
void *final_addr = NULL;
if (addrInBase == NULL)
{
g_Logger.LogError("[SM] Unrecognized library \"%s\" (gameconf \"%s\")",
s_TempSig.library,
m_pFile);
} else {
#if defined PLATFORM_LINUX
if (s_TempSig.sig[0] == '@')
{
Dl_info info;
/* GNU only: returns 0 on error, inconsistent! >:[ */
if (dladdr(addrInBase, &info) != 0)
{
void *handle = dlopen(info.dli_fname, RTLD_NOW);
if (handle)
{
final_addr = dlsym(handle, &s_TempSig.sig[1]);
dlclose(handle);
} else {
g_Logger.LogError("[SM] Unable to load library \"%s\" (gameconf \"%s\")",
s_TempSig.library,
m_pFile);
}
} else {
g_Logger.LogError("[SM] Unable to find library \"%s\" in memory (gameconf \"%s\")",
s_TempSig.library,
m_pFile);
}
}
if (final_addr)
{
goto skip_find;
}
#endif
/* First, preprocess the signature */
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;
}
}
if (real_bytes >= 1)
{
final_addr = g_MemUtils.FindPattern(addrInBase, real_sig, real_bytes);
}
}
#if defined PLATFORM_LINUX
skip_find:
#endif
sm_trie_replace(m_pSigs, m_offset, final_addr);
m_ParseState = PSTATE_GAMEDEFS_SIGNATURES;
break;
}
}
return SMCResult_Continue;
}
bool CGameConfig::Reparse(char *error, size_t maxlength)
{
SMCError err;
SMCStates state = {0, 0};
char path[PLATFORM_MAX_PATH];
g_SourceMod.BuildPath(Path_SM, path, sizeof(path), "gamedata/%s.txt", m_pFile);
/* Backwards compatibility */
if (!g_LibSys.PathExists(path))
{
g_SourceMod.BuildPath(Path_SM, path, sizeof(path), "configs/gamedata/%s.txt", m_pFile);
}
/* Initialize parse states */
m_IgnoreLevel = 0;
bShouldBeReadingDefault = true;
m_ParseState = PSTATE_NONE;
/* Reset cached data */
m_pStrings->Reset();
sm_trie_clear(m_pOffsets);
sm_trie_clear(m_pProps);
sm_trie_clear(m_pKeys);
if ((err=textparsers->ParseSMCFile(path, this, &state, error, maxlength))
!= SMCError_Okay)
{
const char *msg;
msg = textparsers->GetSMCErrorString(err);
g_Logger.LogError("[SM] Error parsing gameconfig file \"%s\":", path);
g_Logger.LogError("[SM] Error %d on line %d, col %d: %s",
err,
state.line,
state.col,
msg ? msg : "Unknown error");
return false;
}
return true;
}
bool CGameConfig::GetOffset(const char *key, int *value)
{
void *obj;
if (!sm_trie_retrieve(m_pOffsets, key, &obj))
{
return false;
}
*value = (int)obj;
return true;
}
const char *CGameConfig::GetKeyValue(const char *key)
{
void *obj;
if (!sm_trie_retrieve(m_pKeys, key, &obj))
{
return NULL;
}
return m_pStrings->GetString((int)obj);
}
SendProp *CGameConfig::GetSendProp(const char *key)
{
SendProp *pProp;
if (!sm_trie_retrieve(m_pProps, key, (void **)&pProp))
{
return NULL;
}
return pProp;
}
bool CGameConfig::GetMemSig(const char *key, void **addr)
{
return sm_trie_retrieve(m_pSigs, key, addr);
}
void CGameConfig::IncRefCount()
{
m_RefCount++;
}
unsigned int CGameConfig::DecRefCount()
{
m_RefCount--;
return m_RefCount;
}
GameConfigManager::GameConfigManager()
{
m_pLookup = sm_trie_create();
}
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)
{
/* 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;
}
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_pFile);
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;
}

View File

@ -1,112 +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_CGAMECONFIGS_H_
#define _INCLUDE_SOURCEMOD_CGAMECONFIGS_H_
#include <IGameConfigs.h>
#include <ITextParsers.h>
#include <sh_list.h>
#include "sm_trie.h"
#include "sm_globals.h"
#include "sm_memtable.h"
using namespace SourceMod;
using namespace SourceHook;
class SendProp;
class CGameConfig :
public ITextListener_SMC,
public IGameConfig
{
friend class GameConfigManager;
public:
CGameConfig(const char *file);
~CGameConfig();
public:
bool Reparse(char *error, size_t maxlength);
public: //ITextListener_SMC
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: //IGameConfig
const char *GetKeyValue(const char *key);
bool GetOffset(const char *key, int *value);
SendProp *GetSendProp(const char *key);
bool GetMemSig(const char *key, void **addr);
public:
void IncRefCount();
unsigned int DecRefCount();
private:
BaseStringTable *m_pStrings;
char *m_pFile;
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;
char m_Class[64];
char m_Prop[64];
char m_offset[64];
char m_Game[256];
bool bShouldBeReadingDefault;
};
class GameConfigManager :
public IGameConfigManager,
public SMGlobalClass
{
public:
GameConfigManager();
~GameConfigManager();
public: //IGameConfigManager
bool LoadGameConfigFile(const char *file, IGameConfig **pConfig, char *error, size_t maxlength);
void CloseGameConfigFile(IGameConfig *cfg);
IGameConfig *ReadHandle(Handle_t hndl,
IdentityToken_t *ident,
HandleError *err);
public: //SMGlobalClass
void OnSourceModStartup(bool late);
void OnSourceModAllInitialized();
void OnSourceModAllShutdown();
private:
List<CGameConfig *> m_cfgs;
Trie *m_pLookup;
};
extern GameConfigManager g_GameConfigs;
extern IGameConfig *g_pGameConf;
#endif //_INCLUDE_SOURCEMOD_CGAMECONFIGS_H_

View File

@ -1,693 +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$
*/
#include "GameDataFetcher.h"
#include "bitbuf.h"
#ifdef PLATFORM_WINDOWS
#include <winsock2.h>
#else
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#define INVALID_SOCKET -1
#define closesocket close
#endif
#include "sh_vector.h"
#include "sh_string.h"
#include "sm_version.h"
#ifdef ORANGEBOX_BUILD
#include "convar_sm_ob.h"
#else
#include "convar_sm.h"
#endif
#include "sourcemm_api.h"
#include "time.h"
#include "TimerSys.h"
#include "compat_wrappers.h"
#define QUERY_MAX_LENGTH 1024
BuildMD5ableBuffer g_MD5Builder;
FetcherThread g_FetchThread;
FILE *logfile = NULL;
bool g_disableGameDataUpdate = false;
bool g_restartAfterUpdate = false;
void FetcherThread::RunThread( IThreadHandle *pHandle )
{
char lock_path[PLATFORM_MAX_PATH];
g_SourceMod.BuildPath(Path_SM, lock_path, sizeof(lock_path), "data/temp");
g_LibSys.CreateFolder(lock_path);
g_SourceMod.BuildPath(Path_SM, lock_path, sizeof(lock_path), "data/temp/gamedata.lock");
g_Logger.LogMessage("Starting experimental gamedata update fetcher... please report problems to bugs.alliedmods.net");
char log_path[PLATFORM_MAX_PATH];
g_SourceMod.BuildPath(Path_SM, log_path, sizeof(log_path), "logs/gamedata");
g_LibSys.CreateFolder(log_path);
time_t t;
GetAdjustedTime(&t);
tm *curtime = localtime(&t);
g_SourceMod.BuildPath(Path_SM, log_path, sizeof(log_path), "logs/gamedata/L%02d%02d.log", curtime->tm_mon + 1, curtime->tm_mday);
logfile = fopen(log_path, "a");
if (!logfile)
{
g_Logger.LogError("Failed to create GameData log file");
return;
}
//Create a blank lock file
FILE *fp = fopen(lock_path, "w");
if (fp)
{
fclose(fp);
}
/* Create a new socket for this connection */
int socketDescriptor = ConnectSocket();
if (socketDescriptor == INVALID_SOCKET)
{
fclose(logfile);
unlink(lock_path);
return;
}
char query[QUERY_MAX_LENGTH];
/* Check for updated gamedata files */
int len = BuildGameDataQuery(query, QUERY_MAX_LENGTH);
if (len == 0)
{
g_Logger.LogToOpenFile(logfile, "Query Writing failed");
closesocket(socketDescriptor);
fclose(logfile);
unlink(lock_path);
return;
}
if (g_disableGameDataUpdate)
{
g_Logger.LogMessage("Skipping GameData Query due to DisableAutoUpdate being set to true");
closesocket(socketDescriptor);
fclose(logfile);
unlink(lock_path);
return;
}
int sent = NonBlockingSend(socketDescriptor, query, len);
g_Logger.LogToOpenFile(logfile, "Sent Query!");
if (sent == 0)
{
g_Logger.LogToOpenFile(logfile, "Failed to send data");
closesocket(socketDescriptor);
fclose(logfile);
unlink(lock_path);
return;
}
ProcessGameDataQuery(socketDescriptor);
/* And we're done! */
closesocket(socketDescriptor);
fclose(logfile);
unlink(lock_path);
}
void FetcherThread::OnTerminate( IThreadHandle *pHandle, bool cancel )
{
//delete this;
}
int FetcherThread::BuildGameDataQuery( char *buffer, int maxlen )
{
char gamedata_path[PLATFORM_MAX_PATH];
g_SourceMod.BuildPath(Path_SM, gamedata_path, sizeof(gamedata_path), "gamedata");
IDirectory *dir = g_LibSys.OpenDirectory(gamedata_path);
if (dir == NULL)
{
return 0;
}
bf_write Writer = bf_write("GameDataQuery", buffer, maxlen);
Writer.WriteByte('A'); //Generic Header char
Writer.WriteByte('G'); //G for gamedata query, or green, like my hat.
short build[4] = { SVN_FILE_VERSION };
Writer.WriteBytes(&build[0], 8);
Writer.WriteByte(0); // Initialize the file counter - Index 10
while (dir->MoreFiles())
{
if (dir->IsEntryFile())
{
const char *name = dir->GetEntryName();
size_t len = strlen(name);
if (len >= 4
&& strcmp(&name[len-4], ".txt") == 0)
{
char file[PLATFORM_MAX_PATH];
g_LibSys.PathFormat(file, sizeof(file), "%s/%s", gamedata_path, name);
SMCStates states;
if (g_TextParser.ParseFile_SMC(file, &g_MD5Builder, &states) == SMCError_Okay)
{
unsigned char *md5 = g_MD5Builder.GetMD5();
if (md5 != NULL)
{
(uint8_t)buffer[10]++; //Increment the file counter
Writer.WriteBytes(md5, 16);
g_Logger.LogToOpenFile(logfile, "%s - \"%s\"", file, g_MD5Builder.GetMD5String());
FileData *data = new FileData();
data->filename = new SourceHook::String(file);
memcpy(data->checksum, g_MD5Builder.GetMD5String(), 33);
filenames.push_back(data);
}
else
{
g_Logger.LogToOpenFile(logfile, "%s no md5?", file);
}
}
else
{
g_Logger.LogToOpenFile(logfile, "%s failed!", file);
}
}
}
dir->NextEntry();
}
return Writer.GetNumBytesWritten();
}
int FetcherThread::ConnectSocket()
{
struct protoent *ptrp;
ptrp = getprotobyname("tcp");
#ifdef WIN32
WSADATA wsaData;
WSAStartup(0x0101, &wsaData);
#endif
if (ptrp == NULL)
{
g_Logger.LogToOpenFile(logfile, "Failed to find TCP");
return INVALID_SOCKET;
}
int socketDescriptor = socket(AF_INET, SOCK_STREAM, ptrp->p_proto);
if (socketDescriptor == INVALID_SOCKET)
{
//bugger aye?
g_Logger.LogToOpenFile(logfile, "Failed to create a new socket");
closesocket(socketDescriptor);
return INVALID_SOCKET;
}
struct hostent *he;
struct sockaddr_in local_addr;
local_addr.sin_family = AF_INET;
local_addr.sin_port = htons((u_short)6500);
he = gethostbyname("hayate.alliedmods.net");
if (!he)
{
if ((local_addr.sin_addr.s_addr = inet_addr("hayate.alliedmods.net")) == INADDR_NONE)
{
g_Logger.LogToOpenFile(logfile, "Couldnt locate address");
closesocket(socketDescriptor);
return INVALID_SOCKET;
}
}
else
{
memcpy(&local_addr.sin_addr, (struct in_addr *)he->h_addr, he->h_length);
}
if (connect(socketDescriptor, (struct sockaddr *) &local_addr, sizeof(local_addr)) < 0)
{
g_Logger.LogToOpenFile(logfile, "Couldn't connect");
closesocket(socketDescriptor);
return INVALID_SOCKET;
}
return socketDescriptor;
}
void FetcherThread::ProcessGameDataQuery(int socketDescriptor)
{
char buffer[50];
g_Logger.LogToOpenFile(logfile, "Waiting for reply!");
//Read in the header bytes
int returnLen = NonBlockingRecv(socketDescriptor, buffer, 12);
g_Logger.LogToOpenFile(logfile, "Recv Completed");
if (returnLen == 0)
{
g_Logger.LogToOpenFile(logfile, ",but it failed.");
/* Timeout or fail? */
return;
}
g_Logger.LogToOpenFile(logfile, "Received Header!");
bf_read Reader = bf_read("GameDataQuery", buffer, 12);
if (Reader.ReadByte() != 'A' || Reader.ReadByte() != 'G')
{
g_Logger.LogToOpenFile(logfile, "Invalid Query to handle");
return;
}
UpdateStatus updateStatus = (UpdateStatus)Reader.ReadByte();
short build[4] = {0,0,0,0};
build[0] = Reader.ReadShort();
build[1] = Reader.ReadShort();
build[2] = Reader.ReadShort();
build[3] = Reader.ReadShort();
g_Logger.LogToOpenFile(logfile, "Update Status: %i - Latest %i.%i.%i.%i", updateStatus, build[0], build[1], build[2], build[3]);
HandleUpdateStatus(updateStatus, build);
int changedFiles = Reader.ReadByte();
g_Logger.LogToOpenFile(logfile, "Files to download: %i", changedFiles);
for (int i=0; i<changedFiles; i++)
{
//Read in the file index and byte count
returnLen = NonBlockingRecv(socketDescriptor, buffer, 5);
if (returnLen == 0)
{
/* Timeout or fail? */
return;
}
Reader.StartReading(buffer, 5);
int index = Reader.ReadByte();
int tempLen = Reader.ReadUBitLong(32);
g_Logger.LogToOpenFile(logfile, "File index %i and length %i", index, tempLen);
void *memPtr;
memtable->CreateMem(tempLen+1, &memPtr);
//Read the contents of our file into the memtable
returnLen = NonBlockingRecv(socketDescriptor, (char *)memPtr, tempLen);
g_Logger.LogToOpenFile(logfile, "Recieved %i bytes", returnLen);
if (returnLen == 0)
{
/* Timeout or fail? */
return;
}
((unsigned char *)memPtr)[tempLen] = '\0';
FileData *data = filenames.at(index);
const char* filename;
if (data != NULL)
{
filename = data->filename->c_str();
FILE *fp = fopen(filename, "w");
if (fp)
{
fprintf(fp, (const char *)memPtr);
fclose(fp);
}
}
else
{
filename = "";
}
memtable->Reset();
g_Logger.LogToOpenFile(logfile, "Updated File %s", filename);
}
g_Logger.LogToOpenFile(logfile, "File Downloads Completed!");
bool needsRestart = false;
if (changedFiles > 0)
{
needsRestart = true;
g_Logger.LogMessage("New GameData Files have been downloaded to your gamedata directory. Please restart your server for these to take effect");
}
//Read changed file count
returnLen = NonBlockingRecv(socketDescriptor, buffer, 1);
if (returnLen == 0)
{
/* Timeout or fail? */
g_Logger.LogToOpenFile(logfile, "Failed to receive unknown count");
return;
}
Reader.StartReading(buffer, 1);
changedFiles = Reader.ReadByte();
if (changedFiles == 0)
{
g_Logger.LogToOpenFile(logfile, "No unknown files. We're all done");
return;
}
char *changedFileIndexes = new char[changedFiles];
g_Logger.LogToOpenFile(logfile, "%i Files were unknown", changedFiles);
returnLen = NonBlockingRecv(socketDescriptor, changedFileIndexes, changedFiles);
if (returnLen == 0)
{
/* Timeout or fail? */
g_Logger.LogToOpenFile(logfile, "Failed to receive unknown list");
return;
}
Reader.StartReading(changedFileIndexes, changedFiles);
for (int i=0; i<changedFiles; i++)
{
int index = Reader.ReadByte();
char fileName[30];
FileData *data = filenames.at(index);
const char* pathname;
if (data != NULL)
{
pathname = data->filename->c_str();
}
else
{
pathname = "";
}
g_LibSys.GetFileFromPath(fileName, sizeof(fileName), pathname);
g_Logger.LogToOpenFile(logfile, "Unknown File %i : %s", index, fileName);
}
delete [] changedFileIndexes;
if (needsRestart && g_restartAfterUpdate)
{
g_Logger.LogMessage("Automatically restarting server after a successful gamedata update!");
engine->ServerCommand("quit\n");
}
}
int FetcherThread::NonBlockingRecv( int socketDescriptor, char *buffer, int len )
{
fd_set fds;
struct timeval tv;
/* Create a 10 Second Timeout */
tv.tv_sec = 10;
tv.tv_usec = 0;
/* Add our socket to a socket set */
FD_ZERO(&fds);
FD_SET(socketDescriptor, &fds);
/* Wait max of 10 seconds for recv to become available */
select(socketDescriptor+1, &fds, NULL, NULL, &tv);
int bytesReceived = 0;
/* Is there a limit on how much we can receive? Some site said 1024 bytes, which will be well short of a file */
if (FD_ISSET(socketDescriptor, &fds))
{
bytesReceived = recv(socketDescriptor, buffer, len, 0);
}
if (bytesReceived == 0 || bytesReceived == -1)
{
return 0;
}
if (bytesReceived < len)
{
return bytesReceived + NonBlockingRecv(socketDescriptor, buffer+bytesReceived, len-bytesReceived);
}
return bytesReceived;
}
int FetcherThread::NonBlockingSend( int socketDescriptor, char *buffer, int len )
{
fd_set fds;
struct timeval tv;
tv.tv_sec = 10;
tv.tv_usec = 0;
FD_ZERO(&fds);
FD_SET(socketDescriptor, &fds);
select(socketDescriptor+1, NULL, &fds, NULL, &tv);
int sentBytes = 0;
if (FD_ISSET(socketDescriptor, &fds))
{
sentBytes = send(socketDescriptor, buffer, len, 0);
}
if (sentBytes == 0 || sentBytes == -1)
{
return 0;
}
if (sentBytes < len)
{
return sentBytes + NonBlockingSend(socketDescriptor, buffer+sentBytes, len-sentBytes);
}
return sentBytes;
}
void FetcherThread::HandleUpdateStatus( UpdateStatus status, short version[4] )
{
switch (status)
{
case Update_Unknown:
case Update_Current:
{
break;
}
case Update_NewBuild:
{
g_Logger.LogMessage("SourceMod Update: A new SVN build is available from sourcemod.net");
g_Logger.LogMessage("Current Version: %i.%i.%i.%i Available: %i.%i.%i.%i", version[0], version[1], version[2], version[3], version[0], version[1], version[2], version[3]);
break;
}
case Update_MinorAvailable:
{
g_Logger.LogMessage("SourceMod Update: An incremental minor release of SourceMod is now available from sourcemod.net");
g_Logger.LogMessage("Current Version: %i.%i.%i Available: %i.%i.%i", version[0], version[1], version[2], version[0], version[1], version[2]);
break;
}
case Update_MajorAvailable:
{
g_Logger.LogMessage("SourceMod Update: An major release of SourceMod is now available from sourcemod.net");
g_Logger.LogMessage("Current Version: %i.%i.%i Available: %i.%i.%i", version[0], version[1], version[2], version[0], version[1], version[2]);
break;
}
case Update_CriticalAvailable:
{
g_Logger.LogError("SourceMod Update: A new critical release of SourceMod is now available from sourcemod.net. It is strongly recommended that you update");
g_Logger.LogMessage("Current Version: %i.%i.%i.%i Available: %i.%i.%i.%i", version[0], version[1], version[2], version[3], version[0], version[1], version[2], version[3]);
break;
}
}
}
bool g_blockGameDataLoad = false;
class InitFetch : public SMGlobalClass
{
public:
void OnSourceModAllInitialized_Post()
{
char lock_path[PLATFORM_MAX_PATH];
g_SourceMod.BuildPath(Path_SM, lock_path, sizeof(lock_path), "data/temp/gamedata.lock");
if (g_LibSys.IsPathFile(lock_path) && g_LibSys.PathExists(lock_path))
{
g_Logger.LogError("sourcemod/data/temp/gamedata.lock file detected. This is most likely due to a crash during GameData updating - Blocking GameData loading");
g_Logger.LogError("If this error persists delete the file manually");
g_blockGameDataLoad = true;
}
ThreadParams fetchThreadParams = ThreadParams();
fetchThreadParams.prio = ThreadPrio_Low;
g_pThreader->MakeThread(&g_FetchThread, &fetchThreadParams);
}
ConfigResult OnSourceModConfigChanged(const char *key,
const char *value,
ConfigSource source,
char *error,
size_t maxlength)
{
if (strcmp(key, "DisableAutoUpdate") == 0)
{
if (strcmp(value, "yes") == 0)
{
g_disableGameDataUpdate = true;
return ConfigResult_Accept;
}
else if (strcmp(value, "no") == 0)
{
g_disableGameDataUpdate = false;
return ConfigResult_Accept;
}
return ConfigResult_Reject;
}
if (strcmp(key, "ForceRestartAfterUpdate") == 0)
{
if (strcmp(value, "yes") == 0)
{
g_restartAfterUpdate = true;
return ConfigResult_Accept;
}
else if (strcmp(value, "no") == 0)
{
g_restartAfterUpdate = false;
return ConfigResult_Accept;
}
return ConfigResult_Reject;
}
return ConfigResult_Ignore;
}
} g_InitFetch;
CON_COMMAND(sm_gamedata_md5, "Checks the MD5 sum for a given gamedata file")
{
#if !defined ORANGEBOX_BUILD
CCommand args;
#endif
if (args.ArgC() < 2)
{
g_SMAPI->ConPrint("Usage: sm_gamedata_md5 <file>\n");
return;
}
const char *file = args.Arg(1);
if (!file || file[0] == '\0')
{
g_SMAPI->ConPrint("Usage: sm_gamedata_md5 <file>\n");
return;
}
SourceHook::CVector<FileData *>::iterator iter = g_FetchThread.filenames.begin();
FileData *curData;
while (iter != g_FetchThread.filenames.end())
{
curData = (*iter);
char fileName[30];
g_LibSys.GetFileFromPath(fileName, sizeof(fileName), curData->filename->c_str());
if (strcmpi(fileName, file) == 0)
{
g_SMAPI->ConPrintf("MD5 Sum: %s\n", curData->checksum);
return;
}
iter++;
}
g_SMAPI->ConPrint("File not found!\n");
}

View File

@ -1,185 +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_GAMEDATAFETCHER_H_
#define _INCLUDE_SOURCEMOD_GAMEDATAFETCHER_H_
#include "sourcemod.h"
#include "TextParsers.h"
#include "IThreader.h"
#include "Logger.h"
#include "LibrarySys.h"
#include "ThreadSupport.h"
#include "md5.h"
#include "sm_memtable.h"
enum UpdateStatus
{
Update_Unknown = 0, /* Version wasn't recognised or version querying is unsupported */
Update_Current = 1, /* Server is running latest version */
Update_NewBuild = 2, /* Server is on a svn release and a newer version is available */
Update_MinorAvailable = 3, /* Server is on a release and a minor release has superceeded it */
Update_MajorAvailable = 4, /* Server is on a release and a major release has superceeded it */
Update_CriticalAvailable = 5, /* A critical update has been released (security fixes etc) */
};
class BuildMD5ableBuffer : public ITextListener_SMC
{
public:
BuildMD5ableBuffer()
{
stringTable = new BaseStringTable(2048);
md5[0] = 0;
md5String[0] = 0;
}
~BuildMD5ableBuffer()
{
delete stringTable;
}
void ReadSMC_ParseStart()
{
checksum = MD5();
}
SMCResult ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value)
{
stringTable->AddString(key);
stringTable->AddString(value);
return SMCResult_Continue;
}
SMCResult ReadSMC_NewSection(const SMCStates *states, const char *name)
{
stringTable->AddString(name);
return SMCResult_Continue;
}
void ReadSMC_ParseEnd(bool halted, bool failed)
{
if (halted || failed)
{
return;
}
void *data = stringTable->GetMemTable()->GetAddress(0);
if (data != NULL)
{
checksum.update((unsigned char *)data, stringTable->GetMemTable()->GetActualMemUsed());
}
checksum.finalize();
checksum.hex_digest(md5String);
checksum.raw_digest(md5);
stringTable->Reset();
}
unsigned char * GetMD5()
{
return md5;
}
unsigned char * GetMD5String()
{
return (unsigned char *)&md5String[0];
}
private:
MD5 checksum;
unsigned char md5[16];
char md5String[33];
BaseStringTable *stringTable;
};
struct FileData
{
SourceHook::String *filename;
unsigned char checksum[33];
};
class FetcherThread : public IThread
{
public:
FetcherThread()
{
//filenames = new BaseStringTable(200);
memtable = new BaseMemTable(4096);
}
~FetcherThread()
{
//delete filenames;
SourceHook::CVector<FileData *>::iterator iter = filenames.begin();
FileData *curData;
while (iter != filenames.end())
{
curData = (*iter);
delete curData->filename;
delete curData;
iter = filenames.erase(iter);
}
}
void RunThread(IThreadHandle *pHandle);
void OnTerminate(IThreadHandle *pHandle, bool cancel);
private:
int BuildGameDataQuery(char *buffer, int maxlen);
void ProcessGameDataQuery(int SocketDescriptor);
/* These names are a lie. It's really NoMoreBlockingThan10Seconds */
int NonBlockingRecv(int socketDescriptor, char *buffer, int len);
int NonBlockingSend(int socketDescriptor, char *buffer, int len);
int ConnectSocket();
void HandleUpdateStatus(UpdateStatus status, short version[4]);
public:
SourceHook::CVector<FileData *> filenames;
private:
BaseMemTable *memtable;
};
extern BuildMD5ableBuffer g_MD5Builder;
extern bool g_blockGameDataLoad;
#endif // _INCLUDE_SOURCEMOD_GAMEDATAFETCHER_H_

View File

@ -1,541 +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$
*/
#include "HalfLife2.h"
#include "sourcemod.h"
#include "sourcemm_api.h"
#include "UserMessages.h"
#include "PlayerManager.h"
#include "sm_stringutil.h"
#include "GameConfigs.h"
#include <compat_wrappers.h>
CHalfLife2 g_HL2;
ConVar *sv_lan = NULL;
namespace SourceHook
{
template<>
int HashFunction<datamap_t *>(datamap_t * const &k)
{
return reinterpret_cast<int>(k);
}
template<>
int Compare<datamap_t *>(datamap_t * const &k1, datamap_t * const &k2)
{
return (k1-k2);
}
}
CHalfLife2::CHalfLife2()
{
m_pClasses = sm_trie_create();
}
CHalfLife2::~CHalfLife2()
{
sm_trie_destroy(m_pClasses);
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();
}
CSharedEdictChangeInfo *g_pSharedChangeInfo = NULL;
bool is_original_engine = false;
void CHalfLife2::OnSourceModStartup(bool late)
{
/* The Ship currently is the only known game to use an older version of the engine */
#if defined METAMOD_PLAPI_VERSION
if (g_SMAPI->GetSourceEngineBuild() == SOURCE_ENGINE_ORIGINAL)
#else
if (strcasecmp(g_SourceMod.GetGameFolderName(), "ship") == 0)
#endif
{
is_original_engine = true;
}
else if (g_pSharedChangeInfo == NULL)
{
g_pSharedChangeInfo = engine->GetSharedEdictChangeInfo();
}
}
void CHalfLife2::OnSourceModAllInitialized()
{
m_MsgTextMsg = g_UserMsgs.GetMessageIndex("TextMsg");
m_HinTextMsg = g_UserMsgs.GetMessageIndex("HintText");
m_VGUIMenu = g_UserMsgs.GetMessageIndex("VGUIMenu");
g_ShareSys.AddInterface(NULL, this);
}
#if !defined METAMOD_PLAPI_VERSION
bool CHalfLife2::IsOriginalEngine()
{
return is_original_engine;
}
#endif
IChangeInfoAccessor *CBaseEdict::GetChangeAccessor()
{
return engine->GetChangeAccessor( (const edict_t *)this );
}
bool UTIL_FindInSendTable(SendTable *pTable,
const char *name,
sm_sendprop_info_t *info,
unsigned int offset)
{
const char *pname;
int props = pTable->GetNumProps();
SendProp *prop;
for (int i=0; i<props; i++)
{
prop = pTable->GetProp(i);
pname = prop->GetName();
if (pname && strcmp(name, pname) == 0)
{
info->prop = prop;
info->actual_offset = offset + info->prop->GetOffset();
return true;
}
if (prop->GetDataTable())
{
if (UTIL_FindInSendTable(prop->GetDataTable(),
name,
info,
offset + prop->GetOffset())
)
{
return true;
}
}
}
return false;
}
typedescription_t *UTIL_FindInDataMap(datamap_t *pMap, const char *name)
{
while (pMap)
{
for (int i=0; i<pMap->dataNumFields; i++)
{
if (pMap->dataDesc[i].fieldName == NULL)
{
continue;
}
if (strcmp(name, pMap->dataDesc[i].fieldName) == 0)
{
return &(pMap->dataDesc[i]);
}
if (pMap->dataDesc[i].td)
{
typedescription_t *_td;
if ((_td=UTIL_FindInDataMap(pMap->dataDesc[i].td, name)) != NULL)
{
return _td;
}
}
}
pMap = pMap->baseMap;
}
return NULL;
}
ServerClass *CHalfLife2::FindServerClass(const char *classname)
{
DataTableInfo *pInfo = _FindServerClass(classname);
if (!pInfo)
{
return NULL;
}
return pInfo->sc;
}
DataTableInfo *CHalfLife2::_FindServerClass(const char *classname)
{
DataTableInfo *pInfo = NULL;
if (!sm_trie_retrieve(m_pClasses, classname, (void **)&pInfo))
{
ServerClass *sc = gamedll->GetAllServerClasses();
while (sc)
{
if (strcmp(classname, sc->GetName()) == 0)
{
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;
}
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 ((prop = pInfo->lookup.retrieve(offset)) == NULL)
{
sm_sendprop_info_t temp_info;
if (!UTIL_FindInSendTable(pInfo->sc->m_pTable, offset, &temp_info, 0))
{
return false;
}
pInfo->lookup.insert(offset, temp_info);
*info = temp_info;
}
else
{
*info = *prop;
}
return true;
}
SendProp *CHalfLife2::FindInSendTable(const char *classname, const char *offset)
{
sm_sendprop_info_t info;
if (!FindSendPropInfo(classname, offset, &info))
{
return NULL;
}
return info.prop;
}
typedescription_t *CHalfLife2::FindInDataMap(datamap_t *pMap, const char *offset)
{
typedescription_t *td = NULL;
DataMapTrie &val = m_Maps[pMap];
if (!val.trie)
{
val.trie = sm_trie_create();
}
if (!sm_trie_retrieve(val.trie, offset, (void **)&td))
{
if ((td = UTIL_FindInDataMap(pMap, offset)) != NULL)
{
sm_trie_insert(val.trie, offset, td);
}
}
return td;
}
void CHalfLife2::SetEdictStateChanged(edict_t *pEdict, unsigned short offset)
{
if (g_pSharedChangeInfo != NULL)
{
if (offset)
{
pEdict->StateChanged(offset);
}
else
{
pEdict->StateChanged();
}
}
else
{
pEdict->m_fStateFlags |= FL_EDICT_CHANGED;
}
}
bool CHalfLife2::TextMsg(int client, int dest, const char *msg)
{
bf_write *pBitBuf = NULL;
cell_t players[] = {client};
if ((pBitBuf = g_UserMsgs.StartMessage(m_MsgTextMsg, players, 1, USERMSG_RELIABLE)) == NULL)
{
return false;
}
pBitBuf->WriteByte(dest);
pBitBuf->WriteString(msg);
g_UserMsgs.EndMessage();
return true;
}
bool CHalfLife2::HintTextMsg(int client, const char *msg)
{
bf_write *pBitBuf = NULL;
cell_t players[] = {client};
if ((pBitBuf = g_UserMsgs.StartMessage(m_HinTextMsg, players, 1, USERMSG_RELIABLE)) == NULL)
{
return false;
}
const char *pre_byte = g_pGameConf->GetKeyValue("HintTextPreByte");
if (pre_byte != NULL && strcmp(pre_byte, "yes") == 0)
{
pBitBuf->WriteByte(1);
}
pBitBuf->WriteString(msg);
g_UserMsgs.EndMessage();
return true;
}
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 ((pBitBuf = g_UserMsgs.StartMessage(m_VGUIMenu, players, 1, USERMSG_RELIABLE)) == NULL)
{
return false;
}
if (data)
{
SubKey = data->GetFirstSubKey();
while (SubKey)
{
count++;
SubKey = SubKey->GetNextKey();
}
SubKey = data->GetFirstSubKey();
}
pBitBuf->WriteString(name);
pBitBuf->WriteByte((show) ? 1 : 0);
pBitBuf->WriteByte(count);
while (SubKey)
{
pBitBuf->WriteString(SubKey->GetName());
pBitBuf->WriteString(SubKey->GetString());
SubKey = SubKey->GetNextKey();
}
g_UserMsgs.EndMessage();
return true;
}
void CHalfLife2::AddToFakeCliCmdQueue(int client, int userid, const char *cmd)
{
DelayedFakeCliCmd *pFake;
if (m_FreeCmds.empty())
{
pFake = new DelayedFakeCliCmd;
} else {
pFake = m_FreeCmds.front();
m_FreeCmds.pop();
}
pFake->client = client;
pFake->userid = userid;
pFake->cmd.assign(cmd);
m_CmdQueue.push(pFake);
}
void CHalfLife2::ProcessFakeCliCmdQueue()
{
while (!m_CmdQueue.empty())
{
DelayedFakeCliCmd *pFake = m_CmdQueue.first();
if (g_Players.GetClientOfUserId(pFake->userid) == pFake->client)
{
CPlayer *pPlayer = g_Players.GetPlayerByIndex(pFake->client);
serverpluginhelpers->ClientCommand(pPlayer->GetEdict(), pFake->cmd.c_str());
}
m_CmdQueue.pop();
}
}
bool CHalfLife2::IsLANServer()
{
sv_lan = icvar->FindVar("sv_lan");
if (!sv_lan)
{
return false;
}
return (sv_lan->GetInt() != 0);
}
bool CHalfLife2::KVLoadFromFile(KeyValues *kv, IBaseFileSystem *filesystem, const char *resourceName, const char *pathID)
{
#if defined METAMOD_PLAPI_VERSION
if (g_SMAPI->GetSourceEngineBuild() == SOURCE_ENGINE_ORIGINAL)
#else
if (strcasecmp(g_SourceMod.GetGameFolderName(), "ship") == 0)
#endif
{
Assert(filesystem);
#ifdef _MSC_VER
Assert(_heapchk() == _HEAPOK);
#endif
FileHandle_t f = filesystem->Open(resourceName, "rb", pathID);
if (!f)
return false;
// load file into a null-terminated buffer
int fileSize = filesystem->Size(f);
char *buffer = (char *)MemAllocScratch(fileSize + 1);
Assert(buffer);
filesystem->Read(buffer, fileSize, f); // read into local buffer
buffer[fileSize] = 0; // null terminate file as EOF
filesystem->Close( f ); // close file after reading
bool retOK = kv->LoadFromBuffer( resourceName, buffer, filesystem );
MemFreeScratch();
return retOK;
}
else
{
return kv->LoadFromFile(filesystem, resourceName, pathID);
}
}
void CHalfLife2::PushCommandStack(const CCommand *cmd)
{
CachedCommandInfo info;
info.args = cmd;
#if !defined ORANGEBOX_BUILD
strncopy(info.cmd, cmd->Arg(0), sizeof(info.cmd));
#endif
m_CommandStack.push(info);
}
const CCommand *CHalfLife2::PeekCommandStack()
{
if (m_CommandStack.empty())
{
return NULL;
}
return m_CommandStack.front().args;
}
void CHalfLife2::PopCommandStack()
{
m_CommandStack.pop();
}
const char *CHalfLife2::CurrentCommandName()
{
#if defined ORANGEBOX_BUILD
return m_CommandStack.front().args->Arg(0);
#else
return m_CommandStack.front().cmd;
#endif
}
void CHalfLife2::AddDelayedKick(int client, int userid, const char *msg)
{
DelayedKickInfo kick;
kick.client = client;
kick.userid = userid;
UTIL_Format(kick.buffer, sizeof(kick.buffer), "%s", msg);
m_DelayedKicks.push(kick);
}
void CHalfLife2::ProcessDelayedKicks()
{
while (!m_DelayedKicks.empty())
{
DelayedKickInfo info = m_DelayedKicks.first();
m_DelayedKicks.pop();
CPlayer *player = g_Players.GetPlayerByIndex(info.client);
if (player == NULL || player->GetUserId() != info.userid)
{
continue;
}
player->Kick(info.buffer);
}
}

View File

@ -1,142 +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_CHALFLIFE2_H_
#define _INCLUDE_SOURCEMOD_CHALFLIFE2_H_
#include <sh_list.h>
#include <sh_string.h>
#include <sh_tinyhash.h>
#include <sm_trie_tpl.h>
#include "sm_trie.h"
#include "sm_globals.h"
#include "sm_queue.h"
#include <IGameHelpers.h>
#include <KeyValues.h>
#include <server_class.h>
#include <datamap.h>
class CCommand;
using namespace SourceHook;
using namespace SourceMod;
#define HUD_PRINTTALK 3
#define HUD_PRINTCENTER 4
struct DataTableInfo
{
ServerClass *sc;
KTrie<sm_sendprop_info_t> lookup;
};
struct DataMapTrie
{
DataMapTrie() : trie(NULL) {}
Trie *trie;
};
struct DelayedFakeCliCmd
{
String cmd;
int client;
int userid;
};
struct CachedCommandInfo
{
const CCommand *args;
#if !defined ORANGEBOX_BUILD
char cmd[300];
#endif
};
struct DelayedKickInfo
{
int userid;
int client;
char buffer[384];
};
class CHalfLife2 :
public SMGlobalClass,
public IGameHelpers
{
public:
CHalfLife2();
~CHalfLife2();
public:
void OnSourceModStartup(bool late);
void OnSourceModAllInitialized();
/*void OnSourceModAllShutdown();*/
public: //IGameHelpers
SendProp *FindInSendTable(const char *classname, const char *offset);
bool FindSendPropInfo(const char *classname, const char *offset, sm_sendprop_info_t *info);
datamap_t *GetDataMap(CBaseEntity *pEntity);
ServerClass *FindServerClass(const char *classname);
typedescription_t *FindInDataMap(datamap_t *pMap, const char *offset);
void SetEdictStateChanged(edict_t *pEdict, unsigned short offset);
bool TextMsg(int client, int dest, const char *msg);
bool HintTextMsg(int client, const char *msg);
bool ShowVGUIMenu(int client, const char *name, KeyValues *data, bool show);
bool IsLANServer();
bool KVLoadFromFile(KeyValues *kv, IBaseFileSystem *filesystem, const char *resourceName, const char *pathID = NULL);
public:
void AddToFakeCliCmdQueue(int client, int userid, const char *cmd);
void ProcessFakeCliCmdQueue();
public:
void PushCommandStack(const CCommand *cmd);
void PopCommandStack();
const CCommand *PeekCommandStack();
const char *CurrentCommandName();
void AddDelayedKick(int client, int userid, const char *msg);
void ProcessDelayedKicks();
#if !defined METAMOD_PLAPI_VERSION
bool IsOriginalEngine();
#endif
private:
DataTableInfo *_FindServerClass(const char *classname);
private:
Trie *m_pClasses;
List<DataTableInfo *> m_Tables;
THash<datamap_t *, DataMapTrie> m_Maps;
int m_MsgTextMsg;
int m_HinTextMsg;
int m_VGUIMenu;
Queue<DelayedFakeCliCmd *> m_CmdQueue;
CStack<DelayedFakeCliCmd *> m_FreeCmds;
CStack<CachedCommandInfo> m_CommandStack;
Queue<DelayedKickInfo> m_DelayedKicks;
};
extern CHalfLife2 g_HL2;
#endif //_INCLUDE_SOURCEMOD_CHALFLIFE2_H_

View File

@ -1,520 +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$
*/
#include <time.h>
#include "sourcemod.h"
#include "sourcemm_api.h"
#include "sm_stringutil.h"
#include "Logger.h"
#include "systems/LibrarySys.h"
#include "TimerSys.h"
#include "sm_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, SVN_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::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::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, SVN_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, ...)
{
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;
}
va_list ap;
va_start(ap, vafmt);
LogToOpenFileEx(fp, vafmt, ap);
va_end(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;
void Engine_LogPrintWrapper(const char *msg)
{
if (g_in_game_log_hook)
{
ENGINE_CALL(LogPrint)(msg);
}
else
{
engine->LogPrint(msg);
}
}

View File

@ -1,106 +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 "sm_globals.h"
using namespace SourceHook;
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 LogFatal(const char *msg, ...);
void LogToOpenFile(FILE *fp, const char *msg, ...);
void LogToOpenFileEx(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_

View File

@ -1,136 +0,0 @@
# (C)2004-2008 SourceMod Development Team
# Makefile written by David "BAILOPAN" Anderson
SMSDK = ..
SRCDS_BASE = ~/srcds
HL2SDK_ORIG = ../../hl2sdk
HL2SDK_OB = ../../hl2sdk-ob
SOURCEMM14 = ../../sourcemm-1.4
SOURCEMM16 = ../../sourcemm-1.6
#####################################
### EDIT BELOW FOR OTHER PROJECTS ###
#####################################
OBJECTS = AdminCache.cpp CDataPack.cpp ConCmdManager.cpp ConVarManager.cpp CoreConfig.cpp \
Database.cpp DebugReporter.cpp EventManager.cpp GameConfigs.cpp HalfLife2.cpp Logger.cpp \
MemoryUtils.cpp PlayerManager.cpp TextParsers.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 sm_crc32.cpp \
frame_hooks.cpp concmd_cleaner.cpp Profiler.cpp PhraseCollection.cpp NextMap.cpp \
NativeOwner.cpp GameDataFetcher.cpp md5.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_float.cpp smn_functions.cpp smn_gameconfigs.cpp smn_halflife.cpp \
smn_handles.cpp smn_keyvalues.cpp smn_banning.cpp smn_maplists.cpp \
smn_lang.cpp smn_player.cpp smn_string.cpp smn_sorting.cpp smn_textparse.cpp smn_timers.cpp \
smn_usermsgs.cpp smn_menus.cpp smn_database.cpp smn_vector.cpp smn_adt_array.cpp \
smn_adt_trie.cpp smn_hudtext.cpp smn_adt_stack.cpp smn_nextmap.cpp
OBJECTS += systems/ExtensionSys.cpp systems/ForwardSys.cpp systems/HandleSys.cpp \
systems/LibrarySys.cpp systems/PluginInfoDatabase.cpp systems/PluginSys.cpp \
systems/ShareSys.cpp
OBJECTS += thread/ThreadWorker.cpp thread/BaseWorker.cpp thread/PosixThreads.cpp ThreadSupport.cpp
##############################################
### CONFIGURE ANY OTHER FLAGS/OPTIONS HERE ###
##############################################
C_OPT_FLAGS = -DNDEBUG -O3 -funroll-loops -pipe -fno-strict-aliasing
C_DEBUG_FLAGS = -D_DEBUG -DDEBUG -g -ggdb3
C_GCC4_FLAGS = -fvisibility=hidden
CPP_GCC4_FLAGS = -fvisibility-inlines-hidden
CPP = gcc-4.1
override ENGSET = false
ifeq "$(ENGINE)" "original"
HL2SDK = $(HL2SDK_ORIG)
HL2PUB = $(HL2SDK_ORIG)/public
HL2LIB = $(HL2SDK_ORIG)/linux_sdk
METAMOD = $(SOURCEMM14)
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_OB)/public
HL2LIB = $(HL2SDK_OB)/linux_sdk
CFLAGS += -DORANGEBOX_BUILD
METAMOD = $(SOURCEMM16)
INCLUDE += -I$(HL2SDK)/public/game/server
SRCDS = $(SRCDS_BASE)/orangebox
BINARY = sourcemod.2.ep2.so
override ENGSET = true
endif
LINK += $(HL2LIB)/tier1_i486.a $(HL2LIB)/mathlib_i486.a vstdlib_i486.so \
tier0_i486.so -lpthread -static-libgcc
INCLUDE_SMSDK = -I$(SMSDK)/public -I$(SMSDK)/public/sourcepawn
INCLUDE_SM16 = -I. -I.. -I$(SOURCEMM16)/sourcehook $(INCLUDE_SMSDK)
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$(METAMOD)/sourcemm -Isystems $(INCLUDE_SMSDK)
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 -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 ###
################################################
ifeq "$(DEBUG)" "true"
BIN_DIR = Debug.$(ENGINE)
CFLAGS += $(C_DEBUG_FLAGS)
else
BIN_DIR = Release.$(ENGINE)
CFLAGS += $(C_OPT_FLAGS)
endif
GCC_VERSION := $(shell $(CPP) -dumpversion >&1 | cut -b1)
ifeq "$(GCC_VERSION)" "4"
CFLAGS += $(C_GCC4_FLAGS)
CPPFLAGS += $(CPP_GCC4_FLAGS)
endif
OBJ_LINUX := $(OBJECTS:%.cpp=$(BIN_DIR)/%.o)
OBJ_LINUX := $(OBJ_LINUX:%.c=$(BIN_DIR)/%.o)
$(BIN_DIR)/%.o: %.cpp
$(CPP) $(INCLUDE) $(CFLAGS) $(CPPFLAGS) -o $@ -c $<
$(BIN_DIR)/%.o: %.c
$(CPP) $(INCLUDE) $(CFLAGS) -o $@ -c $<
all: check
mkdir -p $(BIN_DIR)/systems
mkdir -p $(BIN_DIR)/thread
ln -sf $(SRCDS)/bin/vstdlib_i486.so vstdlib_i486.so;
ln -sf $(SRCDS)/bin/tier0_i486.so tier0_i486.so;
$(MAKE) -f Makefile sourcemod
check:
if [ "$(ENGSET)" == "false" ]; then \
echo "You must supply ENGINE=orangebox or ENGINE=original"; \
exit 1; \
fi
sourcemod: check $(OBJ_LINUX)
$(CPP) $(INCLUDE) $(OBJ_LINUX) $(LINK) -m32 -shared -ldl -lm -o$(BIN_DIR)/$(BINARY)
debug:
$(MAKE) -f Makefile all DEBUG=true
default: all
clean: check
rm -rf $(BIN_DIR)/*.o
rm -rf $(BIN_DIR)/systems/*.o
rm -rf $(BIN_DIR)/thread/*.o
rm -rf $(BIN_DIR)/$(BINARY)

View File

@ -1,220 +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$
*/
#include "MemoryUtils.h"
#include "ShareSys.h"
#ifdef PLATFORM_LINUX
#include <string.h>
#include <elf.h>
#endif
MemoryUtils g_MemUtils;
#if 0
MemoryUtils::MemoryUtils()
{
#ifdef PLATFORM_WINDOWS
SYSTEM_INFO info;
GetSystemInfo(&info);
m_PageSize = info.dwPageSize;
#elif defined PLATFORM_POSIX
m_PageSize = sysconf(_SC_PAGE_SIZE);
#endif
}
#endif
void MemoryUtils::OnSourceModAllInitialized()
{
g_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;
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;
}
bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
{
unsigned long 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<unsigned long>(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<unsigned long>(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);
/* 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];
if (hdr.p_type == PT_LOAD)
{
lib.memorySize += hdr.p_memsz;
}
}
#endif
lib.baseAddress = reinterpret_cast<void *>(baseAddr);
return true;
}

View File

@ -1,60 +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_MEMORYUTILS_H_
#define _INCLUDE_SOURCEMOD_MEMORYUTILS_H_
#include <IMemoryUtils.h>
#include "sm_globals.h"
using namespace SourceMod;
struct DynLibInfo
{
void *baseAddress;
size_t memorySize;
};
class MemoryUtils :
public IMemoryUtils,
public SMGlobalClass
{
public: // SMGlobalClass
void OnSourceModAllInitialized();
public: // IMemoryUtils
void *FindPattern(const void *libPtr, const char *pattern, size_t len);
private:
bool GetLibraryInfo(const void *libPtr, DynLibInfo &lib);
};
extern MemoryUtils g_MemUtils;
#endif // _INCLUDE_SOURCEMOD_MEMORYUTILS_H_

View File

@ -1,802 +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$
*/
#include <time.h>
#include <stdarg.h>
#include <stdlib.h>
#include "MenuManager.h"
#include "MenuVoting.h"
#include "sm_stringutil.h"
#include "sourcemm_api.h"
#include "PlayerManager.h"
#include "MenuStyle_Valve.h"
#include "ShareSys.h"
#include "HandleSys.h"
#include "sourcemm_api.h"
#include "Translator.h"
MenuManager g_Menus;
VoteMenuHandler s_VoteHandler;
ConVar sm_menu_sounds("sm_menu_sounds", "1", 0, "Sets whether SourceMod menus play trigger sounds");
MenuManager::MenuManager()
{
m_Styles.push_back(&g_ValveMenuStyle);
SetDefaultStyle(&g_ValveMenuStyle);
}
void MenuManager::OnSourceModAllInitialized()
{
g_ShareSys.AddInterface(NULL, this);
HandleAccess access;
g_HandleSys.InitAccessDefaults(NULL, &access);
/* Deny cloning to menus */
access.access[HandleAccess_Clone] = HANDLE_RESTRICT_OWNER|HANDLE_RESTRICT_IDENTITY;
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 = g_HandleSys.CreateType("IMenuStyle", this, 0, NULL, &access, g_pCoreIdent, NULL);
}
void MenuManager::OnSourceModAllShutdown()
{
g_HandleSys.RemoveType(m_MenuType, g_pCoreIdent);
g_HandleSys.RemoveType(m_StyleType, g_pCoreIdent);
}
void MenuManager::OnHandleDestroy(HandleType_t type, void *object)
{
if (type == m_MenuType)
{
IBaseMenu *menu = (IBaseMenu *)object;
menu->Destroy(false);
}
else if (type == m_StyleType)
{
/* Do nothing */
}
}
bool MenuManager::GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize)
{
if (type == m_MenuType)
{
*pSize = ((IBaseMenu *)object)->GetApproxMemUsage();
return true;
}
else
{
*pSize = ((IMenuStyle *)object)->GetApproxMemUsage();
return true;
}
return false;
}
Handle_t MenuManager::CreateMenuHandle(IBaseMenu *menu, IdentityToken_t *pOwner)
{
if (m_MenuType == NO_HANDLE_TYPE)
{
return BAD_HANDLE;
}
return g_HandleSys.CreateHandle(m_MenuType, menu, pOwner, g_pCoreIdent, NULL);
}
Handle_t MenuManager::CreateStyleHandle(IMenuStyle *style)
{
if (m_StyleType == NO_HANDLE_TYPE)
{
return BAD_HANDLE;
}
return g_HandleSys.CreateHandle(m_StyleType, style, g_pCoreIdent, g_pCoreIdent, NULL);
}
HandleError MenuManager::ReadMenuHandle(Handle_t handle, IBaseMenu **menu)
{
HandleSecurity sec;
sec.pIdentity = g_pCoreIdent;
sec.pOwner = NULL;
return g_HandleSys.ReadHandle(handle, m_MenuType, &sec, (void **)menu);
}
HandleError MenuManager::ReadStyleHandle(Handle_t handle, IMenuStyle **style)
{
HandleSecurity sec;
sec.pIdentity = g_pCoreIdent;
sec.pOwner = g_pCoreIdent;
return g_HandleSys.ReadHandle(handle, m_StyleType, &sec, (void **)style);
}
bool MenuManager::SetDefaultStyle(IMenuStyle *style)
{
if (!style)
{
return false;
}
m_pDefaultStyle = style;
return true;
}
IMenuStyle *MenuManager::GetStyle(unsigned int index)
{
if (index >= GetStyleCount())
{
return NULL;
}
return m_Styles[index];
}
void MenuManager::AddStyle(IMenuStyle *style)
{
m_Styles.push_back(style);
}
unsigned int MenuManager::GetStyleCount()
{
return (unsigned int)m_Styles.size();
}
IMenuStyle *MenuManager::FindStyleByName(const char *name)
{
unsigned int count = GetStyleCount();
for (unsigned int i=0; i<count; i++)
{
IMenuStyle *ptr = GetStyle(i);
if (strcasecmp(ptr->GetStyleName(), name) == 0)
{
return ptr;
}
}
return NULL;
}
inline bool IsSlotItem(IMenuPanel *display,
unsigned int style)
{
if (!display->CanDrawItem(style))
{
return false;
}
if ((style & ITEMDRAW_IGNORE) == ITEMDRAW_IGNORE)
{
return false;
}
if (style & ITEMDRAW_RAWLINE)
{
return false;
}
return true;
}
IMenuPanel *MenuManager::RenderMenu(int client, menu_states_t &md, ItemOrder order)
{
IBaseMenu *menu = md.menu;
if (!menu)
{
return NULL;
}
struct
{
unsigned int position;
ItemDrawInfo draw;
} drawItems[10];
/* Figure out how many items to draw */
IMenuStyle *style = menu->GetDrawStyle();
unsigned int pgn = menu->GetPagination();
unsigned int maxItems = style->GetMaxPageItems();
bool exitButton = (menu->GetMenuOptionFlags() & MENUFLAG_BUTTON_EXIT) == MENUFLAG_BUTTON_EXIT;
if (pgn != MENU_NO_PAGINATION)
{
maxItems = pgn;
}
else if (exitButton)
{
maxItems--;
}
/* This is very not allowed! */
if (maxItems < 2)
{
return NULL;
}
unsigned int totalItems = menu->GetItemCount();
unsigned int startItem = 0;
/* For pagination, find the starting point. */
if (pgn != MENU_NO_PAGINATION)
{
if (order == ItemOrder_Ascending)
{
startItem = md.lastItem;
/* This shouldn't happen with well-coded menus.
* If the item is out of bounds, switch the order to
* Items_Descending and make us start from the top.
*/
if (startItem >= totalItems)
{
startItem = totalItems - 1;
order = ItemOrder_Descending;
}
}
else if (order == ItemOrder_Descending)
{
startItem = md.firstItem;
/* This shouldn't happen with well-coded menus.
* If searching backwards doesn't give us enough room,
* start from the beginning and change to ascending.
*/
if (startItem <= maxItems)
{
startItem = 0;
order = ItemOrder_Ascending;
}
}
}
/* Get our Display pointer and initialize some crap */
IMenuPanel *panel = menu->CreatePanel();
IMenuHandler *mh = md.mh;
bool foundExtra = false;
unsigned int extraItem = 0;
if (panel == NULL)
{
return NULL;
}
/**
* We keep searching until:
* 1) There are no more items
* 2) We reach one OVER the maximum number of slot items
* 3) We have reached maxItems and pagination is MENU_NO_PAGINATION
*/
unsigned int i = startItem;
unsigned int foundItems = 0;
while (totalItems)
{
ItemDrawInfo &dr = drawItems[foundItems].draw;
/* Is the item valid? */
if (menu->GetItemInfo(i, &dr) != NULL)
{
/* Ask the user to change the style, if necessary */
mh->OnMenuDrawItem(menu, client, i, dr.style);
/* Check if it's renderable */
if (IsSlotItem(panel, dr.style))
{
/* If we've already found the max number of items,
* This means we should just cancel out and log our
* "last item."
*/
if (foundItems >= maxItems)
{
foundExtra = true;
extraItem = i;
break;
}
drawItems[foundItems++].position = i;
}
}
/* If there's no pagination, stop once the menu is full. */
if (pgn == MENU_NO_PAGINATION)
{
/* If we've filled up, then stop */
if (foundItems >= maxItems)
{
break;
}
}
/* If we're descending and this is the first item, stop */
if (order == ItemOrder_Descending)
{
if (i == 0)
{
break;
}
i--;
}
/* If we're ascending and this is the last item, stop */
else if (order == ItemOrder_Ascending)
{
if (i >= totalItems - 1)
{
break;
}
i++;
}
}
/* There were no items to draw! */
if (!foundItems)
{
panel->DeleteThis();
return NULL;
}
bool displayPrev = false;
bool displayNext = false;
/* This is an annoying process.
* Skip it for non-paginated menus, which get special treatment.
*/
if (pgn != MENU_NO_PAGINATION)
{
if (foundExtra)
{
if (order == ItemOrder_Descending)
{
displayPrev = true;
md.firstItem = extraItem;
}
else if (order == ItemOrder_Ascending)
{
displayNext = true;
md.lastItem = extraItem;
}
}
unsigned int lastItem = 0;
ItemDrawInfo dr;
/* Find the last feasible item to search from. */
if (order == ItemOrder_Descending)
{
lastItem = drawItems[0].position;
if (lastItem >= totalItems - 1)
{
goto skip_search;
}
while (++lastItem < totalItems)
{
if (menu->GetItemInfo(lastItem, &dr) != NULL)
{
mh->OnMenuDrawItem(menu, client, lastItem, dr.style);
if (IsSlotItem(panel, dr.style))
{
displayNext = true;
md.lastItem = lastItem;
break;
}
}
}
}
else if (order == ItemOrder_Ascending)
{
lastItem = drawItems[0].position;
if (lastItem == 0)
{
goto skip_search;
}
lastItem--;
while (lastItem != 0)
{
if (menu->GetItemInfo(lastItem, &dr) != NULL)
{
mh->OnMenuDrawItem(menu, client, lastItem, dr.style);
if (IsSlotItem(panel, dr.style))
{
displayPrev = true;
md.firstItem = lastItem;
break;
}
}
lastItem--;
}
}
}
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 (order == ItemOrder_Ascending)
{
md.item_on_page = drawItems[0].position;
for (unsigned int i = 0; i < foundItems; i++)
{
ItemDrawInfo &dr = drawItems[i].draw;
if ((position = mh->OnMenuDisplayItem(menu, client, panel, drawItems[i].position, dr)) == 0)
{
position = panel->DrawItem(dr);
}
if (position != 0)
{
slots[position].item = drawItems[i].position;
if ((dr.style & ITEMDRAW_DISABLED) == ITEMDRAW_DISABLED)
{
slots[position].type = ItemSel_None;
}
else
{
slots[position].type = ItemSel_Item;
}
}
}
}
else if (order == ItemOrder_Descending)
{
unsigned int i = foundItems;
/* NOTE: There will always be at least one item because
* of the check earlier.
*/
md.item_on_page = drawItems[foundItems - 1].position;
while (i--)
{
ItemDrawInfo &dr = drawItems[i].draw;
if ((position = mh->OnMenuDisplayItem(menu, client, panel, drawItems[i].position, dr)) == 0)
{
position = panel->DrawItem(dr);
}
if (position != 0)
{
slots[position].item = drawItems[i].position;
if ((dr.style & ITEMDRAW_DISABLED) == ITEMDRAW_DISABLED)
{
slots[position].type = ItemSel_None;
}
else
{
slots[position].type = ItemSel_Item;
}
}
}
}
/* Now, we need to check if we need to add anything extra */
if (pgn != MENU_NO_PAGINATION || exitButton)
{
bool canDrawDisabled = panel->CanDrawItem(ITEMDRAW_DISABLED|ITEMDRAW_CONTROL);
bool exitBackButton = false;
char text[50];
if (pgn != MENU_NO_PAGINATION
&& (menu->GetMenuOptionFlags() & MENUFLAG_BUTTON_EXITBACK) == MENUFLAG_BUTTON_EXITBACK)
{
exitBackButton = true;
}
/* Calculate how many items we are allowed for control stuff */
unsigned int padding = style->GetMaxPageItems() - maxItems;
/* Add the number of available slots */
padding += (maxItems - foundItems);
/* Someday, if we are able to re-enable this, we will be very lucky men. */
#if 0
if (!style->FeatureExists(MenuStyleFeature_ImplicitExit))
{
#endif
/* Even if we don't draw an exit button, we invalidate the slot. */
padding--;
#if 0
} else {
/* Otherwise, we don't draw anything and leave the slot available */
exitButton = false;
}
#endif
if (pgn != MENU_NO_PAGINATION)
{
/* Subtract two slots for the displayNext/displayPrev padding */
padding -= 2;
}
/* If we have an "Exit Back" button and the space to draw it, do so. */
if (exitBackButton)
{
if (!displayPrev)
{
displayPrev = true;
}
else
{
exitBackButton = false;
}
}
/**
* We allow next/prev to be undrawn if neither exists.
* Thus, we only need padding if one of them will be drawn,
* or the exit button will be drawn.
*/
ItemDrawInfo padItem(NULL, ITEMDRAW_SPACER);
if (exitButton || (displayNext || displayPrev))
{
/* If there are no control options,
* Instead just pad with invisible slots.
*/
if (!displayPrev && !displayPrev)
{
padItem.style = ITEMDRAW_NOTEXT;
}
/* Add spacers so we can pad to the end */
for (unsigned int i=0; i<padding; i++)
{
position = panel->DrawItem(padItem);
slots[position].type = ItemSel_None;
}
}
/* Put a fake spacer before control stuff, if possible */
if ((displayPrev || displayNext) || exitButton)
{
ItemDrawInfo draw("", ITEMDRAW_RAWLINE|ITEMDRAW_SPACER);
panel->DrawItem(draw);
}
ItemDrawInfo dr(text, 0);
/**
* If we have one or the other, we need to have spacers for both.
*/
if (pgn != MENU_NO_PAGINATION)
{
if (displayPrev || displayNext)
{
/* PREVIOUS */
ItemDrawInfo padCtrlItem(NULL, ITEMDRAW_SPACER|ITEMDRAW_CONTROL);
if (displayPrev || canDrawDisabled)
{
if (exitBackButton)
{
if (!CoreTranslate(text, sizeof(text), "%T", 2, NULL, "Back", &client))
{
UTIL_Format(text, sizeof(text), "Back");
}
dr.style = ITEMDRAW_CONTROL;
position = panel->DrawItem(dr);
slots[position].type = ItemSel_ExitBack;
}
else
{
if (!CoreTranslate(text, sizeof(text), "%T", 2, NULL, "Previous", &client))
{
UTIL_Format(text, sizeof(text), "Previous");
}
dr.style = (displayPrev ? 0 : ITEMDRAW_DISABLED)|ITEMDRAW_CONTROL;
position = panel->DrawItem(dr);
slots[position].type = ItemSel_Back;
}
}
else if (displayNext || exitButton)
{
/* If we can't display this, and there is an exit button,
* we need to pad!
*/
position = panel->DrawItem(padCtrlItem);
slots[position].type = ItemSel_None;
}
/* NEXT */
if (displayNext || canDrawDisabled)
{
if (!CoreTranslate(text, sizeof(text), "%T", 2, NULL, "Next", &client))
{
UTIL_Format(text, sizeof(text), "Next");
}
dr.style = (displayNext ? 0 : ITEMDRAW_DISABLED)|ITEMDRAW_CONTROL;
position = panel->DrawItem(dr);
slots[position].type = ItemSel_Next;
}
else if (exitButton)
{
/* If we can't display this,
* but there is an "exit" button, we need to pad!
*/
position = panel->DrawItem(padCtrlItem);
slots[position].type = ItemSel_None;
}
}
else
{
/* Otherwise, bump to two slots! */
ItemDrawInfo numBump(NULL, ITEMDRAW_NOTEXT);
position = panel->DrawItem(numBump);
slots[position].type = ItemSel_None;
position = panel->DrawItem(numBump);
slots[position].type = ItemSel_None;
}
}
/* EXIT */
if (exitButton)
{
if (!CoreTranslate(text, sizeof(text), "%T", 2, NULL, "Exit", &client))
{
UTIL_Format(text, sizeof(text), "Exit");
}
dr.style = ITEMDRAW_CONTROL;
position = panel->DrawItem(dr);
slots[position].type = ItemSel_Exit;
}
}
/* Lastly, fill in any slots we could have missed */
for (unsigned int i = position + 1; i < 10; i++)
{
slots[i].type = ItemSel_None;
}
/* Do title stuff */
mh->OnMenuDisplay(menu, client, panel);
panel->DrawTitle(menu->GetDefaultTitle(), true);
return panel;
}
IMenuStyle *MenuManager::GetDefaultStyle()
{
return m_pDefaultStyle;
}
bool MenuManager::MenuSoundsEnabled()
{
return (sm_menu_sounds.GetInt() != 0);
}
ConfigResult MenuManager::OnSourceModConfigChanged(const char *key,
const char *value,
ConfigSource source,
char *error,
size_t maxlength)
{
if (strcmp(key, "MenuItemSound") == 0)
{
m_SelectSound.assign(value);
return ConfigResult_Accept;
} else if (strcmp(key, "MenuExitBackSound") == 0) {
m_ExitBackSound.assign(value);
return ConfigResult_Accept;
} else if (strcmp(key, "MenuExitSound") == 0) {
m_ExitSound.assign(value);
return ConfigResult_Accept;
}
return ConfigResult_Ignore;
}
const char *MenuManager::GetMenuSound(ItemSelection sel)
{
const char *sound = NULL;
switch (sel)
{
case ItemSel_Back:
case ItemSel_Next:
case ItemSel_Item:
{
if (m_SelectSound.size() > 0)
{
sound = m_SelectSound.c_str();
}
break;
}
case ItemSel_ExitBack:
{
if (m_ExitBackSound.size() > 0)
{
sound = m_ExitBackSound.c_str();
}
break;
}
case ItemSel_Exit:
{
if (m_ExitSound.size() > 0)
{
sound = m_ExitSound.c_str();
}
break;
}
default:
{
break;
}
}
return sound;
}
void MenuManager::OnSourceModLevelChange(const char *mapName)
{
if (m_SelectSound.size() > 0)
{
enginesound->PrecacheSound(m_SelectSound.c_str(), true);
}
if (m_ExitBackSound.size() > 0)
{
enginesound->PrecacheSound(m_ExitBackSound.c_str(), true);
}
if (m_ExitSound.size() > 0)
{
enginesound->PrecacheSound(m_ExitSound.c_str(), true);
}
}
void MenuManager::CancelMenu(IBaseMenu *menu)
{
if (s_VoteHandler.GetCurrentMenu() == menu
&& !s_VoteHandler.IsCancelling())
{
s_VoteHandler.CancelVoting();
return;
}
menu->Cancel();
}
bool MenuManager::StartVote(IBaseMenu *menu, unsigned int num_clients, int clients[], unsigned int max_time, unsigned int flags)
{
return s_VoteHandler.StartVote(menu, num_clients, clients, max_time, flags);
}
bool MenuManager::IsVoteInProgress()
{
return s_VoteHandler.IsVoteInProgress();
}
void MenuManager::CancelVoting()
{
s_VoteHandler.CancelVoting();
}
unsigned int MenuManager::GetRemainingVoteDelay()
{
return s_VoteHandler.GetRemainingVoteDelay();
}
bool MenuManager::IsClientInVotePool(int client)
{
return s_VoteHandler.IsClientInVotePool(client);
}
bool MenuManager::RedrawClientVoteMenu(int client)
{
return s_VoteHandler.RedrawToClient(client);
}

View File

@ -1,119 +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_MENUMANAGER_H_
#define _INCLUDE_SOURCEMOD_MENUMANAGER_H_
#include <IMenuManager.h>
#include <sh_vector.h>
#include <sh_stack.h>
#include <sh_list.h>
#include <sh_string.h>
#include "sm_memtable.h"
#include "sm_globals.h"
using namespace SourceMod;
using namespace SourceHook;
class MenuManager :
public IMenuManager,
public SMGlobalClass,
public IHandleTypeDispatch
{
friend class BroadcastHandler;
friend class VoteHandler;
friend class CBaseMenu;
friend class BaseMenuStyle;
public:
MenuManager();
public: //SMGlobalClass
void OnSourceModAllInitialized();
void OnSourceModAllShutdown();
ConfigResult OnSourceModConfigChanged(const char *key,
const char *value,
ConfigSource source,
char *error,
size_t maxlength);
void OnSourceModLevelChange(const char *mapName);
public: //IMenuManager
virtual const char *GetInterfaceName()
{
return SMINTERFACE_MENUMANAGER_NAME;
}
virtual unsigned int GetInterfaceVersion()
{
return SMINTERFACE_MENUMANAGER_VERSION;
}
public:
unsigned int GetStyleCount();
IMenuStyle *GetStyle(unsigned int index);
IMenuStyle *FindStyleByName(const char *name);
IMenuStyle *GetDefaultStyle();
void AddStyle(IMenuStyle *style);
bool SetDefaultStyle(IMenuStyle *style);
IMenuPanel *RenderMenu(int client, menu_states_t &states, ItemOrder order);
void CancelMenu(IBaseMenu *menu);
bool StartVote(IBaseMenu *menu,
unsigned int num_clients,
int clients[],
unsigned int max_time,
unsigned int flags=0);
bool IsVoteInProgress();
void CancelVoting();
unsigned int GetRemainingVoteDelay();
bool IsClientInVotePool(int client);
bool RedrawClientVoteMenu(int client);
public: //IHandleTypeDispatch
void OnHandleDestroy(HandleType_t type, void *object);
bool GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize);
public:
HandleError ReadMenuHandle(Handle_t handle, IBaseMenu **menu);
HandleError ReadStyleHandle(Handle_t handle, IMenuStyle **style);
public:
bool MenuSoundsEnabled();
const char *GetMenuSound(ItemSelection sel);
protected:
Handle_t CreateMenuHandle(IBaseMenu *menu, IdentityToken_t *pOwner);
Handle_t CreateStyleHandle(IMenuStyle *style);
private:
int m_ShowMenu;
IMenuStyle *m_pDefaultStyle;
CVector<IMenuStyle *> m_Styles;
HandleType_t m_StyleType;
HandleType_t m_MenuType;
String m_SelectSound;
String m_ExitBackSound;
String m_ExitSound;
};
extern MenuManager g_Menus;
#endif //_INCLUDE_SOURCEMOD_MENUMANAGER_H_

View File

@ -1,837 +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$
*/
#include <stdarg.h>
#include "sm_stringutil.h"
#include "MenuStyle_Base.h"
#include "PlayerManager.h"
#include "MenuManager.h"
#include "HandleSys.h"
#include "CellRecipientFilter.h"
#if defined MENU_DEBUG
#include "Logger.h"
#endif
BaseMenuStyle::BaseMenuStyle() : m_WatchList(256), m_hHandle(BAD_HANDLE)
{
}
Handle_t BaseMenuStyle::GetHandle()
{
/* Don't create the handle until we need it */
if (m_hHandle == BAD_HANDLE)
{
m_hHandle = g_Menus.CreateStyleHandle(this);
}
return m_hHandle;
}
void BaseMenuStyle::AddClientToWatch(int client)
{
#if defined MENU_DEBUG
g_Logger.LogMessage("[SM_MENU] AddClientToWatch(%d)", client);
#endif
m_WatchList.push_back(client);
}
void BaseMenuStyle::RemoveClientFromWatch(int client)
{
#if defined MENU_DEBUG
g_Logger.LogMessage("[SM_MENU] RemoveClientFromWatch(%d)", client);
#endif
m_WatchList.remove(client);
}
void BaseMenuStyle::_CancelClientMenu(int client, MenuCancelReason reason, bool bAutoIgnore/* =false */)
{
#if defined MENU_DEBUG
g_Logger.LogMessage("[SM_MENU] _CancelClientMenu() (client %d) (bAutoIgnore %d) (reason %d)", client, bAutoIgnore, reason);
#endif
CBaseMenuPlayer *player = GetMenuPlayer(client);
menu_states_t &states = player->states;
bool bOldIgnore = player->bAutoIgnore;
if (bAutoIgnore)
{
player->bAutoIgnore = true;
}
/* Save states */
IMenuHandler *mh = states.mh;
IBaseMenu *menu = states.menu;
/* Clear menu */
player->bInMenu = false;
if (player->menuHoldTime)
{
RemoveClientFromWatch(client);
}
/* Fire callbacks */
mh->OnMenuCancel(menu, client, reason);
/* Only fire end if there's a valid menu */
if (menu)
{
mh->OnMenuEnd(menu, MenuEnd_Cancelled);
}
if (bAutoIgnore)
{
player->bAutoIgnore = bOldIgnore;
}
}
void BaseMenuStyle::CancelMenu(CBaseMenu *menu)
{
#if defined MENU_DEBUG
g_Logger.LogMessage("[SM_MENU] CancelMenu() (menu %p)", menu);
#endif
int maxClients = g_Players.GetMaxClients();
for (int i=1; i<=maxClients; i++)
{
CBaseMenuPlayer *player = GetMenuPlayer(i);
if (player->bInMenu)
{
menu_states_t &states = player->states;
if (states.menu == menu)
{
_CancelClientMenu(i, MenuCancel_Interrupted);
}
}
}
}
bool BaseMenuStyle::CancelClientMenu(int client, bool autoIgnore)
{
#if defined MENU_DEBUG
g_Logger.LogMessage("[SM_MENU] CancelClientMenu() (client %d) (bAutoIgnore %d)", client, autoIgnore);
#endif
if (client < 1 || client > g_Players.MaxClients())
{
return false;
}
CBaseMenuPlayer *player = GetMenuPlayer(client);
if (!player->bInMenu)
{
return false;
}
_CancelClientMenu(client, MenuCancel_Interrupted, autoIgnore);
return true;
}
MenuSource BaseMenuStyle::GetClientMenu(int client, void **object)
{
if (client < 1 || client > g_Players.GetMaxClients())
{
return MenuSource_None;
}
CBaseMenuPlayer *player = GetMenuPlayer(client);
if (player->bInMenu)
{
IBaseMenu *menu;
if ((menu=player->states.menu) != NULL)
{
if (object)
{
*object = menu;
}
return MenuSource_BaseMenu;
}
return MenuSource_Display;
} else if (player->bInExternMenu) {
if (player->menuHoldTime != 0
&& (gpGlobals->curtime > player->menuStartTime + player->menuHoldTime))
{
player->bInExternMenu = false;
return MenuSource_None;
}
return MenuSource_External;
}
return MenuSource_None;
}
void BaseMenuStyle::OnClientDisconnected(int client)
{
#if defined MENU_DEBUG
g_Logger.LogMessage("[SM_MENU] OnClientDisconnected(%d)", client);
#endif
CBaseMenuPlayer *player = GetMenuPlayer(client);
if (!player->bInMenu)
{
return;
}
_CancelClientMenu(client, MenuCancel_Disconnected, true);
player->bInMenu = false;
player->bInExternMenu = false;
}
static int do_lookup[256];
void BaseMenuStyle::ProcessWatchList()
{
if (!m_WatchList.size())
{
return;
}
#if defined MENU_DEBUG
g_Logger.LogMessage("BaseMenuStyle::ProcessWatchList(%d,%d,%d,%d,%d,%p)",
m_WatchList.m_Size,
m_WatchList.m_FirstLink,
m_WatchList.m_FreeNodes,
m_WatchList.m_LastLink,
m_WatchList.m_MaxSize,
m_WatchList.m_Nodes);
#endif
unsigned int total = 0;
for (FastLink<int>::iterator iter=m_WatchList.begin(); iter!=m_WatchList.end(); ++iter)
{
do_lookup[total++] = (*iter);
}
#if defined MENU_DEBUG
if (total)
{
g_Logger.LogMessage("[SM_MENU] ProcessWatchList() found %d clients", total);
}
#endif
int client;
CBaseMenuPlayer *player;
float curTime = gpGlobals->curtime;
for (unsigned int i=0; i<total; i++)
{
client = do_lookup[i];
player = GetMenuPlayer(client);
#if defined MENU_DEBUG
g_Logger.LogMessage("[SM_MENU] ProcessWatchList() (client %d) (bInMenu %d) (menuHoldTime %d) (curTime %f) (menuStartTime %f)",
client,
player->bInMenu,
player->menuHoldTime,
curTime,
player->menuStartTime);
#endif
if (!player->bInMenu || !player->menuHoldTime)
{
#if defined MENU_DEBUG
g_Logger.LogMessage("[SM_MENU] ProcessWatchList() removing client %d", client);
#endif
m_WatchList.remove(client);
continue;
}
if (curTime > player->menuStartTime + player->menuHoldTime)
{
_CancelClientMenu(client, MenuCancel_Timeout, false);
}
}
}
void BaseMenuStyle::ClientPressedKey(int client, unsigned int key_press)
{
#if defined MENU_DEBUG
g_Logger.LogMessage("[SM_MENU] ClientPressedKey() (client %d) (key_press %d)", client, key_press);
#endif
CBaseMenuPlayer *player = GetMenuPlayer(client);
/* First question: Are we in a menu? */
if (!player->bInMenu)
{
return;
}
bool cancel = false;
unsigned int item = 0;
MenuCancelReason reason = MenuCancel_Exit;
MenuEndReason end_reason = MenuEnd_Selected;
menu_states_t &states = player->states;
/* Save variables */
IMenuHandler *mh = states.mh;
IBaseMenu *menu = states.menu;
unsigned int item_on_page = states.item_on_page;
assert(mh != NULL);
if (menu == NULL)
{
item = key_press;
} else if (key_press < 1 || key_press > GetMaxPageItems()) {
cancel = true;
} else {
ItemSelection type = states.slots[key_press].type;
/* Check if we should play a sound about the type */
if (g_Menus.MenuSoundsEnabled() &&
(!menu || (menu->GetMenuOptionFlags() & MENUFLAG_NO_SOUND) != MENUFLAG_NO_SOUND))
{
CellRecipientFilter filter;
cell_t clients[1];
clients[0] = client;
filter.Initialize(clients, 1);
const char *sound = g_Menus.GetMenuSound(type);
if (sound != NULL)
{
edict_t *pEdict = engine->PEntityOfEntIndex(client);
if (pEdict)
{
ICollideable *pCollideable = pEdict->GetCollideable();
if (pCollideable)
{
const Vector & pos = pCollideable->GetCollisionOrigin();
enginesound->EmitSound(filter,
client,
CHAN_AUTO,
sound,
VOL_NORM,
ATTN_NORM,
0,
PITCH_NORM,
&pos);
}
}
}
}
/* For navigational items, we're going to redisplay */
if (type == ItemSel_Back)
{
if (!RedoClientMenu(client, ItemOrder_Descending))
{
cancel = true;
reason = MenuCancel_NoDisplay;
end_reason = MenuEnd_Cancelled;
} else {
return;
}
} else if (type == ItemSel_Next) {
if (!RedoClientMenu(client, ItemOrder_Ascending))
{
cancel = true; /* I like Saltines. */
reason = MenuCancel_NoDisplay;
end_reason = MenuEnd_Cancelled;
} else {
return;
}
} else if (type == ItemSel_Exit || type == ItemSel_None) {
cancel = true;
reason = MenuCancel_Exit;
end_reason = MenuEnd_Exit;
} else if (type == ItemSel_ExitBack) {
cancel = true;
reason = MenuCancel_ExitBack;
end_reason = MenuEnd_ExitBack;
} else {
item = states.slots[key_press].item;
}
}
/* Clear states */
player->bInMenu = false;
if (player->menuHoldTime)
{
RemoveClientFromWatch(client);
}
if (cancel)
{
mh->OnMenuCancel(menu, client, reason);
} else {
mh->OnMenuSelect(menu, client, item);
if (mh->GetMenuAPIVersion2() >= 13)
{
mh->OnMenuSelect2(menu, client, item, item_on_page);
}
}
/* Only fire end for valid menus */
if (menu)
{
mh->OnMenuEnd(menu, end_reason);
}
}
bool BaseMenuStyle::DoClientMenu(int client, IMenuPanel *menu, IMenuHandler *mh, unsigned int time)
{
#if defined MENU_DEBUG
g_Logger.LogMessage("[SM_MENU] DoClientMenu() (client %d) (panel %p) (mh %p) (time %d)",
client,
menu,
mh,
time);
#endif
CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
if (!pPlayer || pPlayer->IsFakeClient() || !pPlayer->IsInGame())
{
return false;
}
CBaseMenuPlayer *player = GetMenuPlayer(client);
if (player->bAutoIgnore)
{
return false;
}
/* For the duration of this, we are going to totally ignore whether
* the player is already in a menu or not (except to cancel the old one).
* Instead, we are simply going to ignore any further menu displays, so
* this display can't be interrupted.
*/
player->bAutoIgnore = true;
/* Cancel any old menus */
menu_states_t &states = player->states;
if (player->bInMenu)
{
_CancelClientMenu(client, MenuCancel_Interrupted, true);
}
states.firstItem = 0;
states.lastItem = 0;
states.menu = NULL;
states.mh = mh;
states.apiVers = SMINTERFACE_MENUMANAGER_VERSION;
player->bInMenu = true;
player->bInExternMenu = false;
player->menuStartTime = gpGlobals->curtime;
player->menuHoldTime = time;
if (time)
{
AddClientToWatch(client);
}
/* Draw the display */
SendDisplay(client, menu);
/* We can be interrupted again! */
player->bAutoIgnore = false;
return true;
}
bool BaseMenuStyle::DoClientMenu(int client,
CBaseMenu *menu,
unsigned int first_item,
IMenuHandler *mh,
unsigned int time)
{
#if defined MENU_DEBUG
g_Logger.LogMessage("[SM_MENU] DoClientMenu() (client %d) (menu %p) (mh %p) (time %d)",
client,
menu,
mh,
time);
#endif
mh->OnMenuStart(menu);
CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
if (!pPlayer || pPlayer->IsFakeClient() || !pPlayer->IsInGame())
{
#if defined MENU_DEBUG
g_Logger.LogMessage("[SM_MENU] DoClientMenu(): Failed to display to client %d", client);
#endif
mh->OnMenuCancel(menu, client, MenuCancel_NoDisplay);
mh->OnMenuEnd(menu, MenuEnd_Cancelled);
return false;
}
CBaseMenuPlayer *player = GetMenuPlayer(client);
if (player->bAutoIgnore)
{
#if defined MENU_DEBUG
g_Logger.LogMessage("[SM_MENU] DoClientMenu(): Client %d is autoIgnoring", client);
#endif
mh->OnMenuCancel(menu, client, MenuCancel_NoDisplay);
mh->OnMenuEnd(menu, MenuEnd_Cancelled);
return false;
}
/* For the duration of this, we are going to totally ignore whether
* the player is already in a menu or not (except to cancel the old one).
* Instead, we are simply going to ignore any further menu displays, so
* this display can't be interrupted.
*/
player->bAutoIgnore = true;
/* Cancel any old menus */
menu_states_t &states = player->states;
if (player->bInMenu)
{
#if defined MENU_DEBUG
g_Logger.LogMessage("[SM_MENU] DoClientMenu(): Cancelling old menu to client %d", client);
#endif
_CancelClientMenu(client, MenuCancel_Interrupted, true);
}
states.firstItem = 0;
states.lastItem = first_item;
states.menu = menu;
states.mh = mh;
states.apiVers = SMINTERFACE_MENUMANAGER_VERSION;
IMenuPanel *display = g_Menus.RenderMenu(client, states, ItemOrder_Ascending);
if (!display)
{
#if defined MENU_DEBUG
g_Logger.LogMessage("[SM_MENU] DoClientMenu(): Failed to render to client %d", client);
#endif
player->bAutoIgnore = false;
player->bInMenu = false;
mh->OnMenuCancel(menu, client, MenuCancel_NoDisplay);
mh->OnMenuEnd(menu, MenuEnd_Cancelled);
return false;
}
/* Finally, set our states */
player->bInMenu = true;
player->bInExternMenu = false;
player->menuStartTime = gpGlobals->curtime;
player->menuHoldTime = time;
if (time)
{
AddClientToWatch(client);
}
/* Draw the display */
SendDisplay(client, display);
/* Free the display pointer */
display->DeleteThis();
/* We can be interrupted again! */
player->bAutoIgnore = false;
#if defined MENU_DEBUG
g_Logger.LogMessage("[SM_MENU] DoClientMenu() finished successfully (client %d)", client);
#endif
return true;
}
bool BaseMenuStyle::RedoClientMenu(int client, ItemOrder order)
{
#if defined MENU_DEBUG
g_Logger.LogMessage("[SM_MENU] RedoClientMenu() (client %d) (order %d)", client, order);
#endif
CBaseMenuPlayer *player = GetMenuPlayer(client);
menu_states_t &states = player->states;
player->bAutoIgnore = true;
IMenuPanel *display = g_Menus.RenderMenu(client, states, order);
if (!display)
{
#if defined MENU_DEBUG
g_Logger.LogMessage("[SM_MENU] RedoClientMenu(): Failed to render menu");
#endif
if (player->menuHoldTime)
{
RemoveClientFromWatch(client);
}
player->bAutoIgnore = false;
return false;
}
SendDisplay(client, display);
display->DeleteThis();
player->bAutoIgnore = false;
#if defined MENU_DEBUG
g_Logger.LogMessage("[SM_MENU] RedoClientMenu(): Succeeded to client %d", client);
#endif
return true;
}
CBaseMenu::CBaseMenu(IMenuHandler *pHandler, IMenuStyle *pStyle, IdentityToken_t *pOwner) :
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)
{
}
CBaseMenu::~CBaseMenu()
{
}
Handle_t CBaseMenu::GetHandle()
{
if (!m_hHandle)
{
m_hHandle = g_Menus.CreateMenuHandle(this, m_pOwner);
}
return m_hHandle;
}
bool CBaseMenu::AppendItem(const char *info, const ItemDrawInfo &draw)
{
if (m_Pagination == (unsigned)MENU_NO_PAGINATION
&& m_items.size() >= m_pStyle->GetMaxPageItems())
{
return false;
}
CItem item;
item.infoString = m_Strings.AddString(info);
if (draw.display)
{
item.displayString = m_Strings.AddString(draw.display);
}
item.style = draw.style;
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.size() >= m_pStyle->GetMaxPageItems())
{
return false;
}
if (position >= m_items.size())
{
return false;
}
CItem item;
item.infoString = m_Strings.AddString(info);
if (draw.display)
{
item.displayString = m_Strings.AddString(draw.display);
}
item.style = draw.style;
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.size())
{
return false;
}
m_items.erase(m_items.iterAt(position));
if (m_items.size() == 0)
{
m_Strings.Reset();
}
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.size())
{
return NULL;
}
if (draw)
{
draw->display = m_Strings.GetString(m_items[position].displayString);
draw->style = m_items[position].style;
}
return m_Strings.GetString(m_items[position].infoString);
}
unsigned int CBaseMenu::GetItemCount()
{
return m_items.size();
}
bool CBaseMenu::SetPagination(unsigned int itemsPerPage)
{
if (itemsPerPage > 7 || itemsPerPage == 1)
{
return false;
}
if (itemsPerPage == MENU_NO_PAGINATION
&& m_Pagination != MENU_NO_PAGINATION)
{
m_nFlags &= ~MENUFLAG_BUTTON_EXIT;
}
m_Pagination = itemsPerPage;
return true;
}
unsigned int CBaseMenu::GetPagination()
{
return m_Pagination;
}
IMenuStyle *CBaseMenu::GetDrawStyle()
{
return m_pStyle;
}
void CBaseMenu::SetDefaultTitle(const char *message)
{
m_Title.assign(message);
}
const char *CBaseMenu::GetDefaultTitle()
{
return m_Title.c_str();
}
void CBaseMenu::Cancel()
{
if (m_bCancelling)
{
return;
}
#if defined MENU_DEBUG
g_Logger.LogMessage("[SM_MENU] CBaseMenu::Cancel(%p) (m_bShouldDelete %d)",
this,
m_bShouldDelete);
#endif
m_bCancelling = true;
Cancel_Finally();
m_bCancelling = false;
if (m_bShouldDelete)
{
InternalDelete();
}
}
void CBaseMenu::Destroy(bool releaseHandle)
{
/* Check if we shouldn't be here */
if (m_bDeleting)
{
return;
}
#if defined MENU_DEBUG
g_Logger.LogMessage("[SM_MENU] CBaseMenu::Destroy(%p) (release %d) (m_bCancelling %d) (m_bShouldDelete %d)",
this,
releaseHandle,
m_bCancelling,
m_bShouldDelete);
#endif
/* Save the destruction hint about our handle */
m_bWillFreeHandle = releaseHandle;
/* Now actually do stuff */
if (!m_bCancelling || m_bShouldDelete)
{
Cancel();
InternalDelete();
} else {
m_bShouldDelete = true;
}
}
void CBaseMenu::InternalDelete()
{
if (m_bWillFreeHandle && m_hHandle != BAD_HANDLE)
{
Handle_t hndl = m_hHandle;
HandleSecurity sec;
sec.pOwner = m_pOwner;
sec.pIdentity = g_pCoreIdent;
m_hHandle = BAD_HANDLE;
m_bDeleting = true;
g_HandleSys.FreeHandle(hndl, &sec);
}
m_pHandler->OnMenuDestroy(this);
delete this;
}
unsigned int CBaseMenu::GetMenuOptionFlags()
{
return m_nFlags;
}
void CBaseMenu::SetMenuOptionFlags(unsigned int flags)
{
m_nFlags = flags;
}
IMenuHandler *CBaseMenu::GetHandler()
{
return m_pHandler;
}
unsigned int CBaseMenu::GetBaseMemUsage()
{
return m_Title.size()
+ m_Strings.GetMemTable()->GetMemUsage()
+ (m_items.size() * sizeof(CItem));
}

View File

@ -1,157 +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_MENUSTYLE_BASE_H
#define _INCLUDE_MENUSTYLE_BASE_H
#include <IMenuManager.h>
#include <IPlayerHelpers.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;
}
public:
int infoString;
int displayString;
unsigned int style;
unsigned int access;
};
class CBaseMenuPlayer
{
public:
CBaseMenuPlayer() : bInMenu(false), bAutoIgnore(false), bInExternMenu(false)
{
}
menu_states_t states;
bool bInMenu;
bool bAutoIgnore;
float menuStartTime;
unsigned int menuHoldTime;
bool bInExternMenu;
};
class CBaseMenu;
class BaseMenuStyle :
public IMenuStyle,
public IClientListener
{
public:
BaseMenuStyle();
public: //IMenuStyle
bool CancelClientMenu(int client, bool autoIgnore/* =false */);
MenuSource GetClientMenu(int client, void **object);
Handle_t GetHandle();
public: //IClientListener
void OnClientDisconnected(int client);
public: //what derived must implement
virtual CBaseMenuPlayer *GetMenuPlayer(int client) =0;
virtual void SendDisplay(int client, IMenuPanel *display) =0;
public: //what derived may implement
virtual bool DoClientMenu(int client,
CBaseMenu *menu,
unsigned int first_item,
IMenuHandler *mh,
unsigned int time);
virtual bool DoClientMenu(int client, IMenuPanel *menu, IMenuHandler *mh, unsigned int time);
virtual void AddClientToWatch(int client);
virtual void RemoveClientFromWatch(int client);
virtual void ProcessWatchList();
public: //helpers
void CancelMenu(CBaseMenu *menu);
void ClientPressedKey(int client, unsigned int key_press);
protected:
void _CancelClientMenu(int client, MenuCancelReason reason, bool bAutoIgnore=false);
bool RedoClientMenu(int client, ItemOrder order);
protected:
FastLink<int> m_WatchList;
Handle_t m_hHandle;
};
class CBaseMenu : public IBaseMenu
{
public:
CBaseMenu(IMenuHandler *pHandler, IMenuStyle *pStyle, IdentityToken_t *pOwner);
virtual ~CBaseMenu();
public:
virtual bool AppendItem(const char *info, const ItemDrawInfo &draw);
virtual bool InsertItem(unsigned int position, const char *info, const ItemDrawInfo &draw);
virtual bool RemoveItem(unsigned int position);
virtual void RemoveAllItems();
virtual const char *GetItemInfo(unsigned int position, ItemDrawInfo *draw=NULL);
virtual unsigned int GetItemCount();
virtual bool SetPagination(unsigned int itemsPerPage);
virtual unsigned int GetPagination();
virtual IMenuStyle *GetDrawStyle();
virtual void SetDefaultTitle(const char *message);
virtual const char *GetDefaultTitle();
virtual void Cancel();
virtual void Destroy(bool releaseHandle);
virtual void Cancel_Finally() =0;
virtual Handle_t GetHandle();
virtual unsigned int GetMenuOptionFlags();
virtual void SetMenuOptionFlags(unsigned int flags);
virtual IMenuHandler *GetHandler();
unsigned int GetBaseMemUsage();
private:
void InternalDelete();
protected:
String m_Title;
IMenuStyle *m_pStyle;
BaseStringTable m_Strings;
unsigned int m_Pagination;
CVector<CItem> m_items;
bool m_bShouldDelete;
bool m_bCancelling;
IdentityToken_t *m_pOwner;
bool m_bDeleting;
bool m_bWillFreeHandle;
Handle_t m_hHandle;
IMenuHandler *m_pHandler;
unsigned int m_nFlags;
};
#endif //_INCLUDE_MENUSTYLE_BASE_H

View File

@ -1,566 +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$
*/
#include "MenuStyle_Radio.h"
#include "sm_stringutil.h"
#include "UserMessages.h"
#include "GameConfigs.h"
#include "PlayerManager.h"
#if defined MENU_DEBUG
#include "Logger.h"
#endif
extern const char *g_RadioNumTable[];
CRadioStyle g_RadioMenuStyle;
int g_ShowMenuId = -1;
bool g_bRadioInit = false;
unsigned int g_RadioMenuTimeout = 0;
CRadioStyle::CRadioStyle()
{
m_players = new CRadioMenuPlayer[256+1];
for (size_t i = 0; i < 256+1; i++)
{
m_players[i].Radio_SetIndex(i);
}
}
void CRadioStyle::OnSourceModAllInitialized()
{
g_Players.AddClientListener(this);
}
void CRadioStyle::OnSourceModLevelChange(const char *mapName)
{
if (g_bRadioInit)
{
return;
}
g_bRadioInit = true;
const char *msg = g_pGameConf->GetKeyValue("HudRadioMenuMsg");
if (!msg || msg[0] == '\0')
{
return;
}
g_ShowMenuId = g_UserMsgs.GetMessageIndex(msg);
if (!IsSupported())
{
return;
}
const char *val = g_pGameConf->GetKeyValue("RadioMenuTimeout");
if (val != NULL)
{
g_RadioMenuTimeout = atoi(val);
}
else
{
g_RadioMenuTimeout = 0;
}
g_Menus.AddStyle(this);
g_Menus.SetDefaultStyle(this);
g_UserMsgs.HookUserMessage(g_ShowMenuId, this, false);
}
void CRadioStyle::OnSourceModShutdown()
{
g_Players.RemoveClientListener(this);
g_UserMsgs.UnhookUserMessage(g_ShowMenuId, this, false);
while (!m_FreeDisplays.empty())
{
delete m_FreeDisplays.front();
m_FreeDisplays.pop();
}
}
bool CRadioStyle::IsSupported()
{
return (g_ShowMenuId != -1);
}
bool CRadioStyle::OnClientCommand(int client, const char *cmdname, const CCommand &cmd)
{
if (strcmp(cmdname, "menuselect") == 0)
{
if (!m_players[client].bInMenu)
{
m_players[client].bInExternMenu = false;
return false;
}
int arg = atoi(cmd.Arg(1));
ClientPressedKey(client, arg);
return true;
}
return false;
}
static unsigned int g_last_holdtime = 0;
static unsigned int g_last_client_count = 0;
static int g_last_clients[256];
void CRadioStyle::OnUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter)
{
int count = pFilter->GetRecipientCount();
bf_read br(bf->GetBasePointer(), 3);
br.ReadWord();
int c = br.ReadChar();
g_last_holdtime = (c == -1) ? 0 : (unsigned)c;
for (int i=0; i<count; i++)
{
g_last_clients[g_last_client_count++] = pFilter->GetRecipientIndex(i);
}
}
void CRadioStyle::OnUserMessageSent(int msg_id)
{
for (unsigned int i=0; i<g_last_client_count; i++)
{
int client = g_last_clients[i];
#if defined MENU_DEBUG
g_Logger.LogMessage("[SM_MENU] CRadioStyle got ShowMenu (client %d) (bInMenu %d)",
client,
m_players[client].bInExternMenu);
#endif
if (m_players[client].bInMenu)
{
_CancelClientMenu(client, MenuCancel_Interrupted, true);
}
m_players[client].bInExternMenu = true;
m_players[client].menuHoldTime = g_last_holdtime;
}
g_last_client_count = 0;
}
void CRadioStyle::SendDisplay(int client, IMenuPanel *display)
{
CRadioDisplay *rDisplay = (CRadioDisplay *)display;
rDisplay->SendRawDisplay(client, m_players[client].menuHoldTime);
}
IMenuPanel *CRadioStyle::CreatePanel()
{
return g_RadioMenuStyle.MakeRadioDisplay();
}
IBaseMenu *CRadioStyle::CreateMenu(IMenuHandler *pHandler, IdentityToken_t *pOwner)
{
return new CRadioMenu(pHandler, pOwner);
}
unsigned int CRadioStyle::GetMaxPageItems()
{
return 10;
}
const char *CRadioStyle::GetStyleName()
{
return "radio";
}
CBaseMenuPlayer *CRadioStyle::GetMenuPlayer(int client)
{
return &m_players[client];
}
CRadioDisplay *CRadioStyle::MakeRadioDisplay(CRadioMenu *menu)
{
CRadioDisplay *display;
if (m_FreeDisplays.empty())
{
display = new CRadioDisplay();
}
else
{
display = m_FreeDisplays.front();
m_FreeDisplays.pop();
display->Reset();
}
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);
}
CRadioMenuPlayer *CRadioStyle::GetRadioMenuPlayer(int client)
{
return &m_players[client];
}
void CRadioStyle::ProcessWatchList()
{
if (!g_RadioMenuTimeout)
{
BaseMenuStyle::ProcessWatchList();
return;
}
BaseMenuStyle::ProcessWatchList();
CRadioMenuPlayer *pPlayer;
unsigned int max_clients = g_Players.GetMaxClients();
for (unsigned int i = 1; i <= max_clients; i++)
{
pPlayer = GetRadioMenuPlayer(i);
if (!pPlayer->bInMenu || pPlayer->bInExternMenu)
{
continue;
}
if (pPlayer->Radio_NeedsRefresh())
{
pPlayer->Radio_Refresh();
}
}
}
unsigned int CRadioStyle::GetApproxMemUsage()
{
return sizeof(CRadioStyle) + (sizeof(CRadioMenuPlayer) * 257);
}
CRadioDisplay::CRadioDisplay()
{
Reset();
}
CRadioDisplay::CRadioDisplay(CRadioMenu *menu)
{
Reset();
}
bool CRadioDisplay::DrawRawLine(const char *rawline)
{
m_BufferText.append(rawline);
m_BufferText.append("\n");
return true;
}
void CRadioDisplay::Reset()
{
m_BufferText.assign("");
m_Title.assign("");
m_NextPos = 1;
keys = 0;
}
void CRadioDisplay::DirectSet(const char *str, int keymap)
{
m_Title.clear();
m_BufferText.assign(str);
keys = keymap;
}
unsigned int CRadioDisplay::GetCurrentKey()
{
return m_NextPos;
}
bool CRadioDisplay::SetCurrentKey(unsigned int key)
{
if (key < m_NextPos || m_NextPos > 10)
{
return false;
}
m_NextPos = key;
return true;
}
bool CRadioDisplay::SendDisplay(int client, IMenuHandler *handler, unsigned int time)
{
return g_RadioMenuStyle.DoClientMenu(client, this, handler, time);
}
bool CRadioDisplay::SetExtOption(MenuOption option, const void *valuePtr)
{
return false;
}
IMenuStyle *CRadioDisplay::GetParentStyle()
{
return &g_RadioMenuStyle;
}
void CRadioDisplay::DrawTitle(const char *text, bool onlyIfEmpty/* =false */)
{
if (m_Title.size() != 0 && onlyIfEmpty)
{
return;
}
m_Title.assign(text);
}
unsigned int CRadioDisplay::DrawItem(const ItemDrawInfo &item)
{
if (m_NextPos > 10 || !CanDrawItem(item.style))
{
return 0;
}
if (item.style & ITEMDRAW_RAWLINE)
{
if (item.style & ITEMDRAW_SPACER)
{
m_BufferText.append(" \n");
} else {
m_BufferText.append(item.display);
m_BufferText.append("\n");
}
return 0;
} else if (item.style & ITEMDRAW_SPACER) {
m_BufferText.append(" \n");
return m_NextPos++;
} else if (item.style & ITEMDRAW_NOTEXT) {
return m_NextPos++;
}
if (item.style & ITEMDRAW_DISABLED)
{
m_BufferText.append(g_RadioNumTable[m_NextPos]);
m_BufferText.append(item.display);
m_BufferText.append("\n");
} else {
m_BufferText.append("->");
m_BufferText.append(g_RadioNumTable[m_NextPos]);
m_BufferText.append(item.display);
m_BufferText.append("\n");
keys |= (1<<(m_NextPos-1));
}
return m_NextPos++;
}
bool CRadioDisplay::CanDrawItem(unsigned int drawFlags)
{
if ((drawFlags & ITEMDRAW_IGNORE) == ITEMDRAW_IGNORE)
{
return false;
}
if ((drawFlags & ITEMDRAW_DISABLED) && (drawFlags & ITEMDRAW_CONTROL))
{
return false;
}
return true;
}
void CRadioDisplay::SendRawDisplay(int client, unsigned int time)
{
int _sel_keys = (keys == 0) ? (1<<9) : keys;
CRadioMenuPlayer *pPlayer = g_RadioMenuStyle.GetRadioMenuPlayer(client);
pPlayer->Radio_Init(_sel_keys, m_Title.c_str(), m_BufferText.c_str());
pPlayer->Radio_Refresh();
}
void CRadioMenuPlayer::Radio_SetIndex(unsigned int index)
{
m_index = index;
}
bool CRadioMenuPlayer::Radio_NeedsRefresh()
{
return (gpGlobals->curtime - display_last_refresh >= g_RadioMenuTimeout);
}
void CRadioMenuPlayer::Radio_Init(int keys, const char *title, const char *text)
{
if (title[0] != '\0')
{
display_len = UTIL_Format(display_pkt,
sizeof(display_pkt),
"%s\n%s",
title,
text);
}
else
{
display_len = UTIL_Format(display_pkt,
sizeof(display_pkt),
"%s",
text);
}
display_keys = keys;
}
void CRadioMenuPlayer::Radio_Refresh()
{
cell_t players[1] = {m_index};
char *ptr = display_pkt;
char save = 0;
size_t len = display_len;
unsigned int time;
/* Compute the new time */
if (menuHoldTime == 0)
{
time = 0;
}
else
{
time = menuHoldTime - (unsigned int)(gpGlobals->curtime - menuStartTime);
}
while (true)
{
if (len > 240)
{
save = ptr[240];
ptr[240] = '\0';
}
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 );
buffer->WriteString(ptr);
g_UserMsgs.EndMessage();
if (len > 240)
{
ptr[240] = save;
ptr = &ptr[240];
len -= 240;
}
else
{
break;
}
}
display_last_refresh = gpGlobals->curtime;
}
int CRadioDisplay::GetAmountRemaining()
{
size_t amt = m_Title.size() + 1 + m_BufferText.size();
if (amt >= 511)
{
return 0;
}
return (int)(511 - amt);
}
void CRadioDisplay::DeleteThis()
{
delete this;
}
bool CRadioDisplay::SetSelectableKeys(unsigned int keymap)
{
keys = (signed)keymap;
return true;
}
unsigned int CRadioDisplay::GetApproxMemUsage()
{
return sizeof(CRadioDisplay)
+ m_BufferText.size()
+ m_Title.size();
}
CRadioMenu::CRadioMenu(IMenuHandler *pHandler, IdentityToken_t *pOwner) :
CBaseMenu(pHandler, &g_RadioMenuStyle, pOwner)
{
}
bool CRadioMenu::SetExtOption(MenuOption option, const void *valuePtr)
{
return false;
}
IMenuPanel *CRadioMenu::CreatePanel()
{
return g_RadioMenuStyle.MakeRadioDisplay(this);
}
bool CRadioMenu::Display(int client, unsigned int time, IMenuHandler *alt_handler)
{
return DisplayAtItem(client, time, 0, alt_handler);
}
bool CRadioMenu::DisplayAtItem(int client,
unsigned int time,
unsigned int start_item,
IMenuHandler *alt_handler)
{
#if defined MENU_DEBUG
g_Logger.LogMessage("[SM_MENU] CRadioMenu::Display(%p) (client %d) (time %d)",
this,
client,
time);
#endif
if (m_bCancelling)
{
return false;
}
return g_RadioMenuStyle.DoClientMenu(client,
this,
start_item,
alt_handler ? alt_handler : m_pHandler,
time);
}
void CRadioMenu::Cancel_Finally()
{
g_RadioMenuStyle.CancelMenu(this);
}
unsigned int CRadioMenu::GetApproxMemUsage()
{
return sizeof(CRadioMenu) + GetBaseMemUsage();
}
const char *g_RadioNumTable[11] =
{
"0. ", "1. ", "2. ", "3. ", "4. ", "5. ", "6. ", "7. ", "8. ", "9. ", "0. "
};

View File

@ -1,151 +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_MENUSTYLE_RADIO_H
#define _INCLUDE_MENUSTYLE_RADIO_H
#include "sm_globals.h"
#include "MenuManager.h"
#include "MenuStyle_Base.h"
#include "sourcemm_api.h"
#include <IPlayerHelpers.h>
#include <IUserMessages.h>
#include "sm_fastlink.h"
#include <sh_stack.h>
#include <compat_wrappers.h>
using namespace SourceMod;
class CRadioDisplay;
class CRadioMenu;
class CRadioMenuPlayer : public CBaseMenuPlayer
{
public:
void Radio_Init(int keys, const char *title, const char *buffer);
bool Radio_NeedsRefresh();
void Radio_Refresh();
void Radio_SetIndex(unsigned int index);
private:
unsigned int m_index;
size_t display_len;
char display_pkt[512];
int display_keys;
float display_last_refresh;
};
class CRadioStyle :
public BaseMenuStyle,
public SMGlobalClass,
public IUserMessageListener
{
public:
CRadioStyle();
public: //SMGlobalClass
void OnSourceModAllInitialized();
void OnSourceModLevelChange(const char *mapName);
void OnSourceModShutdown();
public: //BaseMenuStyle
CBaseMenuPlayer *GetMenuPlayer(int client);
void SendDisplay(int client, IMenuPanel *display);
void ProcessWatchList();
public: //IMenuStyle
const char *GetStyleName();
IMenuPanel *CreatePanel();
IBaseMenu *CreateMenu(IMenuHandler *pHandler, IdentityToken_t *pOwner);
unsigned int GetMaxPageItems();
unsigned int GetApproxMemUsage();
public: //IUserMessageListener
void OnUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter);
void OnUserMessageSent(int msg_id);
public:
bool IsSupported();
bool OnClientCommand(int client, const char *cmdname, const CCommand &cmd);
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;
};
class CRadioDisplay : public IMenuPanel
{
friend class CRadioStyle;
public:
CRadioDisplay();
CRadioDisplay(CRadioMenu *menu);
public: //IMenuPanel
IMenuStyle *GetParentStyle();
void Reset();
void DrawTitle(const char *text, bool onlyIfEmpty=false);
unsigned int DrawItem(const ItemDrawInfo &item);
bool DrawRawLine(const char *rawline);
bool SetExtOption(MenuOption option, const void *valuePtr);
bool CanDrawItem(unsigned int drawFlags);
bool SendDisplay(int client, IMenuHandler *handler, unsigned int time);
void DeleteThis();
void SendRawDisplay(int client, unsigned int time);
bool SetSelectableKeys(unsigned int keymap);
unsigned int GetCurrentKey();
bool SetCurrentKey(unsigned int key);
int GetAmountRemaining();
unsigned int GetApproxMemUsage();
public:
void DirectSet(const char *str, int keymap);
private:
String m_BufferText;
String m_Title;
unsigned int m_NextPos;
int keys;
};
class CRadioMenu : public CBaseMenu
{
public:
CRadioMenu(IMenuHandler *pHandler, IdentityToken_t *pOwner);
public:
bool SetExtOption(MenuOption option, const void *valuePtr);
IMenuPanel *CreatePanel();
bool Display(int client, unsigned int time, IMenuHandler *alt_handler=NULL);
bool DisplayAtItem(int client,
unsigned int time,
unsigned int start_item,
IMenuHandler *alt_handler/* =NULL */);
void Cancel_Finally();
unsigned int GetApproxMemUsage();
};
extern CRadioStyle g_RadioMenuStyle;
#endif //_INCLUDE_MENUSTYLE_RADIO_H

View File

@ -1,445 +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$
*/
#include "sm_stringutil.h"
#include "PlayerManager.h"
#include "MenuStyle_Valve.h"
#include "Translator.h"
#include "PlayerManager.h"
#include "ConCmdManager.h"
SH_DECL_HOOK4_void(IServerPluginHelpers, CreateMessage, SH_NOATTRIB, false, edict_t *, DIALOG_TYPE, KeyValues *, IServerPluginCallbacks *);
ValveMenuStyle g_ValveMenuStyle;
extern const char *g_OptionNumTable[];
extern const char *g_OptionCmdTable[];
CallClass<IServerPluginHelpers> *g_pSPHCC = NULL;
ValveMenuStyle::ValveMenuStyle() : m_players(new CValveMenuPlayer[256+1])
{
}
CBaseMenuPlayer *ValveMenuStyle::GetMenuPlayer(int client)
{
return &m_players[client];
}
bool ValveMenuStyle::OnClientCommand(int client, const char *cmdname, const CCommand &cmd)
{
if (strcmp(cmdname, "sm_vmenuselect") == 0)
{
int key_press = atoi(cmd.Arg(1));
g_ValveMenuStyle.ClientPressedKey(client, key_press);
return true;
}
return false;
}
void ValveMenuStyle::OnSourceModAllInitialized()
{
g_Players.AddClientListener(this);
SH_ADD_HOOK_MEMFUNC(IServerPluginHelpers, CreateMessage, serverpluginhelpers, this, &ValveMenuStyle::HookCreateMessage, false);
g_pSPHCC = SH_GET_CALLCLASS(serverpluginhelpers);
}
void ValveMenuStyle::OnSourceModShutdown()
{
SH_RELEASE_CALLCLASS(g_pSPHCC);
SH_REMOVE_HOOK_MEMFUNC(IServerPluginHelpers, CreateMessage, serverpluginhelpers, this, &ValveMenuStyle::HookCreateMessage, false);
g_Players.RemoveClientListener(this);
}
void ValveMenuStyle::HookCreateMessage(edict_t *pEdict,
DIALOG_TYPE type,
KeyValues *kv,
IServerPluginCallbacks *plugin)
{
if (type != DIALOG_MENU)
{
return;
}
int client = engine->IndexOfEdict(pEdict);
if (client < 1 || client > 256)
{
return;
}
CValveMenuPlayer *player = &m_players[client];
/* We don't care if the player is in a menu because, for all intents and purposes,
* the menu is completely private. Instead, we just figure out the level we'll need
* in order to override it.
*/
player->curPrioLevel = kv->GetInt("level", player->curPrioLevel);
/* Oh no! What happens if we got a menu that overwrites ours?! */
if (player->bInMenu)
{
/* Okay, let the external menu survive for now. It may live another
* day to avenge its grandfather, killed in the great Menu Interruption
* battle.
*/
_CancelClientMenu(client, MenuCancel_Interrupted, true);
}
}
IMenuPanel *ValveMenuStyle::CreatePanel()
{
return new CValveMenuDisplay();
}
IBaseMenu *ValveMenuStyle::CreateMenu(IMenuHandler *pHandler, IdentityToken_t *pOwner)
{
return new CValveMenu(pHandler, pOwner);
}
const char *ValveMenuStyle::GetStyleName()
{
return "valve";
}
unsigned int ValveMenuStyle::GetMaxPageItems()
{
return 8;
}
void ValveMenuStyle::SendDisplay(int client, IMenuPanel *display)
{
m_players[client].curPrioLevel--;
CValveMenuDisplay *vDisplay = (CValveMenuDisplay *)display;
vDisplay->SendRawDisplay(client, m_players[client].curPrioLevel, m_players[client].menuHoldTime);
}
bool ValveMenuStyle::DoClientMenu(int client, IMenuPanel *menu, IMenuHandler *mh, unsigned int time)
{
if (vsp_interface == NULL)
{
return false;
}
return BaseMenuStyle::DoClientMenu(client, menu, mh, time);
}
bool ValveMenuStyle::DoClientMenu(int client, CBaseMenu *menu, unsigned int first_item, IMenuHandler *mh, unsigned int time)
{
if (vsp_interface == NULL)
{
mh->OnMenuStart(menu);
mh->OnMenuCancel(menu, client, MenuCancel_NoDisplay);
mh->OnMenuEnd(menu, MenuEnd_Cancelled);
return false;
}
return BaseMenuStyle::DoClientMenu(client, menu, first_item, mh, time);
}
unsigned int ValveMenuStyle::GetApproxMemUsage()
{
return sizeof(ValveMenuStyle) + (sizeof(CValveMenuPlayer) * 257);
}
CValveMenuDisplay::CValveMenuDisplay()
{
m_pKv = NULL;
Reset();
}
CValveMenuDisplay::CValveMenuDisplay(CValveMenu *pMenu)
{
m_pKv = NULL;
Reset();
m_pKv->SetColor("color", pMenu->m_IntroColor);
m_pKv->SetString("title", pMenu->m_IntroMsg);
}
void CValveMenuDisplay::DeleteThis()
{
delete this;
}
CValveMenuDisplay::~CValveMenuDisplay()
{
m_pKv->deleteThis();
}
IMenuStyle *CValveMenuDisplay::GetParentStyle()
{
return &g_ValveMenuStyle;
}
void CValveMenuDisplay::Reset()
{
if (m_pKv)
{
m_pKv->deleteThis();
}
m_pKv = new KeyValues("menu");
m_NextPos = 1;
m_TitleDrawn = false;
}
unsigned int CValveMenuDisplay::GetCurrentKey()
{
return m_NextPos;
}
bool CValveMenuDisplay::SetCurrentKey(unsigned int key)
{
if (key < m_NextPos || key > 9)
{
return false;
}
m_NextPos = key;
return true;
}
bool CValveMenuDisplay::SetExtOption(MenuOption option, const void *valuePtr)
{
if (option == MenuOption_IntroMessage)
{
m_pKv->SetString("title", (const char *)valuePtr);
return true;
} else if (option == MenuOption_IntroColor) {
int *array = (int *)valuePtr;
m_pKv->SetColor("color", Color(array[0], array[1], array[2], array[3]));
return true;
} else if (option == MenuOption_Priority) {
m_pKv->SetInt("level", *(int *)valuePtr);
return true;
}
return false;
}
bool CValveMenuDisplay::CanDrawItem(unsigned int drawFlags)
{
/**
* ITEMDRAW_RAWLINE - We can't draw random text, and this doesn't add a slot,
* so it's completely safe to ignore it.
* -----------------------------------------
*/
if (drawFlags & ITEMDRAW_RAWLINE)
{
return false;
}
/**
* Special cases, explained in DrawItem()
*/
if ((drawFlags & ITEMDRAW_NOTEXT)
|| (drawFlags & ITEMDRAW_SPACER))
{
return true;
}
/**
* We can't draw disabled text. We could bump the position, but we
* want DirectDraw() to find some actual items to display.
*/
if (drawFlags & ITEMDRAW_DISABLED)
{
return false;
}
return true;
}
unsigned int CValveMenuDisplay::DrawItem(const ItemDrawInfo &item)
{
if (m_NextPos > 9 || !CanDrawItem(item.style))
{
return 0;
}
/**
* For these cases we can't draw anything at all, but
* we can at least bump the position since we were explicitly asked to.
*/
if ((item.style & ITEMDRAW_NOTEXT)
|| (item.style & ITEMDRAW_SPACER))
{
return m_NextPos++;
}
char buffer[255];
UTIL_Format(buffer, sizeof(buffer), "%d. %s", m_NextPos, item.display);
KeyValues *ki = m_pKv->FindKey(g_OptionNumTable[m_NextPos], true);
ki->SetString("command", g_OptionCmdTable[m_NextPos]);
ki->SetString("msg", buffer);
return m_NextPos++;
}
void CValveMenuDisplay::DrawTitle(const char *text, bool onlyIfEmpty/* =false */)
{
if (onlyIfEmpty && m_TitleDrawn)
{
return;
}
m_pKv->SetString("msg", text);
m_TitleDrawn = true;
}
bool CValveMenuDisplay::DrawRawLine(const char *rawline)
{
return false;
}
void CValveMenuDisplay::SendRawDisplay(int client, int priority, unsigned int time)
{
m_pKv->SetInt("level", priority);
m_pKv->SetInt("time", time ? time : 200);
SH_CALL(g_pSPHCC, &IServerPluginHelpers::CreateMessage)(
engine->PEntityOfEntIndex(client),
DIALOG_MENU,
m_pKv,
vsp_interface);
}
bool CValveMenuDisplay::SendDisplay(int client, IMenuHandler *handler, unsigned int time)
{
return g_ValveMenuStyle.DoClientMenu(client, this, handler, time);
}
bool CValveMenuDisplay::SetSelectableKeys(unsigned int keymap)
{
return false;
}
int CValveMenuDisplay::GetAmountRemaining()
{
/* :TODO: this is a lie, but nothing really seems meaningful... */
return -1;
}
unsigned int CValveMenuDisplay::GetApproxMemUsage()
{
return sizeof(CValveMenuDisplay) + (sizeof(KeyValues) * m_NextPos * 10);
}
CValveMenu::CValveMenu(IMenuHandler *pHandler, IdentityToken_t *pOwner) :
CBaseMenu(pHandler, &g_ValveMenuStyle, pOwner),
m_IntroColor(255, 0, 0, 255)
{
strcpy(m_IntroMsg, "You have a menu, press ESC");
m_Pagination = 5;
}
void CValveMenu::Cancel_Finally()
{
g_ValveMenuStyle.CancelMenu(this);
}
bool CValveMenu::SetPagination(unsigned int itemsPerPage)
{
if (itemsPerPage > 5)
{
return false;
}
return CBaseMenu::SetPagination(itemsPerPage);
}
bool CValveMenu::SetExtOption(MenuOption option, const void *valuePtr)
{
if (option == MenuOption_IntroMessage)
{
strncopy(m_IntroMsg, (const char *)valuePtr, sizeof(m_IntroMsg));
return true;
} else if (option == MenuOption_IntroColor) {
unsigned int *array = (unsigned int *)valuePtr;
m_IntroColor = Color(array[0], array[1], array[2], array[3]);
return true;
}
return false;
}
bool CValveMenu::Display(int client, unsigned int time, IMenuHandler *alt_handler)
{
return DisplayAtItem(client, time, 0, alt_handler);
}
bool CValveMenu::DisplayAtItem(int client,
unsigned int time,
unsigned int start_item,
IMenuHandler *alt_handler/* =NULL */)
{
if (m_bCancelling)
{
return false;
}
return g_ValveMenuStyle.DoClientMenu(client, this, start_item, alt_handler ? alt_handler : m_pHandler, time);
}
IMenuPanel *CValveMenu::CreatePanel()
{
return new CValveMenuDisplay(this);
}
void CValveMenu::SetMenuOptionFlags(unsigned int flags)
{
flags |= MENUFLAG_BUTTON_EXIT;
CBaseMenu::SetMenuOptionFlags(flags);
}
unsigned int CValveMenu::GetApproxMemUsage()
{
return sizeof(CValveMenu) + GetBaseMemUsage();
}
const char *g_OptionNumTable[] =
{
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10"
};
const char *g_OptionCmdTable[] =
{
"sm_vmenuselect 0", /* INVALID! */
"sm_vmenuselect 1",
"sm_vmenuselect 2",
"sm_vmenuselect 3",
"sm_vmenuselect 4",
"sm_vmenuselect 5",
"sm_vmenuselect 6",
"sm_vmenuselect 7",
"sm_vmenuselect 8",
"sm_vmenuselect 9",
"sm_vmenuselect 10"
};

View File

@ -1,141 +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_MENUSTYLE_VALVE_H
#define _INCLUDE_MENUSTYLE_VALVE_H
#include "sm_globals.h"
#include "MenuManager.h"
#include "MenuStyle_Base.h"
#include "sourcemm_api.h"
#include "KeyValues.h"
#include "sm_fastlink.h"
#include <compat_wrappers.h>
using namespace SourceMod;
class CValveMenuPlayer : public CBaseMenuPlayer
{
public:
CValveMenuPlayer() : curPrioLevel(1)
{
}
int curPrioLevel;
};
class CValveMenu;
class CValveMenuDisplay;
class ValveMenuStyle :
public SMGlobalClass,
public BaseMenuStyle
{
public:
ValveMenuStyle();
bool OnClientCommand(int client, const char *cmdname, const CCommand &cmd);
public: //BaseMenuStyle
CBaseMenuPlayer *GetMenuPlayer(int client);
void SendDisplay(int client, IMenuPanel *display);
bool DoClientMenu(int client, CBaseMenu *menu, unsigned int first_item, IMenuHandler *mh, unsigned int time);
bool DoClientMenu(int client, IMenuPanel *menu, IMenuHandler *mh, unsigned int time);
public: //SMGlobalClass
void OnSourceModAllInitialized();
void OnSourceModShutdown();
public: //IMenuStyle
const char *GetStyleName();
IMenuPanel *CreatePanel();
IBaseMenu *CreateMenu(IMenuHandler *pHandler, IdentityToken_t *pOwner);
unsigned int GetMaxPageItems();
unsigned int GetApproxMemUsage();
private:
void HookCreateMessage(edict_t *pEdict, DIALOG_TYPE type, KeyValues *kv, IServerPluginCallbacks *plugin);
private:
CValveMenuPlayer *m_players;
};
class CValveMenu;
class CValveMenuDisplay : public IMenuPanel
{
public:
CValveMenuDisplay();
CValveMenuDisplay(CValveMenu *pMenu);
~CValveMenuDisplay();
public:
IMenuStyle *GetParentStyle();
void Reset();
void DrawTitle(const char *text, bool onlyIfEmpty=false);
unsigned int DrawItem(const ItemDrawInfo &item);
bool DrawRawLine(const char *rawline);
bool SendDisplay(int client, IMenuHandler *handler, unsigned int time);
bool SetExtOption(MenuOption option, const void *valuePtr);
bool CanDrawItem(unsigned int drawFlags);
void SendRawDisplay(int client, int priority, unsigned int time);
void DeleteThis();
bool SetSelectableKeys(unsigned int keymap);
unsigned int GetCurrentKey();
bool SetCurrentKey(unsigned int key);
int GetAmountRemaining();
unsigned int GetApproxMemUsage();
private:
KeyValues *m_pKv;
unsigned int m_NextPos;
bool m_TitleDrawn;
};
class CValveMenu : public CBaseMenu
{
friend class CValveMenuDisplay;
public:
CValveMenu(IMenuHandler *pHandler, IdentityToken_t *pOwner);
public: //IBaseMenu
bool SetExtOption(MenuOption option, const void *valuePtr);
IMenuPanel *CreatePanel();
bool GetExitButton();
bool SetExitButton(bool set);
bool SetPagination(unsigned int itemsPerPage);
bool Display(int client, unsigned int time, IMenuHandler *alt_handler=NULL);
bool DisplayAtItem(int client,
unsigned int time,
unsigned int start_item,
IMenuHandler *alt_handler/* =NULL */);
void SetMenuOptionFlags(unsigned int flags);
unsigned int GetApproxMemUsage();
public: //CBaseMenu
void Cancel_Finally();
private:
Color m_IntroColor;
char m_IntroMsg[128];
};
extern ValveMenuStyle g_ValveMenuStyle;
#endif //_INCLUDE_MENUSTYLE_VALVE_H

View File

@ -1,491 +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$
*/
#include <string.h>
#include <stdlib.h>
#include "MenuVoting.h"
#include "PlayerManager.h"
#include "sourcemm_api.h"
float g_next_vote = 0.0f;
#if defined ORANGEBOX_BUILD
void OnVoteDelayChange(IConVar *cvar, const char *value, float flOldValue);
#else
void OnVoteDelayChange(ConVar *cvar, const char *value);
#endif
ConVar sm_vote_delay("sm_vote_delay",
"30",
0,
"Sets the recommended time in between public votes",
false,
0.0,
false,
0.0,
OnVoteDelayChange);
#if defined ORANGEBOX_BUILD
void OnVoteDelayChange(IConVar *cvar, const char *value, float flOldValue)
#else
void OnVoteDelayChange(ConVar *cvar, const char *value)
#endif
{
/* See if the new vote delay isn't something we need to account for */
if (sm_vote_delay.GetFloat() < 1.0f)
{
g_next_vote = 0.0f;
return;
}
/* If there was never a last vote, ignore this change */
if (g_next_vote < 0.1f)
{
return;
}
/* Subtract the original value, then add the new one. */
g_next_vote -= (float)atof(value);
g_next_vote += sm_vote_delay.GetFloat();
}
unsigned int VoteMenuHandler::GetRemainingVoteDelay()
{
if (g_next_vote <= gpGlobals->curtime)
{
return 0;
}
return (unsigned int)(g_next_vote - gpGlobals->curtime);
}
void VoteMenuHandler::OnSourceModAllInitialized()
{
g_Players.AddClientListener(this);
}
void VoteMenuHandler::OnSourceModShutdown()
{
g_Players.RemoveClientListener(this);
}
void VoteMenuHandler::OnSourceModLevelChange(const char *mapName)
{
g_next_vote = 0.0f;
}
unsigned int VoteMenuHandler::GetMenuAPIVersion2()
{
return m_pHandler->GetMenuAPIVersion2();
}
void VoteMenuHandler::OnClientDisconnected(int client)
{
if (!IsVoteInProgress())
{
return;
}
/* Wipe out their vote if they had one. We have to make sure the the the
* newly connected client is not allowed to vote.
*/
int item;
if ((item = m_ClientVotes[client]) >= -1)
{
if (item >= 0)
{
assert((unsigned)item < m_Items);
assert(m_Votes[item] > 0);
m_Votes[item]--;
}
m_ClientVotes[client] = -2;
}
}
bool VoteMenuHandler::IsVoteInProgress()
{
return (m_pCurMenu != NULL);
}
bool VoteMenuHandler::StartVote(IBaseMenu *menu,
unsigned int num_clients,
int clients[],
unsigned int max_time,
unsigned int flags/* =0 */)
{
if (!InitializeVoting(menu, menu->GetHandler(), max_time, flags))
{
return false;
}
/* Note: we can use game time and not universal time because
* if we're voting then players are in-game.
*/
float fVoteDelay = sm_vote_delay.GetFloat();
if (fVoteDelay < 1.0)
{
g_next_vote = 0.0;
}
else
{
/* This little trick breaks for infinite votes!
* However, we just ignore that since those 1) shouldn't exist and
* 2) people must be checking IsVoteInProgress() beforehand anyway.
*/
g_next_vote = gpGlobals->curtime + fVoteDelay + (float)max_time;
}
m_fStartTime = gpGlobals->curtime;
m_nMenuTime = max_time;
for (unsigned int i=0; i<num_clients; i++)
{
if (clients[i] < 1 || clients[i] > 256)
{
continue;
}
menu->Display(clients[i], max_time, this);
}
StartVoting();
return true;
}
bool VoteMenuHandler::IsClientInVotePool(int client)
{
if (client < 1
|| client > g_Players.MaxClients()
|| m_pCurMenu == NULL)
{
return false;
}
return (m_ClientVotes[client] > -2);
}
bool VoteMenuHandler::GetClientVoteChoice(int client, unsigned int *pItem)
{
if (!IsClientInVotePool(client)
|| m_ClientVotes[client] == -1)
{
return false;
}
*pItem = m_ClientVotes[client];
return true;
}
bool VoteMenuHandler::RedrawToClient(int client)
{
unsigned int time_limit;
if (!IsClientInVotePool(client))
{
return false;
}
if (m_nMenuTime == MENU_TIME_FOREVER)
{
time_limit = m_nMenuTime;
}
else
{
time_limit = (int)((float)m_nMenuTime - (gpGlobals->curtime - m_fStartTime));
/* Make sure this doesn't round to zero */
if (time_limit == MENU_TIME_FOREVER)
{
time_limit = 1;
}
}
return m_pCurMenu->Display(client, time_limit, this);
}
bool VoteMenuHandler::InitializeVoting(IBaseMenu *menu,
IMenuHandler *handler,
unsigned int time,
unsigned int flags)
{
if (IsVoteInProgress())
{
return false;
}
InternalReset();
/* Mark all clients as not voting */
for (int i=1; i<=gpGlobals->maxClients; i++)
{
m_ClientVotes[i] = -2;
}
m_Items = menu->GetItemCount();
if (m_Votes.size() < (size_t)m_Items)
{
/* Only clear the items we need to... */
size_t size = m_Votes.size();
for (size_t i=0; i<size; i++)
{
m_Votes[i] = 0;
}
m_Votes.resize(m_Items, 0);
}
else
{
for (unsigned int i=0; i<m_Items; i++)
{
m_Votes[i] = 0;
}
}
m_pCurMenu = menu;
m_VoteTime = time;
m_VoteFlags = flags;
m_pHandler = handler;
m_pHandler->OnMenuStart(m_pCurMenu);
return true;
}
void VoteMenuHandler::StartVoting()
{
if (!m_pCurMenu)
{
return;
}
m_bStarted = true;
m_pHandler->OnMenuVoteStart(m_pCurMenu);
/* By now we know how many clients were set.
* If there are none, we should end IMMEDIATELY.
*/
if (m_Clients == 0)
{
EndVoting();
}
}
void VoteMenuHandler::DecrementPlayerCount()
{
assert(m_Clients > 0);
m_Clients--;
if (m_bStarted && m_Clients == 0)
{
EndVoting();
}
}
int SortVoteItems(const void *item1, const void *item2)
{
return ((menu_vote_result_t::menu_item_vote_t *)item2)->count
- ((menu_vote_result_t::menu_item_vote_t *)item1)->count;
}
void VoteMenuHandler::EndVoting()
{
/* Set when the next delay ends. We ignore cancellation because a menu
* was, at one point, displayed, which is all that counts. However, we
* do re-calculate the time just in case the menu had no time limit.
*/
float fVoteDelay = sm_vote_delay.GetFloat();
if (fVoteDelay < 1.0)
{
g_next_vote = 0.0;
}
else
{
g_next_vote = gpGlobals->curtime + fVoteDelay;
}
if (m_bCancelled)
{
/* If we were cancelled, don't bother tabulating anything.
* Reset just in case someone tries to redraw, which means
* we need to save our states.
*/
IBaseMenu *menu = m_pCurMenu;
IMenuHandler *handler = m_pHandler;
InternalReset();
handler->OnMenuVoteCancel(menu, VoteCancel_Generic);
handler->OnMenuEnd(menu, MenuEnd_VotingCancelled);
return;
}
menu_vote_result_t vote;
menu_vote_result_t::menu_client_vote_t client_vote[256];
menu_vote_result_t::menu_item_vote_t item_vote[256];
memset(&vote, 0, sizeof(vote));
/* Build the item list */
for (unsigned int i=0; i<m_Items; i++)
{
if (m_Votes[i] > 0)
{
item_vote[vote.num_items].count = m_Votes[i];
item_vote[vote.num_items].item = i;
vote.num_votes += m_Votes[i];
vote.num_items++;
}
}
vote.item_list = item_vote;
if (!vote.num_votes)
{
IBaseMenu *menu = m_pCurMenu;
IMenuHandler *handler = m_pHandler;
InternalReset();
handler->OnMenuVoteCancel(menu, VoteCancel_NoVotes);
handler->OnMenuEnd(menu, MenuEnd_VotingCancelled);
return;
}
/* Build the client list */
for (int i=1; i<=gpGlobals->maxClients; i++)
{
if (m_ClientVotes[i] >= -1)
{
client_vote[vote.num_clients].client = i;
client_vote[vote.num_clients].item = m_ClientVotes[i];
vote.num_clients++;
}
}
vote.client_list = client_vote;
/* Sort the item list descending like we promised */
qsort(item_vote,
vote.num_items,
sizeof(menu_vote_result_t::menu_item_vote_t),
SortVoteItems);
/* Save states, then clear what we've saved.
* This makes us re-entrant, which is always the safe way to go.
*/
IBaseMenu *menu = m_pCurMenu;
IMenuHandler *handler = m_pHandler;
InternalReset();
/* Send vote info */
handler->OnMenuVoteResults(menu, &vote);
handler->OnMenuEnd(menu, MenuEnd_VotingDone);
}
void VoteMenuHandler::OnMenuStart(IBaseMenu *menu)
{
m_Clients++;
}
void VoteMenuHandler::OnMenuEnd(IBaseMenu *menu, MenuEndReason reason)
{
DecrementPlayerCount();
}
void VoteMenuHandler::OnMenuCancel(IBaseMenu *menu, int client, MenuCancelReason reason)
{
m_pHandler->OnMenuCancel(menu, client, reason);
}
void VoteMenuHandler::OnMenuDisplay(IBaseMenu *menu, int client, IMenuPanel *display)
{
m_ClientVotes[client] = -1;
m_pHandler->OnMenuDisplay(menu, client, display);
}
unsigned int VoteMenuHandler::OnMenuDisplayItem(IBaseMenu *menu, int client, IMenuPanel *panel, unsigned int item, const ItemDrawInfo &dr)
{
return m_pHandler->OnMenuDisplayItem(menu, client, panel, item, dr);
}
void VoteMenuHandler::OnMenuDrawItem(IBaseMenu *menu, int client, unsigned int item, unsigned int &style)
{
m_pHandler->OnMenuDrawItem(menu, client, item, style);
}
void VoteMenuHandler::OnMenuSelect(IBaseMenu *menu, int client, unsigned int item)
{
/* Check by our item count, NOT the vote array size */
if (item < m_Items)
{
m_ClientVotes[client] = item;
m_Votes[item]++;
m_NumVotes++;
}
m_pHandler->OnMenuSelect(menu, client, item);
}
void VoteMenuHandler::OnMenuSelect2(IBaseMenu *menu, int client, unsigned int item, unsigned int item_on_page)
{
if (m_pHandler->GetMenuAPIVersion2() >= 13)
{
m_pHandler->OnMenuSelect2(menu, client, item, item_on_page);
}
}
void VoteMenuHandler::InternalReset()
{
m_Clients = 0;
m_Items = 0;
m_bStarted = false;
m_pCurMenu = NULL;
m_NumVotes = 0;
m_bCancelled = false;
m_pHandler = NULL;
}
void VoteMenuHandler::CancelVoting()
{
if (m_bCancelled || !m_pCurMenu)
{
return;
}
m_bCancelled = true;
m_pCurMenu->Cancel();
}
IBaseMenu *VoteMenuHandler::GetCurrentMenu()
{
return m_pCurMenu;
}
bool VoteMenuHandler::IsCancelling()
{
return m_bCancelled;
}

View File

@ -1,104 +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_MENUVOTING_H_
#define _INCLUDE_SOURCEMOD_MENUVOTING_H_
#include <IMenuManager.h>
#include <IPlayerHelpers.h>
#include <sh_vector.h>
#include "sm_globals.h"
using namespace SourceHook;
using namespace SourceMod;
class VoteMenuHandler :
public IMenuHandler,
public SMGlobalClass,
public IClientListener
{
public: //SMGlobalClass
void OnSourceModAllInitialized();
void OnSourceModShutdown();
void OnSourceModLevelChange(const char *mapName);
public: //IClientListener
void OnClientDisconnected(int client);
public: //IMenuHandler
unsigned int GetMenuAPIVersion2();
void OnMenuStart(IBaseMenu *menu);
void OnMenuDisplay(IBaseMenu *menu, int client, IMenuPanel *display);
void OnMenuSelect(IBaseMenu *menu, int client, unsigned int item);
void OnMenuSelect2(IBaseMenu *menu, int client, unsigned int item, unsigned int item_on_page);
void OnMenuCancel(IBaseMenu *menu, int client, MenuCancelReason reason);
void OnMenuEnd(IBaseMenu *menu, MenuEndReason reason);
void OnMenuDrawItem(IBaseMenu *menu, int client, unsigned int item, unsigned int &style);
unsigned int OnMenuDisplayItem(IBaseMenu *menu, int client, IMenuPanel *panel, unsigned int item, const ItemDrawInfo &dr);
public:
bool StartVote(IBaseMenu *menu,
unsigned int num_clients,
int clients[],
unsigned int max_time,
unsigned int flags=0);
bool IsVoteInProgress();
void CancelVoting();
IBaseMenu *GetCurrentMenu();
bool IsCancelling();
unsigned int GetRemainingVoteDelay();
bool IsClientInVotePool(int client);
bool GetClientVoteChoice(int client, unsigned int *pItem);
bool RedrawToClient(int client);
private:
void Reset(IMenuHandler *mh);
void DecrementPlayerCount();
void EndVoting();
void InternalReset();
bool InitializeVoting(IBaseMenu *menu,
IMenuHandler *handler,
unsigned int time,
unsigned int flags);
void StartVoting();
private:
IMenuHandler *m_pHandler;
unsigned int m_Clients;
unsigned int m_Items;
CVector<unsigned int> m_Votes;
IBaseMenu *m_pCurMenu;
bool m_bStarted;
bool m_bCancelled;
unsigned int m_NumVotes;
unsigned int m_VoteTime;
unsigned int m_VoteFlags;
float m_fStartTime;
unsigned int m_nMenuTime;
int m_ClientVotes[256+1];
};
#endif //_INCLUDE_SOURCEMOD_MENUVOTING_H_

View File

@ -1,140 +0,0 @@
#include "NativeOwner.h"
#include "ShareSys.h"
#include "PluginSys.h"
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);
}

View File

@ -1,57 +0,0 @@
#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:
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_

View File

@ -1,90 +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$
*/
#include "NextMap.h"
#include "Logger.h"
#include "sourcemm_api.h"
#include "sm_stringutil.h"
NextMapManager g_NextMap;
SH_DECL_HOOK2_void(IVEngineServer, ChangeLevel, SH_NOATTRIB, 0, const char *, const char *);
ConVar sm_nextmap("sm_nextmap", "", FCVAR_NOTIFY);
void NextMapManager::OnSourceModAllInitialized_Post()
{
#if defined ORANGEBOX_BUILD
SH_ADD_HOOK(IVEngineServer, ChangeLevel, engine, SH_MEMBER(this, &NextMapManager::HookChangeLevel), false);
#else
SH_ADD_HOOK_MEMFUNC(IVEngineServer, ChangeLevel, engine, this, &NextMapManager::HookChangeLevel, false);
#endif
}
void NextMapManager::OnSourceModShutdown()
{
#if defined ORANGEBOX_BUILD
SH_REMOVE_HOOK(IVEngineServer, ChangeLevel, engine, SH_MEMBER(this, &NextMapManager::HookChangeLevel), false);
#else
SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, ChangeLevel, engine, this, &NextMapManager::HookChangeLevel, false);
#endif
}
const char *NextMapManager::GetNextMap()
{
return sm_nextmap.GetString();
}
bool NextMapManager::SetNextMap(const char *map)
{
if (!engine->IsMapValid(map))
{
return false;
}
sm_nextmap.SetValue(map);
return true;
}
void NextMapManager::HookChangeLevel(const char *map, const char *unknown)
{
const char *newmap = sm_nextmap.GetString();
if (newmap[0] == 0 || !engine->IsMapValid(newmap))
{
RETURN_META(MRES_IGNORED);
}
g_Logger.LogMessage("[SM] Changed map to \"%s\"", newmap);
RETURN_META_NEWPARAMS(MRES_IGNORED, &IVEngineServer::ChangeLevel, (newmap, unknown));
}

View File

@ -1,52 +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_NEXTMAP_H_
#define _INCLUDE_SOURCEMOD_NEXTMAP_H_
#include "sm_globals.h"
#include "eiface.h"
class NextMapManager : public SMGlobalClass
{
public:
void OnSourceModAllInitialized_Post();
void OnSourceModShutdown();
const char *GetNextMap();
bool SetNextMap(const char *map);
void HookChangeLevel(const char *map, const char *unknown);
};
extern NextMapManager g_NextMap;
#endif //_INCLUDE_SOURCEMOD_NEXTMAP_H_

View File

@ -1,131 +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$
*/
#include "PhraseCollection.h"
#include "Translator.h"
#include "sm_stringutil.h"
CPhraseCollection::CPhraseCollection()
{
}
CPhraseCollection::~CPhraseCollection()
{
}
void CPhraseCollection::Destroy()
{
delete this;
}
IPhraseFile *CPhraseCollection::AddPhraseFile(const char *filename)
{
size_t i;
unsigned int fid;
IPhraseFile *pFile;
char full_name[PLATFORM_MAX_PATH];
/* No compat shim here. The user should have read the doc. */
UTIL_Format(full_name, sizeof(full_name), "%s.txt", filename);
fid = g_Translator.FindOrAddPhraseFile(full_name);
pFile = g_Translator.GetFileByIndex(fid);
for (i = 0; i < m_Files.size(); i++)
{
if (m_Files[i] == pFile)
{
return pFile;
}
}
m_Files.push_back(pFile);
return pFile;
}
unsigned int CPhraseCollection::GetFileCount()
{
return (unsigned int)m_Files.size();
}
IPhraseFile *CPhraseCollection::GetFile(unsigned int file)
{
if (file >= m_Files.size())
{
return NULL;
}
return m_Files[file];
}
TransError CPhraseCollection::FindTranslation(const char *key, unsigned int langid, Translation *pTrans)
{
size_t i;
for (i = 0; i < m_Files.size(); i++)
{
if (m_Files[i]->GetTranslation(key, langid, pTrans) == Trans_Okay)
{
return Trans_Okay;
}
}
return Trans_BadPhrase;
}
bool CPhraseCollection::FormatString(char *buffer,
size_t maxlength,
const char *format,
void **params,
unsigned int numparams,
size_t *pOutLength,
const char **pFailPhrase)
{
unsigned int arg;
arg = 0;
if (!gnprintf(buffer, maxlength, format, this, params, numparams, arg, pOutLength, pFailPhrase))
{
return false;
}
if (arg != numparams)
{
if (pFailPhrase != NULL)
{
*pFailPhrase = NULL;
}
return false;
}
return true;
}

View File

@ -1,65 +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_PHRASECOLLECTION_H_
#define _INCLUDE_SOURCEMOD_PHRASECOLLECTION_H_
#include <string.h>
#include <sh_vector.h>
#include <ITranslator.h>
using namespace SourceHook;
using namespace SourceMod;
class CPhraseCollection : public IPhraseCollection
{
public:
CPhraseCollection();
~CPhraseCollection();
public:
IPhraseFile *AddPhraseFile(const char *filename);
unsigned int GetFileCount();
IPhraseFile *GetFile(unsigned int file);
void Destroy();
TransError FindTranslation(const char *key, unsigned int langid, Translation *pTrans);
bool FormatString(
char *buffer,
size_t maxlength,
const char *format,
void **params,
unsigned int numparams,
size_t *pOutLength,
const char **pFailPhrase);
private:
CVector<IPhraseFile *> m_Files;
};
#endif //_INCLUDE_SOURCEMOD_PHRASECOLLECTION_H_

File diff suppressed because it is too large Load Diff

View File

@ -1,203 +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_CPLAYERMANAGER_H_
#define _INCLUDE_SOURCEMOD_CPLAYERMANAGER_H_
#include "sm_globals.h"
#include <eiface.h>
#include "sourcemm_api.h"
#include <IForwardSys.h>
#include <IPlayerHelpers.h>
#include <IAdminSystem.h>
#include <sh_string.h>
#include <sh_list.h>
#include <sh_vector.h>
using namespace SourceHook;
#define PLAYER_LIFE_UNKNOWN 0
#define PLAYER_LIFE_ALIVE 1
#define PLAYER_LIFE_DEAD 2
#define MIN_API_FOR_ADMINCALLS 7
class CPlayer : public IGamePlayer
{
friend class PlayerManager;
public:
CPlayer();
public:
const char *GetName();
const char *GetIPAddress();
const char *GetAuthString();
edict_t *GetEdict();
bool IsInGame();
bool WasCountedAsInGame();
bool IsConnected();
bool IsAuthorized();
bool IsFakeClient();
void SetAdminId(AdminId id, bool temporary);
AdminId GetAdminId();
void Kick(const char *str);
IPlayerInfo *GetPlayerInfo();
unsigned int GetLanguageId();
int GetUserId();
bool RunAdminCacheChecks();
void NotifyPostAdminChecks();
public:
void DoBasicAdminChecks();
bool IsInKickQueue();
void MarkAsBeingKicked();
int GetLifeState();
private:
void Initialize(const char *name, const char *ip, edict_t *pEntity);
void Connect();
void Disconnect();
void SetName(const char *name);
void DumpAdmin(bool deleting);
void Authorize(const char *auth);
void Authorize_Post();
void DoPostConnectAuthorization();
private:
bool m_IsConnected;
bool m_IsInGame;
bool m_IsAuthorized;
bool m_bIsInKickQueue;
String m_Name;
String m_Ip;
String m_IpNoPort;
String m_AuthID;
AdminId m_Admin;
bool m_TempAdmin;
edict_t *m_pEdict;
IPlayerInfo *m_Info;
String m_LastPassword;
bool m_bAdminCheckSignalled;
int m_iIndex;
unsigned int m_LangId;
int m_UserId;
};
class PlayerManager :
public SMGlobalClass,
public IPlayerManager
{
friend class CPlayer;
public:
PlayerManager();
~PlayerManager();
public: //SMGlobalClass
void OnSourceModAllInitialized();
void OnSourceModShutdown();
void OnSourceModLevelEnd();
ConfigResult OnSourceModConfigChanged(const char *key, const char *value, ConfigSource source, char *error, size_t maxlength);
public:
CPlayer *GetPlayerByIndex(int client) const;
void RunAuthChecks();
void ClearAdminId(AdminId id);
void ClearAllAdmins();
public:
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);
void OnClientDisconnect(edict_t *pEntity);
void OnClientDisconnect_Post(edict_t *pEntity);
#if defined ORANGEBOX_BUILD
void OnClientCommand(edict_t *pEntity, const CCommand &args);
#else
void OnClientCommand(edict_t *pEntity);
#endif
void OnClientSettingsChanged(edict_t *pEntity);
//void OnClientSettingsChanged_Pre(edict_t *pEntity);
public: //IPlayerManager
void AddClientListener(IClientListener *listener);
void RemoveClientListener(IClientListener *listener);
IGamePlayer *GetGamePlayer(int client);
IGamePlayer *GetGamePlayer(edict_t *pEdict);
int GetMaxClients();
int GetNumPlayers();
int GetClientOfUserId(int userid);
bool IsServerActivated();
int FilterCommandTarget(IGamePlayer *pAdmin, IGamePlayer *pTarget, int flags);
int InternalFilterCommandTarget(CPlayer *pAdmin, CPlayer *pTarget, int flags);
void RegisterCommandTargetProcessor(ICommandTargetProcessor *pHandler);
void UnregisterCommandTargetProcessor(ICommandTargetProcessor *pHandler);
void ProcessCommandTarget(cmd_target_info_t *info);
public:
inline int MaxClients()
{
return m_maxClients;
}
inline int NumPlayers()
{
return m_PlayerCount;
}
inline int ListenClient()
{
return m_ListenClient;
}
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);
private:
void OnServerActivate(edict_t *pEdictList, int edictCount, int clientMax);
private:
List<IClientListener *> m_hooks;
IForward *m_clconnect;
IForward *m_cldisconnect;
IForward *m_cldisconnect_post;
IForward *m_clputinserver;
IForward *m_clcommand;
IForward *m_clinfochanged;
IForward *m_clauth;
IForward *m_onActivate;
IForward *m_onActivate2;
CPlayer *m_Players;
int *m_UserIdLookUp;
int m_maxClients;
int m_PlayerCount;
bool m_FirstPass;
unsigned int *m_AuthQueue;
String m_PassInfoVar;
bool m_QueryLang;
bool m_bIsListenServer;
int m_ListenClient;
};
extern PlayerManager g_Players;
extern bool g_OnMapStarted;
extern const unsigned int *g_NumPlayersToAuth;
#endif //_INCLUDE_SOURCEMOD_CPLAYERMANAGER_H_

View File

@ -1,487 +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$
*/
#include "Profiler.h"
#include "PluginSys.h"
#include "sm_stringutil.h"
#include "Logger.h"
#if defined PLATFORM_POSIX
#include <sys/time.h>
#include <time.h>
#endif
ProfileEngine g_Profiler;
IProfiler *sm_profiler = &g_Profiler;
#if defined PLATFORM_WINDOWS
double WINDOWS_PERFORMANCE_FREQUENCY;
#endif
class EmptyProfiler : public IProfiler
{
public:
void OnNativeBegin(IPluginContext *pContext, sp_native_t *native)
{
}
void OnNativeEnd()
{
}
void OnFunctionBegin(IPluginContext *pContext, const char *name)
{
}
void OnFunctionEnd()
{
}
int OnCallbackBegin(IPluginContext *pContext, sp_public_t *pubfunc)
{
return 0;
}
void OnCallbackEnd(int serial)
{
}
} s_EmptyProfiler;
inline void InitProfPoint(prof_point_t &pt)
{
#if defined PLATFORM_WINDOWS
QueryPerformanceCounter(&pt.value);
#elif defined PLATFORM_POSIX
gettimeofday(&pt.value, NULL);
#endif
pt.is_set = true;
}
ProfileEngine::ProfileEngine()
{
m_serial = 0;
#if defined PLATFORM_WINDOWS
LARGE_INTEGER pf;
if (QueryPerformanceFrequency(&pf))
{
WINDOWS_PERFORMANCE_FREQUENCY = 1.0 / (double)(pf.QuadPart);
}
else
{
WINDOWS_PERFORMANCE_FREQUENCY = -1.0;
}
#endif
if (IsEnabled())
{
InitProfPoint(m_ProfStart);
}
else
{
sm_profiler = &s_EmptyProfiler;
}
}
bool ProfileEngine::IsEnabled()
{
#if defined PLATFORM_WINDOWS
return (WINDOWS_PERFORMANCE_FREQUENCY > 0.0);
#elif defined PLATFORM_POSIX
return true;
#endif
}
inline double DiffProfPoints(const prof_point_t &start, const prof_point_t &end)
{
double seconds;
#if defined PLATFORM_WINDOWS
LONGLONG diff;
diff = end.value.QuadPart - start.value.QuadPart;
seconds = diff * WINDOWS_PERFORMANCE_FREQUENCY;
#elif defined PLATFORM_POSIX
seconds = (double)(end.value.tv_sec - start.value.tv_sec);
if (start.value.tv_usec > end.value.tv_usec)
{
seconds -= 1.0;
seconds += (double)(1000000 - (start.value.tv_usec - end.value.tv_usec)) / 1000000.0;
}
else
{
seconds += (double)(end.value.tv_usec - start.value.tv_usec) / 1000000.0;
}
#endif
return seconds;
}
inline double CalcAtomTime(const prof_atom_t &atom)
{
if (!atom.end.is_set)
{
return atom.base_time;
}
return atom.base_time + DiffProfPoints(atom.start, atom.end);
}
void ProfileEngine::OnNativeBegin(IPluginContext *pContext, sp_native_t *native)
{
PushProfileStack(pContext, SP_PROF_NATIVES, native->name);
}
void ProfileEngine::OnNativeEnd()
{
assert(!m_AtomStack.empty());
assert(m_AtomStack.front().atom_type == SP_PROF_NATIVES);
PopProfileStack(&m_Natives);
}
void ProfileEngine::OnFunctionBegin(IPluginContext *pContext, const char *name)
{
PushProfileStack(pContext, SP_PROF_FUNCTIONS, name);
}
void ProfileEngine::OnFunctionEnd()
{
assert(!m_AtomStack.empty());
assert(m_AtomStack.front().atom_type == SP_PROF_FUNCTIONS);
PopProfileStack(&m_Functions);
}
int ProfileEngine::OnCallbackBegin(IPluginContext *pContext, sp_public_t *pubfunc)
{
PushProfileStack(pContext, SP_PROF_CALLBACKS, pubfunc->name);
return m_serial;
}
void ProfileEngine::OnCallbackEnd(int serial)
{
assert(!m_AtomStack.empty());
/**
* Account for the situation where the JIT discards the
* stack because there was an RTE of sorts.
*/
if (m_AtomStack.front().atom_type != SP_PROF_CALLBACKS
&& m_AtomStack.front().atom_serial != serial)
{
prof_atom_t atom;
double total_time;
/* There was an error, and we need to discard things. */
total_time = 0.0;
while (!m_AtomStack.empty()
&& m_AtomStack.front().atom_type != SP_PROF_CALLBACKS
&& m_AtomStack.front().atom_serial != serial)
{
total_time += CalcAtomTime(m_AtomStack.front());
m_AtomStack.pop();
}
/**
* Now we can end and discard ourselves, without saving the data.
* Since this data is all erroneous anyway, we don't care if it's
* not totally accurate.
*/
assert(!m_AtomStack.empty());
atom = m_AtomStack.front();
m_AtomStack.pop();
/* Note: We don't need to resume ourselves because end is set by Pause(). */
total_time += CalcAtomTime(atom);
ResumeParent(total_time);
return;
}
PopProfileStack(&m_Callbacks);
}
void ProfileEngine::PushProfileStack(IPluginContext *ctx, int type, const char *name)
{
prof_atom_t atom;
PauseParent();
atom.atom_type = type;
atom.base_time = 0.0;
atom.ctx = ctx->GetContext();
atom.name = name;
atom.end.is_set = false;
if (type == SP_PROF_CALLBACKS)
{
atom.atom_serial = ++m_serial;
}
else
{
atom.atom_serial = 0;
}
m_AtomStack.push(atom);
/* Note: We do this after because the stack could grow and skew results */
InitProfPoint(m_AtomStack.front().start);
}
void ProfileEngine::PopProfileStack(ProfileReport *reporter)
{
double total_time;
prof_atom_t &atom = m_AtomStack.front();
/* We're okay to cache our used time. */
InitProfPoint(atom.end);
total_time = CalcAtomTime(atom);
/* Now it's time to save this! This may do a lot of computations which
* is why we've cached the time beforehand.
*/
reporter->SaveAtom(atom);
m_AtomStack.pop();
/* Finally, tell our parent how much time we used. */
ResumeParent(total_time);
}
void ProfileEngine::PauseParent()
{
if (m_AtomStack.empty())
{
return;
}
InitProfPoint(m_AtomStack.front().end);
}
void ProfileEngine::ResumeParent(double addTime)
{
if (m_AtomStack.empty())
{
return;
}
prof_atom_t &atom = m_AtomStack.front();
/* Move its "paused time" to its base (known) time,
* then reset the start/end. Note that since CalcAtomTime()
* reads the base time, we SHOULD NOT use += to add.
*/
atom.base_time = CalcAtomTime(atom);
atom.base_time += addTime;
InitProfPoint(atom.start);
atom.end.is_set = false;
}
void ProfileEngine::Clear()
{
m_Natives.Clear();
m_Callbacks.Clear();
m_Functions.Clear();
InitProfPoint(m_ProfStart);
}
void ProfileEngine::OnSourceModAllInitialized()
{
g_RootMenu.AddRootConsoleCommand("profiler", "Profiler commands", this);
}
void ProfileEngine::OnSourceModShutdown()
{
g_RootMenu.RemoveRootConsoleCommand("profiler", this);
}
void ProfileEngine::OnRootConsoleCommand(const char *cmdname, const CCommand &command)
{
if (command.ArgC() >= 3)
{
if (strcmp(command.Arg(2), "flush") == 0)
{
FILE *fp;
char path[256];
g_SourceMod.BuildPath(Path_SM, path, sizeof(path), "logs/profile_%d.xml", (int)time(NULL));
if ((fp = fopen(path, "wt")) == NULL)
{
g_RootMenu.ConsolePrint("Failed, could not open file for writing: %s", path);
return;
}
GenerateReport(fp);
fclose(fp);
g_RootMenu.ConsolePrint("Profiler report generated as: %s\n", path);
return;
}
}
g_RootMenu.ConsolePrint("Profiler commands:");
g_RootMenu.DrawGenericOption("flush", "Flushes statistics to disk and starts over");
}
bool ProfileEngine::GenerateReport(FILE *fp)
{
time_t t;
double total_time;
prof_point_t end_time;
InitProfPoint(end_time);
total_time = DiffProfPoints(m_ProfStart, end_time);
t = time(NULL);
fprintf(fp, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n");
fprintf(fp, "<profile time=\"%d\" uptime=\"%f\">\n", (int)t, total_time);
WriteReport(fp, &m_Natives, "natives");
WriteReport(fp, &m_Callbacks, "callbacks");
WriteReport(fp, &m_Functions, "functions");
fprintf(fp, "</profile>\n");
return true;
}
void ProfileEngine::WriteReport(FILE *fp, ProfileReport *report, const char *name)
{
size_t i, num;
prof_atom_report_t *ar;
char new_name[512];
fprintf(fp, " <report name=\"%s\">\n", name);
num = report->GetNumReports();
for (i = 0; i < num; i++)
{
ar = report->GetReport(i);
strncopy(new_name, ar->atom_name, sizeof(new_name));
UTIL_ReplaceAll(new_name, sizeof(new_name), "<", "&lt;");
UTIL_ReplaceAll(new_name, sizeof(new_name), ">", "&gt;");
fprintf(fp, " <item name=\"%s\" numcalls=\"%d\" mintime=\"%f\" maxtime=\"%f\" totaltime=\"%f\"/>\n",
new_name,
ar->num_calls,
ar->min_time,
ar->max_time,
ar->total_time);
}
fprintf(fp, " </report>\n");
}
ProfileReport::~ProfileReport()
{
for (size_t i = 0; i < m_Reports.size(); i++)
{
delete m_Reports[i];
}
}
void ProfileReport::Clear()
{
m_ReportLookup.clear();
for (size_t i = 0; i < m_Reports.size(); i++)
{
delete m_Reports[i];
}
m_Reports.clear();
}
size_t ProfileReport::GetNumReports()
{
return m_Reports.size();
}
prof_atom_report_t *ProfileReport::GetReport(size_t i)
{
return m_Reports[i];
}
void ProfileReport::SaveAtom(const prof_atom_t &atom)
{
double atom_time;
char full_name[256];
prof_atom_report_t **pReport, *report;
if (atom.atom_type == SP_PROF_NATIVES)
{
strncopy(full_name, atom.name, sizeof(full_name));
}
else
{
CPlugin *pl;
const char *file;
file = "unknown";
if ((pl = g_PluginSys.GetPluginByCtx(atom.ctx)) != NULL)
{
file = pl->GetFilename();
}
UTIL_Format(full_name, sizeof(full_name), "%s!%s", file, atom.name);
}
atom_time = CalcAtomTime(atom);
if ((pReport = m_ReportLookup.retrieve(full_name)) == NULL)
{
report = new prof_atom_report_t;
strncopy(report->atom_name, full_name, sizeof(report->atom_name));
report->max_time = atom_time;
report->min_time = atom_time;
report->num_calls = 1;
report->total_time = atom_time;
m_ReportLookup.insert(full_name, report);
m_Reports.push_back(report);
}
else
{
report = *pReport;
if (atom_time > report->max_time)
{
report->max_time = atom_time;
}
if (atom_time < report->min_time)
{
report->min_time = atom_time;
}
report->num_calls++;
report->total_time += atom_time;
}
}

View File

@ -1,131 +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_PLUGIN_PROFILER_H_
#define _INCLUDE_SOURCEMOD_PLUGIN_PROFILER_H_
#include <sp_vm_api.h>
#include <sm_platform.h>
#include <sm_trie_tpl.h>
#include <sh_vector.h>
#include <sh_stack.h>
#include <stdio.h>
#include "sm_globals.h"
#include "sm_srvcmds.h"
using namespace SourcePawn;
using namespace SourceHook;
struct prof_point_t
{
#if defined PLATFORM_WINDOWS
LARGE_INTEGER value;
#elif defined PLATFORM_POSIX
struct timeval value;
#endif
bool is_set;
};
struct prof_atom_t
{
int atom_type; /* Type of object we're profiling */
int atom_serial; /* Serial number, if appropriate */
sp_context_t *ctx; /* Plugin context. */
const char *name; /* Name of the function */
prof_point_t start; /* Start time */
prof_point_t end; /* End time */
double base_time; /* Known time from children or pausing. */
};
struct prof_atom_report_t
{
char atom_name[256]; /* Full name to shove to logs */
double total_time; /* Total time spent executing, in s */
unsigned int num_calls; /* Number of invocations */
double min_time; /* Min time spent in one call, in s */
double max_time; /* Max time spent in one call, in s */
};
class ProfileReport
{
public:
~ProfileReport();
public:
void SaveAtom(const prof_atom_t &atom);
size_t GetNumReports();
prof_atom_report_t *GetReport(size_t i);
void Clear();
private:
KTrie<prof_atom_report_t *> m_ReportLookup;
CVector<prof_atom_report_t *> m_Reports;
};
class ProfileEngine :
public SMGlobalClass,
public IRootConsoleCommand,
public IProfiler
{
public:
ProfileEngine();
public:
bool IsEnabled();
bool GenerateReport(FILE *fp);
void Clear();
public: //SMGlobalClass
void OnSourceModAllInitialized();
void OnSourceModShutdown();
public: //IRootConsoleCommand
void OnRootConsoleCommand(const char *cmdname, const CCommand &command);
public: //IProfiler
void OnNativeBegin(IPluginContext *pContext, sp_native_t *native);
void OnNativeEnd() ;
void OnFunctionBegin(IPluginContext *pContext, const char *name);
void OnFunctionEnd();
int OnCallbackBegin(IPluginContext *pContext, sp_public_t *pubfunc);
void OnCallbackEnd(int serial);
private:
void PushProfileStack(IPluginContext *ctx, int type, const char *name);
void PopProfileStack(ProfileReport *reporter);
void PauseParent();
void ResumeParent(double addTime);
void WriteReport(FILE *fp, ProfileReport *report, const char *name);
private:
CStack<prof_atom_t> m_AtomStack;
ProfileReport m_Callbacks;
ProfileReport m_Functions;
ProfileReport m_Natives;
int m_serial;
prof_point_t m_ProfStart;
};
extern ProfileEngine g_Profiler;
#endif //_INCLUDE_SOURCEMOD_PLUGIN_PROFILER_H_

File diff suppressed because it is too large Load Diff

View File

@ -1,91 +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_TEXTPARSERS_H_
#define _INCLUDE_SOURCEMOD_TEXTPARSERS_H_
#include <ITextParsers.h>
#include "sm_globals.h"
using namespace SourceMod;
/**
* @param void * IN: Stream pointer
* @param char * IN/OUT: Stream buffer
* @param size_t IN: Maximum size of buffer
* @param unsigned int * OUT: Number of bytes read (0 = end of stream)
* @return True on success, false on failure
*/
typedef bool (*STREAMREADER)(void *, char *, size_t, unsigned int *);
class TextParsers :
public ITextParsers,
public SMGlobalClass
{
public:
TextParsers();
public: //SMGlobalClass
void OnSourceModAllInitialized();
public:
bool ParseFile_INI(const char *file,
ITextListener_INI *ini_listener,
unsigned int *line,
unsigned int *col);
SMCError ParseFile_SMC(const char *file,
ITextListener_SMC *smc_listener,
SMCStates *states);
SMCError ParseSMCFile(const char *file,
ITextListener_SMC *smc_listener,
SMCStates *states,
char *buffer,
size_t maxsize);
unsigned int GetUTF8CharBytes(const char *stream);
const char *GetSMCErrorString(SMCError err);
bool IsWhitespace(const char *stream);
private:
SMCError ParseString_SMC(const char *stream,
ITextListener_SMC *smc,
SMCStates *states);
SMCError ParseStream_SMC(void *stream,
STREAMREADER srdr,
ITextListener_SMC *smc,
SMCStates *states);
};
extern TextParsers g_TextParser;
#endif //_INCLUDE_SOURCEMOD_TEXTPARSERS_H_

View File

@ -1,52 +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$
*/
#include "ThreadSupport.h"
#include "sm_globals.h"
#include "ShareSys.h"
#if defined PLATFORM_POSIX
#include "thread/PosixThreads.h"
#elif defined PLATFORM_WINDOWS
#include "thread/WinThreads.h"
#endif
MainThreader g_MainThreader;
IThreader *g_pThreader = &g_MainThreader;
class RegThreadStuff : public SMGlobalClass
{
public:
void OnSourceModAllInitialized()
{
g_ShareSys.AddInterface(NULL, g_pThreader);
}
} s_RegThreadStuff;

View File

@ -1,41 +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_THREAD_SUPPORT_H
#define _INCLUDE_SOURCEMOD_THREAD_SUPPORT_H
#include <IThreader.h>
using namespace SourceMod;
extern IThreader *g_pThreader;
#endif //_INCLUDE_SOURCEMOD_THREAD_SUPPORT_H

View File

@ -1,487 +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$
*/
#include <time.h>
#include "TimerSys.h"
#include "ForwardSys.h"
#include "sourcemm_api.h"
#include "frame_hooks.h"
#include "ConVarManager.h"
#define TIMER_MIN_ACCURACY 0.1
TimerSystem g_Timers;
double g_fUniversalTime = 0.0f;
float g_fGameStartTime = 0.0f; /* Game game start time, non-universal */
double g_fTimerThink = 0.0f; /* Timer's next think time */
const double *g_pUniversalTime = &g_fUniversalTime;
ConVar *mp_timelimit = NULL;
int g_TimeLeftMode = 0;
ConVar sm_time_adjustment("sm_time_adjustment", "0", 0, "Adjusts the server time in seconds");
inline double GetSimulatedTime()
{
return g_fUniversalTime;
}
time_t GetAdjustedTime(time_t *buf)
{
time_t val = time(NULL) + sm_time_adjustment.GetInt();
if (buf)
{
*buf = val;
}
return val;
}
class DefaultMapTimer :
public IMapTimer,
public SMGlobalClass,
public IConVarChangeListener
{
public:
DefaultMapTimer()
{
m_bInUse = false;
}
void OnSourceModLevelChange(const char *mapName)
{
g_fGameStartTime = 0.0f;
}
int GetMapTimeLimit()
{
return mp_timelimit->GetInt();
}
void SetMapTimerStatus(bool enabled)
{
if (enabled && !m_bInUse)
{
Enable();
}
else if (!enabled && m_bInUse)
{
Disable();
}
m_bInUse = enabled;
}
void ExtendMapTimeLimit(int extra_time)
{
if (extra_time == 0)
{
mp_timelimit->SetValue(0);
return;
}
extra_time /= 60;
mp_timelimit->SetValue(mp_timelimit->GetInt() + extra_time);
}
void OnConVarChanged(ConVar *pConVar, const char *oldValue, float flOldValue)
{
g_Timers.MapTimeLeftChanged();
}
private:
void Enable()
{
g_ConVarManager.AddConVarChangeListener("mp_timelimit", this);
}
void Disable()
{
g_ConVarManager.RemoveConVarChangeListener("mp_timelimit", this);
}
private:
bool m_bInUse;
} s_DefaultMapTimer;
/**
* If the ticking process has run amok (should be impossible), we
* take care of this by "skipping" the in-between time, to prevent
* a bazillion times from firing on accident. This has the result
* that a drastic jump in time will continue acting normally. Users
* may not expect this, but... I think it is the best solution.
*/
inline double CalcNextThink(double last, float interval)
{
if (g_fUniversalTime - last - interval <= TIMER_MIN_ACCURACY)
{
return last + interval;
}
else
{
return g_fUniversalTime + interval;
}
}
void ITimer::Initialize(ITimedEvent *pCallbacks, float fInterval, float fToExec, void *pData, int flags)
{
m_Listener = pCallbacks;
m_Interval = fInterval;
m_ToExec = fToExec;
m_pData = pData;
m_Flags = flags;
m_InExec = false;
m_KillMe = false;
}
TimerSystem::TimerSystem()
{
m_pMapTimer = NULL;
m_bHasMapTickedYet = false;
m_bHasMapSimulatedYet = false;
m_fLastTickedTime = 0.0f;
}
TimerSystem::~TimerSystem()
{
CStack<ITimer *>::iterator iter;
for (iter=m_FreeTimers.begin(); iter!=m_FreeTimers.end(); iter++)
{
delete (*iter);
}
m_FreeTimers.popall();
}
void TimerSystem::OnSourceModAllInitialized()
{
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()
{
mp_timelimit = icvar->FindVar("mp_timelimit");
if (m_pMapTimer == NULL && mp_timelimit != NULL)
{
SetMapTimer(&s_DefaultMapTimer);
}
}
void TimerSystem::OnSourceModShutdown()
{
SetMapTimer(NULL);
g_Forwards.ReleaseForward(m_pOnGameFrame);
g_Forwards.ReleaseForward(m_pOnMapTimeLeftChanged);
}
void TimerSystem::OnSourceModLevelEnd()
{
m_bHasMapTickedYet = false;
m_bHasMapSimulatedYet = false;
}
void TimerSystem::GameFrame(bool simulating)
{
if (simulating && m_bHasMapTickedYet)
{
g_fUniversalTime += gpGlobals->curtime - m_fLastTickedTime;
if (!m_bHasMapSimulatedYet)
{
m_bHasMapSimulatedYet = true;
MapTimeLeftChanged();
}
}
else
{
g_fUniversalTime += gpGlobals->interval_per_tick;
}
m_fLastTickedTime = gpGlobals->curtime;
m_bHasMapTickedYet = true;
if (g_fUniversalTime >= g_fTimerThink)
{
RunFrame();
g_fTimerThink = CalcNextThink(g_fTimerThink, TIMER_MIN_ACCURACY);
}
RunFrameHooks(simulating);
if (m_pOnGameFrame->GetFunctionCount())
{
m_pOnGameFrame->Execute(NULL);
}
}
void TimerSystem::RunFrame()
{
ITimer *pTimer;
TimerIter iter;
double curtime = GetSimulatedTime();
for (iter=m_SingleTimers.begin(); iter!=m_SingleTimers.end(); )
{
pTimer = (*iter);
if (curtime >= pTimer->m_ToExec)
{
pTimer->m_InExec = true;
pTimer->m_Listener->OnTimer(pTimer, pTimer->m_pData);
pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData);
iter = m_SingleTimers.erase(iter);
m_FreeTimers.push(pTimer);
}
else
{
break;
}
}
ResultType res;
for (iter=m_LoopTimers.begin(); iter!=m_LoopTimers.end(); )
{
pTimer = (*iter);
if (curtime >= pTimer->m_ToExec)
{
pTimer->m_InExec = true;
res = pTimer->m_Listener->OnTimer(pTimer, pTimer->m_pData);
if (pTimer->m_KillMe || (res == Pl_Stop))
{
pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData);
iter = m_LoopTimers.erase(iter);
m_FreeTimers.push(pTimer);
continue;
}
pTimer->m_InExec = false;
pTimer->m_ToExec = CalcNextThink(pTimer->m_ToExec, pTimer->m_Interval);
}
iter++;
}
}
ITimer *TimerSystem::CreateTimer(ITimedEvent *pCallbacks, float fInterval, void *pData, int flags)
{
ITimer *pTimer;
TimerIter iter;
float to_exec = GetSimulatedTime() + fInterval;
if (m_FreeTimers.empty())
{
pTimer = new ITimer;
} else {
pTimer = m_FreeTimers.front();
m_FreeTimers.pop();
}
pTimer->Initialize(pCallbacks, fInterval, to_exec, pData, flags);
if (flags & TIMER_FLAG_REPEAT)
{
m_LoopTimers.push_back(pTimer);
goto return_timer;
}
if (m_SingleTimers.size() >= 1)
{
iter = --m_SingleTimers.end();
if ((*iter)->m_ToExec <= to_exec)
{
goto normal_insert_end;
}
}
for (iter=m_SingleTimers.begin(); iter!=m_SingleTimers.end(); iter++)
{
if ((*iter)->m_ToExec >= to_exec)
{
m_SingleTimers.insert(iter, pTimer);
goto return_timer;
}
}
normal_insert_end:
m_SingleTimers.push_back(pTimer);
return_timer:
return pTimer;
}
void TimerSystem::FireTimerOnce(ITimer *pTimer, bool delayExec)
{
ResultType res;
if (pTimer->m_InExec)
{
return;
}
pTimer->m_InExec = true;
res = pTimer->m_Listener->OnTimer(pTimer, pTimer->m_pData);
if (!(pTimer->m_Flags & TIMER_FLAG_REPEAT))
{
pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData);
m_SingleTimers.remove(pTimer);
m_FreeTimers.push(pTimer);
}
else
{
if ((res != Pl_Stop) && !pTimer->m_KillMe)
{
if (delayExec)
{
pTimer->m_ToExec = GetSimulatedTime() + pTimer->m_Interval;
}
pTimer->m_InExec = false;
return;
}
pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData);
m_LoopTimers.remove(pTimer);
m_FreeTimers.push(pTimer);
}
}
void TimerSystem::KillTimer(ITimer *pTimer)
{
if (pTimer->m_KillMe)
{
return;
}
if (pTimer->m_InExec)
{
pTimer->m_KillMe = true;
return;
}
pTimer->m_InExec = true; /* The timer it's not really executed but this check needs to be done */
pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData);
if (pTimer->m_Flags & TIMER_FLAG_REPEAT)
{
m_LoopTimers.remove(pTimer);
} else {
m_SingleTimers.remove(pTimer);
}
m_FreeTimers.push(pTimer);
}
CStack<ITimer *> s_tokill;
void TimerSystem::RemoveMapChangeTimers()
{
ITimer *pTimer;
TimerIter iter;
for (iter=m_SingleTimers.begin(); iter!=m_SingleTimers.end(); iter++)
{
pTimer = (*iter);
if (pTimer->m_Flags & TIMER_FLAG_NO_MAPCHANGE)
{
s_tokill.push(pTimer);
}
}
for (iter=m_LoopTimers.begin(); iter!=m_LoopTimers.end(); iter++)
{
pTimer = (*iter);
if (pTimer->m_Flags & TIMER_FLAG_NO_MAPCHANGE)
{
s_tokill.push(pTimer);
}
}
while (!s_tokill.empty())
{
KillTimer(s_tokill.front());
s_tokill.pop();
}
}
IMapTimer *TimerSystem::SetMapTimer(IMapTimer *pTimer)
{
IMapTimer *old = m_pMapTimer;
m_pMapTimer = pTimer;
if (m_pMapTimer)
{
m_pMapTimer->SetMapTimerStatus(true);
}
if (old)
{
old->SetMapTimerStatus(false);
}
return old;
}
IMapTimer *TimerSystem::GetMapTimer()
{
return m_pMapTimer;
}
void TimerSystem::MapTimeLeftChanged()
{
m_pOnMapTimeLeftChanged->Execute(NULL);
}
void TimerSystem::NotifyOfGameStart(float offset)
{
g_fGameStartTime = gpGlobals->curtime + offset;
}
float TimerSystem::GetTickedTime()
{
return g_fUniversalTime;
}
bool TimerSystem::GetMapTimeLeft(float *time_left)
{
if (!m_pMapTimer)
{
return false;
}
int time_limit;
if (!m_bHasMapSimulatedYet || (time_limit = m_pMapTimer->GetMapTimeLimit()) < 1)
{
*time_left = -1.0f;
}
else
{
*time_left = (g_fGameStartTime + time_limit * 60.0f) - gpGlobals->curtime;
}
return true;
}

View File

@ -1,110 +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_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"
using namespace SourceHook;
using namespace SourceMod;
typedef List<ITimer *> TimerList;
typedef List<ITimer *>::iterator TimerIter;
class SourceMod::ITimer
{
public:
void Initialize(ITimedEvent *pCallbacks, float fInterval, float fToExec, void *pData, int flags);
ITimedEvent *m_Listener;
void *m_pData;
float m_Interval;
double m_ToExec;
int m_Flags;
bool m_InExec;
bool m_KillMe;
};
class TimerSystem :
public ITimerSystem,
public SMGlobalClass
{
public:
TimerSystem();
~TimerSystem();
public: //SMGlobalClass
void OnSourceModAllInitialized();
void OnSourceModLevelEnd();
void OnSourceModGameInitialized();
void OnSourceModShutdown();
public: //ITimerSystem
ITimer *CreateTimer(ITimedEvent *pCallbacks, float fInterval, void *pData, int flags);
void KillTimer(ITimer *pTimer);
void FireTimerOnce(ITimer *pTimer, bool delayExec=false);
void MapTimeLeftChanged();
IMapTimer *SetMapTimer(IMapTimer *pTimer);
float GetTickedTime();
void NotifyOfGameStart(float offset /* = 0.0f */);
bool GetMapTimeLeft(float *pTime);
public:
void RunFrame();
void RemoveMapChangeTimers();
void GameFrame(bool simulating);
IMapTimer *GetMapTimer();
private:
List<ITimer *> m_SingleTimers;
List<ITimer *> m_LoopTimers;
CStack<ITimer *> m_FreeTimers;
IMapTimer *m_pMapTimer;
/* This is stuff for our manual ticking escapades. */
bool m_bHasMapTickedYet; /** Has the map ticked yet? */
bool m_bHasMapSimulatedYet; /** Has the map simulated yet? */
float m_fLastTickedTime; /** Last time that the game currently gave
us while ticking.
*/
IForward *m_pOnGameFrame;
IForward *m_pOnMapTimeLeftChanged;
};
time_t GetAdjustedTime(time_t *buf = NULL);
extern const double *g_pUniversalTime;
extern TimerSystem g_Timers;
extern int g_TimeLeftMode;
#endif //_INCLUDE_SOURCEMOD_CTIMERSYS_H_

File diff suppressed because it is too large Load Diff

View File

@ -1,177 +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_TRANSLATOR_H_
#define _INCLUDE_SOURCEMOD_TRANSLATOR_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;
class Translator;
enum PhraseParseState
{
PPS_None = 0,
PPS_Phrases,
PPS_InPhrase,
};
struct Language
{
char m_code2[3];
int m_FullName;
};
class CPhraseFile :
public ITextListener_SMC,
public IPhraseFile
{
public:
CPhraseFile(Translator *pTranslator, const char *file);
~CPhraseFile();
public:
void ReparseFile();
const char *GetFilename();
TransError GetTranslation(const char *szPhrase, unsigned int lang_id, Translation *pTrans);
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);
void ReadSMC_ParseEnd(bool halted, bool failed);
private:
void ParseError(const char *message, ...);
void ParseWarning(const char *message, ...);
private:
Trie *m_pPhraseLookup;
String m_File;
Translator *m_pTranslator;
PhraseParseState m_ParseState;
int m_CurPhrase;
BaseMemTable *m_pMemory;
BaseStringTable *m_pStringTab;
unsigned int m_LangCount;
String m_ParseError;
String m_LastPhraseString;
bool m_FileLogged;
};
class Translator :
public ITextListener_SMC,
public SMGlobalClass,
public ITranslator
{
public:
Translator();
~Translator();
public: // SMGlobalClass
ConfigResult OnSourceModConfigChanged(const char *key,
const char *value,
ConfigSource source,
char *error,
size_t maxlength);
void OnSourceModAllInitialized();
void OnSourceModLevelChange(const char *mapName);
void OnSourceModShutdown();
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:
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);
public: //ITranslator
unsigned int GetServerLanguage();
unsigned int GetClientLanguage(int client);
const char *GetInterfaceName();
unsigned int GetInterfaceVersion();
IPhraseCollection *CreatePhraseCollection();
int SetGlobalTarget(int index);
int GetGlobalTarget() const;
size_t FormatString(
char *buffer,
size_t maxlength,
SourcePawn::IPluginContext *pContext,
const cell_t *params,
unsigned int param);
bool FormatString(
char *buffer,
size_t maxlength,
const char *format,
IPhraseCollection *pPhrases,
void **params,
unsigned int numparams,
size_t *pOutLength,
const char **pFailPhrase);
private:
bool AddLanguage(const char *langcode, const char *description);
private:
CVector<Language *> m_Languages;
CVector<CPhraseFile *> m_Files;
BaseStringTable *m_pStringTab;
Trie *m_pLCodeLookup;
bool m_InLanguageSection;
String m_CustomError;
unsigned int m_ServerLang;
char m_InitialLang[3];
};
/* Nice little wrapper to handle error logging and whatnot */
bool CoreTranslate(char *buffer,
size_t maxlength,
const char *format,
unsigned int numparams,
size_t *pOutLength,
...);
extern IPhraseCollection *g_pCorePhrases;
extern unsigned int g_pCorePhraseID;
extern Translator g_Translator;
#endif //_INCLUDE_SOURCEMOD_TRANSLATOR_H_

View File

@ -1,477 +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$
*/
#include "UserMessages.h"
#include "sm_stringutil.h"
UserMessages g_UserMsgs;
SH_DECL_HOOK2(IVEngineServer, UserMessageBegin, SH_NOATTRIB, 0, bf_write *, IRecipientFilter *, int);
SH_DECL_HOOK0_void(IVEngineServer, MessageEnd, SH_NOATTRIB, 0);
UserMessages::UserMessages() : m_InterceptBuffer(m_pBase, 2500)
{
m_Names = sm_trie_create();
m_HookCount = 0;
m_InExec = false;
m_InHook = false;
m_CurFlags = 0;
m_CurId = INVALID_MESSAGE_ID;
}
UserMessages::~UserMessages()
{
sm_trie_destroy(m_Names);
CStack<ListenerInfo *>::iterator iter;
for (iter=m_FreeListeners.begin(); iter!=m_FreeListeners.end(); iter++)
{
delete (*iter);
}
m_FreeListeners.popall();
}
void UserMessages::OnSourceModStartup(bool late)
{
/* -1 means SourceMM was unable to get the user message list */
m_FallbackSearch = (g_SMAPI->GetUserMessageCount() == -1);
}
void UserMessages::OnSourceModAllInitialized()
{
g_ShareSys.AddInterface(NULL, this);
}
void UserMessages::OnSourceModAllShutdown()
{
if (m_HookCount)
{
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)
{
int msgid;
if (!sm_trie_retrieve(m_Names, msg, reinterpret_cast<void **>(&msgid)))
{
if (m_FallbackSearch)
{
char msgbuf[64];
int size;
msgid = 0;
while (gamedll->GetUserMessageInfo(msgid, msgbuf, sizeof(msgbuf), size))
{
if (strcmp(msgbuf, msg) == 0)
{
sm_trie_insert(m_Names, msg, reinterpret_cast<void *>(msgid));
return msgid;
}
msgid++;
}
}
msgid = g_SMAPI->FindUserMessage(msg);
if (msgid != INVALID_MESSAGE_ID)
{
sm_trie_insert(m_Names, msg, reinterpret_cast<void *>(msgid));
}
}
return msgid;
}
bool UserMessages::GetMessageName(int msgid, char *buffer, size_t maxlength) const
{
if (m_FallbackSearch)
{
int size;
return gamedll->GetUserMessageInfo(msgid, buffer, maxlength, size);
}
const char *msg = g_SMAPI->GetUserMessage(msgid);
if (msg)
{
strncopy(buffer, msg, maxlength);
return true;
}
return false;
}
bf_write *UserMessages::StartMessage(int msg_id, const cell_t players[], unsigned int playersNum, int flags)
{
bf_write *buffer;
if (m_InExec || m_InHook)
{
return NULL;
}
if (msg_id < 0 || msg_id >= 255)
{
return NULL;
}
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)
{
buffer = ENGINE_CALL(UserMessageBegin)(static_cast<IRecipientFilter *>(&m_CellRecFilter), msg_id);
} else {
buffer = engine->UserMessageBegin(static_cast<IRecipientFilter *>(&m_CellRecFilter), msg_id);
}
return buffer;
}
bool UserMessages::EndMessage()
{
if (!m_InExec)
{
return false;
}
if (m_CurFlags & USERMSG_BLOCKHOOKS)
{
ENGINE_CALL(MessageEnd)();
} else {
engine->MessageEnd();
}
m_InExec = false;
m_CurFlags = 0;
m_CellRecFilter.Reset();
return true;
}
bool UserMessages::HookUserMessage(int msg_id, IUserMessageListener *pListener, bool intercept)
{
if (msg_id < 0 || msg_id >= 255)
{
return false;
}
ListenerInfo *pInfo;
if (m_FreeListeners.empty())
{
pInfo = new ListenerInfo;
} else {
pInfo = m_FreeListeners.front();
m_FreeListeners.pop();
}
pInfo->Callback = pListener;
pInfo->IsHooked = false;
pInfo->KillMe = false;
if (!m_HookCount++)
{
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)
{
m_msgIntercepts[msg_id].push_back(pInfo);
} else {
m_msgHooks[msg_id].push_back(pInfo);
}
return true;
}
bool UserMessages::UnhookUserMessage(int msg_id, IUserMessageListener *pListener, bool intercept)
{
MsgList *pList;
MsgIter iter;
ListenerInfo *pInfo;
bool deleted = false;
if (msg_id < 0 || msg_id >= 255)
{
return false;
}
pList = (intercept) ? &m_msgIntercepts[msg_id] : &m_msgHooks[msg_id];
for (iter=pList->begin(); iter!=pList->end(); iter++)
{
pInfo = (*iter);
if (pInfo->Callback == pListener)
{
if (pInfo->IsHooked)
{
pInfo->KillMe = true;
return true;
}
pList->erase(iter);
deleted = true;
break;
}
}
if (deleted)
{
_DecRefCounter();
}
return deleted;
}
void UserMessages::_DecRefCounter()
{
if (--m_HookCount == 0)
{
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);
}
}
bf_write *UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_type)
{
bool is_intercept_empty = m_msgIntercepts[msg_type].empty();
bool is_hook_empty = m_msgHooks[msg_type].empty();
if ((is_intercept_empty && is_hook_empty)
|| (m_InExec && (m_CurFlags & USERMSG_BLOCKHOOKS)))
{
m_InHook = false;
RETURN_META_VALUE(MRES_IGNORED, NULL);
}
m_CurId = msg_type;
m_CurRecFilter = filter;
m_InHook = true;
m_BlockEndPost = false;
if (!is_intercept_empty)
{
m_InterceptBuffer.Reset();
RETURN_META_VALUE(MRES_SUPERCEDE, &m_InterceptBuffer);
}
RETURN_META_VALUE(MRES_IGNORED, NULL);
}
bf_write *UserMessages::OnStartMessage_Post(IRecipientFilter *filter, int msg_type)
{
if (!m_InHook)
{
RETURN_META_VALUE(MRES_IGNORED, NULL);
}
m_OrigBuffer = META_RESULT_ORIG_RET(bf_write *);
RETURN_META_VALUE(MRES_IGNORED, NULL);
}
void UserMessages::OnMessageEnd_Post()
{
if (!m_InHook || m_BlockEndPost)
{
RETURN_META(MRES_IGNORED);
}
MsgList *pList;
MsgIter iter;
ListenerInfo *pInfo;
pList = &m_msgIntercepts[m_CurId];
for (iter=pList->begin(); iter!=pList->end(); )
{
pInfo = (*iter);
pInfo->IsHooked = true;
pInfo->Callback->OnUserMessageSent(m_CurId);
if (pInfo->KillMe)
{
iter = pList->erase(iter);
m_FreeListeners.push(pInfo);
_DecRefCounter();
continue;
}
pInfo->IsHooked = false;
iter++;
}
m_InHook = false;
pList = &m_msgHooks[m_CurId];
for (iter=pList->begin(); iter!=pList->end(); )
{
pInfo = (*iter);
pInfo->IsHooked = true;
pInfo->Callback->OnUserMessageSent(m_CurId);
if (pInfo->KillMe)
{
iter = pList->erase(iter);
m_FreeListeners.push(pInfo);
_DecRefCounter();
continue;
}
pInfo->IsHooked = false;
iter++;
}
}
void UserMessages::OnMessageEnd_Pre()
{
if (!m_InHook)
{
RETURN_META(MRES_IGNORED);
}
MsgList *pList;
MsgIter iter;
ListenerInfo *pInfo;
ResultType res;
bool intercepted = false;
bool handled = false;
pList = &m_msgIntercepts[m_CurId];
for (iter=pList->begin(); iter!=pList->end(); )
{
pInfo = (*iter);
pInfo->IsHooked = true;
res = pInfo->Callback->InterceptUserMessage(m_CurId, &m_InterceptBuffer, m_CurRecFilter);
intercepted = true;
switch (res)
{
case Pl_Stop:
{
if (pInfo->KillMe)
{
pList->erase(iter);
m_FreeListeners.push(pInfo);
_DecRefCounter();
goto supercede;
}
pInfo->IsHooked = false;
goto supercede;
}
case Pl_Handled:
{
handled = true;
if (pInfo->KillMe)
{
iter = pList->erase(iter);
m_FreeListeners.push(pInfo);
_DecRefCounter();
continue;
}
break;
}
default:
{
if (pInfo->KillMe)
{
iter = pList->erase(iter);
m_FreeListeners.push(pInfo);
_DecRefCounter();
continue;
}
break;
}
}
pInfo->IsHooked = false;
iter++;
}
if (handled)
{
goto supercede;
}
if (intercepted)
{
bf_write *engine_bfw;
engine_bfw = ENGINE_CALL(UserMessageBegin)(m_CurRecFilter, m_CurId);
m_ReadBuffer.StartReading(m_InterceptBuffer.GetBasePointer(), m_InterceptBuffer.GetNumBytesWritten());
engine_bfw->WriteBitsFromBuffer(&m_ReadBuffer, m_InterceptBuffer.GetNumBitsWritten());
ENGINE_CALL(MessageEnd)();
}
pList = &m_msgHooks[m_CurId];
for (iter=pList->begin(); iter!=pList->end(); )
{
pInfo = (*iter);
pInfo->IsHooked = true;
pInfo->Callback->OnUserMessage(m_CurId, m_OrigBuffer, m_CurRecFilter);
if (pInfo->KillMe)
{
iter = pList->erase(iter);
m_FreeListeners.push(pInfo);
_DecRefCounter();
continue;
}
pInfo->IsHooked = false;
iter++;
}
RETURN_META((intercepted) ? MRES_SUPERCEDE : MRES_IGNORED);
supercede:
m_InHook = false;
m_BlockEndPost = true;
RETURN_META(MRES_SUPERCEDE);
}

View File

@ -1,104 +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_CUSERMESSAGES_H_
#define _INCLUDE_SOURCEMOD_CUSERMESSAGES_H_
#include "ShareSys.h"
#include <IUserMessages.h>
#include "sourcemm_api.h"
#include "sm_trie.h"
#include "CellRecipientFilter.h"
using namespace SourceHook;
using namespace SourceMod;
#define INVALID_MESSAGE_ID -1
struct ListenerInfo
{
IUserMessageListener *Callback;
bool IsHooked;
bool KillMe;
};
typedef List<ListenerInfo *> MsgList;
typedef List<ListenerInfo *>::iterator MsgIter;
class UserMessages :
public IUserMessages,
public SMGlobalClass
{
public:
UserMessages();
~UserMessages();
public: //SMGlobalClass
void OnSourceModStartup(bool late);
void OnSourceModAllInitialized();
void OnSourceModAllShutdown();
public: //IUserMessages
int GetMessageIndex(const char *msg);
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 *StartMessage(int msg_id, const cell_t players[], unsigned int playersNum, int flags);
bool EndMessage();
public:
bf_write *OnStartMessage_Pre(IRecipientFilter *filter, int msg_type);
bf_write *OnStartMessage_Post(IRecipientFilter *filter, int msg_type);
void OnMessageEnd_Pre();
void OnMessageEnd_Post();
private:
void _DecRefCounter();
private:
List<ListenerInfo *> m_msgHooks[255];
List<ListenerInfo *> m_msgIntercepts[255];
CStack<ListenerInfo *> m_FreeListeners;
unsigned char m_pBase[2500];
IRecipientFilter *m_CurRecFilter;
bf_write m_InterceptBuffer;
bf_write *m_OrigBuffer;
bf_read m_ReadBuffer;
size_t m_HookCount;
bool m_InHook;
bool m_BlockEndPost;
bool m_FallbackSearch;
Trie *m_Names;
CellRecipientFilter m_CellRecFilter;
bool m_InExec;
int m_CurFlags;
int m_CurId;
};
extern UserMessages g_UserMsgs;
#endif //_INCLUDE_SOURCEMOD_CUSERMESSAGES_H_

View File

@ -1,175 +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$
*/
#include "sm_globals.h"
#include <sh_list.h>
#include <convar.h>
#include "concmd_cleaner.h"
#include "sm_stringutil.h"
#include "sourcemm_api.h"
#if defined ORANGEBOX_BUILD
SH_DECL_HOOK1_void(ICvar, UnregisterConCommand, SH_NOATTRIB, 0, ConCommandBase *);
#endif
using namespace SourceHook;
struct ConCommandInfo
{
ConCommandBase *pBase;
IConCommandTracker *cls;
char name[64];
};
List<ConCommandInfo *> tracked_bases;
ConCommandBase *FindConCommandBase(const char *name);
class ConCommandCleaner : public SMGlobalClass
{
public:
#if defined ORANGEBOX_BUILD
void OnSourceModAllInitialized()
{
SH_ADD_HOOK_MEMFUNC(ICvar, UnregisterConCommand, icvar, this, &ConCommandCleaner::UnlinkConCommandBase, false);
}
void OnSourceModShutdown()
{
SH_REMOVE_HOOK_MEMFUNC(ICvar, UnregisterConCommand, icvar, this, &ConCommandCleaner::UnlinkConCommandBase, false);
}
#endif
void UnlinkConCommandBase(ConCommandBase *pBase)
{
ConCommandInfo *pInfo;
List<ConCommandInfo *>::iterator iter = tracked_bases.begin();
if (pBase)
{
while (iter != tracked_bases.end())
{
if ((*iter)->pBase == pBase)
{
pInfo = (*iter);
iter = tracked_bases.erase(iter);
pInfo->cls->OnUnlinkConCommandBase(pBase, pBase->GetName(), true);
delete pInfo;
}
else
{
iter++;
}
}
}
else
{
while (iter != tracked_bases.end())
{
/* This is just god-awful! */
if (FindConCommandBase((*iter)->name) != (*iter)->pBase)
{
pInfo = (*iter);
iter = tracked_bases.erase(iter);
pInfo->cls->OnUnlinkConCommandBase(pBase, pInfo->name, false);
delete pInfo;
}
else
{
iter++;
}
}
}
}
void AddTarget(ConCommandBase *pBase, IConCommandTracker *cls)
{
ConCommandInfo *info = new ConCommandInfo;
info->pBase = pBase;
info->cls = cls;
strncopy(info->name, pBase->GetName(), sizeof(info->name));
tracked_bases.push_back(info);
}
void RemoveTarget(ConCommandBase *pBase, IConCommandTracker *cls)
{
List<ConCommandInfo *>::iterator iter;
ConCommandInfo *pInfo;
iter = tracked_bases.begin();
while (iter != tracked_bases.end())
{
pInfo = (*iter);
if (pInfo->pBase == pBase && pInfo->cls == cls)
{
delete pInfo;
iter = tracked_bases.erase(iter);
}
else
{
iter++;
}
}
}
} s_ConCmdTracker;
ConCommandBase *FindConCommandBase(const char *name)
{
const ConCommandBase *pBase = icvar->GetCommands();
while (pBase != NULL)
{
if (strcmp(pBase->GetName(), name) == 0)
{
return const_cast<ConCommandBase *>(pBase);
}
pBase = pBase->GetNext();
}
return NULL;
}
void TrackConCommandBase(ConCommandBase *pBase, IConCommandTracker *me)
{
s_ConCmdTracker.AddTarget(pBase, me);
}
void UntrackConCommandBase(ConCommandBase *pBase, IConCommandTracker *me)
{
s_ConCmdTracker.RemoveTarget(pBase, me);
}
void Global_OnUnlinkConCommandBase(ConCommandBase *pBase)
{
s_ConCmdTracker.UnlinkConCommandBase(pBase);
}

View File

@ -1,46 +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_CONCMD_TRACKER_H_
#define _INCLUDE_CONCMD_TRACKER_H_
class IConCommandTracker
{
public:
virtual void OnUnlinkConCommandBase(ConCommandBase *pBase, const char *name, bool is_read_safe) = 0;
};
ConCommandBase *FindConCommandBase(const char *name);
void TrackConCommandBase(ConCommandBase *pBase, IConCommandTracker *me);
void UntrackConCommandBase(ConCommandBase *pBase, IConCommandTracker *me);
void Global_OnUnlinkConCommandBase(ConCommandBase *pBase);
#endif //_INCLUDE_CONCMD_TRACKER_H_

View File

@ -1,551 +0,0 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $Workfile: $
// $Date: 2006-08-13 06:34:30 -0500 (Sun, 13 Aug 2006) $
//
//-----------------------------------------------------------------------------
// $NoKeywords: $
//=============================================================================//
#ifndef CONVAR_H
#define CONVAR_H
#if _WIN32
#pragma once
#endif
#include "tier0/dbg.h"
#ifdef _WIN32
#define FORCEINLINE_CVAR FORCEINLINE
#elif _LINUX
#define FORCEINLINE_CVAR __inline__ FORCEINLINE
#else
#error "implement me"
#endif
// The default, no flags at all
#define FCVAR_NONE 0
// Command to ConVars and ConCommands
// ConVar Systems
#define FCVAR_UNREGISTERED (1<<0) // If this is set, don't add to linked list, etc.
#define FCVAR_LAUNCHER (1<<1) // defined by launcher
#define FCVAR_GAMEDLL (1<<2) // defined by the game DLL
#define FCVAR_CLIENTDLL (1<<3) // defined by the client DLL
#define FCVAR_MATERIAL_SYSTEM (1<<4) // Defined by the material system.
#define FCVAR_DATACACHE (1<<19) // Defined by the datacache system.
#define FCVAR_STUDIORENDER (1<<15) // Defined by the studiorender system.
#define FCVAR_FILESYSTEM (1<<21) // Defined by the file system.
#define FCVAR_PLUGIN (1<<18) // Defined by a 3rd party plugin.
#define FCVAR_TOOLSYSTEM (1<<20) // Defined by an IToolSystem library
#define FCVAR_SOUNDSYSTEM (1<<23) // Defined by the soundsystem library
#define FCVAR_INPUTSYSTEM (1<<25) // Defined by the inputsystem dll
#define FCVAR_NETWORKSYSTEM (1<<26) // Defined by the network system
// NOTE!! if you add a cvar system, add it here too!!!!
// the engine lacks a cvar flag, but needs it for xbox
// an engine cvar is thus a cvar not marked with any other system
#define FCVAR_NON_ENGINE ((FCVAR_LAUNCHER|FCVAR_GAMEDLL|FCVAR_CLIENTDLL|FCVAR_MATERIAL_SYSTEM|FCVAR_DATACACHE|FCVAR_STUDIORENDER|FCVAR_FILESYSTEM|FCVAR_PLUGIN|FCVAR_TOOLSYSTEM|FCVAR_SOUNDSYSTEM|FCVAR_INPUTSYSTEM|FCVAR_NETWORKSYSTEM))
// ConVar only
#define FCVAR_PROTECTED (1<<5) // It's a server cvar, but we don't send the data since it's a password, etc. Sends 1 if it's not bland/zero, 0 otherwise as value
#define FCVAR_SPONLY (1<<6) // This cvar cannot be changed by clients connected to a multiplayer server.
#define FCVAR_ARCHIVE (1<<7) // set to cause it to be saved to vars.rc
#define FCVAR_NOTIFY (1<<8) // notifies players when changed
#define FCVAR_USERINFO (1<<9) // changes the client's info string
#define FCVAR_CHEAT (1<<14) // Only useable in singleplayer / debug / multiplayer & sv_cheats
#define FCVAR_PRINTABLEONLY (1<<10) // This cvar's string cannot contain unprintable characters ( e.g., used for player name etc ).
#define FCVAR_UNLOGGED (1<<11) // If this is a FCVAR_SERVER, don't log changes to the log file / console if we are creating a log
#define FCVAR_NEVER_AS_STRING (1<<12) // never try to print that cvar
// It's a ConVar that's shared between the client and the server.
// At signon, the values of all such ConVars are sent from the server to the client (skipped for local
// client, of course )
// If a change is requested it must come from the console (i.e., no remote client changes)
// If a value is changed while a server is active, it's replicated to all connected clients
#define FCVAR_REPLICATED (1<<13) // server setting enforced on clients, TODO rename to FCAR_SERVER at some time
#define FCVAR_DEMO (1<<16) // record this cvar when starting a demo file
#define FCVAR_DONTRECORD (1<<17) // don't record these command in demofiles
#define FCVAR_NOT_CONNECTED (1<<22) // cvar cannot be changed by a client that is connected to a server
#define FCVAR_ARCHIVE_XBOX (1<<24) // cvar written to config.cfg on the Xbox
// #define FCVAR_AVAILABLE (1<<27)
// #define FCVAR_AVAILABLE (1<<28)
// #define FCVAR_AVAILABLE (1<<29)
// #define FCVAR_AVAILABLE (1<<30)
// #define FCVAR_AVAILABLE (1<<31)
class ConVar;
class ConCommand;
class ConCommandBase;
// Any executable that wants to use ConVars need to implement one of
// these to hook up access to console variables.
class IConCommandBaseAccessor
{
public:
// Flags is a combination of FCVAR flags in cvar.h.
// hOut is filled in with a handle to the variable.
virtual bool RegisterConCommandBase( ConCommandBase *pVar )=0;
};
// You don't have to instantiate one of these, just call its
// OneTimeInit function when your executable is initializing.
class ConCommandBaseMgr
{
public:
// Call this ONCE when the executable starts up.
static void OneTimeInit( IConCommandBaseAccessor *pAccessor );
#ifdef _XBOX
static bool Fixup( ConCommandBase* pConCommandBase );
#ifndef _RETAIL
static void PublishCommands( bool bForce );
#endif
#endif
};
// Called when a ConVar changes value
typedef void ( *FnChangeCallback )( ConVar *var, char const *pOldString );
// Called when a ConCommand needs to execute
typedef void ( *FnCommandCallback )( void );
#define COMMAND_COMPLETION_MAXITEMS 64
#define COMMAND_COMPLETION_ITEM_LENGTH 64
// Returns 0 to COMMAND_COMPLETION_MAXITEMS worth of completion strings
typedef int ( *FnCommandCompletionCallback )( char const *partial, char commands[ COMMAND_COMPLETION_MAXITEMS ][ COMMAND_COMPLETION_ITEM_LENGTH ] );
//-----------------------------------------------------------------------------
// Purpose: The base console invoked command/cvar interface
//-----------------------------------------------------------------------------
class ConCommandBase
{
friend class ConCommandBaseMgr;
friend class CCvar;
friend class ConVar;
friend class ConCommand;
public:
ConCommandBase( void );
ConCommandBase( char const *pName, char const *pHelpString = 0,
int flags = 0 );
virtual ~ConCommandBase( void );
virtual bool IsCommand( void ) const;
// Check flag
virtual bool IsBitSet( int flag ) const;
// Set flag
virtual void AddFlags( int flags );
// Return name of cvar
virtual char const *GetName( void ) const;
// Return help text for cvar
virtual char const *GetHelpText( void ) const;
// Deal with next pointer
const ConCommandBase *GetNext( void ) const;
void SetNext( ConCommandBase *next );
virtual bool IsRegistered( void ) const;
// Global methods
static ConCommandBase const *GetCommands( void );
static void AddToList( ConCommandBase *var );
static void RemoveFlaggedCommands( int flag );
static void RevertFlaggedCvars( int flag );
static ConCommandBase const *FindCommand( char const *name );
protected:
virtual void Create( char const *pName, char const *pHelpString = 0,
int flags = 0 );
// Used internally by OneTimeInit to initialize.
virtual void Init();
// Internal copy routine ( uses new operator from correct module )
char *CopyString( char const *from );
// Next ConVar in chain
ConCommandBase *m_pNext;
private:
// Has the cvar been added to the global list?
bool m_bRegistered;
// Static data
char const *m_pszName;
char const *m_pszHelpString;
// ConVar flags
int m_nFlags;
protected:
// ConVars add themselves to this list for the executable. Then ConVarMgr::Init() runs through
// all the console variables and registers them.
static ConCommandBase *s_pConCommandBases;
// ConVars in this executable use this 'global' to access values.
static IConCommandBaseAccessor *s_pAccessor;
public: // Hackalicous
inline int GetFlags() const
{
return m_nFlags;
}
inline void SetFlags(int flags)
{
m_nFlags = flags;
}
};
//-----------------------------------------------------------------------------
// Purpose: The console invoked command
//-----------------------------------------------------------------------------
class ConCommand : public ConCommandBase
{
friend class ConCommandBaseMgr;
friend class CCvar;
#ifdef _STATIC_LINKED
friend class G_ConCommand;
friend class C_ConCommand;
friend class M_ConCommand;
friend class S_ConCommand;
friend class D_ConCommand;
#endif
public:
typedef ConCommandBase BaseClass;
ConCommand( void );
ConCommand( char const *pName, FnCommandCallback callback,
char const *pHelpString = 0, int flags = 0, FnCommandCompletionCallback completionFunc = 0 );
virtual ~ConCommand( void );
virtual bool IsCommand( void ) const;
virtual int AutoCompleteSuggest( char const *partial, char commands[ COMMAND_COMPLETION_MAXITEMS ][ COMMAND_COMPLETION_ITEM_LENGTH ] );
virtual bool CanAutoComplete( void );
// Invoke the function
virtual void Dispatch( void );
private:
virtual void Create( char const *pName, FnCommandCallback callback,
char const *pHelpString = 0, int flags = 0, FnCommandCompletionCallback completionFunc = 0 );
// Call this function when executing the command
FnCommandCallback m_fnCommandCallback;
FnCommandCompletionCallback m_fnCompletionCallback;
bool m_bHasCompletionCallback;
public: // Hackalicous
inline FnCommandCallback GetCallback() const
{
return m_fnCommandCallback;
}
};
//-----------------------------------------------------------------------------
// Purpose: A console variable
//-----------------------------------------------------------------------------
class ConVar : public ConCommandBase
{
friend class ConCommandBaseMgr;
friend class CCvar;
friend class CDefaultCvar;
#ifdef _STATIC_LINKED
friend class G_ConVar;
friend class C_ConVar;
friend class M_ConVar;
friend class S_ConVar;
friend class D_ConVar;
#endif
public:
typedef ConCommandBase BaseClass;
ConVar( char const *pName, char const *pDefaultValue, int flags = 0);
ConVar( char const *pName, char const *pDefaultValue, int flags,
char const *pHelpString );
ConVar( char const *pName, char const *pDefaultValue, int flags,
char const *pHelpString, bool bMin, float fMin, bool bMax, float fMax );
ConVar( char const *pName, char const *pDefaultValue, int flags,
char const *pHelpString, FnChangeCallback callback );
ConVar( char const *pName, char const *pDefaultValue, int flags,
char const *pHelpString, bool bMin, float fMin, bool bMax, float fMax,
FnChangeCallback callback );
virtual ~ConVar( void );
virtual bool IsBitSet( int flag ) const;
virtual char const* GetHelpText( void ) const;
virtual bool IsRegistered( void ) const;
virtual char const *GetName( void ) const;
virtual void AddFlags( int flags );
virtual bool IsCommand( void ) const;
// Install a change callback (there shouldn't already be one....)
void InstallChangeCallback( FnChangeCallback callback );
// Retrieve value
FORCEINLINE_CVAR float GetFloat( void ) const;
FORCEINLINE_CVAR int GetInt( void ) const;
FORCEINLINE_CVAR bool GetBool() const { return !!GetInt(); }
FORCEINLINE_CVAR char const *GetString( void ) const;
// Any function that allocates/frees memory needs to be virtual or else you'll have crashes
// from alloc/free across dll/exe boundaries.
// These just call into the IConCommandBaseAccessor to check flags and set the var (which ends up calling InternalSetValue).
virtual void SetValue( char const *value );
virtual void SetValue( float value );
virtual void SetValue( int value );
// Reset to default value
void Revert( void );
// True if it has a min/max setting
bool GetMin( float& minVal ) const;
bool GetMax( float& maxVal ) const;
char const *GetDefault( void ) const;
static void RevertAll( void );
private:
// Called by CCvar when the value of a var is changing.
virtual void InternalSetValue(char const *value);
// For CVARs marked FCVAR_NEVER_AS_STRING
virtual void InternalSetFloatValue( float fNewValue );
virtual void InternalSetIntValue( int nValue );
virtual bool ClampValue( float& value );
virtual void ChangeStringValue( char const *tempVal );
virtual void Create( char const *pName, char const *pDefaultValue, int flags = 0,
char const *pHelpString = 0, bool bMin = false, float fMin = 0.0,
bool bMax = false, float fMax = false, FnChangeCallback callback = 0 );
// Used internally by OneTimeInit to initialize.
virtual void Init();
private:
// This either points to "this" or it points to the original declaration of a ConVar.
// This allows ConVars to exist in separate modules, and they all use the first one to be declared.
// m_pParent->m_pParent must equal m_pParent (ie: m_pParent must be the root, or original, ConVar).
ConVar *m_pParent;
// Static data
char const *m_pszDefaultValue;
// Value
// Dynamically allocated
char *m_pszString;
int m_StringLength;
// Values
float m_fValue;
int m_nValue;
// Min/Max values
bool m_bHasMin;
float m_fMinVal;
bool m_bHasMax;
float m_fMaxVal;
// Call this function when ConVar changes
FnChangeCallback m_fnChangeCallback;
public: // Hackalicous
inline FnChangeCallback GetCallback() const
{
return m_fnChangeCallback;
}
inline void SetMin(bool set, float min=0.0)
{
m_bHasMin = set;
m_fMinVal = min;
}
inline void SetMax(bool set, float max=0.0)
{
m_bHasMax = set;
m_fMaxVal = max;
}
};
//-----------------------------------------------------------------------------
// Purpose: Return ConVar value as a float
// Output : float
//-----------------------------------------------------------------------------
FORCEINLINE_CVAR float ConVar::GetFloat( void ) const
{
return m_pParent->m_fValue;
}
//-----------------------------------------------------------------------------
// Purpose: Return ConVar value as an int
// Output : int
//-----------------------------------------------------------------------------
FORCEINLINE_CVAR int ConVar::GetInt( void ) const
{
return m_pParent->m_nValue;
}
//-----------------------------------------------------------------------------
// Purpose: Return ConVar value as a string, return "" for bogus string pointer, etc.
// Output : char const *
//-----------------------------------------------------------------------------
FORCEINLINE_CVAR char const *ConVar::GetString( void ) const
{
if ( m_nFlags & FCVAR_NEVER_AS_STRING )
{
return "FCVAR_NEVER_AS_STRING";
}
return ( m_pParent->m_pszString ) ? m_pParent->m_pszString : "";
}
#ifdef _STATIC_LINKED
// identifies subsystem via piggybacking constructors with flags
class G_ConCommand : public ConCommand
{
public:
G_ConCommand(char const *pName, FnCommandCallback callback, char const *pHelpString = 0, int flags = 0, FnCommandCompletionCallback completionFunc = 0 ) : ConCommand(pName, callback, pHelpString, flags|FCVAR_GAMEDLL, completionFunc) {}
};
class C_ConCommand : public ConCommand
{
public:
C_ConCommand(char const *pName, FnCommandCallback callback, char const *pHelpString = 0, int flags = 0, FnCommandCompletionCallback completionFunc = 0 ) : ConCommand(pName, callback, pHelpString, flags|FCVAR_CLIENTDLL, completionFunc) {}
};
class M_ConCommand : public ConCommand
{
public:
M_ConCommand(char const *pName, FnCommandCallback callback, char const *pHelpString = 0, int flags = 0, FnCommandCompletionCallback completionFunc = 0 ) : ConCommand(pName, callback, pHelpString, flags|FCVAR_MATERIAL_SYSTEM, completionFunc) {}
};
class S_ConCommand : public ConCommand
{
public:
S_ConCommand(char const *pName, FnCommandCallback callback, char const *pHelpString = 0, int flags = 0, FnCommandCompletionCallback completionFunc = 0 ) : ConCommand(pName, callback, pHelpString, flags|FCVAR_STUDIORENDER, completionFunc) {}
};
class D_ConCommand : public ConCommand
{
public:
D_ConCommand(char const *pName, FnCommandCallback callback, char const *pHelpString = 0, int flags = 0, FnCommandCompletionCallback completionFunc = 0 ) : ConCommand(pName, callback, pHelpString, flags|FCVAR_DATACACHE, completionFunc) {}
};
typedef void ( *G_FnChangeCallback )( G_ConVar *var, char const *pOldString );
typedef void ( *C_FnChangeCallback )( C_ConVar *var, char const *pOldString );
typedef void ( *M_FnChangeCallback )( M_ConVar *var, char const *pOldString );
typedef void ( *S_FnChangeCallback )( S_ConVar *var, char const *pOldString );
typedef void ( *D_FnChangeCallback )( D_ConVar *var, char const *pOldString );
class G_ConVar : public ConVar
{
public:
G_ConVar( char const *pName, char const *pDefaultValue, int flags = 0) : ConVar(pName, pDefaultValue, flags|FCVAR_GAMEDLL) {}
G_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString ) : ConVar(pName, pDefaultValue, flags|FCVAR_GAMEDLL, pHelpString ) {}
G_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, bool bMin, float fMin, bool bMax, float fMax ) : ConVar(pName, pDefaultValue, flags|FCVAR_GAMEDLL, pHelpString, bMin, fMin, bMax, fMax) {}
G_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, G_FnChangeCallback callback ) : ConVar(pName, pDefaultValue, flags|FCVAR_GAMEDLL, pHelpString, (FnChangeCallback)callback ) {}
G_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, bool bMin, float fMin, bool bMax, float fMax, G_FnChangeCallback callback ) : ConVar(pName, pDefaultValue, flags|FCVAR_GAMEDLL, pHelpString, bMin, fMin, bMax, fMax, (FnChangeCallback)callback ) {}
};
class C_ConVar : public ConVar
{
public:
C_ConVar( char const *pName, char const *pDefaultValue, int flags = 0) : ConVar(pName, pDefaultValue, flags|FCVAR_CLIENTDLL) {}
C_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString ) : ConVar(pName, pDefaultValue, flags|FCVAR_CLIENTDLL, pHelpString ) {}
C_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, bool bMin, float fMin, bool bMax, float fMax ) : ConVar(pName, pDefaultValue, flags|FCVAR_CLIENTDLL, pHelpString, bMin, fMin, bMax, fMax) {}
C_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, C_FnChangeCallback callback ) : ConVar(pName, pDefaultValue, flags|FCVAR_CLIENTDLL, pHelpString, (FnChangeCallback)callback ) {}
C_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, bool bMin, float fMin, bool bMax, float fMax, C_FnChangeCallback callback ) : ConVar(pName, pDefaultValue, flags|FCVAR_CLIENTDLL, pHelpString, bMin, fMin, bMax, fMax, (FnChangeCallback)callback ) {}
};
class M_ConVar : public ConVar
{
public:
M_ConVar( char const *pName, char const *pDefaultValue, int flags = 0) : ConVar(pName, pDefaultValue, flags|FCVAR_MATERIAL_SYSTEM) {}
M_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString ) : ConVar(pName, pDefaultValue, flags|FCVAR_MATERIAL_SYSTEM, pHelpString ) {}
M_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, bool bMin, float fMin, bool bMax, float fMax ) : ConVar(pName, pDefaultValue, flags|FCVAR_MATERIAL_SYSTEM, pHelpString, bMin, fMin, bMax, fMax) {}
M_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, M_FnChangeCallback callback ) : ConVar(pName, pDefaultValue, flags|FCVAR_MATERIAL_SYSTEM, pHelpString, (FnChangeCallback)callback ) {}
M_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, bool bMin, float fMin, bool bMax, float fMax, M_FnChangeCallback callback ) : ConVar(pName, pDefaultValue, flags|FCVAR_MATERIAL_SYSTEM, pHelpString, bMin, fMin, bMax, fMax, (FnChangeCallback)callback ) {}
};
class S_ConVar : public ConVar
{
public:
S_ConVar( char const *pName, char const *pDefaultValue, int flags = 0) : ConVar(pName, pDefaultValue, flags|FCVAR_STUDIORENDER) {}
S_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString ) : ConVar(pName, pDefaultValue, flags|FCVAR_STUDIORENDER, pHelpString ) {}
S_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, bool bMin, float fMin, bool bMax, float fMax ) : ConVar(pName, pDefaultValue, flags|FCVAR_STUDIORENDER, pHelpString, bMin, fMin, bMax, fMax) {}
S_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, M_FnChangeCallback callback ) : ConVar(pName, pDefaultValue, flags|FCVAR_STUDIORENDER, pHelpString, (FnChangeCallback)callback ) {}
S_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, bool bMin, float fMin, bool bMax, float fMax, S_FnChangeCallback callback ) : ConVar(pName, pDefaultValue, flags|FCVAR_STUDIORENDER, pHelpString, bMin, fMin, bMax, fMax, (FnChangeCallback)callback ) {}
};
class D_ConVar : public ConVar
{
public:
D_ConVar( char const *pName, char const *pDefaultValue, int flags = 0) : ConVar(pName, pDefaultValue, flags|FCVAR_DATACACHE) {}
D_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString ) : ConVar(pName, pDefaultValue, flags|FCVAR_DATACACHE, pHelpString ) {}
D_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, bool bMin, float fMin, bool bMax, float fMax ) : ConVar(pName, pDefaultValue, flags|FCVAR_DATACACHE, pHelpString, bMin, fMin, bMax, fMax) {}
D_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, M_FnChangeCallback callback ) : ConVar(pName, pDefaultValue, flags|FCVAR_DATACACHE, pHelpString, (FnChangeCallback)callback ) {}
D_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, bool bMin, float fMin, bool bMax, float fMax, D_FnChangeCallback callback ) : ConVar(pName, pDefaultValue, flags|FCVAR_DATACACHE, pHelpString, bMin, fMin, bMax, fMax, (FnChangeCallback)callback ) {}
};
// redirect these declarations to their specific subsystem
#ifdef GAME_DLL
#define ConCommand G_ConCommand
#define ConVar G_ConVar
#endif
#ifdef CLIENT_DLL
#define ConCommand C_ConCommand
#define ConVar C_ConVar
#endif
#ifdef MATERIALSYSTEM_DLL
#define ConCommand M_ConCommand
#define ConVar M_ConVar
#endif
#ifdef STUDIORENDER_DLL
#define ConCommand S_ConCommand
#define ConVar S_ConVar
#endif
#ifdef DATACACHE_DLL
#define ConCommand D_ConCommand
#define ConVar D_ConVar
#endif
#endif // _STATIC_LINKED
//-----------------------------------------------------------------------------
// Purpose: Utility to quicky generate a simple console command
//-----------------------------------------------------------------------------
#define CON_COMMAND( name, description ) \
static void name(); \
static ConCommand name##_command( #name, name, description ); \
static void name()
//-----------------------------------------------------------------------------
// Purpose: Utility to quicky generate a simple console command
//-----------------------------------------------------------------------------
#define CON_COMMAND_F( name, description, flags ) \
static void name(); \
static ConCommand name##_command( #name, name, description, flags ); \
static void name()
#endif // CONVAR_H

View File

@ -1,709 +0,0 @@
//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======//
//
// Purpose:
//
// $Workfile: $
// $Date: $
//
//-----------------------------------------------------------------------------
// $NoKeywords: $
//===========================================================================//
#ifndef CONVAR_H
#define CONVAR_H
#if _WIN32
#pragma once
#endif
#include "tier0/dbg.h"
#include "tier1/iconvar.h"
#include "tier1/utlvector.h"
#include "tier1/utlstring.h"
#include "icvar.h"
#ifdef _WIN32
#define FORCEINLINE_CVAR FORCEINLINE
#elif _LINUX
#define FORCEINLINE_CVAR inline
#else
#error "implement me"
#endif
//-----------------------------------------------------------------------------
// Forward declarations
//-----------------------------------------------------------------------------
class ConVar;
class CCommand;
class ConCommand;
class ConCommandBase;
struct characterset_t;
//-----------------------------------------------------------------------------
// Any executable that wants to use ConVars need to implement one of
// these to hook up access to console variables.
//-----------------------------------------------------------------------------
class IConCommandBaseAccessor
{
public:
// Flags is a combination of FCVAR flags in cvar.h.
// hOut is filled in with a handle to the variable.
virtual bool RegisterConCommandBase( ConCommandBase *pVar ) = 0;
};
//-----------------------------------------------------------------------------
// Helper method for console development
//-----------------------------------------------------------------------------
#if defined( _X360 ) && !defined( _RETAIL )
void ConVar_PublishToVXConsole();
#endif
//-----------------------------------------------------------------------------
// Called when a ConCommand needs to execute
//-----------------------------------------------------------------------------
typedef void ( *FnCommandCallbackV1_t )( void );
typedef void ( *FnCommandCallback_t )( const CCommand &command );
#define COMMAND_COMPLETION_MAXITEMS 64
#define COMMAND_COMPLETION_ITEM_LENGTH 64
//-----------------------------------------------------------------------------
// Returns 0 to COMMAND_COMPLETION_MAXITEMS worth of completion strings
//-----------------------------------------------------------------------------
typedef int ( *FnCommandCompletionCallback )( const char *partial, char commands[ COMMAND_COMPLETION_MAXITEMS ][ COMMAND_COMPLETION_ITEM_LENGTH ] );
//-----------------------------------------------------------------------------
// Interface version
//-----------------------------------------------------------------------------
class ICommandCallback
{
public:
virtual void CommandCallback( const CCommand &command ) = 0;
};
class ICommandCompletionCallback
{
public:
virtual int CommandCompletionCallback( const char *pPartial, CUtlVector< CUtlString > &commands ) = 0;
};
//-----------------------------------------------------------------------------
// Purpose: The base console invoked command/cvar interface
//-----------------------------------------------------------------------------
class ConCommandBase
{
friend class CCvar;
friend class ConVar;
friend class ConCommand;
friend void ConVar_Register( int nCVarFlag, IConCommandBaseAccessor *pAccessor );
friend void ConVar_PublishToVXConsole();
// FIXME: Remove when ConVar changes are done
friend class CDefaultCvar;
public:
ConCommandBase( void );
ConCommandBase( const char *pName, const char *pHelpString = 0,
int flags = 0 );
virtual ~ConCommandBase( void );
virtual bool IsCommand( void ) const;
// Check flag
virtual bool IsFlagSet( int flag ) const;
// Set flag
virtual void AddFlags( int flags );
// Return name of cvar
virtual const char *GetName( void ) const;
// Return help text for cvar
virtual const char *GetHelpText( void ) const;
// Deal with next pointer
const ConCommandBase *GetNext( void ) const;
ConCommandBase *GetNext( void );
void SetNext(ConCommandBase *pBase)
{
m_pNext = pBase;
}
virtual bool IsRegistered( void ) const;
// Returns the DLL identifier
virtual CVarDLLIdentifier_t GetDLLIdentifier() const;
protected:
virtual void Create( const char *pName, const char *pHelpString = 0,
int flags = 0 );
// Used internally by OneTimeInit to initialize/shutdown
virtual void Init();
void Shutdown();
// Internal copy routine ( uses new operator from correct module )
char *CopyString( const char *from );
private:
// Next ConVar in chain
// Prior to register, it points to the next convar in the DLL.
// Once registered, though, m_pNext is reset to point to the next
// convar in the global list
ConCommandBase *m_pNext;
// Has the cvar been added to the global list?
bool m_bRegistered;
// Static data
const char *m_pszName;
const char *m_pszHelpString;
// ConVar flags
int m_nFlags;
protected:
// ConVars add themselves to this list for the executable.
// Then ConVar_Register runs through all the console variables
// and registers them into a global list stored in vstdlib.dll
static ConCommandBase *s_pConCommandBases;
// ConVars in this executable use this 'global' to access values.
static IConCommandBaseAccessor *s_pAccessor;
public: // Hackalicous
inline int GetFlags() const
{
return m_nFlags;
}
inline void SetFlags(int flags)
{
m_nFlags = flags;
}
};
//-----------------------------------------------------------------------------
// Command tokenizer
//-----------------------------------------------------------------------------
class CCommand
{
public:
CCommand();
CCommand( int nArgC, const char **ppArgV );
bool Tokenize( const char *pCommand, characterset_t *pBreakSet = NULL );
void Reset();
int ArgC() const;
const char **ArgV() const;
const char *ArgS() const; // All args that occur after the 0th arg, in string form
const char *GetCommandString() const; // The entire command in string form, including the 0th arg
const char *operator[]( int nIndex ) const; // Gets at arguments
const char *Arg( int nIndex ) const; // Gets at arguments
// Helper functions to parse arguments to commands.
const char* FindArg( const char *pName ) const;
int FindArgInt( const char *pName, int nDefaultVal ) const;
static int MaxCommandLength();
static characterset_t* DefaultBreakSet();
private:
enum
{
COMMAND_MAX_ARGC = 64,
COMMAND_MAX_LENGTH = 512,
};
int m_nArgc;
int m_nArgv0Size;
char m_pArgSBuffer[ COMMAND_MAX_LENGTH ];
char m_pArgvBuffer[ COMMAND_MAX_LENGTH ];
const char* m_ppArgv[ COMMAND_MAX_ARGC ];
};
inline int CCommand::MaxCommandLength()
{
return COMMAND_MAX_LENGTH - 1;
}
inline int CCommand::ArgC() const
{
return m_nArgc;
}
inline const char **CCommand::ArgV() const
{
return m_nArgc ? (const char**)m_ppArgv : NULL;
}
inline const char *CCommand::ArgS() const
{
return m_nArgv0Size ? &m_pArgSBuffer[m_nArgv0Size] : "";
}
inline const char *CCommand::GetCommandString() const
{
return m_nArgc ? m_pArgSBuffer : "";
}
inline const char *CCommand::Arg( int nIndex ) const
{
// FIXME: Many command handlers appear to not be particularly careful
// about checking for valid argc range. For now, we're going to
// do the extra check and return an empty string if it's out of range
if ( nIndex < 0 || nIndex >= m_nArgc )
return "";
return m_ppArgv[nIndex];
}
inline const char *CCommand::operator[]( int nIndex ) const
{
return Arg( nIndex );
}
//-----------------------------------------------------------------------------
// Purpose: The console invoked command
//-----------------------------------------------------------------------------
class ConCommand : public ConCommandBase
{
friend class CCvar;
public:
typedef ConCommandBase BaseClass;
ConCommand( const char *pName, FnCommandCallbackV1_t callback,
const char *pHelpString = 0, int flags = 0, FnCommandCompletionCallback completionFunc = 0 );
ConCommand( const char *pName, FnCommandCallback_t callback,
const char *pHelpString = 0, int flags = 0, FnCommandCompletionCallback completionFunc = 0 );
ConCommand( const char *pName, ICommandCallback *pCallback,
const char *pHelpString = 0, int flags = 0, ICommandCompletionCallback *pCommandCompletionCallback = 0 );
virtual ~ConCommand( void );
virtual bool IsCommand( void ) const;
virtual int AutoCompleteSuggest( const char *partial, CUtlVector< CUtlString > &commands );
virtual bool CanAutoComplete( void );
// Invoke the function
virtual void Dispatch( const CCommand &command );
private:
// NOTE: To maintain backward compat, we have to be very careful:
// All public virtual methods must appear in the same order always
// since engine code will be calling into this code, which *does not match*
// in the mod code; it's using slightly different, but compatible versions
// of this class. Also: Be very careful about adding new fields to this class.
// Those fields will not exist in the version of this class that is instanced
// in mod code.
// Call this function when executing the command
union
{
FnCommandCallbackV1_t m_fnCommandCallbackV1;
FnCommandCallback_t m_fnCommandCallback;
ICommandCallback *m_pCommandCallback;
};
union
{
FnCommandCompletionCallback m_fnCompletionCallback;
ICommandCompletionCallback *m_pCommandCompletionCallback;
};
bool m_bHasCompletionCallback : 1;
bool m_bUsingNewCommandCallback : 1;
bool m_bUsingCommandCallbackInterface : 1;
public: // Hackalicous
inline FnCommandCallback_t GetCallback() const
{
return m_fnCommandCallback;
}
};
//-----------------------------------------------------------------------------
// Purpose: A console variable
//-----------------------------------------------------------------------------
class ConVar : public ConCommandBase, public IConVar
{
friend class CCvar;
friend class ConVarRef;
public:
typedef ConCommandBase BaseClass;
ConVar( const char *pName, const char *pDefaultValue, int flags = 0);
ConVar( const char *pName, const char *pDefaultValue, int flags,
const char *pHelpString );
ConVar( const char *pName, const char *pDefaultValue, int flags,
const char *pHelpString, bool bMin, float fMin, bool bMax, float fMax );
ConVar( const char *pName, const char *pDefaultValue, int flags,
const char *pHelpString, FnChangeCallback_t callback );
ConVar( const char *pName, const char *pDefaultValue, int flags,
const char *pHelpString, bool bMin, float fMin, bool bMax, float fMax,
FnChangeCallback_t callback );
virtual ~ConVar( void );
virtual bool IsFlagSet( int flag ) const;
virtual const char* GetHelpText( void ) const;
virtual bool IsRegistered( void ) const;
virtual const char *GetName( void ) const;
virtual void AddFlags( int flags );
virtual bool IsCommand( void ) const;
// Install a change callback (there shouldn't already be one....)
void InstallChangeCallback( FnChangeCallback_t callback );
// Retrieve value
FORCEINLINE_CVAR float GetFloat( void ) const;
FORCEINLINE_CVAR int GetInt( void ) const;
FORCEINLINE_CVAR bool GetBool() const { return !!GetInt(); }
FORCEINLINE_CVAR char const *GetString( void ) const;
// Any function that allocates/frees memory needs to be virtual or else you'll have crashes
// from alloc/free across dll/exe boundaries.
// These just call into the IConCommandBaseAccessor to check flags and set the var (which ends up calling InternalSetValue).
virtual void SetValue( const char *value );
virtual void SetValue( float value );
virtual void SetValue( int value );
// Reset to default value
void Revert( void );
// True if it has a min/max setting
bool GetMin( float& minVal ) const;
bool GetMax( float& maxVal ) const;
const char *GetDefault( void ) const;
private:
// Called by CCvar when the value of a var is changing.
virtual void InternalSetValue(const char *value);
// For CVARs marked FCVAR_NEVER_AS_STRING
virtual void InternalSetFloatValue( float fNewValue );
virtual void InternalSetIntValue( int nValue );
virtual bool ClampValue( float& value );
virtual void ChangeStringValue( const char *tempVal, float flOldValue );
virtual void Create( const char *pName, const char *pDefaultValue, int flags = 0,
const char *pHelpString = 0, bool bMin = false, float fMin = 0.0,
bool bMax = false, float fMax = false, FnChangeCallback_t callback = 0 );
// Used internally by OneTimeInit to initialize.
virtual void Init();
private:
// This either points to "this" or it points to the original declaration of a ConVar.
// This allows ConVars to exist in separate modules, and they all use the first one to be declared.
// m_pParent->m_pParent must equal m_pParent (ie: m_pParent must be the root, or original, ConVar).
ConVar *m_pParent;
// Static data
const char *m_pszDefaultValue;
// Value
// Dynamically allocated
char *m_pszString;
int m_StringLength;
// Values
float m_fValue;
int m_nValue;
// Min/Max values
bool m_bHasMin;
float m_fMinVal;
bool m_bHasMax;
float m_fMaxVal;
// Call this function when ConVar changes
FnChangeCallback_t m_fnChangeCallback;
public: // Hackalicous
inline FnChangeCallback_t GetCallback() const
{
return m_fnChangeCallback;
}
inline void SetMin(bool set, float min=0.0)
{
m_bHasMin = set;
m_fMinVal = min;
}
inline void SetMax(bool set, float max=0.0)
{
m_bHasMax = set;
m_fMaxVal = max;
}
};
//-----------------------------------------------------------------------------
// Purpose: Return ConVar value as a float
// Output : float
//-----------------------------------------------------------------------------
FORCEINLINE_CVAR float ConVar::GetFloat( void ) const
{
return m_pParent->m_fValue;
}
//-----------------------------------------------------------------------------
// Purpose: Return ConVar value as an int
// Output : int
//-----------------------------------------------------------------------------
FORCEINLINE_CVAR int ConVar::GetInt( void ) const
{
return m_pParent->m_nValue;
}
//-----------------------------------------------------------------------------
// Purpose: Return ConVar value as a string, return "" for bogus string pointer, etc.
// Output : const char *
//-----------------------------------------------------------------------------
FORCEINLINE_CVAR const char *ConVar::GetString( void ) const
{
if ( m_nFlags & FCVAR_NEVER_AS_STRING )
return "FCVAR_NEVER_AS_STRING";
return ( m_pParent->m_pszString ) ? m_pParent->m_pszString : "";
}
//-----------------------------------------------------------------------------
// Used to read/write convars that already exist (replaces the FindVar method)
//-----------------------------------------------------------------------------
class ConVarRef
{
public:
ConVarRef( const char *pName );
ConVarRef( const char *pName, bool bIgnoreMissing );
ConVarRef( IConVar *pConVar );
void Init( const char *pName, bool bIgnoreMissing );
bool IsValid() const;
bool IsFlagSet( int nFlags ) const;
IConVar *GetLinkedConVar();
// Get/Set value
float GetFloat( void ) const;
int GetInt( void ) const;
bool GetBool() const { return !!GetInt(); }
const char *GetString( void ) const;
void SetValue( const char *pValue );
void SetValue( float flValue );
void SetValue( int nValue );
void SetValue( bool bValue );
const char *GetName() const;
const char *GetDefault() const;
private:
// High-speed method to read convar data
IConVar *m_pConVar;
ConVar *m_pConVarState;
};
//-----------------------------------------------------------------------------
// Did we find an existing convar of that name?
//-----------------------------------------------------------------------------
FORCEINLINE_CVAR bool ConVarRef::IsFlagSet( int nFlags ) const
{
return ( m_pConVar->IsFlagSet( nFlags ) != 0 );
}
FORCEINLINE_CVAR IConVar *ConVarRef::GetLinkedConVar()
{
return m_pConVar;
}
FORCEINLINE_CVAR const char *ConVarRef::GetName() const
{
return m_pConVar->GetName();
}
//-----------------------------------------------------------------------------
// Purpose: Return ConVar value as a float
//-----------------------------------------------------------------------------
FORCEINLINE_CVAR float ConVarRef::GetFloat( void ) const
{
return m_pConVarState->m_fValue;
}
//-----------------------------------------------------------------------------
// Purpose: Return ConVar value as an int
//-----------------------------------------------------------------------------
FORCEINLINE_CVAR int ConVarRef::GetInt( void ) const
{
return m_pConVarState->m_nValue;
}
//-----------------------------------------------------------------------------
// Purpose: Return ConVar value as a string, return "" for bogus string pointer, etc.
//-----------------------------------------------------------------------------
FORCEINLINE_CVAR const char *ConVarRef::GetString( void ) const
{
Assert( !IsFlagSet( FCVAR_NEVER_AS_STRING ) );
return m_pConVarState->m_pszString;
}
FORCEINLINE_CVAR void ConVarRef::SetValue( const char *pValue )
{
m_pConVar->SetValue( pValue );
}
FORCEINLINE_CVAR void ConVarRef::SetValue( float flValue )
{
m_pConVar->SetValue( flValue );
}
FORCEINLINE_CVAR void ConVarRef::SetValue( int nValue )
{
m_pConVar->SetValue( nValue );
}
FORCEINLINE_CVAR void ConVarRef::SetValue( bool bValue )
{
m_pConVar->SetValue( bValue ? 1 : 0 );
}
FORCEINLINE_CVAR const char *ConVarRef::GetDefault() const
{
return m_pConVarState->m_pszDefaultValue;
}
//-----------------------------------------------------------------------------
// Called by the framework to register ConCommands with the ICVar
//-----------------------------------------------------------------------------
void ConVar_Register( int nCVarFlag = 0, IConCommandBaseAccessor *pAccessor = NULL );
void ConVar_Unregister( );
//-----------------------------------------------------------------------------
// Utility methods
//-----------------------------------------------------------------------------
void ConVar_PrintFlags( const ConCommandBase *var );
void ConVar_PrintDescription( const ConCommandBase *pVar );
//-----------------------------------------------------------------------------
// Purpose: Utility class to quickly allow ConCommands to call member methods
//-----------------------------------------------------------------------------
#if defined _MSC_VER
#pragma warning (disable : 4355 )
#endif
template< class T >
class CConCommandMemberAccessor : public ConCommand, public ICommandCallback, public ICommandCompletionCallback
{
typedef ConCommand BaseClass;
typedef void ( T::*FnMemberCommandCallback_t )( const CCommand &command );
typedef int ( T::*FnMemberCommandCompletionCallback_t )( const char *pPartial, CUtlVector< CUtlString > &commands );
public:
CConCommandMemberAccessor( T* pOwner, const char *pName, FnMemberCommandCallback_t callback, const char *pHelpString = 0,
int flags = 0, FnMemberCommandCompletionCallback_t completionFunc = 0 ) :
BaseClass( pName, this, pHelpString, flags, ( completionFunc != 0 ) ? this : NULL )
{
m_pOwner = pOwner;
m_Func = callback;
m_CompletionFunc = completionFunc;
}
~CConCommandMemberAccessor()
{
Shutdown();
}
void SetOwner( T* pOwner )
{
m_pOwner = pOwner;
}
virtual void CommandCallback( const CCommand &command )
{
Assert( m_pOwner && m_Func );
(m_pOwner->*m_Func)( command );
}
virtual int CommandCompletionCallback( const char *pPartial, CUtlVector< CUtlString > &commands )
{
Assert( m_pOwner && m_CompletionFunc );
return (m_pOwner->*m_CompletionFunc)( pPartial, commands );
}
private:
T* m_pOwner;
FnMemberCommandCallback_t m_Func;
FnMemberCommandCompletionCallback_t m_CompletionFunc;
};
#if defined _MSC_VER
#pragma warning ( default : 4355 )
#endif
//-----------------------------------------------------------------------------
// Purpose: Utility macros to quicky generate a simple console command
//-----------------------------------------------------------------------------
#define CON_COMMAND( name, description ) \
static void name( const CCommand &args ); \
static ConCommand name##_command( #name, name, description ); \
static void name( const CCommand &args )
#define CON_COMMAND_F( name, description, flags ) \
static void name( const CCommand &args ); \
static ConCommand name##_command( #name, name, description, flags ); \
static void name( const CCommand &args )
#define CON_COMMAND_F_COMPLETION( name, description, flags, completion ) \
static void name( const CCommand &args ); \
static ConCommand name##_command( #name, name, description, flags, completion ); \
static void name( const CCommand &args )
#define CON_COMMAND_EXTERN( name, _funcname, description ) \
void _funcname( const CCommand &args ); \
static ConCommand name##_command( #name, _funcname, description ); \
void _funcname( const CCommand &args )
#define CON_COMMAND_EXTERN_F( name, _funcname, description, flags ) \
void _funcname( const CCommand &args ); \
static ConCommand name##_command( #name, _funcname, description, flags ); \
void _funcname( const CCommand &args )
#define CON_COMMAND_MEMBER_F( _thisclass, name, _funcname, description, flags ) \
void _funcname( const CCommand &args ); \
friend class CCommandMemberInitializer_##_funcname; \
class CCommandMemberInitializer_##_funcname \
{ \
public: \
CCommandMemberInitializer_##_funcname() : m_ConCommandAccessor( NULL, name, &_thisclass::_funcname, description, flags ) \
{ \
m_ConCommandAccessor.SetOwner( GET_OUTER( _thisclass, m_##_funcname##_register ) ); \
} \
private: \
CConCommandMemberAccessor< _thisclass > m_ConCommandAccessor; \
}; \
\
CCommandMemberInitializer_##_funcname m_##_funcname##_register; \
#endif // CONVAR_H

View File

@ -1,64 +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$
*/
#include "frame_hooks.h"
#include "TimerSys.h"
#include "Database.h"
#include "HalfLife2.h"
#include "MenuStyle_Valve.h"
#include "MenuStyle_Radio.h"
#include "PlayerManager.h"
float g_LastMenuTime = 0.0f;
float g_LastAuthCheck = 0.0f;
void RunFrameHooks(bool simulating)
{
/* Frame based hooks */
g_DBMan.RunFrame();
g_HL2.ProcessFakeCliCmdQueue();
g_HL2.ProcessDelayedKicks();
g_SourceMod.ProcessGameFrameHooks(simulating);
float curtime = *g_pUniversalTime;
if (curtime - g_LastMenuTime >= 1.0f)
{
g_ValveMenuStyle.ProcessWatchList();
g_RadioMenuStyle.ProcessWatchList();
g_LastMenuTime = curtime;
}
if (*g_NumPlayersToAuth && curtime - g_LastAuthCheck >= 0.7f)
{
g_Players.RunAuthChecks();
g_LastAuthCheck = curtime;
}
}

View File

@ -1,37 +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_FRAME_HOOKS_H_
#define _INCLUDE_SOURCEMOD_FRAME_HOOKS_H_
void RunFrameHooks(bool simulating);
#endif //_INCLUDE_SOURCEMOD_FRAME_HOOKS_H_

View File

@ -1,485 +0,0 @@
// MD5.CC - source code for the C++/object oriented translation and
// modification of MD5.
// Translation and modification (c) 1995 by Mordechai T. Abzug
// This translation/ modification is provided "as is," without express or
// implied warranty of any kind.
// The translator/ modifier does not claim (1) that MD5 will do what you think
// it does; (2) that this translation/ modification is accurate; or (3) that
// this software is "merchantible." (Language for this disclaimer partially
// copied from the disclaimer below).
/* based on:
MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
MDDRIVER.C - test driver for MD2, MD4 and MD5
Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
rights reserved.
License to copy and use this software is granted provided that it
is identified as the "RSA Data Security, Inc. MD5 Message-Digest
Algorithm" in all material mentioning or referencing this software
or this function.
License is also granted to make and use derivative works provided
that such works are identified as "derived from the RSA Data
Security, Inc. MD5 Message-Digest Algorithm" in all material
mentioning or referencing the derived work.
RSA Data Security, Inc. makes no representations concerning either
the merchantability of this software or the suitability of this
software for any particular purpose. It is provided "as is"
without express or implied warranty of any kind.
These notices must be retained in any copies of any part of this
documentation and/or software.
*/
#include "md5.h"
#include <assert.h>
#include <string.h>
// MD5 simple initialization method
MD5::MD5(){
init();
}
// MD5 block update operation. Continues an MD5 message-digest
// operation, processing another message block, and updating the
// context.
void MD5::update (uint1 *input, uint4 input_length) {
uint4 input_index, buffer_index;
uint4 buffer_space; // how much space is left in buffer
if (finalized){ // so we can't update!
/*cerr << "MD5::update: Can't update a finalized digest!" << endl;*/
return;
}
// Compute number of bytes mod 64
buffer_index = (unsigned int)((count[0] >> 3) & 0x3F);
// Update number of bits
if ( (count[0] += ((uint4) input_length << 3))<((uint4) input_length << 3) )
count[1]++;
count[1] += ((uint4)input_length >> 29);
buffer_space = 64 - buffer_index; // how much space is left in buffer
// Transform as many times as possible.
if (input_length >= buffer_space) { // ie. we have enough to fill the buffer
// fill the rest of the buffer and transform
memcpy (buffer + buffer_index, input, buffer_space);
transform (buffer);
// now, transform each 64-byte piece of the input, bypassing the buffer
for (input_index = buffer_space; input_index + 63 < input_length;
input_index += 64)
transform (input+input_index);
buffer_index = 0; // so we can buffer remaining
}
else
input_index=0; // so we can buffer the whole input
// and here we do the buffering:
memcpy(buffer+buffer_index, input+input_index, input_length-input_index);
}
// MD5 update for files.
// Like above, except that it works on files (and uses above as a primitive.)
void MD5::update(FILE *file){
unsigned char buffer[1024];
int len;
while ((len=fread(buffer, 1, 1024, file)))
update(buffer, len);
fclose (file);
}
// MD5 finalization. Ends an MD5 message-digest operation, writing the
// the message digest and zeroizing the context.
void MD5::finalize (){
unsigned char bits[8];
unsigned int index, padLen;
static uint1 PADDING[64]={
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
if (finalized){
/* cerr << "MD5::finalize: Already finalized this digest!" << endl;*/
return;
}
// Save number of bits
encode (bits, count, 8);
// Pad out to 56 mod 64.
index = (uint4) ((count[0] >> 3) & 0x3f);
padLen = (index < 56) ? (56 - index) : (120 - index);
update (PADDING, padLen);
// Append length (before padding)
update (bits, 8);
// Store state in digest
encode (digest, state, 16);
// Zeroize sensitive information
memset (buffer, 0, sizeof(*buffer));
finalized=1;
}
MD5::MD5(FILE *file){
init(); // must be called be all constructors
update(file);
finalize ();
}
unsigned char *MD5::raw_digest(){
uint1 *s = new uint1[16];
if (!finalized){
/* cerr << "MD5::raw_digest: Can't get digest if you haven't "<<
"finalized the digest!" <<endl;*/
return ( (unsigned char*) "");
}
memcpy(s, digest, 16);
return s;
}
unsigned char *MD5::raw_digest(unsigned char buffer[16])
{
if (!finalized)
{
return ( (unsigned char*) "");
}
memcpy(buffer, digest, 16);
return buffer;
}
char *MD5::hex_digest(){
int i;
char *s= new char[33];
if (!finalized){
/* cerr << "MD5::hex_digest: Can't get digest if you haven't "<<
"finalized the digest!" <<endl;*/
return "";
}
for (i=0; i<16; i++)
sprintf(s+i*2, "%02x", digest[i]);
s[32]='\0';
return s;
}
char *MD5::hex_digest(char buffer[33]){
int i;
if (!finalized)
{
/* cerr << "MD5::hex_digest: Can't get digest if you haven't "<<
"finalized the digest!" <<endl;*/
return "";
}
for (i=0; i<16; i++)
sprintf(buffer+i*2, "%02x", digest[i]);
buffer[32]='\0';
return buffer;
}
// PRIVATE METHODS:
void MD5::init(){
finalized=0; // we just started!
// Nothing counted, so count=0
count[0] = 0;
count[1] = 0;
// Load magic initialization constants.
state[0] = 0x67452301;
state[1] = 0xefcdab89;
state[2] = 0x98badcfe;
state[3] = 0x10325476;
}
// Constants for MD5Transform routine.
// Although we could use C++ style constants, defines are actually better,
// since they let us easily evade scope clashes.
#define S11 7
#define S12 12
#define S13 17
#define S14 22
#define S21 5
#define S22 9
#define S23 14
#define S24 20
#define S31 4
#define S32 11
#define S33 16
#define S34 23
#define S41 6
#define S42 10
#define S43 15
#define S44 21
// MD5 basic transformation. Transforms state based on block.
void MD5::transform (uint1 block[64]){
uint4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
decode (x, block, 64);
assert(!finalized); // not just a user error, since the method is private
/* Round 1 */
FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
/* Round 2 */
GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
/* Round 3 */
HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
/* Round 4 */
II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
// Zeroize sensitive information.
memset ( (uint1 *) x, 0, sizeof(x));
}
// Encodes input (UINT4) into output (unsigned char). Assumes len is
// a multiple of 4.
void MD5::encode (uint1 *output, uint4 *input, uint4 len) {
unsigned int i, j;
for (i = 0, j = 0; j < len; i++, j += 4) {
output[j] = (uint1) (input[i] & 0xff);
output[j+1] = (uint1) ((input[i] >> 8) & 0xff);
output[j+2] = (uint1) ((input[i] >> 16) & 0xff);
output[j+3] = (uint1) ((input[i] >> 24) & 0xff);
}
}
// Decodes input (unsigned char) into output (UINT4). Assumes len is
// a multiple of 4.
void MD5::decode (uint4 *output, uint1 *input, uint4 len){
unsigned int i, j;
for (i = 0, j = 0; j < len; i++, j += 4)
output[i] = ((uint4)input[j]) | (((uint4)input[j+1]) << 8) |
(((uint4)input[j+2]) << 16) | (((uint4)input[j+3]) << 24);
}
// Note: Replace "for loop" with standard memcpy if possible.
void MD5::memcpy (uint1 *output, uint1 *input, uint4 len){
unsigned int i;
for (i = 0; i < len; i++)
output[i] = input[i];
}
// Note: Replace "for loop" with standard memset if possible.
void MD5::memset (uint1 *output, uint1 value, uint4 len){
unsigned int i;
for (i = 0; i < len; i++)
output[i] = value;
}
// ROTATE_LEFT rotates x left n bits.
inline unsigned int MD5::rotate_left (uint4 x, uint4 n){
return (x << n) | (x >> (32-n)) ;
}
// F, G, H and I are basic MD5 functions.
inline unsigned int MD5::F (uint4 x, uint4 y, uint4 z){
return (x & y) | (~x & z);
}
inline unsigned int MD5::G (uint4 x, uint4 y, uint4 z){
return (x & z) | (y & ~z);
}
inline unsigned int MD5::H (uint4 x, uint4 y, uint4 z){
return x ^ y ^ z;
}
inline unsigned int MD5::I (uint4 x, uint4 y, uint4 z){
return y ^ (x | ~z);
}
// FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
// Rotation is separate from addition to prevent recomputation.
inline void MD5::FF(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x,
uint4 s, uint4 ac){
a += F(b, c, d) + x + ac;
a = rotate_left (a, s) +b;
}
inline void MD5::GG(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x,
uint4 s, uint4 ac){
a += G(b, c, d) + x + ac;
a = rotate_left (a, s) +b;
}
inline void MD5::HH(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x,
uint4 s, uint4 ac){
a += H(b, c, d) + x + ac;
a = rotate_left (a, s) +b;
}
inline void MD5::II(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x,
uint4 s, uint4 ac){
a += I(b, c, d) + x + ac;
a = rotate_left (a, s) +b;
}

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