Compare commits

..

No commits in common. "1.10-fork" and "sourcemod-1.0.0" have entirely different histories.

2753 changed files with 186708 additions and 986329 deletions

View File

@ -1,5 +0,0 @@
{
"project_id" : "sourcemod",
"conduit_uri" : "https://phabricator.alliedmods.net/",
"history.immutable" : false
}

12
.gitattributes vendored
View File

@ -1,12 +0,0 @@
# GitHub views all .h files as C, let's assume it's C++
*.h linguist-language=c++
# Internal tools overriding
tools/* linguist-vendored
editor/* linguist-vendored
# Third-party overriding
extensions/curl/curl-src/* linguist-vendored
extensions/geoip/GeoIP.c linguist-vendored
extensions/geoip/GeoIP.h linguist-vendored
extensions/sqlite/sqlite-source/* linguist-vendored

View File

@ -1,74 +0,0 @@
# Contributing to SourceMod
## Issue reports
Please consider the following guidelines when reporting an issue.
#### Not for general support
This is not the right place to get help with using or installing SourceMod, or for issues with specific, third-party SourceMod plugins or extensions.
For help with SourceMod, please consult the [AlliedModders forums](https://forums.alliedmods.net/forumdisplay.php?f=52). Similarly, for assistance with, or to report issues with, third-party SourceMod plugins or extensions, you should post in the existing thread for that plugin or extension on the [AlliedModders forums](https://forums.alliedmods.net/forumdisplay.php?f=52).
#### Details, details, details
Provide as much detail as possible when reporting an issue.
For bugs or other undesired behavior, answers to the following questions are a great start:
* What is the issue?
* What behavior are you expecting instead?
* On what operating system is the game server running?
* What game is the game server running?
* What exact version (full x.y.z.a version number) of Metamod:Source and SourceMod are installed on the game server?
* What is the specific, shortest path to reproducing this issue? If this issue can be reproduced with plugin code, please try to shorten it to the minimum required to trigger the problem.
If this is a feature request, the following are helpful. Generally, not all will apply, but whatever you can answer ahead of time will shorten back and forth conversation.
* What is your end goal, or what are you trying to accomplish?
* Why is this necessary, or what benefit do you see with it?
* Will this be useful to others?
#### Issues with security implications
Please report any security bugs to [security@alliedmods.net](mailto:security@alliedmods.net) rather than to this public issue tracker.
#### We're only human
Please keep in mind that we maintain this project in our spare time, at no cost. There is no SLA, and you are not owed a response or a fix.
#### Conduct
Please refer to the [AlliedModders forum rules.](https://forums.alliedmods.net/misc.php?do=showrules)
## Pull Requests
Firstly, thank you for considering contributing changes to the project!
However, if this is anything more than a small fix such as a gamedata update, a glaring code flaw, or a simple typo in a file like this one, please file an issue first so that it can be discussed, unless you have already spoken to multiple members of the development team about it on IRC or the AlliedModders forums.
We don't like to have to reject pull requests, so we want to avoid those scenarios. We wouldn't want you to feel like you wasted your time writing something only for us to shoot it down.
#### Rejection
*Copied from Phabricator's [Contributing Code guidelines](https://secure.phabricator.com/book/phabcontrib/article/contributing_code/#rejecting-patches), as we largely feel the same way about this.*
> If you send us a patch without coordinating it with us first, it will probably be immediately rejected, or sit in limbo for a long time and eventually be rejected. The reasons we do this vary from patch to patch, but some of the most common reasons are:
>
> **Unjustifiable Costs**: We support code in the upstream forever. Support is enormously expensive and takes up a huge amount of our time. The cost to support a change over its lifetime is often 10x or 100x or 1000x greater than the cost to write the first version of it. Many uncoordinated patches we receive are "white elephants", which would cost much more to maintain than the value they provide.
>
> As an author, it may look like you're giving us free work and we're rejecting it as too expensive, but this viewpoint doesn't align with the reality of a large project which is actively supported by a small, experienced team. Writing code is cheap; maintaining it is expensive.
>
> By coordinating with us first, you can make sure the patch is something we consider valuable enough to put long-term support resources behind, and that you're building it in a way that we're comfortable taking over.
>
> **Not a Good Fit**: Many patches aren't good fits for the upstream: they implement features we simply don't want. You can find more information in Contributing Feature Requests. Coordinating with us first helps make sure we're on the same page and interested in a feature.
>
> The most common type of patch along these lines is a patch which adds new configuration options. We consider additional configuration options to have an exceptionally high lifetime support cost and are very unlikely to accept them. Coordinate with us first.
>
> **Not a Priority**: If you send us a patch against something which isn't a priority, we probably won't have time to look at it. We don't give special treatment to low-priority issues just because there's code written: we'd still be spending time on something lower-priority when we could be spending it on something higher-priority instead.
>
> If you coordinate with us first, you can make sure your patch is in an area of the codebase that we can prioritize.
>
> **Overly Ambitious Patches**: Sometimes we'll get huge patches from new contributors. These can have a lot of fundamental problems and require a huge amount of our time to review and correct. If you're interested in contributing, you'll have more success if you start small and learn as you go.
>
> We can help you break a large change into smaller pieces and learn how the codebase works as you proceed through the implementation, but only if you coordinate with us first.
>
> **Generality**: We often receive several feature requests which ask for similar features, and can come up with a general approach which covers all of the use cases. If you send us a patch for your use case only, the approach may be too specific. When a cleaner and more general approach is available, we usually prefer to pursue it.
>
> By coordinating with us first, we can make you aware of similar use cases and opportunities to generalize an approach. These changes are often small, but can have a big impact on how useful a piece of code is.
>
> **Infrastructure and Sequencing**: Sometimes patches are written against a piece of infrastructure with major planned changes. We don't want to accept these because they'll make the infrastructure changes more difficult to implement.
>
> Coordinate with us first to make sure a change doesn't need to wait on other pieces of infrastructure. We can help you identify technical blockers and possibly guide you through resolving them if you're interested.

8
.github/FUNDING.yml vendored
View File

@ -1,8 +0,0 @@
# These are supported funding model platforms
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
custom: https://www.sourcemod.net/donate.php

View File

@ -1,26 +0,0 @@
# Help us help you
- [ ] I have checked that my issue [doesn't exist yet](https://github.com/alliedmodders/sourcemod/issues).
- [ ] I have tried my absolute best to reduce the problem-space and have provided the absolute smallest test-case possible.
- [ ] I can always reproduce the issue with the provided description below.
# Environment
* Operating System version:
* Game/AppID (with version if applicable):
* Current SourceMod version:
* Current SourceMod snapshot:
* Current Metamod: Source snapshot:
- [ ] I have updated SourceMod to the [latest version](https://www.sourcemod.net/downloads.php) and it still happens.
- [ ] I have updated SourceMod to the [latest snapshot](https://www.sourcemod.net/downloads.php?branch=dev) and it still happens.
- [ ] I have updated SourceMM to the [latest snapshot](https://sourcemm.net/downloads.php?branch=dev) and it still happens.
# Description
# Problematic Code (or Steps to Reproduce)
```
// TODO(you): code here to reproduce the problem
```
# Logs
* Please attach in separate files: game output, library logs, kernel logs, and any other supporting information.
* In case of a crash, please attach minidump or dump analyze output.

38
.gitignore vendored
View File

@ -1,38 +0,0 @@
# Binaries
*.dll
*.dylib
*.exe
*.so
# Files generated by Visual Studio
*.aps
*.ipch
*.ncb
*.opensdf
*.sdf
*.suo
*.user
# Build directories
CrazyDebug*/
Debug*/
Release*/
LIB-Release/
LIB-Debug/
# Files generated by Mac OS X Finder
.DS_Store
# Files generated by Windows Explorer
[Dd]esktop.ini
[Tt]humbs.db
# AMBuild build directories
build/
obj-*/
*~
*.rej
*.orig
*.smx
*.swp
*.gdb_history

6
.gitmodules vendored
View File

@ -1,6 +0,0 @@
[submodule "public/amtl"]
path = public/amtl
url = https://github.com/alliedmodders/amtl
[submodule "sourcepawn"]
path = sourcepawn
url = https://github.com/BotoX/sourcepawn.git

View File

@ -1,118 +0,0 @@
git:
depth: 3
sudo: false
language: cpp
os: linux
dist: trusty
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-trusty-3.9
- llvm-toolchain-trusty-4.0
- llvm-toolchain-trusty-5.0
packages:
- lib32stdc++6
- lib32z1-dev
- libc6-dev-i386
- linux-libc-dev
- g++-multilib
# - clang-3.6
# - clang-3.8
# - clang-4.0
# - clang-5.0
# - g++-6
# - g++-6-multilib
- clang-3.9
- g++-4.8-multilib
- g++-4.8
- g++-4.9-multilib
- g++-4.9
- g++-5-multilib
- g++-5
- g++-7-multilib
- g++-7
cache:
directories:
- ../mysql-5.0
env:
- MATRIX_EVAL="CC=clang-3.9 && CXX=clang++-3.9"
- MATRIX_EVAL="CC=gcc-4.8 && CXX=g++-4.8"
- MATRIX_EVAL="CC=gcc-4.9 && CXX=g++-4.9"
- MATRIX_EVAL="CC=gcc-5 && CXX=g++-5"
- MATRIX_EVAL="CC=gcc-7 && CXX=g++-7"
matrix:
fast_finish: true
include:
- os: linux
sudo: false
language: cpp
addons:
apt:
packages: ['clang-3.6', 'lib32stdc++6', 'lib32z1-dev', 'libc6-dev-i386', 'linux-libc-dev', 'g++-multilib']
cache:
directories: ['../mysql-5.0']
env: ['MATRIX_EVAL="CC=clang-3.6 && CXX=clang++-3.6"']
- os: linux
sudo: false
language: cpp
addons:
apt:
packages: ['clang-3.8', 'lib32stdc++6', 'lib32z1-dev', 'libc6-dev-i386', 'linux-libc-dev', 'g++-multilib']
cache:
directories: ['../mysql-5.0']
env: ['MATRIX_EVAL="CC=clang-3.8 && CXX=clang++-3.8"']
- os: linux
sudo: false
language: cpp
addons:
apt:
sources: ['llvm-toolchain-trusty-4.0']
packages: ['clang-4.0', 'lib32stdc++6', 'lib32z1-dev', 'libc6-dev-i386', 'linux-libc-dev', 'g++-multilib']
cache:
directories: ['../mysql-5.0']
env: ['MATRIX_EVAL="CC=clang-4.0 && CXX=clang++-4.0"']
- os: linux
sudo: false
language: cpp
addons:
apt:
sources: ['llvm-toolchain-trusty-5.0']
packages: ['clang-5.0', 'lib32stdc++6', 'lib32z1-dev', 'libc6-dev-i386', 'linux-libc-dev', 'g++-multilib']
cache:
directories: ['../mysql-5.0']
env: ['MATRIX_EVAL="CC=clang-5.0 && CXX=clang++-5.0"']
- os: linux
sudo: false
language: cpp
addons:
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['g++-6', 'g++-6-multilib', 'lib32stdc++6', 'lib32z1-dev', 'libc6-dev-i386', 'linux-libc-dev', 'g++-multilib']
cache:
directories: ['../mysql-5.0']
env: ['MATRIX_EVAL="CC=gcc-6 && CXX=g++-6"']
allow_failures:
- env: MATRIX_EVAL="CC=clang-3.7 && CXX=clang++-3.7"
- env: MATRIX_EVAL="CC=clang-3.9 && CXX=clang++-3.9"
- env: MATRIX_EVAL="CC=gcc-4.8 && CXX=g++-4.8"
- env: MATRIX_EVAL="CC=gcc-4.9 && CXX=g++-4.9"
- env: MATRIX_EVAL="CC=gcc-5 && CXX=g++-5"
- env: MATRIX_EVAL="CC=gcc-7 && CXX=g++-7"
before_script:
- CHECKOUT_DIR=$PWD && cd .. && $CHECKOUT_DIR/tools/checkout-deps.sh && cd $CHECKOUT_DIR
script:
- mkdir build && cd build
- PATH="~/.local/bin:$PATH"
- eval "${MATRIX_EVAL}"
- python ../configure.py --enable-optimize --sdks=episode1,css,tf2,l4d2,csgo,dota
- ambuild

View File

@ -1,671 +0,0 @@
# vim: set sts=2 ts=8 sw=2 tw=99 et ft=python:
import os, sys
class SDK(object):
def __init__(self, sdk, ext, aDef, name, platform, dir):
self.folder = 'hl2sdk-' + dir
self.envvar = sdk
self.ext = ext
self.code = aDef
self.define = name
self.platform = platform
self.name = dir
self.path = None # Actual path
self.platformSpec = platform
# By default, nothing supports x64.
if type(platform) is list:
self.platformSpec = {p: ['x86'] for p in platform}
else:
self.platformSpec = platform
def shouldBuild(self, target, archs):
if target.platform not in self.platformSpec:
return False
if not len([i for i in self.platformSpec[target.platform] if i in archs]):
return False
return True
WinOnly = ['windows']
WinLinux = ['windows', 'linux']
WinLinuxMac = ['windows', 'linux', 'mac']
CSGO = {
'windows': ['x86'],
'linux': ['x86', 'x64'],
'mac': ['x64']
}
PossibleSDKs = {
'episode1': SDK('HL2SDK', '2.ep1', '1', 'EPISODEONE', WinLinux, 'episode1'),
'ep2': SDK('HL2SDKOB', '2.ep2', '3', 'ORANGEBOX', WinLinux, 'orangebox'),
'css': SDK('HL2SDKCSS', '2.css', '6', 'CSS', WinLinuxMac, 'css'),
'hl2dm': SDK('HL2SDKHL2DM', '2.hl2dm', '7', 'HL2DM', WinLinuxMac, 'hl2dm'),
'dods': SDK('HL2SDKDODS', '2.dods', '8', 'DODS', WinLinuxMac, 'dods'),
'sdk2013': SDK('HL2SDK2013', '2.sdk2013', '9', 'SDK2013', WinLinuxMac, 'sdk2013'),
'tf2': SDK('HL2SDKTF2', '2.tf2', '11', 'TF2', WinLinuxMac, 'tf2'),
'l4d': SDK('HL2SDKL4D', '2.l4d', '12', 'LEFT4DEAD', WinLinuxMac, 'l4d'),
'nucleardawn': SDK('HL2SDKND', '2.nd', '13', 'NUCLEARDAWN', WinLinuxMac, 'nucleardawn'),
'l4d2': SDK('HL2SDKL4D2', '2.l4d2', '15', 'LEFT4DEAD2', WinLinuxMac, 'l4d2'),
'darkm': SDK('HL2SDK-DARKM', '2.darkm', '2', 'DARKMESSIAH', WinOnly, 'darkm'),
'swarm': SDK('HL2SDK-SWARM', '2.swarm', '16', 'ALIENSWARM', WinOnly, 'swarm'),
'bgt': SDK('HL2SDK-BGT', '2.bgt', '4', 'BLOODYGOODTIME', WinOnly, 'bgt'),
'eye': SDK('HL2SDK-EYE', '2.eye', '5', 'EYE', WinOnly, 'eye'),
'csgo': SDK('HL2SDKCSGO', '2.csgo', '21', 'CSGO', CSGO, 'csgo'),
'portal2': SDK('HL2SDKPORTAL2', '2.portal2', '17', 'PORTAL2', [], 'portal2'),
'blade': SDK('HL2SDKBLADE', '2.blade', '18', 'BLADE', WinLinux, 'blade'),
'insurgency': SDK('HL2SDKINSURGENCY', '2.insurgency', '19', 'INSURGENCY', WinLinuxMac, 'insurgency'),
'contagion': SDK('HL2SDKCONTAGION', '2.contagion', '14', 'CONTAGION', WinOnly, 'contagion'),
'bms': SDK('HL2SDKBMS', '2.bms', '10', 'BMS', WinLinux, 'bms'),
'doi': SDK('HL2SDKDOI', '2.doi', '20', 'DOI', WinLinuxMac, 'doi'),
}
def ResolveEnvPath(env, folder):
if env in os.environ:
path = os.environ[env]
if os.path.isdir(path):
return path
return None
head = os.getcwd()
oldhead = None
while head != None and head != oldhead:
path = os.path.join(head, folder)
if os.path.isdir(path):
return path
oldhead = head
head, tail = os.path.split(head)
return None
def Normalize(path):
return os.path.abspath(os.path.normpath(path))
def SetArchFlags(compiler, arch, platform):
if compiler.behavior == 'gcc':
if arch == 'x86':
compiler.cflags += ['-m32']
compiler.linkflags += ['-m32']
if platform == 'mac':
compiler.linkflags += ['-arch', 'i386']
elif arch == 'x64':
compiler.cflags += ['-m64', '-fPIC']
compiler.linkflags += ['-m64']
if platform == 'mac':
compiler.linkflags += ['-arch', 'x86_64']
elif compiler.like('msvc'):
if builder.target.arch == 'x86':
compiler.linkflags += ['/MACHINE:X86']
elif builder.target.arch == 'x64':
compiler.linkflags += ['/MACHINE:X64']
def AppendArchSuffix(binary, name, arch):
if arch == 'x64':
binary.localFolder = name + '.x64'
class SMConfig(object):
def __init__(self):
self.sdks = {}
self.binaries = []
self.extensions = []
self.generated_headers = None
self.mms_root = None
self.mysql_root = {}
self.spcomp = None
self.spcomp_bins = None
self.smx_files = {}
self.versionlib = None
self.archs = builder.target.arch.replace('x86_64', 'x64').split(',')
def use_auto_versioning(self):
if builder.backend != 'amb2':
return False
return not getattr(builder.options, 'disable_auto_versioning', False)
@property
def tag(self):
if builder.options.debug == '1':
return 'Debug'
return 'Release'
def detectProductVersion(self):
builder.AddConfigureFile('product.version')
# For OS X dylib versioning
import re
with open(os.path.join(builder.sourcePath, 'product.version'), 'r') as fp:
productContents = fp.read()
m = re.match('(\d+)\.(\d+)\.(\d+).*', productContents)
if m == None:
self.productVersion = '1.0.0'
else:
major, minor, release = m.groups()
self.productVersion = '{0}.{1}.{2}'.format(major, minor, release)
def detectSDKs(self):
sdk_list = builder.options.sdks.split(',')
use_all = sdk_list[0] == 'all'
use_present = sdk_list[0] == 'present'
for sdk_name in PossibleSDKs:
sdk = PossibleSDKs[sdk_name]
if sdk.shouldBuild(builder.target, self.archs):
if builder.options.hl2sdk_root:
sdk_path = os.path.join(builder.options.hl2sdk_root, sdk.folder)
else:
sdk_path = ResolveEnvPath(sdk.envvar, sdk.folder)
if sdk_path is None or not os.path.isdir(sdk_path):
if use_all or sdk_name in sdk_list:
raise Exception('Could not find a valid path for {0}'.format(sdk.envvar))
continue
if use_all or use_present or sdk_name in sdk_list:
sdk.path = Normalize(sdk_path)
self.sdks[sdk_name] = sdk
if len(self.sdks) < 1 and len(sdk_list):
raise Exception('No SDKs were found that build on {0}-{1}, nothing to do.'.format(
builder.target.platform, builder.target.arch))
if builder.options.mms_path:
self.mms_root = builder.options.mms_path
else:
self.mms_root = ResolveEnvPath('MMSOURCE110', 'mmsource-1.10')
if not self.mms_root:
self.mms_root = ResolveEnvPath('MMSOURCE_DEV', 'metamod-source')
if not self.mms_root:
self.mms_root = ResolveEnvPath('MMSOURCE_DEV', 'mmsource-central')
if not self.mms_root or not os.path.isdir(self.mms_root):
raise Exception('Could not find a source copy of Metamod:Source')
self.mms_root = Normalize(self.mms_root)
if builder.options.hasMySql:
if builder.options.mysql_path:
self.mysql_root['x86'] = builder.options.mysql_path
else:
for i in range(10):
self.mysql_root['x86'] = ResolveEnvPath('MYSQL55', 'mysql-5.' + str(i))
if self.mysql_root['x86']:
break
if not self.mysql_root['x86'] or not os.path.isdir(self.mysql_root['x86']):
raise Exception('Could not find a path to MySQL!')
self.mysql_root['x86'] = Normalize(self.mysql_root['x86'])
# For now, ignore 64-bit MySQL on Windows
if 'x64' in self.archs and builder.target.platform != 'windows':
if builder.options.mysql64_path:
self.mysql_root['x64'] = builder.options.mysql64_path
else:
for i in range(10):
self.mysql_root['x64'] = ResolveEnvPath('MYSQL55_64', 'mysql-5.' + str(i) + '-x86_64')
if self.mysql_root['x64']:
break
if not self.mysql_root['x64'] or not os.path.isdir(self.mysql_root['x64']):
raise Exception('Could not find a path to 64-bit MySQL!')
self.mysql_root['x64'] = Normalize(self.mysql_root['x64'])
def configure(self):
builder.AddConfigureFile('pushbuild.txt')
if not set(self.archs).issubset(['x86', 'x64']):
raise Exception('Unknown target architecture: {0}'.format(builder.target.arch))
cxx = builder.DetectCxx()
if cxx.like('msvc') and len(self.archs) > 1:
raise Exception('Building multiple archs with MSVC is not currently supported')
if cxx.like('gcc'):
self.configure_gcc(cxx)
elif cxx.family == 'msvc':
self.configure_msvc(cxx)
# Optimizaiton
if builder.options.opt == '1':
cxx.defines += ['NDEBUG']
# Debugging
if builder.options.debug == '1':
cxx.defines += ['DEBUG', '_DEBUG']
# Platform-specifics
if builder.target.platform == 'linux':
self.configure_linux(cxx)
elif builder.target.platform == 'mac':
self.configure_mac(cxx)
elif builder.target.platform == 'windows':
self.configure_windows(cxx)
# Finish up.
cxx.defines += [
'SOURCEMOD_BUILD',
'SM_USE_VERSIONLIB',
]
cxx.includes += [
os.path.join(builder.sourcePath, 'public'),
]
if self.use_auto_versioning():
cxx.defines += ['SM_GENERATED_BUILD']
cxx.includes += [
os.path.join(builder.buildPath, 'includes'),
os.path.join(builder.sourcePath, 'versionlib'),
]
def configure_gcc(self, cxx):
cxx.defines += [
'stricmp=strcasecmp',
'_stricmp=strcasecmp',
'_snprintf=snprintf',
'_vsnprintf=vsnprintf',
'HAVE_STDINT_H',
'GNUC',
]
cxx.cflags += [
'-pipe',
'-fno-strict-aliasing',
'-Wall',
'-Werror',
'-Wno-unused',
'-Wno-switch',
'-Wno-array-bounds',
'-msse',
'-fvisibility=hidden',
]
cxx.cxxflags += [
'-std=c++11',
'-fno-exceptions',
'-fno-threadsafe-statics',
'-Wno-non-virtual-dtor',
'-Wno-overloaded-virtual',
'-fvisibility-inlines-hidden',
]
have_gcc = cxx.family == 'gcc'
have_clang = cxx.family == 'clang'
if cxx.version >= 'clang-3.9':
cxx.cxxflags += ['-Wno-expansion-to-defined']
if cxx.version == 'clang-3.9' or cxx.version == 'apple-clang-8.0':
cxx.cflags += ['-Wno-varargs']
if cxx.version >= 'clang-3.6' or cxx.version >= 'apple-clang-7.0':
cxx.cxxflags += ['-Wno-inconsistent-missing-override']
if cxx.version >= 'clang-2.9' or cxx.version >= 'apple-clang-3.0':
cxx.cxxflags += ['-Wno-null-dereference']
if have_clang or (cxx.version >= 'gcc-4.6'):
cxx.cflags += ['-Wno-narrowing']
if have_clang or (cxx.version >= 'gcc-4.7'):
cxx.cxxflags += ['-Wno-delete-non-virtual-dtor']
if cxx.version >= 'gcc-4.8':
cxx.cflags += ['-Wno-unused-result']
if cxx.version >= 'gcc-9.0':
cxx.cxxflags += ['-Wno-class-memaccess', '-Wno-packed-not-aligned']
if have_clang:
cxx.cxxflags += ['-Wno-implicit-exception-spec-mismatch']
if cxx.version >= 'apple-clang-5.1' or cxx.version >= 'clang-3.4':
cxx.cxxflags += ['-Wno-deprecated-register']
else:
cxx.cxxflags += ['-Wno-deprecated']
cxx.cflags += ['-Wno-sometimes-uninitialized']
if have_gcc:
cxx.cflags += ['-mfpmath=sse']
cxx.cflags += ['-Wno-maybe-uninitialized']
if builder.options.opt == '1':
cxx.cflags += ['-O3']
def configure_msvc(self, cxx):
if builder.options.debug == '1':
cxx.cflags += ['/MTd']
cxx.linkflags += ['/NODEFAULTLIB:libcmt']
else:
cxx.cflags += ['/MT']
cxx.defines += [
'_CRT_SECURE_NO_DEPRECATE',
'_CRT_SECURE_NO_WARNINGS',
'_CRT_NONSTDC_NO_DEPRECATE',
'_ITERATOR_DEBUG_LEVEL=0',
]
cxx.cflags += [
'/W3',
]
cxx.cxxflags += [
'/EHsc',
'/GR-',
'/TP',
]
cxx.linkflags += [
'kernel32.lib',
'user32.lib',
'gdi32.lib',
'winspool.lib',
'comdlg32.lib',
'advapi32.lib',
'shell32.lib',
'ole32.lib',
'oleaut32.lib',
'uuid.lib',
'odbc32.lib',
'odbccp32.lib',
]
if builder.options.opt == '1':
cxx.cflags += ['/Ox', '/Zo']
cxx.linkflags += ['/OPT:ICF', '/OPT:REF']
if builder.options.debug == '1':
cxx.cflags += ['/Od', '/RTC1']
# This needs to be after our optimization flags which could otherwise disable it.
# Don't omit the frame pointer.
cxx.cflags += ['/Oy-']
def configure_linux(self, cxx):
cxx.defines += ['_LINUX', 'POSIX', '_FILE_OFFSET_BITS=64']
cxx.linkflags += ['-lm']
if cxx.family == 'gcc':
cxx.linkflags += ['-static-libgcc']
elif cxx.family == 'clang':
cxx.linkflags += ['-lgcc_eh']
def configure_mac(self, cxx):
cxx.defines += ['OSX', '_OSX', 'POSIX', 'KE_ABSOLUTELY_NO_STL']
cxx.cflags += ['-mmacosx-version-min=10.5']
cxx.linkflags += [
'-mmacosx-version-min=10.5',
'-lstdc++',
'-stdlib=libstdc++',
]
cxx.cxxflags += ['-stdlib=libstdc++']
def configure_windows(self, cxx):
cxx.defines += ['WIN32', '_WINDOWS']
def AddVersioning(self, binary, arch):
if builder.target.platform == 'windows':
binary.sources += ['version.rc']
binary.compiler.rcdefines += [
'BINARY_NAME="{0}"'.format(binary.outputFile),
'RC_COMPILE',
]
if self.use_auto_versioning():
binary.compiler.rcdefines += ['SM_GENERATED_BUILD']
elif builder.target.platform == 'mac':
if binary.type == 'library':
binary.compiler.postlink += [
'-compatibility_version', '1.0.0',
'-current_version', self.productVersion
]
if self.use_auto_versioning():
binary.compiler.linkflags += [self.versionlib[arch]]
binary.compiler.sourcedeps += SM.generated_headers
return binary
def LibraryBuilder(self, compiler, name, arch):
binary = compiler.Library(name)
AppendArchSuffix(binary, name, arch)
self.AddVersioning(binary, arch)
if binary.compiler.like('msvc'):
binary.compiler.linkflags += ['/SUBSYSTEM:WINDOWS']
return binary
def ProgramBuilder(self, compiler, name, arch):
binary = compiler.Program(name)
AppendArchSuffix(binary, name, arch)
self.AddVersioning(binary, arch)
if '-static-libgcc' in binary.compiler.linkflags:
binary.compiler.linkflags.remove('-static-libgcc')
if '-lgcc_eh' in binary.compiler.linkflags:
binary.compiler.linkflags.remove('-lgcc_eh')
if binary.compiler.like('gcc'):
binary.compiler.linkflags += ['-lstdc++', '-lpthread']
if binary.compiler.like('msvc'):
binary.compiler.linkflags += ['/SUBSYSTEM:CONSOLE']
return binary
def StaticLibraryBuilder(self, compiler, name, arch):
binary = compiler.StaticLibrary(name)
AppendArchSuffix(binary, name, arch)
return binary;
def Library(self, context, name, arch):
compiler = context.cxx.clone()
SetArchFlags(compiler, arch, builder.target.platform)
return self.LibraryBuilder(compiler, name, arch)
def Program(self, context, name, arch):
compiler = context.cxx.clone()
SetArchFlags(compiler, arch, builder.target.platform)
return self.ProgramBuilder(compiler, name, arch)
def StaticLibrary(self, context, name, arch):
compiler = context.cxx.clone()
SetArchFlags(compiler, arch, builder.target.platform)
return self.StaticLibraryBuilder(compiler, name, arch)
def ConfigureForExtension(self, context, compiler):
compiler.cxxincludes += [
os.path.join(context.currentSourcePath),
os.path.join(context.currentSourcePath, 'sdk'),
os.path.join(builder.sourcePath, 'public', 'extensions'),
os.path.join(builder.sourcePath, 'sourcepawn', 'include'),
os.path.join(builder.sourcePath, 'public', 'amtl', 'amtl'),
os.path.join(builder.sourcePath, 'public', 'amtl'),
]
return compiler
def ExtLibrary(self, context, name, arch):
binary = self.Library(context, name, arch)
self.ConfigureForExtension(context, binary.compiler)
return binary
def ConfigureForHL2(self, binary, sdk, arch):
compiler = binary.compiler
SetArchFlags(compiler, arch, builder.target.platform)
compiler.cxxincludes += [
os.path.join(self.mms_root, 'core'),
os.path.join(self.mms_root, 'core', 'sourcehook'),
]
defines = ['SE_' + PossibleSDKs[i].define + '=' + PossibleSDKs[i].code for i in PossibleSDKs]
compiler.defines += defines
paths = [
['public'],
['public', 'engine'],
['public', 'mathlib'],
['public', 'vstdlib'],
['public', 'tier0'],
['public', 'tier1']
]
if sdk.name == 'episode1' or sdk.name == 'darkm':
paths.append(['public', 'dlls'])
paths.append(['game_shared'])
else:
paths.append(['public', 'game', 'server'])
paths.append(['public', 'toolframework'])
paths.append(['game', 'shared'])
paths.append(['common'])
compiler.defines += ['SOURCE_ENGINE=' + sdk.code]
if sdk.name in ['sdk2013', 'bms'] and compiler.like('gcc'):
# The 2013 SDK already has these in public/tier0/basetypes.h
compiler.defines.remove('stricmp=strcasecmp')
compiler.defines.remove('_stricmp=strcasecmp')
compiler.defines.remove('_snprintf=snprintf')
compiler.defines.remove('_vsnprintf=vsnprintf')
if compiler.like('msvc'):
compiler.defines += ['COMPILER_MSVC', 'COMPILER_MSVC32']
if compiler.version >= 1900:
compiler.linkflags += ['legacy_stdio_definitions.lib']
else:
compiler.defines += ['COMPILER_GCC']
if arch == 'x64':
compiler.defines += ['X64BITS', 'PLATFORM_64BITS']
# For everything after Swarm, this needs to be defined for entity networking
# to work properly with sendprop value changes.
if sdk.name in ['blade', 'insurgency', 'doi', 'csgo']:
compiler.defines += ['NETWORK_VARS_ENABLED']
if sdk.name in ['css', 'hl2dm', 'dods', 'sdk2013', 'bms', 'tf2', 'l4d', 'nucleardawn', 'l4d2']:
if builder.target.platform in ['linux', 'mac']:
compiler.defines += ['NO_HOOK_MALLOC', 'NO_MALLOC_OVERRIDE']
if sdk.name == 'csgo' and builder.target.platform == 'linux':
compiler.linkflags += ['-lstdc++']
compiler.defines += ['_GLIBCXX_USE_CXX11_ABI=0']
for path in paths:
compiler.cxxincludes += [os.path.join(sdk.path, *path)]
if builder.target.platform == 'linux':
if sdk.name == 'episode1':
lib_folder = os.path.join(sdk.path, 'linux_sdk')
elif sdk.name in ['sdk2013', 'bms']:
lib_folder = os.path.join(sdk.path, 'lib', 'public', 'linux32')
elif arch == 'x64':
lib_folder = os.path.join(sdk.path, 'lib', 'linux64')
else:
lib_folder = os.path.join(sdk.path, 'lib', 'linux')
elif builder.target.platform == 'mac':
if sdk.name in ['sdk2013', 'bms']:
lib_folder = os.path.join(sdk.path, 'lib', 'public', 'osx32')
elif arch == 'x64':
lib_folder = os.path.join(sdk.path, 'lib', 'osx64')
else:
lib_folder = os.path.join(sdk.path, 'lib', 'mac')
if builder.target.platform in ['linux', 'mac']:
if sdk.name in ['sdk2013', 'bms'] or arch == 'x64':
compiler.postlink += [
compiler.Dep(os.path.join(lib_folder, 'tier1.a')),
compiler.Dep(os.path.join(lib_folder, 'mathlib.a'))
]
else:
compiler.postlink += [
compiler.Dep(os.path.join(lib_folder, 'tier1_i486.a')),
compiler.Dep(os.path.join(lib_folder, 'mathlib_i486.a'))
]
if sdk.name in ['blade', 'insurgency', 'doi', 'csgo']:
if arch == 'x64':
compiler.postlink += [compiler.Dep(os.path.join(lib_folder, 'interfaces.a'))]
else:
compiler.postlink += [compiler.Dep(os.path.join(lib_folder, 'interfaces_i486.a'))]
dynamic_libs = []
if builder.target.platform == 'linux':
if sdk.name in ['css', 'hl2dm', 'dods', 'tf2', 'sdk2013', 'bms', 'nucleardawn', 'l4d2', 'insurgency', 'doi']:
dynamic_libs = ['libtier0_srv.so', 'libvstdlib_srv.so']
elif arch == 'x64' and sdk.name == 'csgo':
dynamic_libs = ['libtier0_client.so', 'libvstdlib_client.so']
elif sdk.name in ['l4d', 'blade', 'insurgency', 'doi', 'csgo']:
dynamic_libs = ['libtier0.so', 'libvstdlib.so']
else:
dynamic_libs = ['tier0_i486.so', 'vstdlib_i486.so']
elif builder.target.platform == 'mac':
compiler.linkflags.append('-liconv')
dynamic_libs = ['libtier0.dylib', 'libvstdlib.dylib']
elif builder.target.platform == 'windows':
libs = ['tier0', 'tier1', 'vstdlib', 'mathlib']
if sdk.name in ['swarm', 'blade', 'insurgency', 'doi', 'csgo']:
libs.append('interfaces')
for lib in libs:
lib_path = os.path.join(sdk.path, 'lib', 'public', lib) + '.lib'
compiler.linkflags.append(compiler.Dep(lib_path))
for library in dynamic_libs:
source_path = os.path.join(lib_folder, library)
output_path = os.path.join(binary.localFolder, library)
def make_linker(source_path, output_path):
def link(context, binary):
cmd_node, (output,) = context.AddSymlink(source_path, output_path)
return output
return link
linker = make_linker(source_path, output_path)
compiler.linkflags[0:0] = [compiler.Dep(library, linker)]
return binary
def HL2Library(self, context, name, sdk, arch):
binary = self.Library(context, name, arch)
self.ConfigureForExtension(context, binary.compiler)
return self.ConfigureForHL2(binary, sdk, arch)
def HL2Project(self, context, name):
project = context.cxx.LibraryProject(name)
self.ConfigureForExtension(context, project.compiler)
return project
def HL2Config(self, project, name, sdk, arch):
binary = project.Configure(name, '{0} - {1}'.format(self.tag, sdk.name))
AppendArchSuffix(binary, name, arch)
self.AddVersioning(binary, arch)
return self.ConfigureForHL2(binary, sdk, arch)
SM = SMConfig()
SM.detectProductVersion()
SM.detectSDKs()
SM.configure()
if SM.use_auto_versioning():
SM.generated_headers = builder.Build(
'tools/buildbot/Versioning',
{ 'SM': SM }
)
SM.versionlib = builder.Build(
'versionlib/AMBuilder',
{ 'SM': SM }
)
# Build SourcePawn externally.
SP = builder.Build('sourcepawn/AMBuildScript', {
'external_root': SM,
'external_amtl': os.path.join(builder.sourcePath, 'public', 'amtl'),
'external_build': ['core'],
})
if len(SP.spcomp) > 1:
SM.spcomp = SP.spcomp['x86']
else:
SM.spcomp = SP.spcomp[list(SP.spcomp.keys())[0]]
SM.spcomp_bins = list(SP.spcomp.values())
for arch in SM.archs:
SM.binaries += [
SP.libsourcepawn[arch]
]
BuildScripts = [
'loader/AMBuilder',
'core/AMBuilder',
'core/logic/AMBuilder',
'extensions/bintools/AMBuilder',
'extensions/clientprefs/AMBuilder',
'extensions/curl/AMBuilder',
'extensions/cstrike/AMBuilder',
'extensions/geoip/AMBuilder',
'extensions/mysql/AMBuilder',
'extensions/regex/AMBuilder',
'extensions/sdkhooks/AMBuilder',
'extensions/sdktools/AMBuilder',
'extensions/sqlite/AMBuilder',
'extensions/tf2/AMBuilder',
'extensions/topmenus/AMBuilder',
'extensions/updater/AMBuilder',
]
if builder.backend == 'amb2':
BuildScripts += [
'plugins/AMBuilder',
'tools/buildbot/PackageScript',
]
builder.Build(BuildScripts, { 'SM': SM })
if builder.options.breakpad_dump:
builder.Build('tools/buildbot/BreakpadSymbols', { 'SM': SM })

21
NOTICE.txt Normal file
View File

@ -0,0 +1,21 @@
We now use svn:keywords "Id" on all .c/.cpp/.h/.sp/.inc files. Please make sure your client is configured properly.
WINDOWS:
Open your Application Data folder.
Windows XP/2000: C:\Documents and Settings\<user>\Application Data
Windows Vista: C:\Users\<user>\AppData\Roaming
Now go to Subversion. 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
*.sp = svn:keywords=Id
*.inc = svn:keywords=Id

View File

@ -1,27 +0,0 @@
SourceMod
=========
General
-------
- [SourceMod website](http://www.sourcemod.net): Source Engine scripting and server administration
- [Forum](https://forums.alliedmods.net/forumdisplay.php?f=52): Discussion forum including plugin/extension development
- [General documentation](https://wiki.alliedmods.net/Category:SourceMod_Documentation): Miscellaneous information about SourceMod
- [Stable builds](http://www.sourcemod.net/downloads.php?branch=stable): The latest stable SourceMod releases
- [Dev builds](http://www.sourcemod.net/downloads.php?branch=dev): Builds of recent development versions
Development
-----------
- [Issue tracker](https://github.com/alliedmodders/sourcemod/issues): Issues that require back and forth communication
- [Building SourceMod](https://wiki.alliedmods.net/Building_SourceMod): Instructions on how to build SourceMod itself using [AMBuild](https://github.com/alliedmodders/ambuild)
- [SourcePawn scripting](https://wiki.alliedmods.net/Category:SourceMod_Scripting): SourcePawn examples and introduction to the language
- [SourceMod plugin API](https://sm.alliedmods.net/new-api): Online SourceMod plugin API reference generated from the include files
- [SourceMod extension development](https://wiki.alliedmods.net/Category:SourceMod_Development): C++ examples and introduction to various extension interfaces
Contact
-------
- Connect with us on [GameSurge](https://gamesurge.net) IRC in #sourcemod
- Alternatively feel free to join our [Discord](https://discord.gg/HgZctSS) server
License
-------
SourceMod is licensed under the GNU General Public License version 3. Special exceptions are outlined in the LICENSE.txt file inside of the licenses folder.

View File

@ -1,46 +0,0 @@
// vim: set ts=4 sw=4 tw=99 noet:
// =============================================================================
// SourceMod
// Copyright (C) 2004-2015 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>.
#ifndef _INCLUDE_SOURCEMOD_BRIDGE_API_H_
#define _INCLUDE_SOURCEMOD_BRIDGE_API_H_
#include <bridge/include/CoreProvider.h>
#include <bridge/include/LogicProvider.h>
#include <stdint.h>
namespace SourceMod {
// Add 1 to the RHS of this expression to bump the intercom file
// This is to prevent mismatching core/logic binaries
static const uint32_t SM_LOGIC_MAGIC = 0x0F47C0DE - 57;
} // namespace SourceMod
typedef void (*LogicInitFunction)(SourceMod::CoreProvider *core, SourceMod::sm_logic_t *logic);
typedef LogicInitFunction (*LogicLoadFunction)(uint32_t magic);
typedef SourceMod::ITextParsers *(*GetITextParsers)();
#endif // _INCLUDE_SOURCEMOD_BRIDGE_API_H_

View File

@ -1,140 +0,0 @@
// vim: set ts=4 sw=4 tw=99 noet:
// =============================================================================
// SourceMod
// Copyright (C) 2004-2015 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>.
#ifndef _INCLUDE_SOURCEMOD_CORE_PROVIDER_API_H_
#define _INCLUDE_SOURCEMOD_CORE_PROVIDER_API_H_
#include <stddef.h>
#include <stdint.h>
#include <IAdminSystem.h>
#include <amtl/am-function.h>
namespace SourcePawn {
class ISourcePawnEngine;
class ISourcePawnEngine2;
} // namespace SourcePawn
// SDK types.
#if defined(SM_LOGIC)
class ConCommandBase {};
class ConVar : public ConCommandBase {};
#else
class ConCommandBase;
class ConVar;
#endif
class KeyValues;
struct ServerGlobals
{
const double *universalTime;
float *interval_per_tick;
float *frametime;
};
namespace SourceMod {
class ISourceMod;
class IVEngineServerBridge;
class IFileSystemBridge;
class ITimerSystem;
class IPlayerManager;
class IGameHelpers;
class IMenuManager;
struct DatabaseInfo;
class IPlayerInfoBridge;
class ICommandArgs;
typedef ke::Lambda<bool(int client, const ICommandArgs*)> CommandFunc;
class CoreProvider
{
public:
/* Objects */
ISourceMod *sm;
IVEngineServerBridge *engine;
IFileSystemBridge *filesystem;
IPlayerInfoBridge *playerInfo;
ITimerSystem *timersys;
IPlayerManager *playerhelpers;
IGameHelpers *gamehelpers;
IMenuManager *menus;
SourcePawn::ISourcePawnEngine **spe1;
SourcePawn::ISourcePawnEngine2 **spe2;
const char *gamesuffix;
/* Data */
ServerGlobals *serverGlobals;
void * serverFactory;
void * engineFactory;
void * matchmakingDSFactory;
SMGlobalClass * listeners;
// ConVar functions.
virtual ConVar *FindConVar(const char *name) = 0;
virtual const char *GetCvarString(ConVar *cvar) = 0;
virtual bool GetCvarBool(ConVar* cvar) = 0;
// Command functions.
virtual void DefineCommand(const char *cmd, const char *help, const CommandFunc &callback) = 0;
// Game description functions.
virtual bool GetGameName(char *buffer, size_t maxlength) = 0;
virtual const char *GetGameDescription() = 0;
virtual const char *GetSourceEngineName() = 0;
virtual bool SymbolsAreHidden() = 0;
// Game state and helper functions.
virtual bool IsMapLoading() = 0;
virtual bool IsMapRunning() = 0;
virtual int MaxClients() = 0;
virtual bool DescribePlayer(int index, const char **namep, const char **authp, int *useridp) = 0;
virtual void LogToGame(const char *message) = 0;
virtual void ConPrint(const char *message) = 0;
virtual void ConsolePrint(const char *fmt, ...) = 0;
virtual void ConsolePrintVa(const char *fmt, va_list ap) = 0;
// Game engine helper functions.
virtual bool IsClientConVarQueryingSupported() = 0;
virtual int QueryClientConVar(int client, const char *cvar) = 0;
// Metamod:Source functions.
virtual int LoadMMSPlugin(const char *file, bool *ok, char *error, size_t maxlength) = 0;
virtual void UnloadMMSPlugin(int id) = 0;
const char * (*GetCoreConfigValue)(const char*);
void (*DoGlobalPluginLoads)();
bool (*AreConfigsExecuted)();
void (*ExecuteConfigs)(IPluginContext *ctx);
void (*GetDBInfoFromKeyValues)(KeyValues *, DatabaseInfo *);
int (*GetActivityFlags)();
int (*GetImmunityMode)();
void (*UpdateAdminCmdFlags)(const char *cmd, OverrideType type, FlagBits bits, bool remove);
bool (*LookForCommandAdminFlags)(const char *cmd, FlagBits *pFlags);
int (*GetGlobalTarget)();
};
} // namespace SourceMod
#endif // _INCLUDE_SOURCEMOD_CORE_PROVIDER_API_H_

View File

@ -1,81 +0,0 @@
// vim: set ts=4 sw=4 tw=99 noet:
// =============================================================================
// SourceMod
// Copyright (C) 2004-2015 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>.
#ifndef _INCLUDE_SOURCEMOD_BRIDGE_INCLUDE_IEXTBRIDGE_H_
#define _INCLUDE_SOURCEMOD_BRIDGE_INCLUDE_IEXTBRIDGE_H_
#include <sp_vm_api.h>
#include <IExtensionSys.h>
#include <sh_vector.h>
struct edict_t;
namespace SourceMod {
using namespace SourceHook;
using namespace SourcePawn;
class SMPlugin;
class IExtensionSys : public IExtensionManager
{
public:
virtual IExtension *LoadAutoExtension(const char *name, bool bErrorOnMissing=true) = 0;
virtual void TryAutoload() = 0;
virtual void Shutdown() = 0;
virtual IExtension *FindExtensionByFile(const char *name) = 0;
virtual bool LibraryExists(const char *name) = 0;
virtual void CallOnCoreMapStart(edict_t *edictList, int edictCount, int maxClients) = 0;
virtual IExtension *GetExtensionFromIdent(IdentityToken_t *token) = 0;
virtual void BindChildPlugin(IExtension *ext, SMPlugin *plugin) = 0;
virtual void AddRawDependency(IExtension *myself, IdentityToken_t *token, void *iface) = 0;
virtual const CVector<IExtension *> *ListExtensions() = 0;
virtual void FreeExtensionList(const CVector<IExtension *> *list) = 0;
virtual void CallOnCoreMapEnd() = 0;
};
class AutoExtensionList
{
public:
AutoExtensionList(IExtensionSys *extensions)
: extensions_(extensions), list_(extensions_->ListExtensions())
{
}
~AutoExtensionList()
{
extensions_->FreeExtensionList(list_);
}
const CVector<IExtension *> *operator ->()
{
return list_;
}
private:
IExtensionSys *extensions_;
const CVector<IExtension *> *list_;
};
} // namespace SourceMod
#endif // _INCLUDE_SOURCEMOD_BRIDGE_INCLUDE_IEXTBRIDGE_H_

View File

@ -1,63 +0,0 @@
// vim: set ts=4 sw=4 tw=99 noet:
// =============================================================================
// SourceMod
// Copyright (C) 2004-2015 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>.
#ifndef _INCLUDE_SOURCEMOD_BRIDGE_IFILESYSTEM_H_
#define _INCLUDE_SOURCEMOD_BRIDGE_IFILESYSTEM_H_
typedef void * FileHandle_t;
typedef int FileFindHandle_t;
namespace SourceMod {
class IFileSystemBridge
{
public:
virtual const char *FindFirstEx(const char *pWildCard, const char *pPathID, FileFindHandle_t *pHandle) = 0;
virtual const char *FindNext(FileFindHandle_t handle) = 0;
virtual bool FindIsDirectory(FileFindHandle_t handle) = 0;
virtual void FindClose(FileFindHandle_t handle) = 0;
virtual FileHandle_t Open(const char *pFileName, const char *pOptions, const char *pathID = 0) = 0;
virtual void Close(FileHandle_t file) = 0;
virtual char *ReadLine(char *pOutput, int maxChars, FileHandle_t file) = 0;
virtual bool EndOfFile(FileHandle_t file) = 0;
virtual bool FileExists(const char *pFileName, const char *pPathID = 0) = 0;
virtual unsigned int Size(const char *pFileName, const char *pPathID = 0) = 0;
virtual int Read(void* pOutput, int size, FileHandle_t file) = 0;
virtual int Write(void const* pInput, int size, FileHandle_t file) = 0;
virtual void Seek(FileHandle_t file, int post, int seekType) = 0;
virtual unsigned int Tell(FileHandle_t file) = 0;
virtual int FPrint(FileHandle_t file, const char *pData) = 0;
virtual void Flush(FileHandle_t file) = 0;
virtual bool IsOk(FileHandle_t file) = 0;
virtual void RemoveFile(const char *pRelativePath, const char *pathID = 0) = 0;
virtual void RenameFile(char const *pOldPath, char const *pNewPath, const char *pathID = 0) = 0;
virtual bool IsDirectory(const char *pFileName, const char *pathID = 0) = 0;
virtual void CreateDirHierarchy(const char *path, const char *pathID = 0) = 0;
};
} // namespace SourceMod
#endif // _INCLUDE_SOURCEMOD_BRIDGE_IFILESYSTEM_H_

View File

@ -1,43 +0,0 @@
// vim: set ts=4 sw=4 tw=99 noet:
// =============================================================================
// SourceMod
// Copyright (C) 2004-2015 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>.
#ifndef _INCLUDE_SOURCEMOD_BRIDGE_LOGGER_H_
#define _INCLUDE_SOURCEMOD_BRIDGE_LOGGER_H_
namespace SourceMod {
class ILogger
{
public:
virtual void LogMessage(const char *msg, ...) = 0;
virtual void LogError(const char *msg, ...) = 0;
virtual void LogFatal(const char *msg, ...) = 0;
};
} // namespace SourceMod
#endif // _INCLUDE_SOURCEMOD_BRIDGE_LOGGER_H_

View File

@ -1,55 +0,0 @@
// vim: set ts=4 sw=4 tw=99 noet:
// =============================================================================
// SourceMod
// Copyright (C) 2004-2015 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>.
#ifndef _INCLUDE_SOURCEMOD_BRIDGE_INCLUDE_IPLAYERINFO_H_
#define _INCLUDE_SOURCEMOD_BRIDGE_INCLUDE_IPLAYERINFO_H_
class IPlayerInfo;
namespace SourceMod {
class IPlayerInfoBridge
{
public:
virtual bool IsObserver(IPlayerInfo *pInfo) = 0;
virtual int GetTeamIndex(IPlayerInfo *pInfo) = 0;
virtual int GetFragCount(IPlayerInfo *pInfo) = 0;
virtual int GetDeathCount(IPlayerInfo *pInfo) = 0;
virtual int GetArmorValue(IPlayerInfo *pInfo) = 0;
virtual void GetAbsOrigin(IPlayerInfo *pInfo, float *x, float *y, float *z) = 0;
virtual void GetAbsAngles(IPlayerInfo *pInfo, float *x, float *y, float *z) = 0;
virtual void GetPlayerMins(IPlayerInfo *pInfo, float *x, float *y, float *z) = 0;
virtual void GetPlayerMaxs(IPlayerInfo *pInfo, float *x, float *y, float *z) = 0;
virtual const char *GetWeaponName(IPlayerInfo *pInfo) = 0;
virtual const char *GetModelName(IPlayerInfo *pInfo) = 0;
virtual int GetHealth(IPlayerInfo *pInfo) = 0;
virtual void ChangeTeam(IPlayerInfo *pInfo, int iTeamNum) = 0;
};
} // namespace SourceMod
#endif // _INCLUDE_SOURCEMOD_BRIDGE_INCLUDE_IPLAYERINFO_H_

View File

@ -1,45 +0,0 @@
// vim: set ts=4 sw=4 tw=99 noet:
// =============================================================================
// SourceMod
// Copyright (C) 2004-2015 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>.
#ifndef _INCLUDE_SOURCEMOD_BRIDGE_INCLUDE_IPROVIDERCALLBACK_H_
#define _INCLUDE_SOURCEMOD_BRIDGE_INCLUDE_IPROVIDERCALLBACK_H_
namespace SourceMod {
// Global callbacks provided to Core.
class IProviderCallbacks
{
public:
// Called when a log message is printed. Return true to supercede.
virtual bool OnLogPrint(const char *msg) = 0;
// Called each frame tick.
virtual void OnThink(bool simulating) = 0;
};
} // namespace SourceMod
#endif // _INCLUDE_SOURCEMOD_BRIDGE_INCLUDE_IPROVIDERCALLBACK_H_

View File

@ -1,112 +0,0 @@
// vim: set ts=4 sw=4 tw=99 noet:
// =============================================================================
// SourceMod
// Copyright (C) 2004-2015 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>.
#ifndef _INCLUDE_SOURCEMOD_BRIDGE_INCLUDE_ISCRIPTMANAGER_H_
#define _INCLUDE_SOURCEMOD_BRIDGE_INCLUDE_ISCRIPTMANAGER_H_
#include <sp_vm_api.h>
#include <IPluginSys.h>
#include <sh_vector.h>
#include <sh_string.h>
namespace SourceMod {
using namespace SourceHook;
using namespace SourcePawn;
class IChangeableForward;
enum LibraryAction
{
LibraryAction_Removed,
LibraryAction_Added
};
struct AutoConfig
{
SourceHook::String autocfg;
SourceHook::String folder;
bool create;
};
class SMPlugin : public IPlugin
{
public:
virtual size_t GetConfigCount() = 0;
virtual AutoConfig *GetConfig(size_t i) = 0;
virtual void AddLibrary(const char *name) = 0;
virtual void AddConfig(bool create, const char *cfg, const char *folder) = 0;
virtual void EvictWithError(PluginStatus status, const char *fmt, ...) = 0;
};
class IScriptManager
{
public:
virtual void LoadAll(const char *config_path, const char *plugins_path) = 0;
virtual void RefreshAll() = 0;
virtual void Shutdown() = 0;
virtual IdentityToken_t *GetIdentity() = 0;
virtual void SyncMaxClients(int maxClients) = 0;
virtual void AddPluginsListener(IPluginsListener *listener) = 0;
virtual void RemovePluginsListener(IPluginsListener *listener) = 0;
virtual IPluginIterator *GetPluginIterator() = 0;
virtual void OnLibraryAction(const char *name, LibraryAction action) = 0;
virtual bool LibraryExists(const char *name) = 0;
virtual SMPlugin *FindPluginByOrder(unsigned num) = 0;
virtual SMPlugin *FindPluginByIdentity(IdentityToken_t *ident) = 0;
virtual SMPlugin *FindPluginByContext(IPluginContext *ctx) = 0;
virtual SMPlugin *FindPluginByContext(sp_context_t *ctx) = 0;
virtual SMPlugin *FindPluginByConsoleArg(const char *text) = 0;
virtual SMPlugin *FindPluginByHandle(Handle_t hndl, HandleError *errp) = 0;
virtual bool UnloadPlugin(IPlugin *plugin) = 0;
virtual const CVector<SMPlugin *> *ListPlugins() = 0;
virtual void FreePluginList(const CVector<SMPlugin *> *list) = 0;
virtual void AddFunctionsToForward(const char *name, IChangeableForward *fwd) = 0;
};
class AutoPluginList
{
public:
AutoPluginList(IScriptManager *scripts)
: scripts_(scripts), list_(scripts->ListPlugins())
{
}
~AutoPluginList()
{
scripts_->FreePluginList(list_);
}
const CVector<SMPlugin *> *operator ->()
{
return list_;
}
private:
IScriptManager *scripts_;
const CVector<SMPlugin *> *list_;
};
} // namespace SourceMod
#endif // _INCLUDE_SOURCEMOD_BRIDGE_INCLUDE_ISCRIPTMANAGER_H_

View File

@ -1,48 +0,0 @@
// vim: set ts=4 sw=4 tw=99 noet:
// =============================================================================
// SourceMod
// Copyright (C) 2004-2015 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>.
#ifndef _INCLUDE_SOURCEMOD_BRIDGE_IVENGINESERVER_H_
#define _INCLUDE_SOURCEMOD_BRIDGE_IVENGINESERVER_H_
struct edict_t;
namespace SourceMod {
class IVEngineServerBridge
{
public:
virtual bool IsDedicatedServer() = 0;
virtual void InsertServerCommand(const char *cmd) = 0;
virtual void ServerCommand(const char *cmd) = 0;
virtual void ServerExecute() = 0;
virtual const char *GetClientConVarValue(int clientIndex, const char *name) = 0;
virtual void ClientCommand(edict_t *pEdict, const char *szCommand) = 0;
virtual void FakeClientCommand(edict_t *pEdict, const char *szCommand) = 0;
};
} // namespace SourceMod
#endif // _INCLUDE_SOURCEMOD_BRIDGE_IVENGINESERVER_H_

View File

@ -1,92 +0,0 @@
// vim: set ts=4 sw=4 tw=99 noet:
// =============================================================================
// SourceMod
// Copyright (C) 2004-2015 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>.
#ifndef _INCLUDE_SOURCEMOD_LOGIC_PROVIDER_API_H_
#define _INCLUDE_SOURCEMOD_LOGIC_PROVIDER_API_H_
#include <sp_vm_api.h>
class SMGlobalClass;
namespace SourceMod {
using namespace SourcePawn;
class CoreProvider;
class IThreader;
class ITranslator;
class IGameConfig;
class IScriptManager;
class IShareSys;
class IHandleSys;
class ICommandArgs;
class IForwardManager;
class IAdminSystem;
class IRootConsole;
class IProviderCallbacks;
class IExtensionSys;
class ITextParsers;
class ILogger;
class ICellArray;
struct sm_logic_t
{
SMGlobalClass *head;
IThreader *threader;
ITranslator *translator;
const char *(*stristr)(const char *, const char *);
size_t (*atcprintf)(char *, size_t, const char *, IPluginContext *, const cell_t *, int *);
bool (*CoreTranslate)(char *, size_t, const char *, unsigned int, size_t *, ...);
void (*AddCorePhraseFile)(const char *filename);
unsigned int (*ReplaceAll)(char*, size_t, const char *, const char *, bool);
char *(*ReplaceEx)(char *, size_t, const char *, size_t, const char *, size_t, bool);
size_t (*DecodeHexString)(unsigned char *, size_t, const char *);
IGameConfig * (*GetCoreGameConfig)();
IDebugListener *debugger;
void (*GenerateError)(IPluginContext *, cell_t, int, const char *, ...);
void (*AddNatives)(sp_nativeinfo_t *natives);
void (*RegisterProfiler)(IProfilingTool *tool);
ICellArray * (*CreateCellArray)(size_t blocksize);
void (*FreeCellArray)(ICellArray *arr);
void * (*FromPseudoAddress)(uint32_t pseudoAddr);
uint32_t (*ToPseudoAddress)(void *addr);
IScriptManager *scripts;
IShareSys *sharesys;
IExtensionSys *extsys;
IHandleSys *handlesys;
IForwardManager *forwardsys;
IAdminSystem *adminsys;
IdentityToken_t *core_ident;
ILogger *logger;
IRootConsole *rootmenu;
IProviderCallbacks *callbacks;
float sentinel;
};
} // namespace SourceMod
#endif // _INCLUDE_SOURCEMOD_LOGIC_PROVIDER_API_H_

View File

@ -1,472 +0,0 @@
SourceMod Changelog
----------------------------
SourceMod 1.3.6 [2010-10-31]
URL: http://wiki.alliedmods.net/SourceMod_1.3.6_Release_Notes
User Changes:
- Updated support for latest Left 4 Dead 1 (bug 4681).
Developer Changes:
- Updated TF2 custom kill defines (bug 4682).
----------------------------
SourceMod 1.3.5 [2010-10-17]
URL: http://wiki.alliedmods.net/SourceMod_1.3.5_Release_Notes
User Changes:
- Updated support for CS:S, Garry's Mod, DoD:S, TF2, HL2DM.
- Added support for Firearms: Source (bug 4537).
- Added support for Fistful of Frags (bug 3883).
- Added support for Alien Swarm (bug 4530).
- Fixed living players hearing dead players if alltalk is disabled while deadtalk is on (bug 4533, thanks Zach Callear).
- Fixed timeleft not getting reset on Game_Commencing in CS:S (bug 4557).
- Fixed PlayerRunCmd being hooked when not used (bug 3990).
- Fixed errors and missing effects caused by missing sprites on L4D2 (bug 4512).
- Fixed 'sm plugins' public command skipping plugins in recommended listing (bug 4501).
- Fixed corruption with large database.cfg files (bug 4286).
Developer Changes:
- Added TF2 object stocks (bug 4536).
- Added TF2_MakeBleed native to TF2 ext (bug 4542).
- Added support for logical entities in Synergy (bug 4534).
- Updated TF2 conditions enum and defines (bug 4526).
- Fixed potential crash with IMemUtils::FindPattern on Linux (bug 4554).
----------------------------
SourceMod 1.3.4 [2010-07-18]
URL: http://wiki.alliedmods.net/SourceMod_1.3.4_Release_Notes
User Changes:
- Support for latest TF update (bug 4506).
- Support for latest L4D2 update (bug 4509).
Developer Changes:
- Added FindFlagChar native (bug 3776).
- Added GetConVarDefault native (bug 4502).
- Added forward for TF's GetHoliday function (bug 4462).
----------------------------
SourceMod 1.3.3 [2010-06-23]
URL: http://wiki.alliedmods.net/SourceMod_1.3.3_Release_Notes
User Changes:
- Added support for CS:S on Orange Box
- Added gamedata for Resistance and Liberation (bug 4418).
- Updated gamedata for SourceForts, Empires, Obsidian Conflict, Zombie Master.
- Fixed memory corruption and leaks with some voice functionality (bug 4415).
- Fixed UI bug in sm_motd (bug 4460).
Developer Changes:
- Added new player condition (TFCond_CritCola, bug 4447).
- Fixed clientprefs deleting cookies twice in rare cases (bug 4412).
- Fixed OnClientConnected forward not firing for bots (bug 4443).
- Fixed sm_dump_datamaps crash (bug 4424).
- Fixed switch case comparisons failing with large numbers (bug 4457).
- Fixed rare crash in output hooks (bug 4422).
- Fixed bug with dynamically sized arrays being sliced (bug 4428).
- Fixed SendConVarValue() on TF2, DOD:S, L4D, and L4D2 (bug 4273).
- Fixed TF2 natives not being marked optional (bug 4389).
----------------------------
SourceMod 1.3.2 [2010-05-02]
URL: http://wiki.alliedmods.net/SourceMod_1.3.2_Release_Notes
User Changes:
- Support for recent TF, DoD, and L4D2 updates (bug 4356, bug 4361, bug 4371, bug 4374, bug 4375).
- Fixed rare crash when replicating cvars to clients (bug 4315).
- Lots of extra game support for Insurgency, ZPS, CSProMod, PVKII, and FortressForever (thanks
Nicholas "psychonic" hastings).
Developer Changes:
- Added TF functions for stunning, conditions, regeneration, and power play (bug 4166, bug 4331).
----------------------------
SourceMod 1.3.1 [2010-02-09]
URL: http://wiki.alliedmods.net/SourceMod_1.3.1_Release_Notes
User Changes:
- Added extended support for CSProMod (bug 4255).
- Fixed client disconnect crash on many third party games (bug 4231).
- Improved support for Battlegrounds 2 (bug 4146).
- Improved support for Insurgency (bug 4180).
- Improved support for Garry's Mod (bug 4230, bug 4268).
- Improved support for Synergy (bug 4235).
- Updated Day of Defeat support for 20010123 update (bug 4262).
- Fixed Webternet extension not loading on Windows 2000 (bug 4234).
Developer Changes:
- Fixed compiler complaints when using |any| tag on array arguments (bug 4274).
- Fixed GetClientCookieTime not being exported (bug 4237).
- Fixed potential crash in entity handling code (bug 4249).
----------------------------
SourceMod 1.3.0 [2010-01-15]
URL: http://wiki.alliedmods.net/SourceMod_1.3.0_Release_Notes
Major Features:
* Left 4 Dead 2 support
* Non-networked entity support
User Changes:
- Added Left 4 Dead 2 support (bug 4075).
- Added much richer voting progress feedback (bug 1997).
- Improved support for various third-party games (Nicholas "psychonic" Hastings).
- Added @spec target (bug 2718).
- Added sm_resetcvar command (bug 3636).
- Added "motd" chat trigger (bug 2694).
- Updated GeoIP to OCT-2009.
- Fixed rare map vote error (bug 3905).
- Fixed small leak in the nominations plugin (bug 4104).
- Fixed last client being excluded from some command effects (bug 3984).
- Fixed crashes in plugin [|un|re]loading (bug 4034, bug 4038, bug 4044, bug 4153).
- Special target "@me" is now filtered for certain statuses properly (bug 4000).
- Improved non-admin to admin chat (bug 3844).
- Removed "auto.*" extension folders (bug 3949).
Developer Changes:
- Added non-networked entity support (bug 2459).
- Added improved random number generator (bug 3831).
- Added GetClientCookieTime native (bug 3736).
- Added AskPluginLoad2 callback (bug 3716).
- Added PlayerRunCmd callback (bug 3289).
- Added PointOutsideWorld native (bug 3906).
- Added API for "blanket" command hooks (bug 4015).
- Added ability to test for SourceMod features (bug 4021).
- Added ability to change broadcast status on hooked events (bug 3886).
- OnClientCommand no longer receives unconnected clients (bug 3732).
- Fixed various bugs in client listening API (bug 3818).
- Fixed crash in BanClient (bug 3912).
- Fixed various crashes in self-removing callbacks (bug 4059).
- Fixed rare HUD text crash on TF (bug 4016).
- Fixed OnConfigsExecuted not running on EP1 games with large configs (bug 3828).
- Fixed entity output hooks not working (bug 3988).
- Gamedata folder matches are now case-insensitive (bug 3913).
- Blocked plugins from hooking "sm" command (bug 4013).
----------------------------
SourceMod 1.2.4 [2009-10-03]
URL: http://wiki.alliedmods.net/SourceMod_1.2.4_Release_Notes
- Updated for L4D changes (bugs 4032, 4033, 4035).
- Updated GeoLite Country database for GeoIP extension.
- Fixed crash when block-loading more than eight plugins (bug 4034).
- Fixed rare crash in hudtext code on TF (bug 4016).
- Fixed crash when reloading a blocked plugin failed (bug 4038).
- Fixed Huntsman not firing critical callback on TF (bug 3927).
- Registering the "sm" command no longer has any effect (bug 4013).
- Fixed translation bug in extension API (bug 4010).
----------------------------
SourceMod 1.2.3 [2009-08-28]
URL: http://wiki.alliedmods.net/SourceMod_1.2.3_Release_Notes
- Fix extension filename lookup. (bug 3975).
----------------------------
SourceMod 1.2.2 [2009-08-28]
URL: http://wiki.alliedmods.net/SourceMod_1.2.2_Release_Notes
- Removed auto folders. (bug 3949).
- Added PointOutsideWorld native to sdktools. (bug 3906).
- Added "motd" chat trigger to basetriggers. (bug 2694).
- Added manual extension reloading command to root console menu. (bug 3934)
- Fixed 'list' type custom menu entries overwriting admin restrictions. (bug 3783).
- Added sm_resetcvar command to basecommands. (bug 3636).
- Updated gamedata for DOD:S. (bug 3948).
- Updated gamedata for TF2. (bug 3948).
- Added new .ep2v build config for valve OB based games. (bug 3948).
- Fixed incorrect escaping in clientprefs SQLite queries. (bug 3904)
- Updated gamedata for Synergy. (bug 3315).
- Upgraded to pcre-7.9 (bug 3923).
- Switched Insurgency chat printing to SayText. (bug 3738).
- Updated gamedata for Insurgency. (bug 3511).
- Updated gamedata for ZM. (bug 3746).
- Updated gamedata for Empires. (bug 3500).
- Updated gamedata for ZPS. (bug 3877).
- Updated gamedata for AoC. (bug 3891).
- Fixed RemovePlayerDisguise signature for TF2. (bug 3892).
----------------------------
SourceMod 1.2.1 [2009-05-31]
URL: http://wiki.alliedmods.net/SourceMod_1.2.1_Release_Notes
- Updated SDKTools for latest Team Fortress update.
- Added L4D handling to GuessSDKVersion() (bug 3842).
- Updated Zombie Panic Source offsets (bug 3632).
- Fixed crash when clientprefs saw disconnect from 64th client (bug 3821).
- Fixed Plugin_Handled acting like a Stop in usermsg hooks (bug 3685).
- Fixed early tv_enable causing crashes (bug 3766).
- Fixed unhook event crash (bug 3814).
- Fixed compiler reading uninitialized strings while processing varargs (bug 3811).
- Fixed compiler choosing whether to emit stradjust.pri on dynamic arrays based on uninitialized memory (bug 3810).
- Fixed Windows L4D CreateFakeClient signature (bug 3792).
- Fixed sm_slap for EP1 games (bug 3768).
- Fixed casting problems in TextParsers breaking TrimString for non-ASCII characters (bug 3800).
- Fixed OnClientConnect rejectmsg handling, improved doc (bug 3690).
- Fixed clientprefs not loading cookies for clients on late load (bug 3735).
- Fixed GetCommandFlags on original engine games (bug 3759).
- Fixed compiler asserting when returning a string literal (bug 3836).
- Fixed compiler erroring when tagging functions for string return (bug 3837).
- Fixed compiler not handling constant chained relational operators correctly (bug 3838).
- Fixed revote bug and inflexibilities in RedrawClientVoteMenu (bug 3834).
- Fixed auto update URL being set too late (bug 3699).
- Disabled nextmap in Synergy and Dystopia (bug 3687, bug 3741).
- Removed unnecessary SSE optimizations from msvc9 project files (bug 3756).
- Removed short-lived tag system (bug 3751).
- Removed the alive check from sm_rename. (bug 3698).
- Switched FortressForever to Valve menus (bug 3819).
----------------------------
SourceMod 1.2.0 [2009-03-05]
URL: http://wiki.alliedmods.net/SourceMod_1.2.0_Release_Notes
Major Features:
* Left 4 Dead Support
* Dark Messiah Support
* New and Improved Updater
Changes:
- Added Left 4 Dead support (bug 3414).
- Added Dark Messiah game support (requires Metamod:Source 1.7.1 or higher).
- Added sm_name command (bug 2150).
- Added extension-level dynamic hooking to bintools (bug 2616).
- Added client validation API to replace passing userids asynchronously.
- Added cURL extension, available to other extensions (bug 3560).
- Added parsing of custom gamedata files (bug 3644).
- Added case insensitivity search to ReplaceString (bug 3639, Fyren).
- Added more detail to certain player-oriented menu titles (bug 2740, Fyren).
- Added sv_tags API (bug 3677).
- Greatly improved admin-sql-prefetch performance for large tables (bug 3354, FLOOR_MASTER).
- Exposed IServer address to extensions (bug 3545).
- New gamedata organization; files are now smaller and per-game (bug 3546).
- Split sound functions into a new plugin, sounds.smx.
- Fixed slap and slay on Insurgency (bug 2560).
- Fixed blank admins being created from invalid admin file lines (bug 3431).
- Fixed basetriggers not working on Insurgency (bug 3497).
- Fixed client preferences missing some clients (bug 3616).
- Improved database fallback mechanism in clientprefs (bug 3564).
- Improved timer handling in funcommands (bug 3498).
- Improved compile.sh to take filenames (bug 3550, jonasfietz).
- sm_kick now shows the kick reason when available.
- Fixed MsgPostHook (ex MsgSentNotify) callbacks not firing on intercept hook (bug 3631).
- Note: SourceMod now adds "sourcemod" to the sv_tags cvar.
----------------------------
SourceMod 1.1.2 [2009-02-26]
URL: http://wiki.alliedmods.net/SourceMod_1.1.2_Release_Notes
Changes:
- Fixed critical hits being permanently disabled (bug 2674)
----------------------------
SourceMod 1.1.1 [2009-02-25]
URL: http://wiki.alliedmods.net/SourceMod_1.1.1_Release_Notes
Changes:
- Added Age of Chivalry support (bug 3366, IceMatrix).
- Added Obsidian Conflict support (bug 2699, The DOO).
- Fixed compatibility issues with latest TF2 update.
- Fixed crash when an event handler fired an event of the same name (bug 3468).
- Fixed rare crash in the event manager on post hooks (bug 3548).
- Fixed formatting error with zero precision floats (bug 3447).
- Fixed various Insurgency offsets (bug 3544).
- Fixed admin menu (topmenu) categories being selectable when not usable (bug 3256).
- Fixed sm_sql_addgroup not working (bug 3578).
- Fixed memory leak when events were hooked as EventHookMode_Post.
- Fixed nextmap trigger showing wrong output with end-of-map voting disabled and sm_trigger_show set to zero (bug 3597, mr.e.unk).
----------------------------
SourceMod 1.1.0 [2008-12-28]
URL: http://wiki.alliedmods.net/SourceMod_1.1.0_Release_Notes
Major features:
* New map management plugins.
* New reserved slot type.
* GameData updates are retrieved remotely
* Client Preferences extension for per-client "cookies"
* New incremental and independent JIT
Changes:
- Added new client preferences extension (API in clientprefs.inc, bug 1925).
- Added new gamedata auto-update functionality (bug 2602).
- Revamped and greatly expanded map management plugins and their functionality (bug 2201).
- Debug mode is now always on; as there is no longer a performance loss, there is no non-debug mode.
- The timeleft trigger can now handle mp_winlimit, mp_fraglimit, and mp_maxrounds (bug 2344).
- Translations can now be in separate files and placed in language-unique folders.
- The leading "STEAM_0:" or "STEAM_1:" in SteamIDs can now be omitted from admin files.
- Added sm_revote command so clients can participate in a vote that fell off their screen (bug 2156).
- Added Core API for creating stack structures (adt_stack.inc, bug 2441).
- Added API for extending mapchooser (mapchooser.inc, bug 2201).
- Added Core API for map transition control and history (nextmap.inc).
- Added TF2 forward for overriding how critical hits are calculated.
- Added SetClientInfo() native for modifying how a server sees a client's setinfo properties.
- Added CreateDirectory() native (bug 3253).
- Added "magic" MaxClients variable to replace slower GetMaxClients() call.
- Added support for three-letter language codes (bug 3526).
- Functions to control client versus client mic listening now work as described (bug 2498).
- Fixed SDKTools not being reloadable, and fixed a related bug in Handle type removal (bug 2753).
- Rewrote internal translation handling. Extensions now have access to an ITranslator API (bug 2535).
- Rewrote internal handling of dependencies (especially relating to native providers) (bug 2466).
- Added user config hooks to IGameConfigManager, for parsing user-defined sections.
- Revamped SourcePawn API. Removed and deprecated many structures and functions accidentally exposed publicly.
- Revamped SourcePawn structure, it is now separable from SourceMod for other projects.
- Renamed basefuncommands.phrases.txt to funcommands.phrases.txt (bug 2485).
- Renamed basefunvotes.phrases.txt to funvotes.phrases.txt (bug 2485).
- Added IDBDriver API call for extensions to handle IDBDriver dependencies properly.
- Usermessage natives now validate clients to prevent crashing.
- Fixed OnConfigsExecuted not working on listen servers.
- Fixed out-of-handle conditions in CreateTimer() causing crashes (bug 3381).
- Fixed accessing invalid Handles causing crashes (bug 3359).
- Fixed memory corruption with MySQL + FetchString (bug 3352).
- Fixed ReadFileString ignoring its fourth parameter (bug 3459).
- Fixed sm_sql_addadmin reading the immunity field as a password (bug 3395).
- Fixed ReadFile sign-extending instead of zero-extending (bug 3449).
----------------------------
SourceMod 1.0.4 [2008-09-14]
Changes:
- Fixed amb1986: Format() with very long strings could crash if the input and output buffers overlapped.
- Fixed amb1938: The compiler ate too many characters in preprocessor macros.
- Fixed amb1935: Topmenu child names were not uncached when a category was deleted.
- Fixed amb1929: Banning via the console threw a runtime error.
- Fixed amb1918: Ban menu should compare userids, not client indexes
- Fixed amb1916: Threaded query delay is now 50ms instead of 500ms.
- Fixed amb1899: Duplicate maps in auto generated maplists.
- Fixed amb1891: Basechat didn't check for blank message in private says.
- Fixed amb1853: Ternary operators with string assignments could chop strings off.
- Fixed amb1815: Custom admin menu wasn't escaping input.
- Fixed amb1808: KickClient() is now delayed to prevent crashes, use KickClientEx for old functionality.
- Fixed amb1802: Possible crash when a client disconnected.
- Fixed amb1801: Improved bot detection, and fixed bots crashing if inside an OrangeBox server.cfg.
- Fixed amb1780: admin-sql-threaded had a debug spew turned on.
- Fixed amb1779: Crash in GetTeamName() on mods that don't support it.
- Fixed amb1763: Function call status is now cleared on a new function call.
- Fixed amb1749: Updated and improved DoD:S SDKTools coverage.
- Fixed team native crashes in SDKTools for mods like Insurgency.
- Fixed various file handle leaks.
----------------------------
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,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

@ -16,7 +16,7 @@
// "@Full Admins" // "@Full Admins"
// //
// You can also specify immunity values. Two examples: // You can also specify immunity values. Two examples:
// "83:abcdefgh" //Immunity is 83, flags are abcdefgh // "83:abcdefg" //Immunity is 83, flags are abcefgh
// "6:@Full Admins" //Immunity is 6, group is "Full Admins" // "6:@Full Admins" //Immunity is 6, group is "Full Admins"
// //
// Immunity values can be any number. An admin cannot target an admin with // Immunity values can be any number. An admin cannot target an admin with
@ -37,9 +37,9 @@
//////////////////////////////// ////////////////////////////////
// Examples: (do not put // in front of real lines, as // means 'comment') // Examples: (do not put // in front of real lines, as // means 'comment')
// //
// "STEAM_0:1:16" "bce" //generic, kick, unban for this steam ID, no immunity // "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 // "!127.0.0.1" "99:z" //all permissions for this ip, immunity value is 99
// "BAILOPAN" "abc" "Gab3n" //name BAILOPAN, password "Gab3n": gets reservation, generic, kick // "BAILOPAN" "abc" "Gab3n" //name BAILOPAN, password "Gab3n": gets reservation, kick, ban
// //
//////////////////////////////// ////////////////////////////////

View File

@ -1,16 +0,0 @@
"banreasons"
{
"Abusive" "Abusive"
"Racism" "Racism"
"General cheating/exploits" "General cheating/exploits"
"Wallhack" "Wallhack"
"Aimbot" "Aimbot"
"Speedhacking" "Speedhacking"
"Mic spamming" "Mic spamming"
"Admin disrespect" "Admin disrespect"
"Camping" "Camping"
"Team killing" "Team killing"
"Unacceptable Spray" "Unacceptable Spray"
"Breaking Server Rules" "Breaking Server Rules"
"Other" "Other"
}

View File

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

View File

@ -65,10 +65,6 @@ sm_flood_time 0.75
// no reserved slot access (spectator players are selected first) is kicked to make room. Thus, the reserved // 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 // 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. // if the server is full with reserve slot access clients.
// 2 : The same as sm_reserve_type 1 except once a certain number of admins have been reached, the reserve slot
// stops kicking people and anyone can join to fill the server. You can use this to simulate having a large
// number of reserved slots with sm_reserve_type 0 but with only need to have 1 slot unavailable when there are
// less admins connected.
// -- // --
// Requires: reservedslots.smx // Requires: reservedslots.smx
// Default: 0 // Default: 0
@ -84,21 +80,21 @@ sm_reserve_type 0
sm_reserved_slots 0 sm_reserved_slots 0
// Specifies whether or not reserved slots will be hidden (subtracted from max // Specifies whether or not reserved slots will be hidden (subtracted from max
// slot count). Valid values are 0 (Visible) or 1 (Hidden). // slot count). Valid values are 0 (visible) or 1 (hidden).
// -- // --
// Requires: reservedslots.smx // Requires: reservedslots.smx
// Default: 0 // Default: 0
sm_hide_slots 0 sm_hide_slots 0
// Specifies whether or not non-admins can send messages to admins using // Specifies whether or not non-admins can send messages to admins using
// say_team @<message>. Valid values are 0 (Disabled) or 1 (Enabled) // say_team @<message>. Valid values are 0 (disabled) or 1 (enabled)
// -- // --
// Requires: basechat.smx // Requires: basechat.smx
// Default: 1 // Default: 1
sm_chat_mode 1 sm_chat_mode 1
// Specifies whether or not "timeleft" will automatically be triggered every // Specifies whether or not "timeleft" will automaticly be triggered every
// x seconds. Valid values are 0 (Disabled) to 1800 seconds. // x seconds. Valid values are 0 (disabled) to 1800 seconds.
// -- // --
// Requires: basetriggers.smx // Requires: basetriggers.smx
// Default: 0 // Default: 0
@ -109,30 +105,5 @@ sm_timeleft_interval 0
// 1 (Enabled) // 1 (Enabled)
// -- // --
// Requires: basetriggers.smx // Requires: basetriggers.smx
// Default: 0 // Default: 1
sm_trigger_show 0 sm_trigger_show 1
// Specifies whether or not to display vote progress to clients in the
// "hint" box (near the bottom of the screen in most games).
// Valid values are 0 (Disabled) or 1 (Enabled).
// --
// Default: 0
sm_vote_progress_hintbox 0
// Specifies whether or not to display vote progress to clients in the
// chat area. Valid values are 0 (Disabled) or 1 (Enabled).
// --
// Default: 0
sm_vote_progress_chat 0
// Specifies whether or not to display vote progress in the server console.
// Valid values are 0 (Disabled) or 1 (Enabled).
// --
// Default: 0
sm_vote_progress_console 0
// Specifies whether or not to display vote progress to clients in the
// client console. Valid values are 0 (Disabled) or 1 (Enabled).
// --
// Default: 0
sm_vote_progress_client_console 0

View File

@ -4,6 +4,14 @@
*/ */
"Core" "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. * This option determines if SourceMod logging is enabled.
* *
@ -30,12 +38,12 @@
"ServerLang" "en" "ServerLang" "en"
/** /**
* List of characters to use for public chat triggers. Set an empty list to disable. * String to use as the public chat trigger. Set an empty string to disable.
*/ */
"PublicChatTrigger" "!" "PublicChatTrigger" "!"
/** /**
* List of characters to use for silent chat triggers. Set an empty list to disable. * String to use as the silent chat trigger. Set an empty string to disable.
*/ */
"SilentChatTrigger" "/" "SilentChatTrigger" "/"
@ -44,7 +52,7 @@
* but it does not evaluate to an actual command, it will be displayed * but it does not evaluate to an actual command, it will be displayed
* publicly. This setting allows you to suppress accidental typings. * publicly. This setting allows you to suppress accidental typings.
* *
* The default value is "no". A value of "yes" will suppress. * The default value is "no". A value of "yes" will supress.
*/ */
"SilentFailSuppress" "no" "SilentFailSuppress" "no"
@ -80,70 +88,4 @@
* "off" - Translate using default server's language * "off" - Translate using default server's language
*/ */
"AllowClLanguageVar" "On" "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"
/**
* If set to yes, a successful gamedata update will attempt to restart SourceMod.
* SourceMod is unloaded and reloaded, and the map is changed to the current map.
* Since gamedata updates occur when the server loads, impact should be minimal.
* But to be safe, this option is disabled by default.
*/
"ForceRestartAfterUpdate" "no"
/**
* URL to use for retrieving update information.
* SSL is not yet supported.
*/
"AutoUpdateURL" "http://update.sourcemod.net/update/"
/**
* Whether to show debug spew.
* Currently this will log details about the gamedata updating process.
*/
"DebugSpew" "no"
/**
* If set to yes, SourceMod will validate steamid auth strings with the Steam backend before giving out admin access.
* This can prevent malicious users from impersonating admins with stolen Steam apptickets.
* If Steam is down, admins will not be authenticated until Steam comes back up.
* This option increases the security of your server, but is still experimental.
*/
"SteamAuthstringValidation" "yes"
/**
* Enables or disables whether SourceMod blocks known or potentially malicious plugins from loading.
* It is STRONGLY advised that this is left enabled, there have been cases in the past with plugins that
* allow anyone to delete files on the server, gain full rcon control, etc.
*
* "yes" - Block malware or illegal plugins from loading (default)
* "no" - Warn about malware or illegal plugins loading
*/
"BlockBadPlugins" "yes"
/**
* If a plugin takes too long to execute, hanging or freezing the game server in the process,
* SourceMod will attempt to terminate that plugin after the specified timeout length has
* passed. You can disable this feature by setting the value to "0".
*/
"SlowScriptTimeout" "8"
/**
* Per "http://blog.counter-strike.net/index.php/server_guidelines/", certain plugin
* functionality will trigger all of the game server owner's Game Server Login Tokens
* (GSLTs) to get banned when executed on a Counter-Strike: Global Offensive game server.
*
* Enabling this option will block plugins from using functionality that is known to cause this.
* This option only has any effect on CS:GO. Note that this does NOT guarantee that you cannot
* receive a ban.
*
* Disable this option at your own risk.
*/
"FollowCSGOServerGuidelines" "yes"
} }

View File

@ -2,8 +2,6 @@
{ {
"driver_default" "mysql" "driver_default" "mysql"
// When specifying "host", you may use an IP address, a hostname, or a socket file path
"default" "default"
{ {
"driver" "default" "driver" "default"
@ -20,15 +18,4 @@
"driver" "sqlite" "driver" "sqlite"
"database" "sourcemod-local" "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,4 +1,6 @@
"Languages" "Languages"
{ {
"en" "English" "en" "English"
"es" "Español"
} }

View File

@ -51,8 +51,8 @@
"target" "default" "target" "default"
} }
/* For the "nominations" plugin */ /* For the "randomcycle" plugin */
"nominations" "rockthevote"
{ {
"target" "default" "target" "default"
} }

View File

@ -0,0 +1,38 @@
/**
* 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,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,42 +0,0 @@
# vim: set ts=2 sw=2 tw=99 noet:
import sys
try:
from ambuild2 import run, util
except:
try:
import ambuild
sys.stderr.write('It looks like you have AMBuild 1 installed, but this project uses AMBuild 2.\n')
sys.stderr.write('Upgrade to the latest version of AMBuild to continue.\n')
except:
sys.stderr.write('AMBuild must be installed to build this project.\n')
sys.stderr.write('http://www.alliedmods.net/ambuild\n')
sys.exit(1)
def make_objdir_name(p):
return 'obj-' + util.Platform() + '-' + p.target_arch
parser = run.BuildParser(sourcePath=sys.path[0], api='2.1')
parser.default_arch = 'x86'
parser.default_build_folder = make_objdir_name
parser.options.add_option('--hl2sdk-root', type=str, dest='hl2sdk_root', default=None,
help='Root search folder for HL2SDKs')
parser.options.add_option('--mysql-path', type=str, dest='mysql_path', default=None,
help='Path to MySQL 5')
parser.options.add_option('--mysql64-path', type=str, dest='mysql64_path', default=None,
help='Path to 64-bit MySQL 5')
parser.options.add_option('--mms-path', type=str, dest='mms_path', default=None,
help='Path to Metamod:Source')
parser.options.add_option('--enable-debug', action='store_const', const='1', dest='debug',
help='Enable debugging symbols')
parser.options.add_option('--enable-optimize', action='store_const', const='1', dest='opt',
help='Enable optimization')
parser.options.add_option('--no-mysql', action='store_false', default=True, dest='hasMySql',
help='Disable building MySQL extension')
parser.options.add_option('-s', '--sdks', default='all', dest='sdks',
help='Build against specified SDKs; valid args are "all", "present", or '
'comma-delimited list of engine names (default: %default)')
parser.options.add_option('--breakpad-dump', action='store_true', dest='breakpad_dump',
default=False, help='Dump and upload breakpad symbols')
parser.options.add_option('--disable-auto-versioning', action='store_true', dest='disable_auto_versioning',
default=False, help='Disable the auto versioning script')
parser.Configure()

View File

@ -1,8 +1,8 @@
/** /**
* vim: set ts=4 sw=4 tw=99 noet : * vim: set ts=4 :
* ============================================================================= * =============================================================================
* SourceMod * SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
* ============================================================================= * =============================================================================
* *
* This program is free software; you can redistribute it and/or modify it under * This program is free software; you can redistribute it and/or modify it under
@ -30,6 +30,7 @@
*/ */
#include "ADTFactory.h" #include "ADTFactory.h"
#include "sm_globals.h"
#include "ShareSys.h" #include "ShareSys.h"
ADTFactory g_AdtFactory; ADTFactory g_AdtFactory;
@ -56,30 +57,32 @@ IBasicTrie *ADTFactory::CreateBasicTrie()
BaseTrie::BaseTrie() BaseTrie::BaseTrie()
{ {
m_pTrie = sm_trie_create();
} }
BaseTrie::~BaseTrie() BaseTrie::~BaseTrie()
{ {
sm_trie_destroy(m_pTrie);
} }
bool BaseTrie::Insert(const char *key, void *value) bool BaseTrie::Insert(const char *key, void *value)
{ {
return map_.insert(key, value); return sm_trie_insert(m_pTrie, key, value);
} }
bool BaseTrie::Retrieve(const char *key, void **value) bool BaseTrie::Retrieve(const char *key, void **value)
{ {
return map_.retrieve(key, value); return sm_trie_retrieve(m_pTrie, key, value);
} }
bool BaseTrie::Delete(const char *key) bool BaseTrie::Delete(const char *key)
{ {
return map_.remove(key); return sm_trie_delete(m_pTrie, key);
} }
void BaseTrie::Clear() void BaseTrie::Clear()
{ {
map_.clear(); sm_trie_clear(m_pTrie);
} }
void BaseTrie::Destroy() void BaseTrie::Destroy()
@ -89,5 +92,5 @@ void BaseTrie::Destroy()
bool BaseTrie::Replace(const char *key, void *value) bool BaseTrie::Replace(const char *key, void *value)
{ {
return map_.replace(key, value); return sm_trie_replace(m_pTrie, key, value);
} }

View File

@ -1,8 +1,8 @@
/** /**
* vim: set ts=4 sw=4 tw=99 noet : * vim: set ts=4 :
* ============================================================================= * =============================================================================
* SourceMod * SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
* ============================================================================= * =============================================================================
* *
* This program is free software; you can redistribute it and/or modify it under * This program is free software; you can redistribute it and/or modify it under
@ -33,8 +33,8 @@
#define _INCLUDE_SOURCEMOD_ADTFACTORY_H_ #define _INCLUDE_SOURCEMOD_ADTFACTORY_H_
#include <IADTFactory.h> #include <IADTFactory.h>
#include "common_logic.h" #include "sm_globals.h"
#include <sm_stringhashmap.h> #include "sm_trie.h"
using namespace SourceMod; using namespace SourceMod;
@ -50,7 +50,7 @@ public:
virtual void Clear(); virtual void Clear();
virtual void Destroy(); virtual void Destroy();
private: private:
StringHashMap<void *> map_; Trie *m_pTrie;
}; };
class ADTFactory : class ADTFactory :

View File

@ -1,113 +0,0 @@
# vim: set sts=2 ts=8 sw=2 tw=99 et ft=python:
import os
project = SM.HL2Project(builder, 'sourcemod')
project.sources += [
'MenuStyle_Valve.cpp',
'logic_bridge.cpp',
'smn_entities.cpp',
'sm_stringutil.cpp',
'MenuVoting.cpp',
'smn_events.cpp',
'frame_hooks.cpp',
'smn_nextmap.cpp',
'sourcemm_api.cpp',
'ChatTriggers.cpp',
'smn_player.cpp',
'sourcemod.cpp',
'concmd_cleaner.cpp',
'HalfLife2.cpp',
'NextMap.cpp',
'ConCmdManager.cpp',
'ConVarManager.cpp',
'PlayerManager.cpp',
'TimerSys.cpp',
'CoreConfig.cpp',
'Logger.cpp',
'smn_halflife.cpp',
'smn_console.cpp',
'UserMessages.cpp',
'MenuManager.cpp',
'smn_hudtext.cpp',
'smn_usermsgs.cpp',
'MenuStyle_Base.cpp',
'smn_keyvalues.cpp',
'smn_vector.cpp',
'EventManager.cpp',
'MenuStyle_Radio.cpp',
'sm_autonatives.cpp',
'ConsoleDetours.cpp',
'vprof_tool.cpp',
'smn_commandline.cpp',
'GameHooks.cpp',
]
for sdk_name in SM.sdks:
sdk = SM.sdks[sdk_name]
for arch in SM.archs:
if not arch in sdk.platformSpec[builder.target.platform]:
continue
binary_name = 'sourcemod.' + sdk.ext
binary = SM.HL2Config(project, binary_name, sdk, arch)
compiler = binary.compiler
compiler.cxxincludes += [
builder.sourcePath
]
if sdk.name == 'csgo':
compiler.cxxincludes += [
os.path.join(sdk.path, 'common', 'protobuf-2.5.0', 'src'),
os.path.join(sdk.path, 'public', 'engine', 'protobuf'),
os.path.join(sdk.path, 'public', 'game', 'shared', 'csgo', 'protobuf')
]
if compiler.like('msvc'):
compiler.defines += ['_ALLOW_KEYWORD_MACROS']
if builder.target.platform == 'linux':
compiler.postlink += ['-lpthread', '-lrt']
if sdk.name == 'csgo':
if builder.target.platform == 'linux':
if arch == 'x86':
lib_path = os.path.join(sdk.path, 'lib', 'linux32', 'release', 'libprotobuf.a')
elif arch == 'x64':
lib_path = os.path.join(sdk.path, 'lib', 'linux64', 'release', 'libprotobuf.a')
compiler.linkflags += ['-Wl,--exclude-libs=libprotobuf.a']
elif builder.target.platform == 'mac':
if arch == 'x86':
lib_path = os.path.join(sdk.path, 'lib', 'osx32', 'release', 'libprotobuf.a')
elif arch == 'x64':
lib_path = os.path.join(sdk.path, 'lib', 'osx64', 'release', 'libprotobuf.a')
elif builder.target.platform == 'windows':
msvc_ver = compiler.version
vs_year = ''
if msvc_ver == 1800:
vs_year = '2013'
elif 1900 <= msvc_ver < 2000:
vs_year = '2015'
else:
raise Exception('Cannot find libprotobuf for MSVC version "' + str(compiler.version) + '"')
if 'DEBUG' in compiler.defines:
lib_path = os.path.join(sdk.path, 'lib', 'win32', 'debug', 'vs' + vs_year, 'libprotobuf.lib')
else:
lib_path = os.path.join(sdk.path, 'lib', 'win32', 'release', 'vs' + vs_year, 'libprotobuf.lib')
compiler.linkflags.insert(0, binary.Dep(lib_path))
if sdk.name == 'csgo':
binary.sources += ['smn_protobuf.cpp']
else:
binary.sources += ['smn_bitbuffer.cpp']
if sdk.name == 'csgo':
binary.sources += [
os.path.join(sdk.path, 'public', 'engine', 'protobuf', 'netmessages.pb.cc'),
os.path.join(sdk.path, 'public', 'game', 'shared', 'csgo', 'protobuf', 'cstrike15_usermessages.pb.cc'),
os.path.join(sdk.path, 'public', 'game', 'shared', 'csgo', 'protobuf', 'cstrike15_usermessage_helpers.cpp'),
]
SM.binaries += builder.Add(project)

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,8 @@
/** /**
* vim: set ts=4 sw=4 tw=99 noet : * vim: set ts=4 :
* ============================================================================= * =============================================================================
* SourceMod * SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
* ============================================================================= * =============================================================================
* *
* This program is free software; you can redistribute it and/or modify it under * This program is free software; you can redistribute it and/or modify it under
@ -32,15 +32,13 @@
#ifndef _INCLUDE_SOURCEMOD_ADMINCACHE_H_ #ifndef _INCLUDE_SOURCEMOD_ADMINCACHE_H_
#define _INCLUDE_SOURCEMOD_ADMINCACHE_H_ #define _INCLUDE_SOURCEMOD_ADMINCACHE_H_
#include "common_logic.h"
#include <IAdminSystem.h>
#include "sm_memtable.h" #include "sm_memtable.h"
#include <sm_trie.h> #include <sm_trie.h>
#include <sh_list.h> #include <sh_list.h>
#include <sh_string.h> #include <sh_string.h>
#include <IAdminSystem.h>
#include "sm_globals.h"
#include <IForwardSys.h> #include <IForwardSys.h>
#include <sm_stringhashmap.h>
#include <sm_namehashset.h>
using namespace SourceHook; using namespace SourceHook;
@ -49,8 +47,6 @@ using namespace SourceHook;
#define USR_MAGIC_SET 0xDEADFACE #define USR_MAGIC_SET 0xDEADFACE
#define USR_MAGIC_UNSET 0xFADEDEAD #define USR_MAGIC_UNSET 0xFADEDEAD
typedef StringHashMap<OverrideRule> OverrideMap;
struct AdminGroup struct AdminGroup
{ {
uint32_t magic; /* Magic flag, for memory validation (ugh) */ uint32_t magic; /* Magic flag, for memory validation (ugh) */
@ -60,8 +56,8 @@ struct AdminGroup
* [1...N] = immune targets * [1...N] = immune targets
*/ */
int immune_table; int immune_table;
OverrideMap *pCmdTable; /* Command override table (can be NULL) */ Trie *pCmdTable; /* Command override table (can be NULL) */
OverrideMap *pCmdGrpTable; /* Command group override table (can be NULL) */ Trie *pCmdGrpTable; /* Command group override table (can be NULL) */
int next_grp; /* Next group in the chain */ int next_grp; /* Next group in the chain */
int prev_grp; /* Previous group in the chain */ int prev_grp; /* Previous group in the chain */
int nameidx; /* Name */ int nameidx; /* Name */
@ -71,21 +67,7 @@ struct AdminGroup
struct AuthMethod struct AuthMethod
{ {
String name; String name;
StringHashMap<AdminId> identities; Trie *table;
AuthMethod(const char *name)
: name(name)
{
}
static inline bool matches(const char *name, const AuthMethod *method)
{
return strcmp(name, method->name.c_str()) == 0;
}
static inline uint32_t hash(const detail::CharsAndLength &key)
{
return key.hash();
}
}; };
struct UserAuth struct UserAuth
@ -171,7 +153,6 @@ public: //IAdminSystem
bool FindFlag(const char *str, AdminFlag *pFlag); bool FindFlag(const char *str, AdminFlag *pFlag);
bool FindFlag(char c, AdminFlag *pAdmFlag); bool FindFlag(char c, AdminFlag *pAdmFlag);
FlagBits ReadFlagString(const char *flags, const char **end); FlagBits ReadFlagString(const char *flags, const char **end);
size_t FillFlagString(FlagBits bits, char *buffer, size_t maxlen);
unsigned int GetAdminSerialChange(AdminId id); unsigned int GetAdminSerialChange(AdminId id);
bool CanAdminUseCommand(int client, const char *cmd); bool CanAdminUseCommand(int client, const char *cmd);
const char *GetGroupName(GroupId gid); const char *GetGroupName(GroupId gid);
@ -183,47 +164,36 @@ public: //IAdminSystem
const char *cmd, const char *cmd,
FlagBits flags, FlagBits flags,
bool override_only); bool override_only);
bool FindFlagChar(AdminFlag flag, char *c);
bool IsValidAdmin(AdminId id);
bool CheckClientCommandAccess(int client, const char *cmd, FlagBits cmdflags);
public: public:
bool DumpCache(const char *filename); bool IsValidAdmin(AdminId id);
AdminGroup *GetGroup(GroupId gid);
AdminUser *GetUser(AdminId id);
const char *GetString(int idx);
bool CheckAdminCommandAccess(AdminId adm, const char *cmd, FlagBits flags);
private: private:
void _UnsetCommandOverride(const char *cmd); void _UnsetCommandOverride(const char *cmd);
void _UnsetCommandGroupOverride(const char *group); void _UnsetCommandGroupOverride(const char *group);
void InvalidateGroupCache(); void InvalidateGroupCache();
void InvalidateAdminCache(bool unlink_admins); void InvalidateAdminCache(bool unlink_admins);
void DumpCommandOverrideCache(OverrideType type); void DumpCommandOverrideCache(OverrideType type);
AuthMethod *GetMethodByIndex(unsigned int index); Trie *GetMethodByIndex(unsigned int index);
bool GetMethodIndex(const char *name, unsigned int *_index); bool GetMethodIndex(const char *name, unsigned int *_index);
const char *GetMethodName(unsigned int index);
void NameFlag(const char *str, AdminFlag flag); void NameFlag(const char *str, AdminFlag flag);
bool GetUnifiedSteamIdentity(const char *ident, char *out, size_t maxlen);
public: public:
typedef StringHashMap<FlagBits> FlagMap;
BaseStringTable *m_pStrings; BaseStringTable *m_pStrings;
BaseMemTable *m_pMemory; BaseMemTable *m_pMemory;
FlagMap m_CmdOverrides; Trie *m_pCmdOverrides;
FlagMap m_CmdGrpOverrides; Trie *m_pCmdGrpOverrides;
int m_FirstGroup; int m_FirstGroup;
int m_LastGroup; int m_LastGroup;
int m_FreeGroupList; int m_FreeGroupList;
StringHashMap<GroupId> m_Groups; Trie *m_pGroups;
List<IAdminListener *> m_hooks; List<IAdminListener *> m_hooks;
List<AuthMethod *> m_AuthMethods; List<AuthMethod> m_AuthMethods;
NameHashSet<AuthMethod *> m_AuthTables; Trie *m_pAuthTables;
IForward *m_pCacheFwd; IForward *m_pCacheFwd;
int m_FirstUser; int m_FirstUser;
int m_LastUser; int m_LastUser;
int m_FreeUserList; int m_FreeUserList;
bool m_InvalidatingAdmins; bool m_InvalidatingAdmins;
bool m_destroying; bool m_destroying;
StringHashMap<AdminFlag> m_LevelNames; Trie *m_pLevelNames;
}; };
extern AdminCache g_Admins; extern AdminCache g_Admins;

259
core/CDataPack.cpp Normal file
View File

@ -0,0 +1,259 @@
/**
* vim: set ts=4 :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2007 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

@ -2,7 +2,7 @@
* vim: set ts=4 : * vim: set ts=4 :
* ============================================================================= * =============================================================================
* SourceMod * SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
* ============================================================================= * =============================================================================
* *
* This program is free software; you can redistribute it and/or modify it under * This program is free software; you can redistribute it and/or modify it under
@ -29,52 +29,43 @@
* Version: $Id$ * Version: $Id$
*/ */
#ifndef _INCLUDE_SOURCEMOD_THREAD_SUPPORT_H #ifndef _INCLUDE_SOURCEMOD_CDATAPACK_H_
#define _INCLUDE_SOURCEMOD_THREAD_SUPPORT_H #define _INCLUDE_SOURCEMOD_CDATAPACK_H_
#include <IThreader.h> #include <IDataPack.h>
#include <am-thread-utils.h>
#include <am-utility.h>
using namespace SourceMod; using namespace SourceMod;
class CompatMutex : public IMutex class CDataPack : public IDataPack
{ {
public: public:
bool TryLock() { CDataPack();
return mutex_.TryLock(); ~CDataPack();
} public: //IDataReader
void Lock() { void Reset() const;
mutex_.Lock(); size_t GetPosition() const;
} bool SetPosition(size_t pos) const;
void Unlock() { cell_t ReadCell() const;
mutex_.Unlock(); float ReadFloat() const;
} bool IsReadable(size_t bytes) const;
void DestroyThis() { const char *ReadString(size_t *len) const;
delete this; void *GetMemory() const;
} void *ReadMemory(size_t *size) const;
private: public: //IDataPack
ke::Mutex mutex_; void ResetSize();
}; void PackCell(cell_t cell);
void PackFloat(float val);
class CompatCondVar : public IEventSignal void PackString(const char *string);
{ size_t CreateMemory(size_t size, void **addr);
public: public:
void Wait() { void Initialize();
ke::AutoLock lock(&cv_);
cv_.Wait();
}
void Signal() {
ke::AutoLock lock(&cv_);
cv_.Notify();
}
void DestroyThis() {
delete this;
}
private: private:
ke::ConditionVariable cv_; void CheckSize(size_t sizetype);
private:
char *m_pBase;
mutable char *m_curptr;
size_t m_capacity;
size_t m_size;
}; };
extern IThreader *g_pThreader; #endif //_INCLUDE_SOURCEMOD_CDATAPACK_H_
#endif //_INCLUDE_SOURCEMOD_THREAD_SUPPORT_H

View File

@ -2,7 +2,7 @@
* vim: set ts=4 : * vim: set ts=4 :
* ============================================================================= * =============================================================================
* SourceMod * SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
* ============================================================================= * =============================================================================
* *
* This program is free software; you can redistribute it and/or modify it under * This program is free software; you can redistribute it and/or modify it under
@ -29,57 +29,25 @@
* Version: $Id$ * Version: $Id$
*/ */
#ifndef _INCLUDE_SOURCEMOD_CELLARRAY_H_ #include <malloc.h>
#define _INCLUDE_SOURCEMOD_CELLARRAY_H_
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <ICellArray.h>
extern HandleType_t htCellArray; extern HandleType_t htCellArray;
class CellArray : public ICellArray class CellArray
{ {
public: public:
CellArray(size_t blocksize) : m_Data(NULL), m_BlockSize(blocksize), m_AllocSize(0), m_Size(0) CellArray(size_t blocksize) : m_Data(NULL), m_BlockSize(blocksize), m_AllocSize(0), m_Size(0)
{ {
} }
~CellArray() ~CellArray()
{ {
free(m_Data); free(m_Data);
} }
/**
* @brief Creates a cell array object.
*
* @param blocksize The number of cells each member of the array can
* hold. For example, 32 cells is equivalent to:
* new Array[X][32]
* @return A new ICellArray object.
*/
static ICellArray *New(size_t blocksize)
{
return new CellArray(blocksize);
}
/**
* @brief Releases a cell array's resources.
*
* @param pack An ICellArray object to release.
*/
static void Free(ICellArray *arr)
{
delete arr;
}
// ICellArray
public:
size_t size() const size_t size() const
{ {
return m_Size; return m_Size;
} }
cell_t *push() cell_t *push()
{ {
if (!GrowIfNeeded(1)) if (!GrowIfNeeded(1))
@ -90,22 +58,18 @@ public:
m_Size++; m_Size++;
return arr; return arr;
} }
cell_t *at(size_t b) const cell_t *at(size_t b) const
{ {
return &m_Data[b * m_BlockSize]; return &m_Data[b * m_BlockSize];
} }
size_t blocksize() const size_t blocksize() const
{ {
return m_BlockSize; return m_BlockSize;
} }
void clear() void clear()
{ {
m_Size = 0; m_Size = 0;
} }
bool swap(size_t item1, size_t item2) bool swap(size_t item1, size_t item2)
{ {
/* Make sure there is extra space available */ /* Make sure there is extra space available */
@ -126,7 +90,6 @@ public:
return true; return true;
} }
void remove(size_t index) void remove(size_t index)
{ {
/* If we're at the end, take the easy way out */ /* If we're at the end, take the easy way out */
@ -144,7 +107,6 @@ public:
m_Size--; m_Size--;
} }
cell_t *insert_at(size_t index) cell_t *insert_at(size_t index)
{ {
/* Make sure it'll fit */ /* Make sure it'll fit */
@ -162,7 +124,6 @@ public:
return src; return src;
} }
bool resize(size_t count) bool resize(size_t count)
{ {
if (count <= m_Size) if (count <= m_Size)
@ -180,18 +141,12 @@ public:
return true; return true;
} }
ICellArray *clone() CellArray *clone()
{ {
CellArray *array = new CellArray(m_BlockSize); CellArray *array = new CellArray(m_BlockSize);
array->m_AllocSize = m_AllocSize; array->m_AllocSize = m_AllocSize;
array->m_Size = m_Size; array->m_Size = m_Size;
array->m_Data = (cell_t *)malloc(sizeof(cell_t) * m_BlockSize * m_AllocSize); array->m_Data = (cell_t *)malloc(sizeof(cell_t) * m_BlockSize * m_AllocSize);
if (!array->m_Data)
{
delete array;
return NULL;
}
memcpy(array->m_Data, m_Data, sizeof(cell_t) * m_BlockSize * m_Size); memcpy(array->m_Data, m_Data, sizeof(cell_t) * m_BlockSize * m_Size);
return array; return array;
} }
@ -227,17 +182,11 @@ private:
/* finally, allocate the new block */ /* finally, allocate the new block */
if (m_Data) if (m_Data)
{ {
cell_t *data = static_cast<cell_t*>(realloc(m_Data, sizeof(cell_t) * m_BlockSize * m_AllocSize)); m_Data = (cell_t *)realloc(m_Data, sizeof(cell_t) * m_BlockSize * m_AllocSize);
if (!data) // allocation failure
{
return false;
}
m_Data = data;
} else { } else {
m_Data = static_cast<cell_t*>(malloc(sizeof(cell_t) * m_BlockSize * m_AllocSize)); m_Data = (cell_t *)malloc(sizeof(cell_t) * m_BlockSize * m_AllocSize);
} }
return (m_Data != nullptr); return (m_Data != NULL);
} }
private: private:
cell_t *m_Data; cell_t *m_Data;
@ -245,6 +194,3 @@ private:
size_t m_AllocSize; size_t m_AllocSize;
size_t m_Size; size_t m_Size;
}; };
#endif /* _INCLUDE_SOURCEMOD_CELLARRAY_H_ */

View File

@ -2,7 +2,7 @@
* vim: set ts=4 : * vim: set ts=4 :
* ============================================================================= * =============================================================================
* SourceMod * SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
* ============================================================================= * =============================================================================
* *
* This program is free software; you can redistribute it and/or modify it under * This program is free software; you can redistribute it and/or modify it under
@ -81,17 +81,11 @@ inline int CellRecipientFilter::GetRecipientCount() const
inline int CellRecipientFilter::GetRecipientIndex(int slot) const inline int CellRecipientFilter::GetRecipientIndex(int slot) const
{ {
int ret;
if ((slot < 0) || (slot >= GetRecipientCount())) if ((slot < 0) || (slot >= GetRecipientCount()))
{ {
ret = -1; return -1;
} }
else return static_cast<int>(m_Players[slot]);
{
ret = static_cast<int>(m_Players[slot]);
}
return ret;
} }
inline void CellRecipientFilter::SetToInit(bool isinitmsg) inline void CellRecipientFilter::SetToInit(bool isinitmsg)

View File

@ -1,8 +1,8 @@
/** /**
* vim: set ts=4 sw=4 tw=99 noet : * vim: set ts=4 :
* ============================================================================= * =============================================================================
* SourceMod * SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
* ============================================================================= * =============================================================================
* *
* This program is free software; you can redistribute it and/or modify it under * This program is free software; you can redistribute it and/or modify it under
@ -34,55 +34,47 @@
#include "sm_stringutil.h" #include "sm_stringutil.h"
#include "ConCmdManager.h" #include "ConCmdManager.h"
#include "PlayerManager.h" #include "PlayerManager.h"
#include "Translator.h"
#include "HalfLife2.h" #include "HalfLife2.h"
#include "logic_bridge.h"
#include "sourcemod.h" /* :HACKHACK: We can't SH_DECL here because ConCmdManager.cpp does.
#include "provider.h" * While the OB build only runs on MM:S 1.6.0+ (SH 5+), the older one
#include <bridge/include/ILogger.h> * can technically be compiled against any MM:S version after 1.4.2.
#include <amtl/am-string.h> */
#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; ChatTriggers g_ChatTriggers;
bool g_bSupressSilentFails = false; bool g_bSupressSilentFails = false;
CPhraseFile *g_pFloodPhrases = NULL;
ChatTriggers::ChatTriggers() : m_bWillProcessInPost(false), ChatTriggers::ChatTriggers() : m_pSayCmd(NULL), m_bWillProcessInPost(false),
m_ReplyTo(SM_REPLY_CONSOLE), m_ArgSBackup(NULL) m_bTriggerWasSilent(false), m_ReplyTo(SM_REPLY_CONSOLE)
{ {
m_PubTrigger = "!"; m_PubTrigger = sm_strdup("!");
m_PrivTrigger = "/"; m_PrivTrigger = sm_strdup("/");
m_PubTriggerSize = 1;
m_PrivTriggerSize = 1;
m_bIsChatTrigger = false; m_bIsChatTrigger = false;
m_bPluginIgnored = true;
#if SOURCE_ENGINE == SE_EPISODEONE
m_bIsINS = false;
#endif
} }
ChatTriggers::~ChatTriggers() ChatTriggers::~ChatTriggers()
{ {
delete [] m_ArgSBackup; delete [] m_PubTrigger;
m_ArgSBackup = NULL; m_PubTrigger = NULL;
} delete [] m_PrivTrigger;
m_PrivTrigger = NULL;
void ChatTriggers::SetChatTrigger(ChatTriggerType type, const char *value)
{
ke::AutoPtr<char[]> filtered(new char[strlen(value) + 1]);
const char *src = value;
char *dest = filtered.get();
char c;
while ((c = *src++) != '\0') {
if (c <= ' ' || c == '"' || c == '\'' || (c >= '0' && c <= '9') || c == ';' || (c >= 'A' && c <= 'Z') || c == '\\' || (c >= 'a' && c <= 'z') || c >= 0x7F) {
logger->LogError("Ignoring %s chat trigger character '%c', not in valid set: %s", (type == ChatTrigger_Private ? "silent" : "public"), c, "!#$%&()*+,-./:<=>?@[]^_`{|}~");
continue;
}
*dest++ = c;
}
*dest = '\0';
if (type == ChatTrigger_Private) {
m_PrivTrigger = filtered.get();
} else {
m_PubTrigger = filtered.get();
}
} }
ConfigResult ChatTriggers::OnSourceModConfigChanged(const char *key, ConfigResult ChatTriggers::OnSourceModConfigChanged(const char *key,
@ -93,12 +85,16 @@ ConfigResult ChatTriggers::OnSourceModConfigChanged(const char *key,
{ {
if (strcmp(key, "PublicChatTrigger") == 0) if (strcmp(key, "PublicChatTrigger") == 0)
{ {
SetChatTrigger(ChatTrigger_Public, value); delete [] m_PubTrigger;
m_PubTrigger = sm_strdup(value);
m_PubTriggerSize = strlen(m_PubTrigger);
return ConfigResult_Accept; return ConfigResult_Accept;
} }
else if (strcmp(key, "SilentChatTrigger") == 0) else if (strcmp(key, "SilentChatTrigger") == 0)
{ {
SetChatTrigger(ChatTrigger_Private, value); delete [] m_PrivTrigger;
m_PrivTrigger = sm_strdup(value);
m_PrivTriggerSize = strlen(m_PrivTrigger);
return ConfigResult_Accept; return ConfigResult_Accept;
} }
else if (strcmp(key, "SilentFailSuppress") == 0) else if (strcmp(key, "SilentFailSuppress") == 0)
@ -112,231 +108,224 @@ ConfigResult ChatTriggers::OnSourceModConfigChanged(const char *key,
void ChatTriggers::OnSourceModAllInitialized() void ChatTriggers::OnSourceModAllInitialized()
{ {
m_pShouldFloodBlock = forwardsys->CreateForward("OnClientFloodCheck", ET_Event, 1, NULL, Param_Cell); m_pShouldFloodBlock = g_Forwards.CreateForward("OnClientFloodCheck", ET_Event, 1, NULL, Param_Cell);
m_pDidFloodBlock = forwardsys->CreateForward("OnClientFloodResult", ET_Event, 2, NULL, Param_Cell, Param_Cell); m_pDidFloodBlock = g_Forwards.CreateForward("OnClientFloodResult", ET_Event, 2, NULL, Param_Cell, Param_Cell);
m_pOnClientSayCmd = forwardsys->CreateForward("OnClientSayCommand", ET_Event, 3, NULL, Param_Cell, Param_String, Param_String);
m_pOnClientSayCmd_Post = forwardsys->CreateForward("OnClientSayCommand_Post", ET_Ignore, 3, NULL, Param_Cell, Param_String, Param_String);
} }
void ChatTriggers::OnSourceModAllInitialized_Post() void ChatTriggers::OnSourceModAllInitialized_Post()
{ {
logicore.AddCorePhraseFile("antiflood.phrases"); unsigned int file_id;
file_id = g_Translator.FindOrAddPhraseFile("antiflood.phrases.txt");
g_pFloodPhrases = g_Translator.GetFileByIndex(file_id);
} }
void ChatTriggers::OnSourceModGameInitialized() void ChatTriggers::OnSourceModGameInitialized()
{ {
ConCommand *say_team = FindCommand("say_team"); unsigned int total = 2;
ConCommandBase *pCmd = icvar->GetCommands();
CommandHook::Callback pre_hook = [this] (int client, const ICommandArgs *args) -> bool { const char *name;
return this->OnSayCommand_Pre(client, args); while (pCmd)
}; {
CommandHook::Callback post_hook = [this] (int client, const ICommandArgs *args) -> bool { if (pCmd->IsCommand())
return this->OnSayCommand_Post(client, args); {
}; name = pCmd->GetName();
if (!m_pSayCmd && strcmp(name, "say") == 0)
if (ConCommand *say = FindCommand("say")) { {
hooks_.append(sCoreProviderImpl.AddCommandHook(say, pre_hook)); m_pSayCmd = (ConCommand *)pCmd;
hooks_.append(sCoreProviderImpl.AddPostCommandHook(say, post_hook)); if (--total == 0)
{
break;
} }
if (ConCommand *say_team = FindCommand("say_team")) { } else if (!m_pSayTeamCmd && strcmp(name, "say_team") == 0) {
hooks_.append(sCoreProviderImpl.AddCommandHook(say_team, pre_hook)); m_pSayTeamCmd = (ConCommand *)pCmd;
hooks_.append(sCoreProviderImpl.AddPostCommandHook(say_team, post_hook)); if (--total == 0)
{
break;
}
}
}
pCmd = const_cast<ConCommandBase *>(pCmd->GetNext());
} }
#if SOURCE_ENGINE == SE_EPISODEONE if (m_pSayCmd)
m_bIsINS = (strcmp(g_SourceMod.GetGameFolderName(), "insurgency") == 0); {
if (m_bIsINS) { SH_ADD_HOOK_MEMFUNC(ConCommand, Dispatch, m_pSayCmd, this, &ChatTriggers::OnSayCommand_Pre, false);
if (ConCommand *say2 = FindCommand("say2")) { SH_ADD_HOOK_MEMFUNC(ConCommand, Dispatch, m_pSayCmd, this, &ChatTriggers::OnSayCommand_Post, true);
hooks_.append(sCoreProviderImpl.AddCommandHook(say2, pre_hook));
hooks_.append(sCoreProviderImpl.AddPostCommandHook(say2, post_hook));
} }
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);
} }
#elif SOURCE_ENGINE == SE_NUCLEARDAWN
if (ConCommand *say_squad = FindCommand("say_squad")) {
hooks_.append(sCoreProviderImpl.AddCommandHook(say_squad, pre_hook));
hooks_.append(sCoreProviderImpl.AddPostCommandHook(say_squad, post_hook));
}
#endif
} }
void ChatTriggers::OnSourceModShutdown() void ChatTriggers::OnSourceModShutdown()
{ {
hooks_.clear(); if (m_pSayTeamCmd)
{
forwardsys->ReleaseForward(m_pShouldFloodBlock); SH_REMOVE_HOOK_MEMFUNC(ConCommand, Dispatch, m_pSayTeamCmd, this, &ChatTriggers::OnSayCommand_Post, true);
forwardsys->ReleaseForward(m_pDidFloodBlock); SH_REMOVE_HOOK_MEMFUNC(ConCommand, Dispatch, m_pSayTeamCmd, this, &ChatTriggers::OnSayCommand_Pre, false);
forwardsys->ReleaseForward(m_pOnClientSayCmd); }
forwardsys->ReleaseForward(m_pOnClientSayCmd_Post); 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);
} }
bool ChatTriggers::OnSayCommand_Pre(int client, const ICommandArgs *command) 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_bIsChatTrigger = false;
m_bWasFloodedMessage = false; m_bWasFloodedMessage = false;
m_bPluginIgnored = true;
const char *args = command->ArgS();
if (!args)
return false;
/* Save these off for post hook as the command data returned from the engine in older engine versions
* can be NULL, despite the data still being there and valid. */
m_Arg0Backup = command->Arg(0);
size_t len = strlen(args);
#if SOURCE_ENGINE == SE_EPISODEONE
if (m_bIsINS)
{
if (strcmp(m_Arg0Backup, "say2") == 0 && len >= 4)
{
args += 4;
len -= 4;
}
if (len == 0)
return true;
}
#endif
/* The first pair of quotes are stripped from client say commands, but not console ones.
* We do not want the forwards to differ from what is displayed.
* So only strip the first pair of quotes from client say commands. */
bool is_quoted = false;
if (
#if SOURCE_ENGINE == SE_EPISODEONE
!m_bIsINS &&
#endif
client != 0 && args[0] == '"' && args[len-1] == '"')
{
/* The server normally won't display empty say commands, but in this case it does.
* I don't think it's desired so let's block it. */
if (len <= 2)
return true;
args++;
len--;
is_quoted = true;
}
/* Some? engines strip the last quote when printing the string to chat.
* This results in having a double-quoted message passed to the OnClientSayCommand ("message") forward,
* but losing the last quote in the OnClientSayCommand_Post ("message) forward.
* To compensate this, we copy the args into our own buffer where the engine won't mess with
* and strip the quotes. */
delete [] m_ArgSBackup;
m_ArgSBackup = new char[CCommand::MaxCommandLength()+1];
memcpy(m_ArgSBackup, args, len+1);
/* Strip the quotes from the argument */
if (is_quoted)
{
if (m_ArgSBackup[len-1] == '"')
{
m_ArgSBackup[--len] = '\0';
}
}
/* The server console cannot do this */ /* The server console cannot do this */
if (client == 0) if (client == 0 || (pPlayer = g_Players.GetPlayerByIndex(client)) == NULL)
{ {
if (CallOnClientSayCommand(client) >= Pl_Handled) RETURN_META(MRES_IGNORED);
return true;
return false;
} }
CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
/* We guarantee the client is connected */ /* We guarantee the client is connected */
if (!pPlayer || !pPlayer->IsConnected()) if (!pPlayer->IsConnected())
return false; {
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 */ /* Check if we need to block this message from being sent */
if (ClientIsFlooding(client)) if (ClientIsFlooding(client))
{ {
char buffer[128]; char buffer[128];
if (!logicore.CoreTranslate(buffer, sizeof(buffer), "%T", 2, NULL, "Flooding the server", &client)) /* :TODO: log an error? */
ke::SafeSprintf(buffer, sizeof(buffer), "You are flooding the server!"); if (g_Translator.CoreTransEx(g_pFloodPhrases,
client,
buffer,
sizeof(buffer),
"Flooding the server",
NULL,
NULL)
!= Trans_Okay)
{
UTIL_Format(buffer, sizeof(buffer), "You are flooding the server!");
}
/* :TODO: we should probably kick people who spam too much. */ /* :TODO: we should probably kick people who spam too much. */
char fullbuffer[192]; char fullbuffer[192];
ke::SafeSprintf(fullbuffer, sizeof(fullbuffer), "[SM] %s", buffer); UTIL_Format(fullbuffer, sizeof(fullbuffer), "[SM] %s", buffer);
g_HL2.TextMsg(client, HUD_PRINTTALK, fullbuffer); g_HL2.TextMsg(client, HUD_PRINTTALK, fullbuffer);
m_bWasFloodedMessage = true; m_bWasFloodedMessage = true;
return 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_trigger = false;
bool is_silent = false; bool is_silent = false;
// Prefer the silent trigger in case of clashes. /* Check for either trigger */
if (strchr(m_PrivTrigger.chars(), m_ArgSBackup[0])) { 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_trigger = true;
is_silent = true; is_silent = true;
} else if (strchr(m_PubTrigger.chars(), m_ArgSBackup[0])) { args = &args[m_PrivTriggerSize];
is_trigger = true;
} }
if (is_trigger) { if (!is_trigger)
// Bump the args past the chat trigger - we only support single-character triggers now. {
args = &m_ArgSBackup[1]; RETURN_META(MRES_IGNORED);
} }
/** /**
* Test if this is actually a command! * Test if this is actually a command!
*/ */
if (is_trigger && PreProcessTrigger(PEntityOfEntIndex(client), args)) 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; m_bIsChatTrigger = true;
/** /**
* We'll execute it in post. * We'll execute it in post.
*/ */
m_bWillProcessInPost = true; m_bWillProcessInPost = true;
m_bTriggerWasSilent = is_silent;
/* If we're silent, block */
if (is_silent)
{
RETURN_META(MRES_SUPERCEDE);
} }
if (is_silent && (m_bIsChatTrigger || (g_bSupressSilentFails && pPlayer->GetAdminId() != INVALID_ADMIN_ID)))
return true;
if (CallOnClientSayCommand(client) >= Pl_Handled)
return true;
/* Otherwise, let the command continue */ /* Otherwise, let the command continue */
return false; RETURN_META(MRES_IGNORED);
} }
bool ChatTriggers::OnSayCommand_Post(int client, const ICommandArgs *command) #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) if (m_bWillProcessInPost)
{ {
/* Reset this for re-entrancy */ /* Reset this for re-entrancy */
m_bWillProcessInPost = false; m_bWillProcessInPost = false;
/* Execute the cached command */ /* Execute the cached command */
int client = g_ConCmds.GetCommandClient();
unsigned int old = SetReplyTo(SM_REPLY_CHAT); unsigned int old = SetReplyTo(SM_REPLY_CHAT);
serverpluginhelpers->ClientCommand(PEntityOfEntIndex(client), m_ToExecute); serverpluginhelpers->ClientCommand(engine->PEntityOfEntIndex(client), m_ToExecute);
SetReplyTo(old); SetReplyTo(old);
} }
if (!m_bPluginIgnored && m_pOnClientSayCmd_Post->GetFunctionCount() != 0)
{
m_pOnClientSayCmd_Post->PushCell(client);
m_pOnClientSayCmd_Post->PushString(m_Arg0Backup);
m_pOnClientSayCmd_Post->PushString(m_ArgSBackup);
m_pOnClientSayCmd_Post->Execute(NULL);
} }
m_bIsChatTrigger = false; bool ChatTriggers::PreProcessTrigger(edict_t *pEdict, const char *args, bool is_quoted)
m_bWasFloodedMessage = false;
return false;
}
bool ChatTriggers::PreProcessTrigger(edict_t *pEdict, const char *args)
{ {
/* Extract a command. This is kind of sloppy. */ /* Extract a command. This is kind of sloppy. */
char cmd_buf[64]; char cmd_buf[64];
@ -371,7 +360,7 @@ bool ChatTriggers::PreProcessTrigger(edict_t *pEdict, const char *args)
*/ */
char new_buf[80]; char new_buf[80];
strcpy(new_buf, "sm_"); strcpy(new_buf, "sm_");
ke::SafeStrcpy(&new_buf[3], sizeof(new_buf)-3, cmd_buf); strncopy(&new_buf[3], cmd_buf, sizeof(new_buf)-3);
/* Recheck */ /* Recheck */
if (!g_ConCmds.LookForSourceModCommand(new_buf)) if (!g_ConCmds.LookForSourceModCommand(new_buf))
@ -383,40 +372,33 @@ bool ChatTriggers::PreProcessTrigger(edict_t *pEdict, const char *args)
} }
/* See if we need to do extra string manipulation */ /* See if we need to do extra string manipulation */
if (prepended) if (is_quoted || prepended)
{ {
size_t len; size_t len;
/* Check if we need to prepend sm_ */ /* Check if we need to prepend sm_ */
if (prepended) if (prepended)
{ {
len = ke::SafeSprintf(m_ToExecute, sizeof(m_ToExecute), "sm_%s", args); len = UTIL_Format(m_ToExecute, sizeof(m_ToExecute), "sm_%s", args);
} else { } else {
len = ke::SafeStrcpy(m_ToExecute, sizeof(m_ToExecute), args); 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 { } else {
ke::SafeStrcpy(m_ToExecute, sizeof(m_ToExecute), args); strncopy(m_ToExecute, args, sizeof(m_ToExecute));
} }
return true; return true;
} }
cell_t ChatTriggers::CallOnClientSayCommand(int client)
{
cell_t res = Pl_Continue;
if (m_pOnClientSayCmd->GetFunctionCount() != 0)
{
m_pOnClientSayCmd->PushCell(client);
m_pOnClientSayCmd->PushString(m_Arg0Backup);
m_pOnClientSayCmd->PushString(m_ArgSBackup);
m_pOnClientSayCmd->Execute(&res);
}
m_bPluginIgnored = (res >= Pl_Stop);
return res;
}
unsigned int ChatTriggers::SetReplyTo(unsigned int reply) unsigned int ChatTriggers::SetReplyTo(unsigned int reply)
{ {
unsigned int old = m_ReplyTo; unsigned int old = m_ReplyTo;

View File

@ -1,8 +1,8 @@
/** /**
* vim: set ts=4 sw=4 tw=99 noet : * vim: set ts=4 :
* ============================================================================= * =============================================================================
* SourceMod * SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
* ============================================================================= * =============================================================================
* *
* This program is free software; you can redistribute it and/or modify it under * This program is free software; you can redistribute it and/or modify it under
@ -34,11 +34,9 @@
#include "sm_globals.h" #include "sm_globals.h"
#include "sourcemm_api.h" #include "sourcemm_api.h"
#include "GameHooks.h"
#include <IGameHelpers.h> #include <IGameHelpers.h>
#include <compat_wrappers.h> #include <compat_wrappers.h>
#include <IForwardSys.h> #include <IForwardSys.h>
#include <amtl/am-string.h>
class ChatTriggers : public SMGlobalClass class ChatTriggers : public SMGlobalClass
{ {
@ -56,41 +54,36 @@ public: //SMGlobalClass
char *error, char *error,
size_t maxlength); size_t maxlength);
private: //ConCommand private: //ConCommand
bool OnSayCommand_Pre(int client, const ICommandArgs *args); #if defined ORANGEBOX_BUILD
bool OnSayCommand_Post(int client, const ICommandArgs *args); void OnSayCommand_Pre(const CCommand &command);
void OnSayCommand_Post(const CCommand &command);
#else
void OnSayCommand_Pre();
void OnSayCommand_Post();
#endif
public: public:
unsigned int GetReplyTo(); unsigned int GetReplyTo();
unsigned int SetReplyTo(unsigned int reply); unsigned int SetReplyTo(unsigned int reply);
bool IsChatTrigger(); bool IsChatTrigger();
bool WasFloodedMessage(); bool WasFloodedMessage();
private: private:
enum ChatTriggerType { bool PreProcessTrigger(edict_t *pEdict, const char *args, bool is_quoted);
ChatTrigger_Public,
ChatTrigger_Private,
};
void SetChatTrigger(ChatTriggerType type, const char *value);
bool PreProcessTrigger(edict_t *pEdict, const char *args);
bool ClientIsFlooding(int client); bool ClientIsFlooding(int client);
cell_t CallOnClientSayCommand(int client);
private: private:
ke::Vector<ke::RefPtr<CommandHook>> hooks_; ConCommand *m_pSayCmd;
ke::AString m_PubTrigger; ConCommand *m_pSayTeamCmd;
ke::AString m_PrivTrigger; char *m_PubTrigger;
size_t m_PubTriggerSize;
char *m_PrivTrigger;
size_t m_PrivTriggerSize;
bool m_bWillProcessInPost; bool m_bWillProcessInPost;
bool m_bTriggerWasSilent;
bool m_bIsChatTrigger; bool m_bIsChatTrigger;
bool m_bWasFloodedMessage; bool m_bWasFloodedMessage;
bool m_bPluginIgnored;
unsigned int m_ReplyTo; unsigned int m_ReplyTo;
char m_ToExecute[300]; char m_ToExecute[300];
const char *m_Arg0Backup;
char *m_ArgSBackup;
IForward *m_pShouldFloodBlock; IForward *m_pShouldFloodBlock;
IForward *m_pDidFloodBlock; IForward *m_pDidFloodBlock;
IForward *m_pOnClientSayCmd;
IForward *m_pOnClientSayCmd_Post;
#if SOURCE_ENGINE == SE_EPISODEONE
bool m_bIsINS;
#endif
}; };
extern ChatTriggers g_ChatTriggers; extern ChatTriggers g_ChatTriggers;

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,8 @@
/** /**
* vim: set ts=4 sw=4 tw=99 noet : * vim: set ts=4 :
* ============================================================================= * =============================================================================
* SourceMod * SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
* ============================================================================= * =============================================================================
* *
* This program is free software; you can redistribute it and/or modify it under * This program is free software; you can redistribute it and/or modify it under
@ -34,93 +34,75 @@
#include "sm_globals.h" #include "sm_globals.h"
#include "sourcemm_api.h" #include "sourcemm_api.h"
#include <IForwardSys.h> #include "ForwardSys.h"
#include "sm_trie.h"
#include "sm_memtable.h"
#include <sh_list.h> #include <sh_list.h>
#include <sh_string.h> #include <sh_string.h>
#include <IRootConsoleMenu.h> #include <IRootConsoleMenu.h>
#include <IAdminSystem.h> #include <IAdminSystem.h>
#include "concmd_cleaner.h" #include "concmd_cleaner.h"
#include "GameHooks.h"
#include <am-autoptr.h>
#include <sm_stringhashmap.h>
#include <am-utility.h>
#include <am-inlinelist.h>
#include <am-linkedlist.h>
#include <am-refcounting.h>
using namespace SourceHook; using namespace SourceHook;
struct CmdHook; enum CmdType
struct ConCmdInfo;
struct CommandGroup : public ke::Refcounted<CommandGroup>
{ {
ke::LinkedList<CmdHook *> hooks; Cmd_Server,
Cmd_Console,
Cmd_Admin,
}; };
struct AdminCmdInfo struct AdminCmdInfo
{ {
AdminCmdInfo(const ke::RefPtr<CommandGroup> &group, FlagBits flags) AdminCmdInfo()
: group(group),
flags(flags),
eflags(0)
{ {
cmdGrpId = -1;
flags = 0;
eflags = 0;
} }
ke::RefPtr<CommandGroup> group; int cmdGrpId; /* index into cmdgroup string table */
FlagBits flags; /* default flags */ FlagBits flags; /* default flags */
FlagBits eflags; /* effective flags */ FlagBits eflags; /* effective flags */
}; };
struct CmdHook : public ke::InlineListNode<CmdHook> struct CmdHook
{ {
enum Type { CmdHook()
Server,
Client
};
CmdHook(Type type, ConCmdInfo *cmd, IPluginFunction *fun, const char *description)
: type(type),
info(cmd),
pf(fun),
helptext(description)
{ {
pf = NULL;
pAdmin = NULL;
} }
Type type;
ConCmdInfo *info;
IPluginFunction *pf; /* function hook */ IPluginFunction *pf; /* function hook */
ke::AString helptext; /* help text */ String helptext; /* help text */
ke::AutoPtr<AdminCmdInfo> admin; /* admin requirements, if any */ AdminCmdInfo *pAdmin; /* admin requirements, if any */
}; };
typedef ke::InlineList<CmdHook> CmdHookList;
struct ConCmdInfo struct ConCmdInfo
{ {
ConCmdInfo() ConCmdInfo()
{ {
pPlugin = nullptr;
sourceMod = false; sourceMod = false;
pCmd = nullptr; pCmd = NULL;
eflags = 0;
} }
bool sourceMod; /**< Determines whether or not concmd was created by a SourceMod plugin */ bool sourceMod; /**< Determines whether or not concmd was created by a SourceMod plugin */
ConCommand *pCmd; /**< Pointer to the command itself */ ConCommand *pCmd; /**< Pointer to the command itself */
CmdHookList hooks; /**< Hook list */ List<CmdHook *> srvhooks; /**< Hooks as a server command */
FlagBits eflags; /**< Effective admin flags */ List<CmdHook *> conhooks; /**< Hooks as a console command */
ke::RefPtr<CommandHook> sh_hook; /**< SourceHook hook, if any. */ AdminCmdInfo admin; /**< Admin info, if any */
IPlugin *pPlugin; /**< Owning plugin handle. */ bool is_admin_set; /**< Whether or not admin info is set */
}; };
typedef List<ConCmdInfo *> ConCmdList;
class ConCmdManager : class ConCmdManager :
public SMGlobalClass, public SMGlobalClass,
public IRootConsoleCommand, public IRootConsoleCommand,
public IPluginsListener, public IPluginsListener,
public IConCommandTracker public IConCommandTracker
{ {
friend void CommandCallback(DISPATCH_ARGS); #if defined ORANGEBOX_BUILD
friend void CommandCallback(const CCommand &command);
#else
friend void CommandCallback();
#endif
public: public:
ConCmdManager(); ConCmdManager();
~ConCmdManager(); ~ConCmdManager();
@ -130,49 +112,50 @@ public: //SMGlobalClass
public: //IPluginsListener public: //IPluginsListener
void OnPluginDestroyed(IPlugin *plugin); void OnPluginDestroyed(IPlugin *plugin);
public: //IRootConsoleCommand public: //IRootConsoleCommand
void OnRootConsoleCommand(const char *cmdname, const ICommandArgs *command) override; void OnRootConsoleCommand(const char *cmdname, const CCommand &command);
public: //IConCommandTracker public: //IConCommandTracker
void OnUnlinkConCommandBase(ConCommandBase *pBase, const char *name) override; void OnUnlinkConCommandBase(ConCommandBase *pBase, const char *name, bool is_read_safe);
public: public:
bool AddServerCommand(IPluginFunction *pFunction, const char *name, const char *description, int flags, IPlugin *pPlugin); 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, bool AddAdminCommand(IPluginFunction *pFunction,
const char *name, const char *name,
const char *group, const char *group,
int adminflags, int adminflags,
const char *description, const char *description,
int flags, int flags);
IPlugin *pPlugin);
ResultType DispatchClientCommand(int client, const char *cmd, int args, ResultType type); ResultType DispatchClientCommand(int client, const char *cmd, int args, ResultType type);
void UpdateAdminCmdFlags(const char *cmd, OverrideType type, FlagBits bits, bool remove); void UpdateAdminCmdFlags(const char *cmd, OverrideType type, FlagBits bits, bool remove);
bool LookForSourceModCommand(const char *cmd); bool LookForSourceModCommand(const char *cmd);
bool LookForCommandAdminFlags(const char *cmd, FlagBits *pFlags); bool LookForCommandAdminFlags(const char *cmd, FlagBits *pFlags);
bool CheckCommandAccess(int client, const char *cmd, FlagBits flags);
private: private:
bool InternalDispatch(int client, const ICommandArgs *args); void InternalDispatch(const CCommand &command);
ResultType RunAdminCommand(ConCmdInfo *pInfo, int client, int args); ResultType RunAdminCommand(ConCmdInfo *pInfo, int client, int args);
ConCmdInfo *AddOrFindCommand(const char *name, const char *description, int flags, IPlugin *pPlugin); ConCmdInfo *AddOrFindCommand(const char *name, const char *description, int flags);
void SetCommandClient(int client);
void AddToCmdList(ConCmdInfo *info); void AddToCmdList(ConCmdInfo *info);
void RemoveConCmd(ConCmdInfo *info, const char *cmd, bool untrack); 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); bool CheckAccess(int client, const char *cmd, AdminCmdInfo *pAdmin);
// Case insensitive
ConCmdList::iterator FindInList(const char *name);
// Case sensitive
ConCmdInfo *FindInTrie(const char *name);
public: public:
inline int GetCommandClient()
{
return m_CmdClient;
}
inline const List<ConCmdInfo *> & GetCommandList() inline const List<ConCmdInfo *> & GetCommandList()
{ {
return m_CmdList; return m_CmdList;
} }
private: private:
typedef StringHashMap<ke::RefPtr<CommandGroup> > GroupMap; Trie *m_pCmds; /* command lookup */
Trie *m_pCmdGrps; /* command group lookup */
StringHashMap<ConCmdInfo *> m_Cmds; /* command lookup */ List<ConCmdInfo *> m_CmdList; /* command list */
GroupMap m_CmdGrps; /* command group map */ int m_CmdClient; /* current client */
ConCmdList m_CmdList; /* command list */ BaseStringTable m_Strings; /* string table */
}; };
extern ConCmdManager g_ConCmds; extern ConCmdManager g_ConCmds;
#endif // _INCLUDE_SOURCEMOD_CONCMDMANAGER_H_ #endif // _INCLUDE_SOURCEMOD_CONCMDMANAGER_H_

View File

@ -1,89 +0,0 @@
/**
* vim: set ts=4 sw=4 tw=99 noet :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2010 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_CON_COMMAND_BASE_ITERATOR_H_
#define _INCLUDE_SOURCEMOD_CON_COMMAND_BASE_ITERATOR_H_
#if SOURCE_ENGINE >= SE_LEFT4DEAD
class ConCommandBaseIterator
{
public:
inline ConCommandBaseIterator() : iter(icvar)
{
iter.SetFirst();
}
inline bool IsValid()
{
return iter.IsValid();
}
inline void Next()
{
iter.Next();
}
inline ConCommandBase *Get()
{
return iter.Get();
}
private:
ICvar::Iterator iter;
};
#else
class ConCommandBaseIterator
{
public:
inline ConCommandBaseIterator()
{
iter = icvar->GetCommands();
}
inline bool IsValid()
{
return iter != NULL;
}
inline void Next()
{
iter = const_cast<ConCommandBase *>(iter->GetNext());
}
inline ConCommandBase *Get()
{
return iter;
}
private:
ConCommandBase *iter;
};
#endif
#endif /* _INCLUDE_SOURCEMOD_CON_COMMAND_BASE_ITERATOR_H_ */

View File

@ -1,8 +1,8 @@
/** /**
* vim: set ts=4 sw=4 tw=99 noet : * vim: set ts=4 :
* ============================================================================= * =============================================================================
* SourceMod * SourceMod
* Copyright (C) 2004-2009 AlliedModders LLC. All rights reserved. * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
* ============================================================================= * =============================================================================
* *
* This program is free software; you can redistribute it and/or modify it under * This program is free software; you can redistribute it and/or modify it under
@ -25,59 +25,40 @@
* this exception to all derivative works. AlliedModders LLC defines further * this exception to all derivative works. AlliedModders LLC defines further
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
* or <http://www.sourcemod.net/license.php>. * or <http://www.sourcemod.net/license.php>.
*
* Version: $Id$
*/ */
#include "ConVarManager.h" #include "ConVarManager.h"
#include "HalfLife2.h" #include "HalfLife2.h"
#include "PluginSys.h"
#include "ForwardSys.h"
#include "HandleSys.h"
#include "sm_srvcmds.h"
#include "sm_stringutil.h" #include "sm_stringutil.h"
#include <sh_vector.h> #include <sh_vector.h>
#include <sm_namehashset.h> #include <sm_trie_tpl.h>
#include "logic_bridge.h"
#include "sourcemod.h"
#include "provider.h"
#include <bridge/include/IScriptManager.h>
ConVarManager g_ConVarManager; 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}; const ParamType CONVARCHANGE_PARAMS[] = {Param_Cell, Param_String, Param_String};
typedef List<const ConVar *> ConVarList; typedef List<const ConVar *> ConVarList;
NameHashSet<ConVarInfo *> convar_cache; KTrie<ConVarInfo *> convar_cache;
class ConVarReentrancyGuard ConVarManager::ConVarManager() : m_ConVarType(0), m_bIsDLLQueryHooked(false), m_bIsVSPQueryHooked(false)
{
ConVar *cvar;
ConVarReentrancyGuard *up;
public:
static ConVarReentrancyGuard *chain;
ConVarReentrancyGuard(ConVar *cvar)
: cvar(cvar), up(chain)
{
chain = this;
}
~ConVarReentrancyGuard()
{
assert(chain == this);
chain = up;
}
static bool IsCvarInChain(ConVar *cvar)
{
ConVarReentrancyGuard *guard = chain;
while (guard != NULL)
{
if (guard->cvar == cvar)
return true;
guard = guard->up;
}
return false;
}
};
ConVarReentrancyGuard *ConVarReentrancyGuard::chain = NULL;
ConVarManager::ConVarManager() : m_ConVarType(0)
{ {
} }
@ -95,17 +76,26 @@ void ConVarManager::OnSourceModStartup(bool late)
sec.access[HandleAccess_Clone] = HANDLE_RESTRICT_IDENTITY | HANDLE_RESTRICT_OWNER; sec.access[HandleAccess_Clone] = HANDLE_RESTRICT_IDENTITY | HANDLE_RESTRICT_OWNER;
/* Create the 'ConVar' handle type */ /* Create the 'ConVar' handle type */
m_ConVarType = handlesys->CreateType("ConVar", this, 0, NULL, &sec, g_pCoreIdent, NULL); m_ConVarType = g_HandleSys.CreateType("ConVar", this, 0, NULL, &sec, g_pCoreIdent, NULL);
} }
void ConVarManager::OnSourceModAllInitialized() void ConVarManager::OnSourceModAllInitialized()
{ {
g_Players.AddClientListener(this); /**
* 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
scripts->AddPluginsListener(this); SH_ADD_HOOK_STATICFUNC(ICvar, CallGlobalChangeCallbacks, icvar, OnConVarChanged, false);
/* Add the 'convars' option to the 'sm' console command */ /* Add the 'convars' option to the 'sm' console command */
rootmenu->AddRootConsoleCommand3("cvars", "View convars created by a plugin", this); g_RootMenu.AddRootConsoleCommand("cvars", "View convars created by a plugin", this);
} }
void ConVarManager::OnSourceModShutdown() void ConVarManager::OnSourceModShutdown()
@ -120,10 +110,10 @@ void ConVarManager::OnSourceModShutdown()
iter = m_ConVars.erase(iter); iter = m_ConVars.erase(iter);
handlesys->FreeHandle(pInfo->handle, &sec); g_HandleSys.FreeHandle(pInfo->handle, &sec);
if (pInfo->pChangeForward != NULL) if (pInfo->pChangeForward != NULL)
{ {
forwardsys->ReleaseForward(pInfo->pChangeForward); g_Forwards.ReleaseForward(pInfo->pChangeForward);
} }
if (pInfo->sourceMod) if (pInfo->sourceMod)
{ {
@ -151,23 +141,73 @@ void ConVarManager::OnSourceModShutdown()
} }
convar_cache.clear(); convar_cache.clear();
g_Players.RemoveClientListener(this); /* 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 */ /* Remove the 'convars' option from the 'sm' console command */
rootmenu->RemoveRootConsoleCommand("cvars", this); g_RootMenu.RemoveRootConsoleCommand("cvars", this);
scripts->RemovePluginsListener(this);
/* Remove the 'ConVar' handle type */ /* Remove the 'ConVar' handle type */
handlesys->RemoveType(m_ConVarType, g_pCoreIdent); 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) bool convar_cache_lookup(const char *name, ConVarInfo **pVar)
{ {
return convar_cache.retrieve(name, pVar); ConVarInfo **pLookup = convar_cache.retrieve(name);
if (pLookup != NULL)
{
*pVar = *pLookup;
return true;
}
else
{
return false;
}
} }
void ConVarManager::OnUnlinkConCommandBase(ConCommandBase *pBase, const char *name) void ConVarManager::OnUnlinkConCommandBase(ConCommandBase *pBase, const char *name, bool is_read_safe)
{ {
/* Only check convars that have not been created by SourceMod's core */ /* Only check convars that have not been created by SourceMod's core */
ConVarInfo *pInfo; ConVarInfo *pInfo;
@ -183,7 +223,7 @@ void ConVarManager::OnUnlinkConCommandBase(ConCommandBase *pBase, const char *na
convar_cache.remove(name); convar_cache.remove(name);
/* Now make sure no plugins are referring to this pointer */ /* Now make sure no plugins are referring to this pointer */
IPluginIterator *pl_iter = scripts->GetPluginIterator(); IPluginIterator *pl_iter = g_PluginSys.GetPluginIterator();
while (pl_iter->MorePlugins()) while (pl_iter->MorePlugins())
{ {
IPlugin *pl = pl_iter->GetPlugin(); IPlugin *pl = pl_iter->GetPlugin();
@ -199,51 +239,19 @@ void ConVarManager::OnUnlinkConCommandBase(ConCommandBase *pBase, const char *na
} }
/* Free resources */ /* Free resources */
handlesys->FreeHandle(pInfo->handle, &sec); g_HandleSys.FreeHandle(pInfo->handle, &sec);
delete pInfo; delete pInfo;
} }
void ConVarManager::OnPluginUnloaded(IPlugin *plugin) void ConVarManager::OnPluginUnloaded(IPlugin *plugin)
{ {
ConVarList *pConVarList; ConVarList *pConVarList;
List<ConVarQuery>::iterator iter;
/* If plugin has a convar list, free its memory */ /* If plugin has a convar list, free its memory */
if (plugin->GetProperty("ConVarList", (void **)&pConVarList, true)) if (plugin->GetProperty("ConVarList", (void **)&pConVarList, true))
{ {
delete pConVarList; delete pConVarList;
} }
const IPluginRuntime * pRuntime = plugin->GetRuntime();
/* Remove convar queries for this plugin that haven't returned results yet */
for (iter = m_ConVarQueries.begin(); iter != m_ConVarQueries.end();)
{
ConVarQuery &query = (*iter);
if (query.pCallback->GetParentRuntime() == pRuntime)
{
iter = m_ConVarQueries.erase(iter);
continue;
}
++iter;
}
}
void ConVarManager::OnClientDisconnected(int client)
{
/* Remove convar queries for this client that haven't returned results yet */
for (List<ConVarQuery>::iterator iter = m_ConVarQueries.begin(); iter != m_ConVarQueries.end();)
{
ConVarQuery &query = (*iter);
if (query.client == client)
{
iter = m_ConVarQueries.erase(iter);
continue;
}
++iter;
}
} }
void ConVarManager::OnHandleDestroy(HandleType_t type, void *object) void ConVarManager::OnHandleDestroy(HandleType_t type, void *object)
@ -256,27 +264,20 @@ bool ConVarManager::GetHandleApproxSize(HandleType_t type, void *object, unsigne
return true; return true;
} }
void ConVarManager::OnRootConsoleCommand(const char *cmdname, const ICommandArgs *command) void ConVarManager::OnRootConsoleCommand(const char *cmdname, const CCommand &command)
{ {
int argcount = command->ArgC(); int argcount = command.ArgC();
if (argcount >= 3) if (argcount >= 3)
{ {
bool wantReset = false;
/* Get plugin index that was passed */ /* Get plugin index that was passed */
const char *arg = command->Arg(2); const char *arg = command.Arg(2);
if (argcount >= 4 && strcmp(arg, "reset") == 0)
{
wantReset = true;
arg = command->Arg(3);
}
/* Get plugin object */ /* Get plugin object */
IPlugin *plugin = scripts->FindPluginByConsoleArg(arg); CPlugin *plugin = g_PluginSys.FindPluginByConsoleArg(arg);
if (!plugin) if (!plugin)
{ {
UTIL_ConsolePrint("[SM] Plugin \"%s\" was not found.", arg); g_RootMenu.ConsolePrint("[SM] Plugin \"%s\" was not found.", arg);
return; return;
} }
@ -290,38 +291,25 @@ void ConVarManager::OnRootConsoleCommand(const char *cmdname, const ICommandArgs
/* If no convar list... */ /* If no convar list... */
if (!plugin->GetProperty("ConVarList", (void **)&pConVarList)) if (!plugin->GetProperty("ConVarList", (void **)&pConVarList))
{ {
UTIL_ConsolePrint("[SM] No convars found for: %s", plname); g_RootMenu.ConsolePrint("[SM] No convars found for: %s", plname);
return; return;
} }
if (!wantReset) g_RootMenu.ConsolePrint("[SM] Listing %d convars for: %s", pConVarList->size(), plname);
{ g_RootMenu.ConsolePrint(" %-32.31s %s", "[Name]", "[Value]");
UTIL_ConsolePrint("[SM] Listing %d convars for: %s", pConVarList->size(), plname);
UTIL_ConsolePrint(" %-32.31s %s", "[Name]", "[Value]");
}
/* Iterate convar list and display/reset each one */ /* Iterate convar list and display each one */
for (iter = pConVarList->begin(); iter != pConVarList->end(); iter++) for (iter = pConVarList->begin(); iter != pConVarList->end(); iter++)
{ {
/*const */ConVar *pConVar = const_cast<ConVar *>(*iter); const ConVar *pConVar = (*iter);
if (!wantReset) g_RootMenu.ConsolePrint(" %-32.31s %s", pConVar->GetName(), pConVar->GetString());
{
UTIL_ConsolePrint(" %-32.31s %s", pConVar->GetName(), pConVar->GetString());
} else {
pConVar->Revert();
}
}
if (wantReset)
{
UTIL_ConsolePrint("[SM] Reset %d convars for: %s", pConVarList->size(), plname);
} }
return; return;
} }
/* Display usage of subcommand */ /* Display usage of subcommand */
UTIL_ConsolePrint("[SM] Usage: sm cvars [reset] <plugin #>"); 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) 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)
@ -353,7 +341,7 @@ Handle_t ConVarManager::CreateConVar(IPluginContext *pContext, const char *name,
pInfo->pVar = pConVar; pInfo->pVar = pConVar;
/* If we don't, then create a new handle from the convar */ /* If we don't, then create a new handle from the convar */
hndl = handlesys->CreateHandle(m_ConVarType, pInfo, NULL, g_pCoreIdent, NULL); hndl = g_HandleSys.CreateHandle(m_ConVarType, pInfo, NULL, g_pCoreIdent, NULL);
if (hndl == BAD_HANDLE) if (hndl == BAD_HANDLE)
{ {
delete pInfo; delete pInfo;
@ -371,12 +359,19 @@ Handle_t ConVarManager::CreateConVar(IPluginContext *pContext, const char *name,
} }
} }
/* Prevent creating a convar that has the same name as a console command */ /* To prevent creating a convar that has the same name as a console command... ugh */
if (FindCommand(name)) ConCommandBase *pBase = icvar->GetCommands();
while (pBase)
{
if (pBase->IsCommand() && strcmp(pBase->GetName(), name) == 0)
{ {
return BAD_HANDLE; return BAD_HANDLE;
} }
pBase = const_cast<ConCommandBase *>(pBase->GetNext());
}
/* Create and initialize ConVarInfo structure */ /* Create and initialize ConVarInfo structure */
pInfo = new ConVarInfo(); pInfo = new ConVarInfo();
pInfo->handle = hndl; pInfo->handle = hndl;
@ -384,7 +379,7 @@ Handle_t ConVarManager::CreateConVar(IPluginContext *pContext, const char *name,
pInfo->pChangeForward = NULL; pInfo->pChangeForward = NULL;
/* Create a handle from the new convar */ /* Create a handle from the new convar */
hndl = handlesys->CreateHandle(m_ConVarType, pInfo, NULL, g_pCoreIdent, NULL); hndl = g_HandleSys.CreateHandle(m_ConVarType, pInfo, NULL, g_pCoreIdent, NULL);
if (hndl == BAD_HANDLE) if (hndl == BAD_HANDLE)
{ {
delete pInfo; delete pInfo;
@ -413,13 +408,7 @@ Handle_t ConVarManager::FindConVar(const char *name)
ConVarInfo *pInfo; ConVarInfo *pInfo;
Handle_t hndl; Handle_t hndl;
/* Check convar cache to find out if we already have a handle */ /* Search for convar */
if (convar_cache_lookup(name, &pInfo))
{
return pInfo->handle;
}
/* Couldn't find it in cache, so search for it */
pConVar = icvar->FindVar(name); pConVar = icvar->FindVar(name);
/* If it doesn't exist, then return an invalid handle */ /* If it doesn't exist, then return an invalid handle */
@ -428,6 +417,12 @@ Handle_t ConVarManager::FindConVar(const char *name)
return BAD_HANDLE; 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 */ /* Create and initialize ConVarInfo structure */
pInfo = new ConVarInfo(); pInfo = new ConVarInfo();
pInfo->sourceMod = false; pInfo->sourceMod = false;
@ -435,7 +430,7 @@ Handle_t ConVarManager::FindConVar(const char *name)
pInfo->pVar = pConVar; pInfo->pVar = pConVar;
/* If we don't have a handle, then create a new one */ /* If we don't have a handle, then create a new one */
hndl = handlesys->CreateHandle(m_ConVarType, pInfo, NULL, g_pCoreIdent, NULL); hndl = g_HandleSys.CreateHandle(m_ConVarType, pInfo, NULL, g_pCoreIdent, NULL);
if (hndl == BAD_HANDLE) if (hndl == BAD_HANDLE)
{ {
delete pInfo; delete pInfo;
@ -493,7 +488,7 @@ void ConVarManager::HookConVarChange(ConVar *pConVar, IPluginFunction *pFunction
/* If forward does not exist, create it */ /* If forward does not exist, create it */
if (!pForward) if (!pForward)
{ {
pForward = forwardsys->CreateForwardEx(NULL, ET_Ignore, 3, CONVARCHANGE_PARAMS); pForward = g_Forwards.CreateForwardEx(NULL, ET_Ignore, 3, CONVARCHANGE_PARAMS);
pInfo->pChangeForward = pForward; pInfo->pChangeForward = pForward;
} }
@ -529,11 +524,10 @@ void ConVarManager::UnhookConVarChange(ConVar *pConVar, IPluginFunction *pFuncti
} }
/* If the forward now has 0 functions in it... */ /* If the forward now has 0 functions in it... */
if (pForward->GetFunctionCount() == 0 && if (pForward->GetFunctionCount() == 0)
!ConVarReentrancyGuard::IsCvarInChain(pConVar))
{ {
/* Free this forward */ /* Free this forward */
forwardsys->ReleaseForward(pForward); g_Forwards.ReleaseForward(pForward);
pInfo->pChangeForward = NULL; pInfo->pChangeForward = NULL;
} }
} }
@ -541,13 +535,24 @@ void ConVarManager::UnhookConVarChange(ConVar *pConVar, IPluginFunction *pFuncti
QueryCvarCookie_t ConVarManager::QueryClientConVar(edict_t *pPlayer, const char *name, IPluginFunction *pCallback, Handle_t hndl) QueryCvarCookie_t ConVarManager::QueryClientConVar(edict_t *pPlayer, const char *name, IPluginFunction *pCallback, Handle_t hndl)
{ {
QueryCvarCookie_t cookie = sCoreProviderImpl.QueryClientConVar(IndexOfEdict(pPlayer), name); QueryCvarCookie_t cookie;
if (pCallback != NULL) /* Call StartQueryCvarValue() in either the IVEngineServer or IServerPluginHelpers depending on situation */
if (m_bIsDLLQueryHooked)
{ {
ConVarQuery query = { cookie, pCallback, (cell_t) hndl, IndexOfEdict(pPlayer) }; cookie = engine->StartQueryCvarValue(pPlayer, name);
m_ConVarQueries.push_back(query);
} }
else if (m_bIsVSPQueryHooked)
{
cookie = serverpluginhelpers->StartQueryCvarValue(pPlayer, name);
}
else
{
return InvalidQueryCvarCookie;
}
ConVarQuery query = {cookie, pCallback, hndl};
m_ConVarQueries.push_back(query);
return cookie; return cookie;
} }
@ -559,7 +564,7 @@ void ConVarManager::AddConVarToPluginList(IPluginContext *pContext, const ConVar
bool inserted = false; bool inserted = false;
const char *orig = pConVar->GetName(); const char *orig = pConVar->GetName();
IPlugin *plugin = scripts->FindPluginByContext(pContext->GetContext()); IPlugin *plugin = g_PluginSys.FindPluginByContext(pContext->GetContext());
/* Check plugin for an existing convar list */ /* Check plugin for an existing convar list */
if (!plugin->GetProperty("ConVarList", (void **)&pConVarList)) if (!plugin->GetProperty("ConVarList", (void **)&pConVarList))
@ -590,7 +595,11 @@ void ConVarManager::AddConVarToPluginList(IPluginContext *pContext, const ConVar
} }
} }
#if defined ORANGEBOX_BUILD
void ConVarManager::OnConVarChanged(ConVar *pConVar, const char *oldValue, float flOldValue) 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 the values are the same, exit early in order to not trigger callbacks */
if (strcmp(pConVar->GetString(), oldValue) == 0) if (strcmp(pConVar->GetString(), oldValue) == 0)
@ -610,14 +619,20 @@ void ConVarManager::OnConVarChanged(ConVar *pConVar, const char *oldValue, float
if (pInfo->changeListeners.size() != 0) if (pInfo->changeListeners.size() != 0)
{ {
for (auto i = pInfo->changeListeners.begin(); i != pInfo->changeListeners.end(); i++) for (List<IConVarChangeListener *>::iterator i = pInfo->changeListeners.begin();
i != pInfo->changeListeners.end();
i++)
{
#if defined ORANGEBOX_BUILD
(*i)->OnConVarChanged(pConVar, oldValue, flOldValue); (*i)->OnConVarChanged(pConVar, oldValue, flOldValue);
#else
(*i)->OnConVarChanged(pConVar, oldValue, atof(oldValue));
#endif
}
} }
if (pForward != NULL) if (pForward != NULL)
{ {
ConVarReentrancyGuard guard(pConVar);
/* Now call forwards in plugins that have hooked this */ /* Now call forwards in plugins that have hooked this */
pForward->PushCell(pInfo->handle); pForward->PushCell(pInfo->handle);
pForward->PushString(oldValue); pForward->PushString(oldValue);
@ -628,15 +643,10 @@ void ConVarManager::OnConVarChanged(ConVar *pConVar, const char *oldValue, float
bool ConVarManager::IsQueryingSupported() bool ConVarManager::IsQueryingSupported()
{ {
return sCoreProviderImpl.IsClientConVarQueryingSupported(); return (m_bIsDLLQueryHooked || m_bIsVSPQueryHooked);
} }
#if SOURCE_ENGINE != SE_DARKMESSIAH void ConVarManager::OnQueryCvarValueFinished(QueryCvarCookie_t cookie, edict_t *pPlayer, EQueryCvarValueStatus result, const char *cvarName, const char *cvarValue)
void ConVarManager::OnClientQueryFinished(QueryCvarCookie_t cookie,
int client,
EQueryCvarValueStatus result,
const char *cvarName,
const char *cvarValue)
{ {
IPluginFunction *pCallback = NULL; IPluginFunction *pCallback = NULL;
cell_t value = 0; cell_t value = 0;
@ -658,7 +668,7 @@ void ConVarManager::OnClientQueryFinished(QueryCvarCookie_t cookie,
cell_t ret; cell_t ret;
pCallback->PushCell(cookie); pCallback->PushCell(cookie);
pCallback->PushCell(client); pCallback->PushCell(engine->IndexOfEdict(pPlayer));
pCallback->PushCell(result); pCallback->PushCell(result);
pCallback->PushString(cvarName); pCallback->PushString(cvarName);
@ -677,14 +687,13 @@ void ConVarManager::OnClientQueryFinished(QueryCvarCookie_t cookie,
m_ConVarQueries.erase(iter); m_ConVarQueries.erase(iter);
} }
} }
#endif
HandleError ConVarManager::ReadConVarHandle(Handle_t hndl, ConVar **pVar) HandleError ConVarManager::ReadConVarHandle(Handle_t hndl, ConVar **pVar)
{ {
ConVarInfo *pInfo; ConVarInfo *pInfo;
HandleError error; HandleError error;
if ((error = handlesys->ReadHandle(hndl, m_ConVarType, NULL, (void **)&pInfo)) != HandleError_None) if ((error = g_HandleSys.ReadHandle(hndl, m_ConVarType, NULL, (void **)&pInfo)) != HandleError_None)
{ {
return error; return error;
} }

View File

@ -1,8 +1,8 @@
/** /**
* vim: set ts=4 sw=4 tw=99 noet : * vim: set ts=4 :
* ============================================================================= * =============================================================================
* SourceMod * SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
* ============================================================================= * =============================================================================
* *
* This program is free software; you can redistribute it and/or modify it under * This program is free software; you can redistribute it and/or modify it under
@ -39,11 +39,8 @@
#include <IForwardSys.h> #include <IForwardSys.h>
#include <IHandleSys.h> #include <IHandleSys.h>
#include <IRootConsoleMenu.h> #include <IRootConsoleMenu.h>
#include <IPlayerHelpers.h>
#include <compat_wrappers.h> #include <compat_wrappers.h>
#include "concmd_cleaner.h" #include "concmd_cleaner.h"
#include "PlayerManager.h"
#include <sm_stringhashmap.h>
using namespace SourceHook; using namespace SourceHook;
@ -63,15 +60,6 @@ struct ConVarInfo
IChangeableForward *pChangeForward; /**< Forward associated with convar */ IChangeableForward *pChangeForward; /**< Forward associated with convar */
ConVar *pVar; /**< The actual convar */ ConVar *pVar; /**< The actual convar */
List<IConVarChangeListener *> changeListeners; List<IConVarChangeListener *> changeListeners;
static inline bool matches(const char *name, const ConVarInfo *info)
{
return strcmp(name, info->pVar->GetName()) == 0;
}
static inline uint32_t hash(const detail::CharsAndLength &key)
{
return key.hash();
}
}; };
/** /**
@ -82,7 +70,6 @@ struct ConVarQuery
QueryCvarCookie_t cookie; /**< Cookie that identifies query */ QueryCvarCookie_t cookie; /**< Cookie that identifies query */
IPluginFunction *pCallback; /**< Function that will be called when query is finished */ IPluginFunction *pCallback; /**< Function that will be called when query is finished */
cell_t value; /**< Optional value passed to query function */ cell_t value; /**< Optional value passed to query function */
cell_t client; /**< Only used for cleaning up on client disconnection */
}; };
class ConVarManager : class ConVarManager :
@ -90,8 +77,7 @@ class ConVarManager :
public IHandleTypeDispatch, public IHandleTypeDispatch,
public IPluginsListener, public IPluginsListener,
public IRootConsoleCommand, public IRootConsoleCommand,
public IConCommandTracker, public IConCommandTracker
public IClientListener
{ {
public: public:
ConVarManager(); ConVarManager();
@ -100,17 +86,16 @@ public: // SMGlobalClass
void OnSourceModStartup(bool late); void OnSourceModStartup(bool late);
void OnSourceModAllInitialized(); void OnSourceModAllInitialized();
void OnSourceModShutdown(); void OnSourceModShutdown();
void OnSourceModVSPReceived();
public: // IHandleTypeDispatch public: // IHandleTypeDispatch
void OnHandleDestroy(HandleType_t type, void *object); void OnHandleDestroy(HandleType_t type, void *object);
bool GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize); bool GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize);
public: // IPluginsListener public: // IPluginsListener
void OnPluginUnloaded(IPlugin *plugin); void OnPluginUnloaded(IPlugin *plugin);
public: //IRootConsoleCommand public: //IRootConsoleCommand
void OnRootConsoleCommand(const char *cmdname, const ICommandArgs *command) override; void OnRootConsoleCommand(const char *cmdname, const CCommand &command);
public: //IConCommandTracker public: //IConCommandTracker
void OnUnlinkConCommandBase(ConCommandBase *pBase, const char *name) override; void OnUnlinkConCommandBase(ConCommandBase *pBase, const char *name, bool is_read_safe);
public: //IClientListener
void OnClientDisconnected(int client);
public: public:
/** /**
* Create a convar and return a handle to it. * Create a convar and return a handle to it.
@ -146,26 +131,32 @@ public:
HandleError ReadConVarHandle(Handle_t hndl, ConVar **pVar); HandleError ReadConVarHandle(Handle_t hndl, ConVar **pVar);
// Called via game hooks.
void OnConVarChanged(ConVar *pConVar, const char *oldValue, float flOldValue);
#if SOURCE_ENGINE != SE_DARKMESSIAH
void OnClientQueryFinished(
QueryCvarCookie_t cookie,
int client,
EQueryCvarValueStatus result,
const char *cvarName,
const char *cvarValue);
#endif
private: private:
/** /**
* Adds a convar to a plugin's list. * Adds a convar to a plugin's list.
*/ */
static void AddConVarToPluginList(IPluginContext *pContext, const ConVar *pConVar); 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: private:
HandleType_t m_ConVarType; HandleType_t m_ConVarType;
List<ConVarInfo *> m_ConVars; List<ConVarInfo *> m_ConVars;
List<ConVarQuery> m_ConVarQueries; List<ConVarQuery> m_ConVarQueries;
bool m_bIsDLLQueryHooked;
bool m_bIsVSPQueryHooked;
}; };
extern ConVarManager g_ConVarManager; extern ConVarManager g_ConVarManager;

View File

@ -1,409 +0,0 @@
/**
* vim: set ts=4 sw=4 tw=99 noet :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2009 AlliedModders LLC. All rights reserved.
* =============================================================================
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 3.0, as published by the
* Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
* As a special exception, AlliedModders LLC gives you permission to link the
* code of this program (as well as its derivative works) to "Half-Life 2," the
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
* by the Valve Corporation. You must obey the GNU General Public License in
* all respects for all other code used. Additionally, AlliedModders LLC grants
* this exception to all derivative works. AlliedModders LLC defines further
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
* or <http://www.sourcemod.net/license.php>.
*
* Version: $Id$
*/
/**
* On SourceHook v4.3 or lower, there are no DVP hooks. Very sad, right?
* Only do this on newer versions. For the older code, we'll do an incredibly
* hacky detour.
*
* The idea of the "non-hacky" (yeah... no) code is that every unique
* ConCommand vtable gets its own DVP hook. We watch for unloading and
* loading commands to remove stale hooks from SH.
*/
#include "sourcemod.h"
#include "sourcemm_api.h"
#include "Logger.h"
#include "compat_wrappers.h"
#include "ConsoleDetours.h"
#include <IGameConfigs.h>
#include "sm_stringutil.h"
#include "ConCmdManager.h"
#include "HalfLife2.h"
#include "ConCommandBaseIterator.h"
#include "logic_bridge.h"
#include "command_args.h"
#include "provider.h"
#include <am-utility.h>
#include <bridge/include/ILogger.h>
#if defined PLATFORM_POSIX
# include <dlfcn.h>
# include <sys/mman.h>
# include <stdint.h>
# include <unistd.h>
#endif
#if SOURCE_ENGINE >= SE_ORANGEBOX
SH_DECL_EXTERN1_void(ConCommand, Dispatch, SH_NOATTRIB, false, const CCommand &);
#else
SH_DECL_EXTERN0_void(ConCommand, Dispatch, SH_NOATTRIB, false);
#endif
class GenericCommandHooker : public IConCommandLinkListener
{
struct HackInfo
{
void **vtable;
int hook;
unsigned int refcount;
};
CVector<HackInfo> vtables;
bool enabled;
SourceHook::MemFuncInfo dispatch;
inline void **GetVirtualTable(ConCommandBase *pBase)
{
return *reinterpret_cast<void***>(reinterpret_cast<char*>(pBase) +
dispatch.thisptroffs +
dispatch.vtbloffs);
}
inline bool FindVtable(void **ptr, size_t& index)
{
for (size_t i = 0; i < vtables.size(); i++)
{
if (vtables[i].vtable == ptr)
{
index = i;
return true;
}
}
return false;
}
void MakeHookable(ConCommandBase *pBase)
{
if (!pBase->IsCommand())
return;
ConCommand *cmd = (ConCommand*)pBase;
void **vtable = GetVirtualTable(cmd);
size_t index;
if (!FindVtable(vtable, index))
{
HackInfo hack;
hack.vtable = vtable;
hack.hook = SH_ADD_VPHOOK(ConCommand, Dispatch, cmd, SH_MEMBER(this, &GenericCommandHooker::Dispatch), false);
hack.refcount = 1;
vtables.push_back(hack);
}
else
{
vtables[index].refcount++;
}
}
#if SOURCE_ENGINE >= SE_ORANGEBOX
void Dispatch(const CCommand& args)
#else
void Dispatch()
#endif
{
cell_t res = ConsoleDetours::Dispatch(META_IFACEPTR(ConCommand)
#if SOURCE_ENGINE >= SE_ORANGEBOX
, args
#endif
);
if (res >= Pl_Handled)
RETURN_META(MRES_SUPERCEDE);
}
void ReparseCommandList()
{
for (size_t i = 0; i < vtables.size(); i++)
vtables[i].refcount = 0;
for (ConCommandBaseIterator iter; iter.IsValid(); iter.Next())
MakeHookable(iter.Get());
CVector<HackInfo>::iterator iter = vtables.begin();
while (iter != vtables.end())
{
if ((*iter).refcount)
{
iter++;
continue;
}
/* Damn it. This event happens AFTER the plugin has unloaded!
* There's two options. Remove the hook now and hope SH's memory
* protection will prevent a crash. Otherwise, we can wait until
* the server shuts down and more likely crash then.
*
* This situation only arises if:
* 1) Someone has used AddCommandFilter()
* 2) ... on a Dark Messiah server (mm:s new api)
* 3) ... and another MM:S plugin that uses ConCommands has unloaded.
*
* Even though the impact is really small, we'll wait until the
* server shuts down, so normal operation isn't interrupted.
*
* See bug 4018.
*/
iter = vtables.erase(iter);
}
}
void UnhookCommand(ConCommandBase *pBase)
{
if (!pBase->IsCommand())
return;
ConCommand *cmd = (ConCommand*)pBase;
void **vtable = GetVirtualTable(cmd);
size_t index;
if (!FindVtable(vtable, index))
{
logger->LogError("Console detour tried to unhook command \"%s\" but it wasn't found", pBase->GetName());
return;
}
assert(vtables[index].refcount > 0);
vtables[index].refcount--;
if (vtables[index].refcount == 0)
{
SH_REMOVE_HOOK_ID(vtables[index].hook);
vtables.erase(vtables.iterAt(index));
}
}
public:
GenericCommandHooker() : enabled(false)
{
}
bool Enable()
{
SourceHook::GetFuncInfo(&ConCommand::Dispatch, dispatch);
if (dispatch.thisptroffs < 0)
{
logger->LogError("Command filter could not determine ConCommand layout");
return false;
}
for (ConCommandBaseIterator iter; iter.IsValid(); iter.Next())
MakeHookable(iter.Get());
if (!vtables.size())
{
logger->LogError("Command filter could not find any cvars!");
return false;
}
enabled = true;
return true;
}
void Disable()
{
for (size_t i = 0; i < vtables.size(); i++)
SH_REMOVE_HOOK_ID(vtables[i].hook);
vtables.clear();
}
virtual void OnLinkConCommand(ConCommandBase *pBase)
{
if (!enabled)
return;
MakeHookable(pBase);
}
virtual void OnUnlinkConCommand(ConCommandBase *pBase)
{
if (!enabled)
return;
if (pBase == NULL)
ReparseCommandList();
else
UnhookCommand(pBase);
}
};
/**
* BEGIN THE ACTUALLY GENERIC CODE.
*/
#define FEATURECAP_COMMANDLISTENER "command listener"
static GenericCommandHooker s_GenericHooker;
ConsoleDetours g_ConsoleDetours;
ConsoleDetours::ConsoleDetours() : status(FeatureStatus_Unknown)
{
}
void ConsoleDetours::OnSourceModAllInitialized()
{
m_pForward = forwardsys->CreateForwardEx("OnAnyCommand", ET_Hook, 3, NULL, Param_Cell,
Param_String, Param_Cell);
sharesys->AddCapabilityProvider(NULL, this, FEATURECAP_COMMANDLISTENER);
}
void ConsoleDetours::OnSourceModShutdown()
{
for (StringHashMap<IChangeableForward *>::iterator iter = m_Listeners.iter();
!iter.empty();
iter.next())
{
forwardsys->ReleaseForward(iter->value);
}
forwardsys->ReleaseForward(m_pForward);
s_GenericHooker.Disable();
}
FeatureStatus ConsoleDetours::GetFeatureStatus(FeatureType type, const char *name)
{
return GetStatus();
}
FeatureStatus ConsoleDetours::GetStatus()
{
if (status == FeatureStatus_Unknown)
{
status = s_GenericHooker.Enable() ? FeatureStatus_Available : FeatureStatus_Unavailable;
}
return status;
}
bool ConsoleDetours::AddListener(IPluginFunction *fun, const char *command)
{
if (GetStatus() != FeatureStatus_Available)
return false;
if (command == NULL)
{
m_pForward->AddFunction(fun);
}
else
{
ke::AutoPtr<char[]> str(UTIL_ToLowerCase(command));
IChangeableForward *forward;
if (!m_Listeners.retrieve(str.get(), &forward))
{
forward = forwardsys->CreateForwardEx(NULL, ET_Hook, 3, NULL, Param_Cell,
Param_String, Param_Cell);
m_Listeners.insert(str.get(), forward);
}
forward->AddFunction(fun);
}
return true;
}
bool ConsoleDetours::RemoveListener(IPluginFunction *fun, const char *command)
{
if (command == NULL)
{
return m_pForward->RemoveFunction(fun);
}
else
{
ke::AutoPtr<char[]> str(UTIL_ToLowerCase(command));
IChangeableForward *forward;
if (!m_Listeners.retrieve(str.get(), &forward))
return false;
return forward->RemoveFunction(fun);
}
}
cell_t ConsoleDetours::InternalDispatch(int client, const ICommandArgs *args)
{
char name[255];
const char *realname = args->Arg(0);
size_t len = strlen(realname);
// Disallow command strings that are too long, for now.
if (len >= sizeof(name) - 1)
return Pl_Continue;
for (size_t i = 0; i < len; i++)
{
if (realname[i] >= 'A' && realname[i] <= 'Z')
name[i] = tolower(realname[i]);
else
name[i] = realname[i];
}
name[len] = '\0';
cell_t result = Pl_Continue;
m_pForward->PushCell(client);
m_pForward->PushString(name);
m_pForward->PushCell(args->ArgC() - 1);
m_pForward->Execute(&result, NULL);
/* Don't let plugins block this. */
if (strcmp(name, "sm") == 0)
result = Pl_Continue;
if (result >= Pl_Handled)
return result;
IChangeableForward *forward;
if (!m_Listeners.retrieve(name, &forward))
return result;
if (forward->GetFunctionCount() == 0)
return result;
cell_t result2 = Pl_Continue;
forward->PushCell(client);
forward->PushString(name);
forward->PushCell(args->ArgC() - 1);
forward->Execute(&result2, NULL);
if (result2 > result)
result = result2;
/* "sm" should not have flown through the above. */
assert(strcmp(name, "sm") != 0 || result == Pl_Continue);
return result;
}
#if SOURCE_ENGINE >= SE_ORANGEBOX
cell_t ConsoleDetours::Dispatch(ConCommand *pBase, const CCommand& args)
{
#else
cell_t ConsoleDetours::Dispatch(ConCommand *pBase)
{
CCommand args;
#endif
EngineArgs cargs(args);
cell_t res;
{
AutoEnterCommand autoEnterCommand(&cargs);
res = g_ConsoleDetours.InternalDispatch(sCoreProviderImpl.CommandClient(), &cargs);
}
return res;
}

View File

@ -1,8 +1,8 @@
/** /**
* vim: set ts=4 sw=4 tw=99 noet : * vim: set ts=4 :
* ============================================================================= * =============================================================================
* SourceMod * SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
* ============================================================================= * =============================================================================
* *
* This program is free software; you can redistribute it and/or modify it under * This program is free software; you can redistribute it and/or modify it under
@ -33,189 +33,69 @@
#include "CoreConfig.h" #include "CoreConfig.h"
#include "sourcemod.h" #include "sourcemod.h"
#include "sourcemm_api.h" #include "sourcemm_api.h"
#include "sm_srvcmds.h"
#include "sm_version.h"
#include "sm_stringutil.h" #include "sm_stringutil.h"
#include "LibrarySys.h"
#include "Logger.h" #include "Logger.h"
#include "frame_hooks.h" #include "PluginSys.h"
#include "logic_bridge.h" #include "ForwardSys.h"
#include "compat_wrappers.h"
#include <sourcemod_version.h>
#include <amtl/os/am-path.h>
#include <amtl/os/am-fsutil.h>
#include <sh_list.h>
#include <IForwardSys.h>
#include <bridge/include/IScriptManager.h>
#include <bridge/include/ILogger.h>
using namespace SourceHook;
#ifdef PLATFORM_WINDOWS #ifdef PLATFORM_WINDOWS
ConVar sm_corecfgfile("sm_corecfgfile", "addons\\sourcemod\\configs\\core.cfg", 0, "SourceMod core configuration file"); ConVar sm_corecfgfile("sm_corecfgfile", "addons\\sourcemod\\configs\\core.cfg", 0, "SourceMod core configuration file");
#elif defined PLATFORM_LINUX || defined PLATFORM_APPLE #elif defined PLATFORM_LINUX
ConVar sm_corecfgfile("sm_corecfgfile", "addons/sourcemod/configs/core.cfg", 0, "SourceMod core configuration file"); ConVar sm_corecfgfile("sm_corecfgfile", "addons/sourcemod/configs/core.cfg", 0, "SourceMod core configuration file");
#endif #endif
IForward *g_pOnServerCfg = NULL; IForward *g_pOnServerCfg = NULL;
IForward *g_pOnConfigsExecuted = NULL; IForward *g_pOnConfigsExecuted = NULL;
IForward *g_pOnAutoConfigsBuffered = NULL;
CoreConfig g_CoreConfig; CoreConfig g_CoreConfig;
bool g_bConfigsExecd = false; 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 SOURCE_ENGINE >= SE_ORANGEBOX
SH_DECL_EXTERN1_void(ConCommand, Dispatch, SH_NOATTRIB, false, const CCommand &);
void Hook_ExecDispatchPre(const CCommand &cmd)
#else
SH_DECL_EXTERN0_void(ConCommand, Dispatch, SH_NOATTRIB, false);
void Hook_ExecDispatchPre()
#endif
{
#if SOURCE_ENGINE <= SE_DARKMESSIAH
CCommand cmd;
#endif
const char *arg = cmd.Arg(1);
if (!g_bServerExecd && arg != NULL && strcmp(arg, g_ServerCfgFile->GetString()) == 0)
{
g_bGotTrigger = true;
}
}
#if SOURCE_ENGINE >= SE_ORANGEBOX
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)
{
g_PendingInternalPush = true;
}
}
void CoreConfig::OnSourceModAllInitialized() void CoreConfig::OnSourceModAllInitialized()
{ {
rootmenu->AddRootConsoleCommand3("config", "Set core configuration options", this); g_RootMenu.AddRootConsoleCommand("config", "Set core configuration options", this);
g_pOnServerCfg = forwardsys->CreateForward("OnServerCfg", ET_Ignore, 0, NULL); g_pOnServerCfg = g_Forwards.CreateForward("OnServerCfg", ET_Ignore, 0, NULL);
g_pOnConfigsExecuted = forwardsys->CreateForward("OnConfigsExecuted", ET_Ignore, 0, NULL); g_pOnConfigsExecuted = g_Forwards.CreateForward("OnConfigsExecuted", ET_Ignore, 0, NULL);
g_pOnAutoConfigsBuffered = forwardsys->CreateForward("OnAutoConfigsBuffered", ET_Ignore, 0, NULL);
}
CoreConfig::CoreConfig()
{
}
CoreConfig::~CoreConfig()
{
} }
void CoreConfig::OnSourceModShutdown() void CoreConfig::OnSourceModShutdown()
{ {
rootmenu->RemoveRootConsoleCommand("config", this); g_RootMenu.RemoveRootConsoleCommand("config", this);
forwardsys->ReleaseForward(g_pOnServerCfg); g_Forwards.ReleaseForward(g_pOnServerCfg);
forwardsys->ReleaseForward(g_pOnConfigsExecuted); g_Forwards.ReleaseForward(g_pOnConfigsExecuted);
forwardsys->ReleaseForward(g_pOnAutoConfigsBuffered);
if (g_pExecPtr != NULL)
{
SH_REMOVE_HOOK(ConCommand, Dispatch, g_pExecPtr, SH_STATIC(Hook_ExecDispatchPre), false);
SH_REMOVE_HOOK(ConCommand, Dispatch, g_pExecPtr, SH_STATIC(Hook_ExecDispatchPost), true);
g_pExecPtr = NULL;
}
} }
void CoreConfig::OnSourceModLevelChange(const char *mapName) void CoreConfig::OnSourceModLevelChange(const char *mapName)
{ {
static bool already_checked = false;
if (!already_checked)
{
if (engine->IsDedicatedServer())
{
g_ServerCfgFile = icvar->FindVar("servercfgfile");
}
else
{
g_ServerCfgFile = icvar->FindVar("lservercfgfile");
}
if (g_ServerCfgFile != NULL)
{
g_pExecPtr = FindCommand("exec");
if (g_pExecPtr != NULL)
{
SH_ADD_HOOK(ConCommand, Dispatch, g_pExecPtr, SH_STATIC(Hook_ExecDispatchPre), false);
SH_ADD_HOOK(ConCommand, Dispatch, g_pExecPtr, SH_STATIC(Hook_ExecDispatchPost), true);
}
else
{
g_ServerCfgFile = NULL;
}
}
already_checked = true;
}
g_bConfigsExecd = false; g_bConfigsExecd = false;
g_bServerExecd = false;
g_bGotServerStart = false;
g_bGotTrigger = false;
} }
void CoreConfig::OnRootConsoleCommand(const char *cmdname, const ICommandArgs *command) void CoreConfig::OnRootConsoleCommand(const char *cmdname, const CCommand &command)
{ {
int argcount = command->ArgC(); int argcount = command.ArgC();
if (argcount >= 4) if (argcount >= 4)
{ {
const char *option = command->Arg(2); const char *option = command.Arg(2);
const char *value = command->Arg(3); const char *value = command.Arg(3);
char error[255]; char error[255];
ConfigResult res = SetConfigOption(option, value, ConfigSource_Console, error, sizeof(error)); ConfigResult res = SetConfigOption(option, value, ConfigSource_Console, error, sizeof(error));
if (res == ConfigResult_Reject) if (res == ConfigResult_Reject)
{ {
UTIL_ConsolePrint("[SM] Could not set config option \"%s\" to \"%s\". (%s)", option, value, error); g_RootMenu.ConsolePrint("[SM] Could not set config option \"%s\" to \"%s\" (%s)", option, value, error);
} else if (res == ConfigResult_Ignore) {
g_RootMenu.ConsolePrint("[SM] No such config option \"%s\" exists.", option);
} else { } else {
if (res == ConfigResult_Ignore) { g_RootMenu.ConsolePrint("Config option \"%s\" successfully set to \"%s.\"", option, value);
UTIL_ConsolePrint("[SM] WARNING: Config option \"%s\" is not registered.", option);
}
UTIL_ConsolePrint("[SM] Config option \"%s\" set to \"%s\".", option, value);
}
return;
} else if (argcount >= 3) {
const char *option = command->Arg(2);
const char *value = GetCoreConfigValue(option);
if (value == NULL)
{
UTIL_ConsolePrint("[SM] No such config option \"%s\" exists.", option);
} else {
UTIL_ConsolePrint("[SM] Config option \"%s\" is set to \"%s\".", option, value);
} }
return; return;
} }
UTIL_ConsolePrint("[SM] Usage: sm config <option> [value]"); g_RootMenu.ConsolePrint("[SM] Usage: sm config <option> <value>");
} }
void CoreConfig::Initialize() void CoreConfig::Initialize()
@ -226,38 +106,21 @@ void CoreConfig::Initialize()
/* Try to get command line value of core config convar */ /* Try to get command line value of core config convar */
const char *corecfg = icvar->GetCommandLineValue("sm_corecfgfile"); const char *corecfg = icvar->GetCommandLineValue("sm_corecfgfile");
/* If sm_corecfgfile is on the command line, use that /* If sm_corecfgfile not specified on command line, use default value */
* If sm_corecfgfile isn't there, check sm_basepath on the command line and build the path off that if (!corecfg)
* If sm_basepath isn't there, just use the default path for the cfg
*/
if (corecfg)
{ {
ke::path::Format(filePath, sizeof(filePath), "%s/%s", g_SourceMod.GetGamePath(), corecfg); corecfg = sm_corecfgfile.GetDefault();
} }
else
{
const char *basepath = icvar->GetCommandLineValue("sm_basepath");
/* Format path to config file */ /* Format path to config file */
if (basepath) g_LibSys.PathFormat(filePath, sizeof(filePath), "%s/%s", g_SourceMod.GetGamePath(), corecfg);
{
ke::path::Format(filePath, sizeof(filePath), "%s/%s/%s", g_SourceMod.GetGamePath(), basepath, "configs/core.cfg");
}
else
{
ke::path::Format(filePath, sizeof(filePath), "%s/%s", g_SourceMod.GetGamePath(), sm_corecfgfile.GetDefault());
}
}
/* Reset cached key values */
m_KeyValues.clear();
/* Parse config file */ /* Parse config file */
if ((err=textparsers->ParseFile_SMC(filePath, this, NULL)) != SMCError_Okay) if ((err=textparsers->ParseFile_SMC(filePath, this, NULL)) != SMCError_Okay)
{ {
/* :TODO: This won't actually log or print anything :( - So fix that somehow */ /* :TODO: This won't actually log or print anything :( - So fix that somehow */
const char *error = textparsers->GetSMCErrorString(err); const char *error = textparsers->GetSMCErrorString(err);
logger->LogFatal("[SM] Error encountered parsing core config file: %s", error ? error : ""); g_Logger.LogFatal("[SM] Error encountered parsing core config file: %s", error ? error : "");
} }
} }
@ -269,7 +132,7 @@ SMCResult CoreConfig::ReadSMC_KeyValue(const SMCStates *states, const char *key,
if (err == ConfigResult_Reject) if (err == ConfigResult_Reject)
{ {
/* This is a fatal error */ /* This is a fatal error */
logger->LogFatal("Config error (key: %s) (value: %s) %s", key, value, error); g_Logger.LogFatal("Config error (key: %s) (value: %s) %s", key, value, error);
} }
return SMCResult_Continue; return SMCResult_Continue;
@ -277,7 +140,7 @@ SMCResult CoreConfig::ReadSMC_KeyValue(const SMCStates *states, const char *key,
ConfigResult CoreConfig::SetConfigOption(const char *option, const char *value, ConfigSource source, char *error, size_t maxlength) ConfigResult CoreConfig::SetConfigOption(const char *option, const char *value, ConfigSource source, char *error, size_t maxlength)
{ {
ConfigResult result = ConfigResult_Ignore; ConfigResult result;
/* Notify! */ /* Notify! */
SMGlobalClass *pBase = SMGlobalClass::head; SMGlobalClass *pBase = SMGlobalClass::head;
@ -285,23 +148,12 @@ ConfigResult CoreConfig::SetConfigOption(const char *option, const char *value,
{ {
if ((result = pBase->OnSourceModConfigChanged(option, value, source, error, maxlength)) != ConfigResult_Ignore) if ((result = pBase->OnSourceModConfigChanged(option, value, source, error, maxlength)) != ConfigResult_Ignore)
{ {
break; return result;
} }
pBase = pBase->m_pGlobalClassNext; pBase = pBase->m_pGlobalClassNext;
} }
ke::AString vstr(value); return ConfigResult_Ignore;
m_KeyValues.replace(option, ke::Move(vstr));
return result;
}
const char *CoreConfig::GetCoreConfigValue(const char *key)
{
StringHashMap<ke::AString>::Result r = m_KeyValues.find(key);
if (!r.found())
return NULL;
return r->value.chars();
} }
bool SM_AreConfigsExecuted() bool SM_AreConfigsExecuted()
@ -313,12 +165,12 @@ inline bool IsPathSepChar(char c)
{ {
#if defined PLATFORM_WINDOWS #if defined PLATFORM_WINDOWS
return (c == '\\' || c == '/'); return (c == '\\' || c == '/');
#elif defined PLATFORM_LINUX || defined PLATFORM_POSIX #elif defined PLATFORM_LINUX
return (c == '/'); return (c == '/');
#endif #endif
} }
bool SM_ExecuteConfig(IPlugin *pl, AutoConfig *cfg, bool can_create) bool SM_ExecuteConfig(CPlugin *pl, AutoConfig *cfg, bool can_create)
{ {
bool will_create = false; bool will_create = false;
@ -336,12 +188,12 @@ bool SM_ExecuteConfig(IPlugin *pl, AutoConfig *cfg, bool can_create)
g_SourceMod.BuildPath(Path_Game, path, sizeof(path), "cfg/%s", folder); g_SourceMod.BuildPath(Path_Game, path, sizeof(path), "cfg/%s", folder);
if (!ke::file::IsDirectory(path)) if (!g_LibSys.IsPathDirectory(path))
{ {
char *cur_ptr = path; char *cur_ptr = path;
size_t len; size_t len;
ke::path::Format(path, sizeof(path), "%s", folder); g_LibSys.PathFormat(path, sizeof(path), "%s", folder);
len = g_SourceMod.BuildPath(Path_Game, build, sizeof(build), "cfg"); len = g_SourceMod.BuildPath(Path_Game, build, sizeof(build), "cfg");
do do
@ -362,12 +214,14 @@ bool SM_ExecuteConfig(IPlugin *pl, AutoConfig *cfg, bool can_create)
{ {
next_ptr = NULL; next_ptr = NULL;
} }
len += ke::path::Format(&build[len], len += g_LibSys.PathFormat(&build[len],
sizeof(build)-len, sizeof(build)-len,
"/%s", "/%s",
cur_ptr); cur_ptr);
if (!ke::file::CreateDirectory(build)) if (!g_LibSys.CreateFolder(build))
{
break; break;
}
cur_ptr = next_ptr; cur_ptr = next_ptr;
} while (cur_ptr); } while (cur_ptr);
} }
@ -379,13 +233,13 @@ bool SM_ExecuteConfig(IPlugin *pl, AutoConfig *cfg, bool can_create)
if (cfg->folder.size()) if (cfg->folder.size())
{ {
ke::path::Format(local, g_LibSys.PathFormat(local,
sizeof(local), sizeof(local),
"%s/%s.cfg", "%s/%s.cfg",
cfg->folder.c_str(), cfg->folder.c_str(),
cfg->autocfg.c_str()); cfg->autocfg.c_str());
} else { } else {
ke::path::Format(local, g_LibSys.PathFormat(local,
sizeof(local), sizeof(local),
"%s.cfg", "%s.cfg",
cfg->autocfg.c_str()); cfg->autocfg.c_str());
@ -393,7 +247,7 @@ bool SM_ExecuteConfig(IPlugin *pl, AutoConfig *cfg, bool can_create)
g_SourceMod.BuildPath(Path_Game, file, sizeof(file), "cfg/%s", local); g_SourceMod.BuildPath(Path_Game, file, sizeof(file), "cfg/%s", local);
bool file_exists = ke::file::IsFile(file); bool file_exists = g_LibSys.IsPathFile(file);
if (!file_exists && will_create) if (!file_exists && will_create)
{ {
List<const ConVar *> *convars = NULL; List<const ConVar *> *convars = NULL;
@ -403,7 +257,7 @@ bool SM_ExecuteConfig(IPlugin *pl, AutoConfig *cfg, bool can_create)
FILE *fp = fopen(file, "wt"); FILE *fp = fopen(file, "wt");
if (fp) if (fp)
{ {
fprintf(fp, "// This file was auto-generated by SourceMod (v%s)\n", SOURCEMOD_VERSION); fprintf(fp, "// This file was auto-generated by SourceMod (v%s)\n", SVN_FULL_VERSION);
fprintf(fp, "// ConVars for plugin \"%s\"\n", pl->GetFilename()); fprintf(fp, "// ConVars for plugin \"%s\"\n", pl->GetFilename());
fprintf(fp, "\n\n"); fprintf(fp, "\n\n");
@ -412,11 +266,8 @@ bool SM_ExecuteConfig(IPlugin *pl, AutoConfig *cfg, bool can_create)
for (iter = convars->begin(); iter != convars->end(); iter++) for (iter = convars->begin(); iter != convars->end(); iter++)
{ {
const ConVar *cvar = (*iter); const ConVar *cvar = (*iter);
#if SOURCE_ENGINE >= SE_ORANGEBOX
if (cvar->IsFlagSet(FCVAR_DONTRECORD)) if ((cvar->GetFlags() & FCVAR_DONTRECORD) == FCVAR_DONTRECORD)
#else
if (cvar->IsBitSet(FCVAR_DONTRECORD))
#endif
{ {
continue; continue;
} }
@ -425,7 +276,7 @@ bool SM_ExecuteConfig(IPlugin *pl, AutoConfig *cfg, bool can_create)
char *dptr = descr; char *dptr = descr;
/* Print comments until there is no more */ /* Print comments until there is no more */
ke::SafeStrcpy(descr, sizeof(descr), cvar->GetHelpText()); strncopy(descr, cvar->GetHelpText(), sizeof(descr));
while (*dptr != '\0') while (*dptr != '\0')
{ {
/* Find the next line */ /* Find the next line */
@ -463,18 +314,13 @@ bool SM_ExecuteConfig(IPlugin *pl, AutoConfig *cfg, bool can_create)
can_create = false; can_create = false;
fclose(fp); fclose(fp);
} }
else
{
logger->LogError("Failed to auto generate config for %s, make sure the directory has write permission.", pl->GetFilename());
return can_create;
}
} }
} }
if (file_exists) if (file_exists)
{ {
char cmd[255]; char cmd[255];
ke::SafeSprintf(cmd, sizeof(cmd), "exec %s\n", local); UTIL_Format(cmd, sizeof(cmd), "exec %s\n", local);
engine->ServerCommand(cmd); engine->ServerCommand(cmd);
} }
@ -498,10 +344,10 @@ void SM_DoSingleExecFwds(IPluginContext *ctx)
void SM_ConfigsExecuted_Plugin(unsigned int serial) void SM_ConfigsExecuted_Plugin(unsigned int serial)
{ {
IPluginIterator *iter = scripts->GetPluginIterator(); IPluginIterator *iter = g_PluginSys.GetPluginIterator();
while (iter->MorePlugins()) while (iter->MorePlugins())
{ {
IPlugin *plugin = iter->GetPlugin(); CPlugin *plugin = (CPlugin *)(iter->GetPlugin());
if (plugin->GetSerial() == serial) if (plugin->GetSerial() == serial)
{ {
SM_DoSingleExecFwds(plugin->GetBaseContext()); SM_DoSingleExecFwds(plugin->GetBaseContext());
@ -514,7 +360,7 @@ void SM_ConfigsExecuted_Plugin(unsigned int serial)
void SM_ExecuteForPlugin(IPluginContext *ctx) void SM_ExecuteForPlugin(IPluginContext *ctx)
{ {
SMPlugin *plugin = scripts->FindPluginByContext(ctx->GetContext()); CPlugin *plugin = (CPlugin *)g_PluginSys.GetPluginByCtx(ctx->GetContext());
unsigned int num = plugin->GetConfigCount(); unsigned int num = plugin->GetConfigCount();
if (!num) if (!num)
@ -529,34 +375,35 @@ void SM_ExecuteForPlugin(IPluginContext *ctx)
can_create = SM_ExecuteConfig(plugin, plugin->GetConfig(i), can_create); can_create = SM_ExecuteConfig(plugin, plugin->GetConfig(i), can_create);
} }
char cmd[255]; char cmd[255];
ke::SafeSprintf(cmd, sizeof(cmd), "sm_internal 2 %d\n", plugin->GetSerial()); UTIL_Format(cmd, sizeof(cmd), "sm internal 2 %d\n", plugin->GetSerial());
engine->ServerCommand(cmd); engine->ServerCommand(cmd);
} }
} }
void SM_ExecuteAllConfigs() void SM_ExecuteAllConfigs()
{ {
if (g_bGotServerStart) if (g_bConfigsExecd)
{ {
return; return;
} }
engine->ServerCommand("exec sourcemod/sourcemod.cfg\n"); engine->ServerCommand("exec sourcemod/sourcemod.cfg\n");
AutoPluginList plugins(scripts); IPluginIterator *iter = g_PluginSys.GetPluginIterator();
for (size_t i = 0; i < plugins->size(); i++) while (iter->MorePlugins())
{ {
SMPlugin *plugin = plugins->at(i); CPlugin *plugin = (CPlugin *)(iter->GetPlugin());
unsigned int num = plugin->GetConfigCount(); unsigned int num = plugin->GetConfigCount();
bool can_create = true; bool can_create = true;
for (unsigned int i=0; i<num; i++) for (unsigned int i=0; i<num; i++)
{ {
can_create = SM_ExecuteConfig(plugin, plugin->GetConfig(i), can_create); can_create = SM_ExecuteConfig(plugin, plugin->GetConfig(i), can_create);
} }
iter->NextPlugin();
} }
iter->Release();
g_bGotServerStart = true; engine->ServerCommand("sm internal 1\n");
CheckAndFinalizeConfigs();
} }
void SM_ConfigsExecuted_Global() void SM_ConfigsExecuted_Global()
@ -571,29 +418,3 @@ void SM_ConfigsExecuted_Global()
g_pOnServerCfg->Execute(NULL); g_pOnServerCfg->Execute(NULL);
g_pOnConfigsExecuted->Execute(NULL); g_pOnConfigsExecuted->Execute(NULL);
} }
void SM_InternalCmdTrigger()
{
/* 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");
g_PendingInternalPush = false;
}
CON_COMMAND(sm_internal, "")
{
#if SOURCE_ENGINE <= SE_DARKMESSIAH
CCommand args;
#endif
if (args.ArgC() < 1)
return;
const char *arg = args.Arg(1);
if (strcmp(arg, "1") == 0) {
SM_ConfigsExecuted_Global();
} else if (strcmp(arg, "2") == 0) {
if (args.ArgC() >= 3)
SM_ConfigsExecuted_Plugin(atoi(args.Arg(2)));
}
}

View File

@ -1,8 +1,8 @@
/** /**
* vim: set ts=4 sw=4 tw=99 noet : * vim: set ts=4 :
* ============================================================================= * =============================================================================
* SourceMod * SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
* ============================================================================= * =============================================================================
* *
* This program is free software; you can redistribute it and/or modify it under * This program is free software; you can redistribute it and/or modify it under
@ -35,8 +35,6 @@
#include "sm_globals.h" #include "sm_globals.h"
#include <ITextParsers.h> #include <ITextParsers.h>
#include <IRootConsoleMenu.h> #include <IRootConsoleMenu.h>
#include <am-string.h>
#include <sm_stringhashmap.h>
using namespace SourceMod; using namespace SourceMod;
@ -45,9 +43,6 @@ class CoreConfig :
public ITextListener_SMC, public ITextListener_SMC,
public IRootConsoleCommand public IRootConsoleCommand
{ {
public:
CoreConfig();
~CoreConfig();
public: // SMGlobalClass public: // SMGlobalClass
void OnSourceModAllInitialized(); void OnSourceModAllInitialized();
void OnSourceModShutdown(); void OnSourceModShutdown();
@ -55,20 +50,17 @@ public: // SMGlobalClass
public: // ITextListener_SMC public: // ITextListener_SMC
SMCResult ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value); SMCResult ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value);
public: // IRootConsoleCommand public: // IRootConsoleCommand
void OnRootConsoleCommand(const char *cmdname, const ICommandArgs *command) override; void OnRootConsoleCommand(const char *cmdname, const CCommand &command);
public: public:
/** /**
* Initializes CoreConfig by reading from core.cfg file * Initializes CoreConfig by reading from core.cfg file
*/ */
void Initialize(); void Initialize();
const char *GetCoreConfigValue(const char *key);
private: private:
/** /**
* Sets configuration option by notifying SourceMod components that rely on core.cfg * 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); ConfigResult SetConfigOption(const char *option, const char *value, ConfigSource, char *Error, size_t maxlength);
private:
StringHashMap<ke::AString> m_KeyValues;
}; };
extern bool SM_AreConfigsExecuted(); extern bool SM_AreConfigsExecuted();
@ -76,7 +68,6 @@ extern void SM_ExecuteAllConfigs();
extern void SM_ExecuteForPlugin(IPluginContext *ctx); extern void SM_ExecuteForPlugin(IPluginContext *ctx);
extern void SM_ConfigsExecuted_Global(); extern void SM_ConfigsExecuted_Global();
extern void SM_ConfigsExecuted_Plugin(unsigned int serial); extern void SM_ConfigsExecuted_Plugin(unsigned int serial);
extern void SM_InternalCmdTrigger();
extern CoreConfig g_CoreConfig; extern CoreConfig g_CoreConfig;

145
core/CrazyDebugger.cpp Normal file
View File

@ -0,0 +1,145 @@
/**
* vim: set ts=4 :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2007 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$
*/
#if 0
#include "sm_globals.h"
#include "sourcemm_api.h"
#include "Tlhelp32.h"
#include "LibrarySys.h"
#include "minidump.h"
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);
}
class CrazyWindowsDebugger : public SMGlobalClass
{
public:
void OnSourceModAllInitialized()
{
HANDLE hModuleList = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetCurrentProcessId());
MODULEENTRY32 me32;
me32.dwSize = sizeof(MODULEENTRY32);
if (!Module32First(hModuleList, &me32))
{
Error("Could not initialize crazy debugger!");
}
bool found = false;
do
{
if (strcasecmp(me32.szModule, "steam.dll") == 0)
{
IMAGE_DOS_HEADER *dos = (IMAGE_DOS_HEADER *)me32.modBaseAddr;
if (dos->e_magic != IMAGE_DOS_SIGNATURE)
{
Error("[SM] Could not detect steam.dll with valid DOS signature");
}
char *base = (char *)dos;
IMAGE_NT_HEADERS *nt = (IMAGE_NT_HEADERS *)(base + dos->e_lfanew);
if (nt->Signature != IMAGE_NT_SIGNATURE)
{
Error("[SM] Could not detect steam.dll with valid NT signature");
}
IMAGE_IMPORT_DESCRIPTOR *desc =
(IMAGE_IMPORT_DESCRIPTOR *)
(base + nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
if (base == (char *)desc)
{
Error("[SM] Could not find the steam.dll IAT");
}
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, "GetProcAddress") == 0)
{
DWORD oldprot, oldprot2;
VirtualProtect(iat, 4, PAGE_READWRITE, &oldprot);
*iat = (DWORD)GetProcAddress2;
VirtualProtect(iat, 4, oldprot, &oldprot2);
found = true;
goto _end;
}
}
data++;
iat++;
}
}
desc++;
}
break;
}
} while (Module32Next(hModuleList, &me32));
_end:
if (!found)
{
Error("Could not find steam.dll's GetProcAddress IAT entry");
}
CloseHandle(hModuleList);
}
} s_CrazyDebugger;
#endif

View File

@ -1,8 +1,8 @@
/** /**
* vim: set ts=4 sw=4 tw=99 noet : * vim: set ts=4 :
* ============================================================================= * =============================================================================
* SourceMod * SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
* ============================================================================= * =============================================================================
* *
* This program is free software; you can redistribute it and/or modify it under * This program is free software; you can redistribute it and/or modify it under
@ -30,14 +30,14 @@
*/ */
#include "Database.h" #include "Database.h"
#include "ISourceMod.h"
#include "HandleSys.h" #include "HandleSys.h"
#include "ShareSys.h"
#include "sourcemod.h"
#include "sm_stringutil.h"
#include "Logger.h"
#include "ExtensionSys.h" #include "ExtensionSys.h"
#include "PluginSys.h"
#include <stdlib.h> #include <stdlib.h>
#include <IThreader.h> #include "ThreadSupport.h"
#include <bridge/include/ILogger.h>
#include <bridge/include/CoreProvider.h>
#define DBPARSE_LEVEL_NONE 0 #define DBPARSE_LEVEL_NONE 0
#define DBPARSE_LEVEL_MAIN 1 #define DBPARSE_LEVEL_MAIN 1
@ -47,16 +47,10 @@ DBManager g_DBMan;
static bool s_OneTimeThreaderErrorMsg = false; static bool s_OneTimeThreaderErrorMsg = false;
DBManager::DBManager() DBManager::DBManager()
: m_Terminate(false), : m_StrTab(512), m_ParseLevel(0), m_ParseState(0), m_pDefault(NULL)
m_pDefault(NULL)
{ {
} }
static void FrameHook(bool simulating)
{
g_DBMan.RunFrame();
}
void DBManager::OnSourceModAllInitialized() void DBManager::OnSourceModAllInitialized()
{ {
HandleAccess sec; HandleAccess sec;
@ -70,30 +64,44 @@ void DBManager::OnSourceModAllInitialized()
g_ShareSys.AddInterface(NULL, this); g_ShareSys.AddInterface(NULL, this);
g_pSM->BuildPath(Path_SM, m_Filename, sizeof(m_Filename), "configs/databases.cfg"); g_SourceMod.BuildPath(Path_SM, m_Filename, sizeof(m_Filename), "configs/databases.cfg");
m_Builder.SetPath(m_Filename);
m_pConfigLock = g_pThreader->MakeMutex();
m_pThinkLock = g_pThreader->MakeMutex();
m_pQueueLock = g_pThreader->MakeMutex();
g_PluginSys.AddPluginsListener(this); g_PluginSys.AddPluginsListener(this);
g_pSM->AddGameFrameHook(&FrameHook);
auto sm_reload_databases = [this] (int client, const ICommandArgs *args) -> bool {
m_Builder.StartParse();
return true;
};
bridge->DefineCommand("sm_reload_databases", "Reparse database configurations file", sm_reload_databases);
} }
void DBManager::OnSourceModLevelChange(const char *mapName) void DBManager::OnSourceModLevelChange(const char *mapName)
{ {
m_Builder.StartParse(); 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() void DBManager::OnSourceModShutdown()
{ {
g_pSM->RemoveGameFrameHook(&FrameHook);
KillWorkerThread(); KillWorkerThread();
g_PluginSys.RemovePluginsListener(this); g_PluginSys.RemovePluginsListener(this);
m_pConfigLock->DestroyThis();
m_pThinkLock->DestroyThis();
m_pQueueLock->DestroyThis();
g_HandleSys.RemoveType(m_DatabaseType, g_pCoreIdent); g_HandleSys.RemoveType(m_DatabaseType, g_pCoreIdent);
g_HandleSys.RemoveType(m_DriverType, g_pCoreIdent); g_HandleSys.RemoveType(m_DriverType, g_pCoreIdent);
} }
@ -123,10 +131,128 @@ void DBManager::OnHandleDestroy(HandleType_t type, void *object)
} }
} }
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) bool DBManager::Connect(const char *name, IDBDriver **pdr, IDatabase **pdb, bool persistent, char *error, size_t maxlength)
{ {
ConfDbInfoList *list = m_Builder.GetConfigList(); ConfDbInfo *pInfo = GetDatabaseConf(name);
ke::RefPtr<ConfDbInfo> pInfo = list->GetDatabaseConf(name);
if (!pInfo) if (!pInfo)
{ {
@ -135,7 +261,7 @@ bool DBManager::Connect(const char *name, IDBDriver **pdr, IDatabase **pdb, bool
*pdr = NULL; *pdr = NULL;
} }
*pdb = NULL; *pdb = NULL;
g_pSM->Format(error, maxlength, "Configuration \"%s\" not found", name); UTIL_Format(error, maxlength, "Configuration \"%s\" not found", name);
return false; return false;
} }
@ -145,12 +271,11 @@ bool DBManager::Connect(const char *name, IDBDriver **pdr, IDatabase **pdb, bool
/* Try to assign a real driver pointer */ /* Try to assign a real driver pointer */
if (pInfo->info.driver[0] == '\0') if (pInfo->info.driver[0] == '\0')
{ {
ke::AString defaultDriver = list->GetDefaultDriver(); if (!m_pDefault && m_DefDriver.size() > 0)
if (!m_pDefault && defaultDriver.length() > 0)
{ {
m_pDefault = FindOrLoadDriver(defaultDriver.chars()); m_pDefault = FindOrLoadDriver(m_DefDriver.c_str());
} }
dname = defaultDriver.length() ? defaultDriver.chars() : "default"; dname = m_DefDriver.size() ? m_DefDriver.c_str() : "default";
pInfo->realDriver = m_pDefault; pInfo->realDriver = m_pDefault;
} else { } else {
pInfo->realDriver = FindOrLoadDriver(pInfo->info.driver); pInfo->realDriver = FindOrLoadDriver(pInfo->info.driver);
@ -173,7 +298,8 @@ bool DBManager::Connect(const char *name, IDBDriver **pdr, IDatabase **pdb, bool
} }
*pdb = NULL; *pdb = NULL;
g_pSM->Format(error, maxlength, "Driver \"%s\" not found", dname); UTIL_Format(error, maxlength, "Driver \"%s\" not found", dname);
return false; return false;
} }
@ -206,23 +332,17 @@ void DBManager::RemoveDriver(IDBDriver *pDriver)
} }
} }
ConfDbInfoList *list = m_Builder.GetConfigList(); /* Make sure NOTHING references this! */
for (size_t i = 0; i < list->length(); i++) List<ConfDbInfo>::iterator iter;
for (iter=m_confs.begin(); iter!=m_confs.end(); iter++)
{ {
ke::RefPtr<ConfDbInfo> current = list->at(i); ConfDbInfo &db = (*iter);
if (current->realDriver == pDriver) if (db.realDriver == pDriver)
{ {
current->realDriver = NULL; db.realDriver = NULL;
} }
} }
/* Someone unloaded the default driver? Silly.. */
if (pDriver == m_pDefault)
{
m_pDefault = NULL;
}
/* Now that the driver is gone, we have to test the think queue. /* Now that the driver is gone, we have to test the think queue.
* Whatever happens therein is up to the db op! * Whatever happens therein is up to the db op!
*/ */
@ -252,11 +372,9 @@ void DBManager::RemoveDriver(IDBDriver *pDriver)
IDBDriver *DBManager::GetDefaultDriver() IDBDriver *DBManager::GetDefaultDriver()
{ {
ConfDbInfoList *list = m_Builder.GetConfigList(); if (!m_pDefault && m_DefDriver.size() > 0)
ke::AString defaultDriver = list->GetDefaultDriver();
if (!m_pDefault && defaultDriver.length() > 0)
{ {
m_pDefault = FindOrLoadDriver(defaultDriver.chars()); m_pDefault = FindOrLoadDriver(m_DefDriver.c_str());
} }
return m_pDefault; return m_pDefault;
@ -319,26 +437,29 @@ IDBDriver *DBManager::GetDriver(unsigned int index)
const DatabaseInfo *DBManager::FindDatabaseConf(const char *name) const DatabaseInfo *DBManager::FindDatabaseConf(const char *name)
{ {
ConfDbInfoList *list = m_Builder.GetConfigList(); ConfDbInfo *info = GetDatabaseConf(name);
ke::RefPtr<ConfDbInfo> info = list->GetDatabaseConf(name);
if (!info)
{
// couldn't find requested conf, return default if exists
info = list->GetDefaultConfiguration();
if (!info) if (!info)
{ {
return NULL; return NULL;
} }
}
return &info->info; return &info->info;
} }
ConfDbInfo *DBManager::GetDatabaseConf(const char *name) ConfDbInfo *DBManager::GetDatabaseConf(const char *name)
{ {
ConfDbInfoList *list = m_Builder.GetConfigList(); List<ConfDbInfo>::iterator iter;
ke::RefPtr<ConfDbInfo> info(list->GetDatabaseConf(name));
return info; 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) IDBDriver *DBManager::FindOrLoadDriver(const char *name)
@ -353,7 +474,7 @@ IDBDriver *DBManager::FindOrLoadDriver(const char *name)
} }
char filename[PLATFORM_MAX_PATH]; char filename[PLATFORM_MAX_PATH];
g_pSM->Format(filename, sizeof(filename), "dbi.%s.ext", name); UTIL_Format(filename, sizeof(filename), "dbi.%s.ext", name);
IExtension *pExt = g_Extensions.LoadAutoExtension(filename); IExtension *pExt = g_Extensions.LoadAutoExtension(filename);
if (!pExt || !pExt->IsLoaded() || m_drivers.size() <= last_size) if (!pExt || !pExt->IsLoaded() || m_drivers.size() <= last_size)
@ -374,17 +495,12 @@ IDBDriver *DBManager::FindOrLoadDriver(const char *name)
void DBManager::KillWorkerThread() void DBManager::KillWorkerThread()
{ {
if (m_Worker) if (m_pWorker)
{ {
{ m_pWorker->Stop(false);
ke::AutoLock lock(&m_QueueEvent); g_pThreader->DestroyWorker(m_pWorker);
m_Terminate = true; m_pWorker = NULL;
m_QueueEvent.Notify();
}
m_Worker->Join();
m_Worker = nullptr;
s_OneTimeThreaderErrorMsg = false; s_OneTimeThreaderErrorMsg = false;
m_Terminate = false;
} }
} }
@ -397,108 +513,99 @@ bool DBManager::AddToThreadQueue(IDBThreadOperation *op, PrioQueueLevel prio)
return false; return false;
} }
if (!m_Worker) if (!m_pWorker)
{ {
m_Worker = new ke::Thread([this]() -> void { m_pWorker = g_pThreader->MakeWorker(this, true);
Run(); if (!m_pWorker)
}, "SM SQL Worker");
if (!m_Worker->Succeeded())
{ {
if (!s_OneTimeThreaderErrorMsg) if (!s_OneTimeThreaderErrorMsg)
{ {
logger->LogError("[SM] Unable to create db threader (error unknown)"); g_Logger.LogError("[SM] Unable to create db threader (error unknown)");
s_OneTimeThreaderErrorMsg = true; s_OneTimeThreaderErrorMsg = true;
} }
m_Worker = nullptr; 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; return false;
} }
} }
/* Add to the queue */ /* Add to the queue */
{ {
ke::AutoLock lock(&m_QueueEvent); m_pQueueLock->Lock();
Queue<IDBThreadOperation *> &queue = m_OpQueue.GetQueue(prio); Queue<IDBThreadOperation *> &queue = m_OpQueue.GetQueue(prio);
queue.push(op); queue.push(op);
m_QueueEvent.Notify(); m_pQueueLock->Unlock();
} }
/* Make the thread */
m_pWorker->MakeThread(this);
return true; return true;
} }
void DBManager::Run() void DBManager::OnWorkerStart(IThreadWorker *pWorker)
{ {
// Initialize DB threadsafety. m_drSafety.clear();
for (size_t i=0; i<m_drivers.size(); i++) for (size_t i=0; i<m_drivers.size(); i++)
{ {
if (m_drivers[i]->IsThreadSafe()) if (m_drivers[i]->IsThreadSafe())
{
m_drSafety.push_back(m_drivers[i]->InitializeThreadSafety()); m_drSafety.push_back(m_drivers[i]->InitializeThreadSafety());
else } else {
m_drSafety.push_back(false); m_drSafety.push_back(false);
} }
}
}
// Run actual worker thread logic. void DBManager::OnWorkerStop(IThreadWorker *pWorker)
ThreadMain(); {
// Shutdown DB threadsafety.
for (size_t i=0; i<m_drivers.size(); i++) for (size_t i=0; i<m_drivers.size(); i++)
{ {
if (m_drSafety[i]) if (m_drSafety[i])
{
m_drivers[i]->ShutdownThreadSafety(); m_drivers[i]->ShutdownThreadSafety();
} }
}
m_drSafety.clear(); m_drSafety.clear();
} }
void DBManager::ThreadMain() void DBManager::RunThread(IThreadHandle *pThread)
{ {
ke::AutoLock lock(&m_QueueEvent); IDBThreadOperation *op = NULL;
while (true) { /* Get something from the queue */
// The lock has been acquired. Grab everything we can out of the
// queue. Since we want to flush the queue even if we're terminated,
// we process all operations we can before checking to terminate.
// There's no risk of starvation since the main thread blocks on us
// terminating.
while (true)
{ {
m_pQueueLock->Lock();
Queue<IDBThreadOperation *> &queue = m_OpQueue.GetLikelyQueue(); Queue<IDBThreadOperation *> &queue = m_OpQueue.GetLikelyQueue();
if (queue.empty()) if (!queue.empty())
break;
IDBThreadOperation *op = queue.first();
queue.pop();
// Unlock the queue when we run the query, so the main thread can
// keep pumping events. We re-acquire the lock to check for more
// items. It's okay if we terminate while unlocked; the main
// thread would be blocked and we'd need to flush the queue
// anyway, so after we've depleted the queue here, we'll just
// reach the terminate at the top of the loop.
{ {
ke::AutoUnlock unlock(&m_QueueEvent); op = queue.first();
queue.pop();
}
m_pQueueLock->Unlock();
}
/* whoa. hi. did we get something? we should have. */
if (!op)
{
/* wtf? */
return;
}
op->RunThreadPart(); op->RunThreadPart();
ke::AutoLock lock(&m_ThinkLock); m_pThinkLock->Lock();
m_ThinkQueue.push(op); m_ThinkQueue.push(op);
} m_pThinkLock->Unlock();
if (!m_Terminate)
{
ke::AutoUnlock unlock(&m_QueueEvent);
#ifdef _WIN32
Sleep(20);
#else
usleep(20000);
#endif
}
}
if (m_Terminate)
return;
// Release the lock and wait for a signal.
m_QueueEvent.Wait();
}
} }
void DBManager::RunFrame() void DBManager::RunFrame()
@ -510,16 +617,19 @@ void DBManager::RunFrame()
} }
/* Dump one thing per-frame so the server stays sane. */ /* Dump one thing per-frame so the server stays sane. */
IDBThreadOperation *op; m_pThinkLock->Lock();
{ IDBThreadOperation *op = m_ThinkQueue.first();
ke::AutoLock lock(&m_ThinkLock);
op = m_ThinkQueue.first();
m_ThinkQueue.pop(); m_ThinkQueue.pop();
} m_pThinkLock->Unlock();
op->RunThinkPart(); op->RunThinkPart();
op->Destroy(); op->Destroy();
} }
void DBManager::OnTerminate(IThreadHandle *pThread, bool cancel)
{
/* Do nothing */
}
void DBManager::OnSourceModIdentityDropped(IdentityToken_t *pToken) void DBManager::OnSourceModIdentityDropped(IdentityToken_t *pToken)
{ {
s_pAddBlock = pToken; s_pAddBlock = pToken;
@ -557,7 +667,7 @@ void DBManager::OnSourceModIdentityDropped(IdentityToken_t *pToken)
s_pAddBlock = NULL; s_pAddBlock = NULL;
} }
void DBManager::OnPluginWillUnload(IPlugin *plugin) void DBManager::OnPluginUnloaded(IPlugin *plugin)
{ {
/* Kill the thread so we can flush everything into the think queue... */ /* Kill the thread so we can flush everything into the think queue... */
KillWorkerThread(); KillWorkerThread();
@ -583,7 +693,9 @@ void DBManager::OnPluginWillUnload(IPlugin *plugin)
} }
} }
for (iter = templist.begin(); iter != templist.end(); iter++) for (iter = templist.begin();
iter != templist.end();
iter++)
{ {
IDBThreadOperation *op = (*iter); IDBThreadOperation *op = (*iter);
op->RunThinkPart(); op->RunThinkPart();
@ -591,13 +703,17 @@ void DBManager::OnPluginWillUnload(IPlugin *plugin)
} }
} }
ke::AString DBManager::GetDefaultDriverName() void DBManager::LockConfig()
{ {
ConfDbInfoList *list = m_Builder.GetConfigList(); m_pConfigLock->Lock();
return list->GetDefaultDriver();
} }
void DBManager::AddDependency(IExtension *myself, IDBDriver *driver) void DBManager::UnlockConfig()
{ {
g_Extensions.AddRawDependency(myself, driver->GetIdentity(), driver); m_pConfigLock->Unlock();
}
const char *DBManager::GetDefaultDriverName()
{
return m_DefDriver.c_str();
} }

View File

@ -1,8 +1,8 @@
/** /**
* vim: set ts=4 sw=4 tw=99 noet : * vim: set ts=4 :
* ============================================================================= * =============================================================================
* SourceMod * SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
* ============================================================================= * =============================================================================
* *
* This program is free software; you can redistribute it and/or modify it under * This program is free software; you can redistribute it and/or modify it under
@ -32,24 +32,42 @@
#ifndef _INCLUDE_DATABASE_MANAGER_H_ #ifndef _INCLUDE_DATABASE_MANAGER_H_
#define _INCLUDE_DATABASE_MANAGER_H_ #define _INCLUDE_DATABASE_MANAGER_H_
#include "common_logic.h" #include <IDBDriver.h>
#include "sm_globals.h"
#include <sh_vector.h> #include <sh_vector.h>
#include <am-string.h> #include <sh_string.h>
#include <sh_list.h> #include <sh_list.h>
#include <ITextParsers.h>
#include "sm_memtable.h"
#include <IThreader.h> #include <IThreader.h>
#include <IPluginSys.h>
#include <am-thread-utils.h>
#include "sm_simple_prioqueue.h" #include "sm_simple_prioqueue.h"
#include <am-refcounting.h> #include "PluginSys.h"
#include "DatabaseConfBuilder.h"
using namespace SourceHook; 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 : class DBManager :
public IDBManager, public IDBManager,
public SMGlobalClass, public SMGlobalClass,
public IHandleTypeDispatch, public IHandleTypeDispatch,
public ITextListener_SMC,
public IThread,
public IThreadWorkerCallbacks,
public IPluginsListener public IPluginsListener
{ {
public: public:
@ -68,31 +86,40 @@ public: //IDBManager
void AddDriver(IDBDriver *pDrivera); void AddDriver(IDBDriver *pDrivera);
void RemoveDriver(IDBDriver *pDriver); void RemoveDriver(IDBDriver *pDriver);
const DatabaseInfo *FindDatabaseConf(const char *name); const DatabaseInfo *FindDatabaseConf(const char *name);
ConfDbInfo *GetDatabaseConf(const char *name);
bool Connect(const char *name, IDBDriver **pdr, IDatabase **pdb, bool persistent, char *error, size_t maxlength); bool Connect(const char *name, IDBDriver **pdr, IDatabase **pdb, bool persistent, char *error, size_t maxlength);
unsigned int GetDriverCount(); unsigned int GetDriverCount();
IDBDriver *GetDriver(unsigned int index); IDBDriver *GetDriver(unsigned int index);
Handle_t CreateHandle(DBHandleType type, void *ptr, IdentityToken_t *pToken); Handle_t CreateHandle(DBHandleType type, void *ptr, IdentityToken_t *pToken);
HandleError ReadHandle(Handle_t hndl, DBHandleType type, void **ptr); HandleError ReadHandle(Handle_t hndl, DBHandleType type, void **ptr);
HandleError ReleaseHandle(Handle_t hndl, DBHandleType type, IdentityToken_t *token); HandleError ReleaseHandle(Handle_t hndl, DBHandleType type, IdentityToken_t *token);
void AddDependency(IExtension *myself, IDBDriver *driver); public: //ITextListener_SMC
public: //ke::IRunnable void ReadSMC_ParseStart();
void Run(); SMCResult ReadSMC_NewSection(const SMCStates *states, const char *name);
void ThreadMain(); 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 public: //IPluginsListener
void OnPluginWillUnload(IPlugin *plugin); void OnPluginUnloaded(IPlugin *plugin);
public: public:
ConfDbInfo *GetDatabaseConf(const char *name);
IDBDriver *FindOrLoadDriver(const char *name); IDBDriver *FindOrLoadDriver(const char *name);
IDBDriver *GetDefaultDriver(); IDBDriver *GetDefaultDriver();
ke::AString GetDefaultDriverName(); const char *GetDefaultDriverName();
bool AddToThreadQueue(IDBThreadOperation *op, PrioQueueLevel prio); bool AddToThreadQueue(IDBThreadOperation *op, PrioQueueLevel prio);
void LockConfig();
void UnlockConfig();
void RunFrame(); void RunFrame();
inline HandleType_t GetDatabaseType() inline HandleType_t GetDatabaseType()
{ {
return m_DatabaseType; return m_DatabaseType;
} }
private: private:
void ClearConfigs();
void KillWorkerThread(); void KillWorkerThread();
private: private:
CVector<IDBDriver *> m_drivers; CVector<IDBDriver *> m_drivers;
@ -101,15 +128,19 @@ private:
PrioQueue<IDBThreadOperation *> m_OpQueue; PrioQueue<IDBThreadOperation *> m_OpQueue;
Queue<IDBThreadOperation *> m_ThinkQueue; Queue<IDBThreadOperation *> m_ThinkQueue;
CVector<bool> m_drSafety; /* which drivers are safe? */ CVector<bool> m_drSafety; /* which drivers are safe? */
ke::AutoPtr<ke::Thread> m_Worker; IThreadWorker *m_pWorker; /* Worker thread object */
ke::ConditionVariable m_QueueEvent; IMutex *m_pConfigLock; /* Configuration lock */
ke::Mutex m_ThinkLock; IMutex *m_pQueueLock; /* Queue safety lock */
bool m_Terminate; IMutex *m_pThinkLock; /* Think-queue lock */
DatabaseConfBuilder m_Builder; List<ConfDbInfo> m_confs;
HandleType_t m_DriverType; HandleType_t m_DriverType;
HandleType_t m_DatabaseType; HandleType_t m_DatabaseType;
String m_DefDriver;
BaseStringTable m_StrTab;
char m_Filename[PLATFORM_MAX_PATH]; char m_Filename[PLATFORM_MAX_PATH];
unsigned int m_ParseLevel;
unsigned int m_ParseState;
IDBDriver *m_pDefault; IDBDriver *m_pDefault;
}; };

View File

@ -1,8 +1,8 @@
/** /**
* vim: set ts=4 sw=4 tw=99 noet : * vim: set ts=4 :
* ============================================================================= * =============================================================================
* SourceMod * SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
* ============================================================================= * =============================================================================
* *
* This program is free software; you can redistribute it and/or modify it under * This program is free software; you can redistribute it and/or modify it under
@ -29,47 +29,34 @@
* Version: $Id$ * Version: $Id$
*/ */
#include <ISourceMod.h>
#include <IPluginSys.h>
#include <stdarg.h>
#include "DebugReporter.h" #include "DebugReporter.h"
#include "Logger.h" #include "Logger.h"
#include "PluginSys.h"
#include "sm_stringutil.h"
DebugReport g_DbgReporter; DebugReport g_DbgReporter;
/* I'm really lazy. This should probably be exported to ISourcePawnEngine someday,
* but we need to make sure the JIT will deal with the version bump.
*/
extern const char *GetSourcePawnErrorMessage(int error);
void DebugReport::OnSourceModAllInitialized() void DebugReport::OnSourceModAllInitialized()
{ {
g_pSourcePawn->SetDebugListener(this); g_pSourcePawn->SetDebugListener(this);
} }
void DebugReport::OnDebugSpew(const char *msg, ...)
{
va_list ap;
char buffer[512];
va_start(ap, msg);
ke::SafeVsprintf(buffer, sizeof(buffer), msg, ap);
va_end(ap);
g_Logger.LogMessage("[SM] %s", buffer);
}
void DebugReport::GenerateError(IPluginContext *ctx, cell_t func_idx, int err, const char *message, ...) void DebugReport::GenerateError(IPluginContext *ctx, cell_t func_idx, int err, const char *message, ...)
{ {
va_list ap; va_list ap;
char buffer[512];
va_start(ap, message); va_start(ap, message);
GenerateErrorVA(ctx, func_idx, err, message, ap); UTIL_FormatArgs(buffer, sizeof(buffer), message, ap);
va_end(ap); va_end(ap);
}
void DebugReport::GenerateErrorVA(IPluginContext *ctx, cell_t func_idx, int err, const char *message, va_list ap) const char *plname = g_PluginSys.FindPluginByContext(ctx->GetContext())->GetFilename();
{ const char *error = GetSourcePawnErrorMessage(err);
char buffer[512];
ke::SafeVsprintf(buffer, sizeof(buffer), message, ap);
const char *plname = pluginsys->FindPluginByContext(ctx->GetContext())->GetFilename();
const char *error = g_pSourcePawn2->GetErrorString(err);
if (error) if (error)
{ {
@ -86,7 +73,7 @@ void DebugReport::GenerateErrorVA(IPluginContext *ctx, cell_t func_idx, int err,
{ {
func_idx >>= 1; func_idx >>= 1;
sp_public_t *function; sp_public_t *function;
if (ctx->GetRuntime()->GetPublicByIndex(func_idx, &function) == SP_ERROR_NONE) 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); g_Logger.LogError("[SM] Unable to call function \"%s\" due to above error(s).", function->name);
} }
@ -100,11 +87,11 @@ void DebugReport::GenerateCodeError(IPluginContext *pContext, uint32_t code_addr
char buffer[512]; char buffer[512];
va_start(ap, message); va_start(ap, message);
ke::SafeVsprintf(buffer, sizeof(buffer), message, ap); UTIL_FormatArgs(buffer, sizeof(buffer), message, ap);
va_end(ap); va_end(ap);
const char *plname = pluginsys->FindPluginByContext(pContext->GetContext())->GetFilename(); const char *plname = g_PluginSys.FindPluginByContext(pContext->GetContext())->GetFilename();
const char *error = g_pSourcePawn2->GetErrorString(err); const char *error = GetSourcePawnErrorMessage(err);
if (error) if (error)
{ {
@ -116,7 +103,7 @@ void DebugReport::GenerateCodeError(IPluginContext *pContext, uint32_t code_addr
g_Logger.LogError("[SM] %s", buffer); g_Logger.LogError("[SM] %s", buffer);
IPluginDebugInfo *pDebug; IPluginDebugInfo *pDebug;
if ((pDebug = pContext->GetRuntime()->GetDebugInfo()) == NULL) if ((pDebug = pContext->GetDebugInfo()) == NULL)
{ {
g_Logger.LogError("[SM] Debug mode is not enabled for \"%s\"", plname); 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", g_Logger.LogError("[SM] To enable debug mode, edit plugin_settings.cfg, or type: sm plugins debug %d on",
@ -133,10 +120,55 @@ void DebugReport::GenerateCodeError(IPluginContext *pContext, uint32_t 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 DebugReport::_GetPluginIndex(IPluginContext *ctx)
{ {
int id = 1; int id = 1;
IPluginIterator *iter = pluginsys->GetPluginIterator(); IPluginIterator *iter = g_PluginSys.GetPluginIterator();
for (; iter->MorePlugins(); iter->NextPlugin(), id++) for (; iter->MorePlugins(); iter->NextPlugin(), id++)
{ {
@ -149,98 +181,6 @@ int DebugReport::_GetPluginIndex(IPluginContext *ctx)
} }
iter->Release(); iter->Release();
return -1;
/* If we don't know which plugin this is, it's one being loaded. Fake its index for now. */
return pluginsys->GetPluginCount() + 1;
} }
void DebugReport::ReportError(const IErrorReport &report, IFrameIterator &iter)
{
// Don't log an error if a function wasn't runnable.
// This is necassary due to the way SM is handling and exposing
// scripted functions. It's too late to change that now.
if (report.Code() == SP_ERROR_NOT_RUNNABLE)
return;
const char *blame = nullptr;
if (report.Blame())
{
blame = report.Blame()->DebugName();
} else {
// Find the nearest plugin to blame.
for (; !iter.Done(); iter.Next())
{
if (iter.IsScriptedFrame())
{
IPlugin *plugin = pluginsys->FindPluginByContext(iter.Context()->GetContext());
if (plugin)
{
blame = plugin->GetFilename();
} else {
blame = iter.Context()->GetRuntime()->GetFilename();
}
break;
}
}
}
iter.Reset();
g_Logger.LogError("[SM] Exception reported: %s", report.Message());
if (blame)
{
g_Logger.LogError("[SM] Blaming: %s", blame);
}
ke::Vector<ke::AString> arr = GetStackTrace(&iter);
for (size_t i = 0; i < arr.length(); i++)
{
g_Logger.LogError("%s", arr[i].chars());
}
}
ke::Vector<ke::AString> DebugReport::GetStackTrace(IFrameIterator *iter)
{
char temp[3072];
ke::Vector<ke::AString> trace;
iter->Reset();
if (!iter->Done())
{
trace.append("[SM] Call stack trace:");
for (int index = 0; !iter->Done(); iter->Next(), index++)
{
const char *fn = iter->FunctionName();
if (!fn)
{
fn = "<unknown function>";
}
if (iter->IsNativeFrame())
{
g_pSM->Format(temp, sizeof(temp), "[SM] [%d] %s", index, fn);
trace.append(temp);
continue;
}
if (iter->IsScriptedFrame())
{
const char *file = iter->FilePath();
if (!file)
{
file = "<unknown>";
}
g_pSM->Format(temp, sizeof(temp), "[SM] [%d] Line %d, %s::%s",
index,
iter->LineNumber(),
file,
fn);
trace.append(temp);
}
}
}
return trace;
}

View File

@ -2,7 +2,7 @@
* vim: set ts=4 : * vim: set ts=4 :
* ============================================================================= * =============================================================================
* SourceMod * SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
* ============================================================================= * =============================================================================
* *
* This program is free software; you can redistribute it and/or modify it under * This program is free software; you can redistribute it and/or modify it under
@ -33,9 +33,7 @@
#define _INCLUDE_SOURCEMOD_CDBGREPORTER_H_ #define _INCLUDE_SOURCEMOD_CDBGREPORTER_H_
#include "sp_vm_api.h" #include "sp_vm_api.h"
#include "common_logic.h" #include "sm_globals.h"
#include <am-vector.h>
#include <am-string.h>
class DebugReport : class DebugReport :
public SMGlobalClass, public SMGlobalClass,
@ -44,13 +42,9 @@ class DebugReport :
public: // SMGlobalClass public: // SMGlobalClass
void OnSourceModAllInitialized(); void OnSourceModAllInitialized();
public: // IDebugListener public: // IDebugListener
void ReportError(const IErrorReport &report, IFrameIterator &iter); void OnContextExecuteError(IPluginContext *ctx, IContextTrace *error);
void OnDebugSpew(const char *msg, ...);
public:
void GenerateError(IPluginContext *ctx, cell_t func_idx, int err, const char *message, ...); void GenerateError(IPluginContext *ctx, cell_t func_idx, int err, const char *message, ...);
void GenerateErrorVA(IPluginContext *ctx, cell_t func_idx, int err, const char *message, va_list ap);
void GenerateCodeError(IPluginContext *ctx, uint32_t code_addr, int err, const char *message, ...); void GenerateCodeError(IPluginContext *ctx, uint32_t code_addr, int err, const char *message, ...);
ke::Vector<ke::AString> GetStackTrace(IFrameIterator *iter);
private: private:
int _GetPluginIndex(IPluginContext *ctx); int _GetPluginIndex(IPluginContext *ctx);
}; };

View File

@ -1,8 +1,8 @@
/** /**
* vim: set ts=4 sw=4 tw=99 noet : * vim: set ts=4 :
* ============================================================================= * =============================================================================
* SourceMod * SourceMod
* Copyright (C) 2004-2010 AlliedModders LLC. All rights reserved. * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
* ============================================================================= * =============================================================================
* *
* This program is free software; you can redistribute it and/or modify it under * This program is free software; you can redistribute it and/or modify it under
@ -30,11 +30,10 @@
*/ */
#include "EventManager.h" #include "EventManager.h"
#include "ForwardSys.h"
#include "HandleSys.h"
#include "PluginSys.h"
#include "sm_stringutil.h" #include "sm_stringutil.h"
#include "PlayerManager.h"
#include "logic_bridge.h"
#include <bridge/include/IScriptManager.h>
EventManager g_EventManager; EventManager g_EventManager;
@ -43,26 +42,16 @@ SH_DECL_HOOK2(IGameEventManager2, FireEvent, SH_NOATTRIB, 0, bool, IGameEvent *,
const ParamType GAMEEVENT_PARAMS[] = {Param_Cell, Param_String, Param_Cell}; const ParamType GAMEEVENT_PARAMS[] = {Param_Cell, Param_String, Param_Cell};
typedef List<EventHook *> EventHookList; typedef List<EventHook *> EventHookList;
class EventForwardFilter : public IForwardFilter
{
EventInfo *pEventInfo;
public:
EventForwardFilter(EventInfo *pEventInfo) : pEventInfo(pEventInfo)
{
}
void Preprocess(IPluginFunction *fun, FwdParamInfo *params)
{
params[2].val = pEventInfo->bDontBroadcast ? 1 : 0;
}
};
EventManager::EventManager() : m_EventType(0) EventManager::EventManager() : m_EventType(0)
{ {
/* Create an event lookup trie */
m_EventHooks = sm_trie_create();
} }
EventManager::~EventManager() EventManager::~EventManager()
{ {
sm_trie_destroy(m_EventHooks);
/* Free memory used by EventInfo structs if any */ /* Free memory used by EventInfo structs if any */
CStack<EventInfo *>::iterator iter; CStack<EventInfo *>::iterator iter;
for (iter = m_FreeEvents.begin(); iter != m_FreeEvents.end(); iter++) for (iter = m_FreeEvents.begin(); iter != m_FreeEvents.end(); iter++)
@ -76,8 +65,8 @@ EventManager::~EventManager()
void EventManager::OnSourceModAllInitialized() void EventManager::OnSourceModAllInitialized()
{ {
/* Add a hook for IGameEventManager2::FireEvent() */ /* Add a hook for IGameEventManager2::FireEvent() */
SH_ADD_HOOK(IGameEventManager2, FireEvent, gameevents, SH_MEMBER(this, &EventManager::OnFireEvent), false); SH_ADD_HOOK_MEMFUNC(IGameEventManager2, FireEvent, gameevents, this, &EventManager::OnFireEvent, false);
SH_ADD_HOOK(IGameEventManager2, FireEvent, gameevents, SH_MEMBER(this, &EventManager::OnFireEvent_Post), true); SH_ADD_HOOK_MEMFUNC(IGameEventManager2, FireEvent, gameevents, this, &EventManager::OnFireEvent_Post, true);
HandleAccess sec; HandleAccess sec;
@ -87,17 +76,17 @@ void EventManager::OnSourceModAllInitialized()
sec.access[HandleAccess_Clone] = HANDLE_RESTRICT_IDENTITY | HANDLE_RESTRICT_OWNER; sec.access[HandleAccess_Clone] = HANDLE_RESTRICT_IDENTITY | HANDLE_RESTRICT_OWNER;
/* Create the 'GameEvent' handle type */ /* Create the 'GameEvent' handle type */
m_EventType = handlesys->CreateType("GameEvent", this, 0, NULL, &sec, g_pCoreIdent, NULL); m_EventType = g_HandleSys.CreateType("GameEvent", this, 0, NULL, &sec, g_pCoreIdent, NULL);
} }
void EventManager::OnSourceModShutdown() void EventManager::OnSourceModShutdown()
{ {
/* Remove hook for IGameEventManager2::FireEvent() */ /* Remove hook for IGameEventManager2::FireEvent() */
SH_REMOVE_HOOK(IGameEventManager2, FireEvent, gameevents, SH_MEMBER(this, &EventManager::OnFireEvent), false); SH_REMOVE_HOOK_MEMFUNC(IGameEventManager2, FireEvent, gameevents, this, &EventManager::OnFireEvent, false);
SH_REMOVE_HOOK(IGameEventManager2, FireEvent, gameevents, SH_MEMBER(this, &EventManager::OnFireEvent_Post), true); SH_REMOVE_HOOK_MEMFUNC(IGameEventManager2, FireEvent, gameevents, this, &EventManager::OnFireEvent_Post, true);
/* Remove the 'GameEvent' handle type */ /* Remove the 'GameEvent' handle type */
handlesys->RemoveType(m_EventType, g_pCoreIdent); g_HandleSys.RemoveType(m_EventType, g_pCoreIdent);
/* Remove ourselves as listener for events */ /* Remove ourselves as listener for events */
gameevents->RemoveListener(this); gameevents->RemoveListener(this);
@ -135,12 +124,12 @@ void EventManager::OnPluginUnloaded(IPlugin *plugin)
{ {
if (pHook->pPreHook) if (pHook->pPreHook)
{ {
forwardsys->ReleaseForward(pHook->pPreHook); g_Forwards.ReleaseForward(pHook->pPreHook);
} }
if (pHook->pPostHook) if (pHook->pPostHook)
{ {
forwardsys->ReleaseForward(pHook->pPostHook); g_Forwards.ReleaseForward(pHook->pPostHook);
} }
delete pHook; delete pHook;
@ -158,13 +147,6 @@ void EventManager::FireGameEvent(IGameEvent *pEvent)
Just need to add ourselves as a listener to make our hook on IGameEventManager2::FireEvent work */ Just need to add ourselves as a listener to make our hook on IGameEventManager2::FireEvent work */
} }
#if SOURCE_ENGINE >= SE_LEFT4DEAD
int EventManager::GetEventDebugID()
{
return EVENT_DEBUG_ID_INIT;
}
#endif
EventHookError EventManager::HookEvent(const char *name, IPluginFunction *pFunction, EventHookMode mode) EventHookError EventManager::HookEvent(const char *name, IPluginFunction *pFunction, EventHookMode mode)
{ {
EventHook *pHook; EventHook *pHook;
@ -181,10 +163,10 @@ EventHookError EventManager::HookEvent(const char *name, IPluginFunction *pFunct
} }
/* If a hook structure does not exist... */ /* If a hook structure does not exist... */
if (!m_EventHooks.retrieve(name, &pHook)) if (!sm_trie_retrieve(m_EventHooks, name, (void **)&pHook))
{ {
EventHookList *pHookList; EventHookList *pHookList;
IPlugin *plugin = scripts->FindPluginByContext(pFunction->GetParentContext()->GetContext()); IPlugin *plugin = g_PluginSys.GetPluginByCtx(pFunction->GetParentContext()->GetContext());
/* Check plugin for an existing EventHook list */ /* Check plugin for an existing EventHook list */
if (!plugin->GetProperty("EventHooks", (void **)&pHookList)) if (!plugin->GetProperty("EventHooks", (void **)&pHookList))
@ -199,27 +181,24 @@ EventHookError EventManager::HookEvent(const char *name, IPluginFunction *pFunct
if (mode == EventHookMode_Pre) if (mode == EventHookMode_Pre)
{ {
/* Create forward for a pre hook */ /* Create forward for a pre hook */
pHook->pPreHook = forwardsys->CreateForwardEx(NULL, ET_Hook, 3, GAMEEVENT_PARAMS); pHook->pPreHook = g_Forwards.CreateForwardEx(NULL, ET_Hook, 3, GAMEEVENT_PARAMS);
/* Add to forward list */ /* Add to forward list */
pHook->pPreHook->AddFunction(pFunction); pHook->pPreHook->AddFunction(pFunction);
} else { } else {
/* Create forward for a post hook */ /* Create forward for a post hook */
pHook->pPostHook = forwardsys->CreateForwardEx(NULL, ET_Ignore, 3, GAMEEVENT_PARAMS); pHook->pPostHook = g_Forwards.CreateForwardEx(NULL, ET_Ignore, 3, GAMEEVENT_PARAMS);
/* Should we copy data from a pre hook to the post hook? */ /* Should we copy data from a pre hook to the post hook? */
pHook->postCopy = (mode == EventHookMode_Post); pHook->postCopy = (mode == EventHookMode_Post);
/* Add to forward list */ /* Add to forward list */
pHook->pPostHook->AddFunction(pFunction); pHook->pPostHook->AddFunction(pFunction);
} }
/* Cache the name for post hooks */
pHook->name = name;
/* Increase reference count */ /* Increase reference count */
pHook->refCount++; pHook->refCount++;
/* Add hook structure to hook lists */ /* Add hook structure to hook lists */
pHookList->push_back(pHook); pHookList->push_back(pHook);
m_EventHooks.insert(name, pHook); sm_trie_insert(m_EventHooks, name, pHook);
return EventHookErr_Okay; return EventHookErr_Okay;
} }
@ -231,7 +210,7 @@ EventHookError EventManager::HookEvent(const char *name, IPluginFunction *pFunct
/* Create pre hook forward if necessary */ /* Create pre hook forward if necessary */
if (!pHook->pPreHook) if (!pHook->pPreHook)
{ {
pHook->pPreHook = forwardsys->CreateForwardEx(NULL, ET_Event, 3, GAMEEVENT_PARAMS); pHook->pPreHook = g_Forwards.CreateForwardEx(NULL, ET_Event, 3, GAMEEVENT_PARAMS);
} }
/* Add plugin function to forward list */ /* Add plugin function to forward list */
@ -240,7 +219,7 @@ EventHookError EventManager::HookEvent(const char *name, IPluginFunction *pFunct
/* Create post hook forward if necessary */ /* Create post hook forward if necessary */
if (!pHook->pPostHook) if (!pHook->pPostHook)
{ {
pHook->pPostHook = forwardsys->CreateForwardEx(NULL, ET_Ignore, 3, GAMEEVENT_PARAMS); pHook->pPostHook = g_Forwards.CreateForwardEx(NULL, ET_Ignore, 3, GAMEEVENT_PARAMS);
} }
/* If postCopy is false, then we may want to set it to true */ /* If postCopy is false, then we may want to set it to true */
@ -265,7 +244,7 @@ EventHookError EventManager::UnhookEvent(const char *name, IPluginFunction *pFun
IChangeableForward **pEventForward; IChangeableForward **pEventForward;
/* If hook does not exist at all */ /* If hook does not exist at all */
if (!m_EventHooks.retrieve(name, &pHook)) if (!sm_trie_retrieve(m_EventHooks, name, (void **)&pHook))
{ {
return EventHookErr_NotActive; return EventHookErr_NotActive;
} }
@ -287,7 +266,7 @@ EventHookError EventManager::UnhookEvent(const char *name, IPluginFunction *pFun
/* If forward's list contains 0 functions now, free it */ /* If forward's list contains 0 functions now, free it */
if ((*pEventForward)->GetFunctionCount() == 0) if ((*pEventForward)->GetFunctionCount() == 0)
{ {
forwardsys->ReleaseForward(*pEventForward); g_Forwards.ReleaseForward(*pEventForward);
*pEventForward = NULL; *pEventForward = NULL;
} }
@ -297,7 +276,7 @@ EventHookError EventManager::UnhookEvent(const char *name, IPluginFunction *pFun
/* If reference count is now 0, free hook structure */ /* If reference count is now 0, free hook structure */
EventHookList *pHookList; EventHookList *pHookList;
IPlugin *plugin = scripts->FindPluginByContext(pFunction->GetParentContext()->GetContext()); IPlugin *plugin = g_PluginSys.GetPluginByCtx(pFunction->GetParentContext()->GetContext());
/* Get plugin's event hook list */ /* Get plugin's event hook list */
if (!plugin->GetProperty("EventHooks", (void**)&pHookList)) if (!plugin->GetProperty("EventHooks", (void**)&pHookList))
@ -315,7 +294,7 @@ EventHookError EventManager::UnhookEvent(const char *name, IPluginFunction *pFun
pHookList->remove(pHook); pHookList->remove(pHook);
/* Delete entry in trie */ /* Delete entry in trie */
m_EventHooks.remove(name); sm_trie_delete(m_EventHooks, name);
/* And finally free structure memory */ /* And finally free structure memory */
delete pHook; delete pHook;
@ -342,7 +321,6 @@ EventInfo *EventManager::CreateEvent(IPluginContext *pContext, const char *name,
pInfo->pEvent = pEvent; pInfo->pEvent = pEvent;
pInfo->pOwner = pContext->GetIdentity(); pInfo->pOwner = pContext->GetIdentity();
pInfo->bDontBroadcast = false;
return pInfo; return pInfo;
} }
@ -362,13 +340,6 @@ void EventManager::FireEvent(EventInfo *pInfo, bool bDontBroadcast)
m_FreeEvents.push(pInfo); m_FreeEvents.push(pInfo);
} }
void EventManager::FireEventToClient(EventInfo *pInfo, IClient *pClient)
{
// The IClient vtable is +sizeof(void *) from the IGameEventListener2 (CBaseClient) vtable due to multiple inheritance.
IGameEventListener2 *pGameClient = (IGameEventListener2 *)((intptr_t)pClient - sizeof(void *));
pGameClient->FireGameEvent(pInfo->pEvent);
}
void EventManager::CancelCreatedEvent(EventInfo *pInfo) void EventManager::CancelCreatedEvent(EventInfo *pInfo)
{ {
/* Free event from IGameEventManager2 */ /* Free event from IGameEventManager2 */
@ -388,64 +359,41 @@ bool EventManager::OnFireEvent(IGameEvent *pEvent, bool bDontBroadcast)
IChangeableForward *pForward; IChangeableForward *pForward;
const char *name; const char *name;
cell_t res = Pl_Continue; cell_t res = Pl_Continue;
bool broadcast = bDontBroadcast;
/* 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(); name = pEvent->GetName();
if (m_EventHooks.retrieve(name, &pHook)) m_EventNames.push(name);
{
/* Push the event onto the event stack. The reference count is increased to make sure
* the structure is not garbage collected in between now and the post hook.
*/
pHook->refCount++;
m_EventStack.push(pHook);
if (sm_trie_retrieve(m_EventHooks, name, reinterpret_cast<void **>(&pHook)))
{
pForward = pHook->pPreHook; pForward = pHook->pPreHook;
if (pForward) if (pForward)
{ {
EventInfo info(pEvent, NULL); EventInfo info = { pEvent, NULL };
HandleSecurity sec(NULL, g_pCoreIdent);
Handle_t hndl = handlesys->CreateHandle(m_EventType, &info, NULL, g_pCoreIdent, NULL);
info.bDontBroadcast = bDontBroadcast;
EventForwardFilter filter(&info);
Handle_t hndl = g_HandleSys.CreateHandle(m_EventType, &info, NULL, g_pCoreIdent, NULL);
pForward->PushCell(hndl); pForward->PushCell(hndl);
pForward->PushString(name); pForward->PushString(name);
pForward->PushCell(bDontBroadcast); pForward->PushCell(bDontBroadcast);
pForward->Execute(&res, &filter); pForward->Execute(&res, NULL);
broadcast = info.bDontBroadcast; HandleSecurity sec(NULL, g_pCoreIdent);
g_HandleSys.FreeHandle(hndl, &sec);
handlesys->FreeHandle(hndl, &sec);
} }
if (pHook->postCopy) if (pHook->postCopy)
{ {
m_EventCopies.push(gameevents->DuplicateEvent(pEvent)); pHook->pEventCopy = gameevents->DuplicateEvent(pEvent);
} }
if (res >= Pl_Handled) if (res)
{ {
gameevents->FreeEvent(pEvent); gameevents->FreeEvent(pEvent);
RETURN_META_VALUE(MRES_SUPERCEDE, false); RETURN_META_VALUE(MRES_SUPERCEDE, false);
} }
} }
else
{
m_EventStack.push(NULL);
}
if (broadcast != bDontBroadcast)
RETURN_META_VALUE_NEWPARAMS(MRES_IGNORED, true, &IGameEventManager2::FireEvent, (pEvent, broadcast));
RETURN_META_VALUE(MRES_IGNORED, true); RETURN_META_VALUE(MRES_IGNORED, true);
} }
@ -453,38 +401,32 @@ bool EventManager::OnFireEvent(IGameEvent *pEvent, bool bDontBroadcast)
/* IGameEventManager2::FireEvent post hook */ /* IGameEventManager2::FireEvent post hook */
bool EventManager::OnFireEvent_Post(IGameEvent *pEvent, bool bDontBroadcast) bool EventManager::OnFireEvent_Post(IGameEvent *pEvent, bool bDontBroadcast)
{ {
IGameEvent *pEventCopy = NULL;
EventHook *pHook; EventHook *pHook;
EventInfo info;
IChangeableForward *pForward; IChangeableForward *pForward;
const char *name;
Handle_t hndl = 0; Handle_t hndl = 0;
/* The engine accepts NULL without crashing, so to prevent a crash in SM we ignore these */ name = m_EventNames.front();
if (!pEvent)
{
RETURN_META_VALUE(MRES_IGNORED, false);
}
pHook = m_EventStack.front(); if (sm_trie_retrieve(m_EventHooks, name, reinterpret_cast<void **>(&pHook)))
if (pHook != NULL)
{ {
pForward = pHook->pPostHook; pForward = pHook->pPostHook;
if (pForward) if (pForward)
{ {
EventInfo info = { pHook->pEventCopy, NULL };
if (pHook->postCopy) if (pHook->postCopy)
{ {
info.bDontBroadcast = bDontBroadcast; hndl = g_HandleSys.CreateHandle(m_EventType, &info, NULL, g_pCoreIdent, NULL);
info.pEvent = m_EventCopies.front();
info.pOwner = NULL;
hndl = handlesys->CreateHandle(m_EventType, &info, NULL, g_pCoreIdent, NULL);
pForward->PushCell(hndl); pForward->PushCell(hndl);
} else { } else {
pForward->PushCell(BAD_HANDLE); pForward->PushCell(BAD_HANDLE);
} }
pForward->PushString(pHook->name.chars()); pForward->PushString(name);
pForward->PushCell(bDontBroadcast); pForward->PushCell(bDontBroadcast);
pForward->Execute(NULL); pForward->Execute(NULL);
@ -492,25 +434,16 @@ bool EventManager::OnFireEvent_Post(IGameEvent *pEvent, bool bDontBroadcast)
{ {
/* Free handle */ /* Free handle */
HandleSecurity sec(NULL, g_pCoreIdent); HandleSecurity sec(NULL, g_pCoreIdent);
handlesys->FreeHandle(hndl, &sec); g_HandleSys.FreeHandle(hndl, &sec);
/* Free event structure */ /* Free event structure */
gameevents->FreeEvent(info.pEvent); gameevents->FreeEvent(pEventCopy);
m_EventCopies.pop(); pHook->pEventCopy = NULL;
}
} }
} }
/* Decrement reference count, check if a delayed delete is needed */ m_EventNames.pop();
if (--pHook->refCount == 0)
{
assert(pHook->pPostHook == NULL);
assert(pHook->pPreHook == NULL);
m_EventHooks.remove(pHook->name.chars());
delete pHook;
}
}
m_EventStack.pop();
RETURN_META_VALUE(MRES_IGNORED, true); RETURN_META_VALUE(MRES_IGNORED, true);
} }

View File

@ -1,8 +1,8 @@
/** /**
* vim: set ts=4 sw=4 tw=99 noet : * vim: set ts=4 :
* ============================================================================= * =============================================================================
* SourceMod * SourceMod
* Copyright (C) 2004-2010 AlliedModders LLC. All rights reserved. * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
* ============================================================================= * =============================================================================
* *
* This program is free software; you can redistribute it and/or modify it under * This program is free software; you can redistribute it and/or modify it under
@ -34,28 +34,19 @@
#include "sm_globals.h" #include "sm_globals.h"
#include "sourcemm_api.h" #include "sourcemm_api.h"
#include <sm_namehashset.h> #include "sm_trie.h"
#include <sh_list.h> #include <sh_list.h>
#include <sh_stack.h> #include <sh_stack.h>
#include <IHandleSys.h> #include <IHandleSys.h>
#include <IForwardSys.h> #include <IForwardSys.h>
#include <IPluginSys.h> #include <IPluginSys.h>
class IClient;
using namespace SourceHook; using namespace SourceHook;
struct EventInfo struct EventInfo
{ {
EventInfo()
{
}
EventInfo(IGameEvent *ev, IdentityToken_t *owner) : pEvent(ev), pOwner(owner)
{
}
IGameEvent *pEvent; IGameEvent *pEvent;
IdentityToken_t *pOwner; IdentityToken_t *pOwner;
bool bDontBroadcast;
}; };
struct EventHook struct EventHook
@ -65,22 +56,14 @@ struct EventHook
pPreHook = NULL; pPreHook = NULL;
pPostHook = NULL; pPostHook = NULL;
postCopy = false; postCopy = false;
pEventCopy = NULL;
refCount = 0; refCount = 0;
} }
IChangeableForward *pPreHook; IChangeableForward *pPreHook;
IChangeableForward *pPostHook; IChangeableForward *pPostHook;
bool postCopy; bool postCopy;
IGameEvent *pEventCopy;
unsigned int refCount; unsigned int refCount;
ke::AString name;
static inline bool matches(const char *name, const EventHook *hook)
{
return strcmp(name, hook->name.chars()) == 0;
}
static inline uint32_t hash(const detail::CharsAndLength &key)
{
return key.hash();
}
}; };
enum EventHookMode enum EventHookMode
@ -116,9 +99,6 @@ public: // IPluginsListener
void OnPluginUnloaded(IPlugin *plugin); void OnPluginUnloaded(IPlugin *plugin);
public: // IGameEventListener2 public: // IGameEventListener2
void FireGameEvent(IGameEvent *pEvent); void FireGameEvent(IGameEvent *pEvent);
#if SOURCE_ENGINE >= SE_LEFT4DEAD
int GetEventDebugID();
#endif
public: public:
/** /**
* Get the 'GameEvent' handle type ID. * Get the 'GameEvent' handle type ID.
@ -132,17 +112,15 @@ public:
EventHookError UnhookEvent(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); EventInfo *CreateEvent(IPluginContext *pContext, const char *name, bool force=false);
void FireEvent(EventInfo *pInfo, bool bDontBroadcast=false); void FireEvent(EventInfo *pInfo, bool bDontBroadcast=false);
void FireEventToClient(EventInfo *pInfo, IClient *pClient);
void CancelCreatedEvent(EventInfo *pInfo); void CancelCreatedEvent(EventInfo *pInfo);
private: // IGameEventManager2 hooks private: // IGameEventManager2 hooks
bool OnFireEvent(IGameEvent *pEvent, bool bDontBroadcast); bool OnFireEvent(IGameEvent *pEvent, bool bDontBroadcast);
bool OnFireEvent_Post(IGameEvent *pEvent, bool bDontBroadcast); bool OnFireEvent_Post(IGameEvent *pEvent, bool bDontBroadcast);
private: private:
HandleType_t m_EventType; HandleType_t m_EventType;
NameHashSet<EventHook *> m_EventHooks; Trie *m_EventHooks;
CStack<EventInfo *> m_FreeEvents; CStack<EventInfo *> m_FreeEvents;
CStack<EventHook *> m_EventStack; CStack<const char *> m_EventNames;
CStack<IGameEvent *> m_EventCopies;
}; };
extern EventManager g_EventManager; extern EventManager g_EventManager;

View File

@ -2,7 +2,7 @@
* vim: set ts=4 : * vim: set ts=4 :
* ============================================================================= * =============================================================================
* SourceMod * SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
* ============================================================================= * =============================================================================
* *
* This program is free software; you can redistribute it and/or modify it under * This program is free software; you can redistribute it and/or modify it under
@ -32,20 +32,26 @@
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include "GameConfigs.h" #include "GameConfigs.h"
//#include "sm_stringutil.h" #include "sm_stringutil.h"
//#include "sourcemod.h" #include "sourcemod.h"
//#include "sourcemm_api.h" #include "sourcemm_api.h"
//#include "HalfLife2.h" #include "HalfLife2.h"
//#include "Logger.h" #include "Logger.h"
//#include "ShareSys.h" #include "ShareSys.h"
//#include "MemoryUtils.h" #include "MemoryUtils.h"
//#include "LibrarySys.h" #include "LibrarySys.h"
//#include "HandleSys.h" #include "HandleSys.h"
//#include "sm_crc32.h" #include "sm_crc32.h"
//#if defined PLATFORM_LINUX #if defined PLATFORM_LINUX
//#include <dlfcn.h> #include <dlfcn.h>
//#endif #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_NONE 0
#define PSTATE_GAMES 1 #define PSTATE_GAMES 1
@ -58,53 +64,47 @@
#define PSTATE_GAMEDEFS_SIGNATURES_SIG 8 #define PSTATE_GAMEDEFS_SIGNATURES_SIG 8
#define PSTATE_GAMEDEFS_CRC 9 #define PSTATE_GAMEDEFS_CRC 9
#define PSTATE_GAMEDEFS_CRC_BINARY 10 #define PSTATE_GAMEDEFS_CRC_BINARY 10
#define PSTATE_GAMEDEFS_CUSTOM 11
#define WIN 0
#define LIN 1
#if defined PLATFORM_WINDOWS
#define PLATFORM_NAME "windows"
#define PLATFORM_SERVER_BINARY "server.dll"
#elif defined PLATFORM_LINUX
#define PLATFORM_NAME "linux" #define PLATFORM_NAME "linux"
#define PLATFORM_SERVER_BINARY "server_i486.so" #define PLATFORM_SERVER_BINARY "server_i486.so"
#endif
Offset *tempOffset; struct TempSigInfo
Sig *tempSig; {
void Reset()
{
library[0] = '\0';
sig[0] = '\0';
}
char sig[512];
char library[64];
} s_TempSig;
unsigned int s_ServerBinCRC; unsigned int s_ServerBinCRC;
bool s_ServerBinCRC_Ok = false; bool s_ServerBinCRC_Ok = false;
bool /*CGameConfig::*/DoesGameMatch(const char *value) CGameConfig::CGameConfig(const char *file)
{ {
if (strcmp(value, /*m_gdcG*/game) == 0) m_pFile = sm_strdup(file);
{ m_pOffsets = sm_trie_create();
return true; m_pProps = sm_trie_create();
} m_pKeys = sm_trie_create();
return false; m_pSigs = sm_trie_create();
} m_pStrings = new BaseStringTable(512);
bool /*CGameConfig::*/DoesEngineMatch(const char *value)
{
if (strcmp(value, /*m_gdcE*/engine) == 0)
{
return true;
}
return false;
}
CGameConfig::CGameConfig()//const char *file)//, const char *game, const char *engine)
{
// strncopy(m_File, file, sizeof(m_File));
// strncopy(m_gdcGame, game, sizeof(m_gdcGame));
// strncopy(m_gdcEngine, engine, sizeof(m_gdcEngine));
//m_pStrings = new BaseStringTable(512);
m_RefCount = 0; m_RefCount = 0;
m_CustomLevel = 0;
m_CustomHandler = NULL;
} }
CGameConfig::~CGameConfig() CGameConfig::~CGameConfig()
{ {
// delete m_pStrings; sm_trie_destroy(m_pOffsets);
sm_trie_destroy(m_pProps);
sm_trie_destroy(m_pKeys);
sm_trie_destroy(m_pSigs);
delete [] m_pFile;
delete m_pStrings;
} }
SMCResult CGameConfig::ReadSMC_NewSection(const SMCStates *states, const char *name) SMCResult CGameConfig::ReadSMC_NewSection(const SMCStates *states, const char *name)
@ -129,9 +129,11 @@ SMCResult CGameConfig::ReadSMC_NewSection(const SMCStates *states, const char *n
} }
case PSTATE_GAMES: case PSTATE_GAMES:
{ {
if (strcmp(name, "*") == 0 || if ((strcmp(name, "*") == 0)
strcmp(name, "#default") == 0 || || (strcmp(name, "#default") == 0)
DoesGameMatch(name)) || (strcasecmp(name, g_Game) == 0)
|| (strcasecmp(name, g_GameDesc) == 0)
|| (strcasecmp(name, g_GameName) == 0))
{ {
bShouldBeReadingDefault = true; bShouldBeReadingDefault = true;
m_ParseState = PSTATE_GAMEDEFS; m_ParseState = PSTATE_GAMEDEFS;
@ -151,15 +153,12 @@ SMCResult CGameConfig::ReadSMC_NewSection(const SMCStates *states, const char *n
{ {
m_ParseState = PSTATE_GAMEDEFS_KEYS; m_ParseState = PSTATE_GAMEDEFS_KEYS;
} }
else if ((strcmp(name, "#supported") == 0) && (strcmp(m_Game, "#default") == 0)) else if ((strcmp(name, "#supported") == 0)
&& (strcmp(m_Game, "#default") == 0))
{ {
m_ParseState = PSTATE_GAMEDEFS_SUPPORTED; m_ParseState = PSTATE_GAMEDEFS_SUPPORTED;
/* Ignore this section unless we get a game. */ /* Ignore this section unless we get a game. */
bShouldBeReadingDefault = false; bShouldBeReadingDefault = false;
had_game = false;
matched_game = false;
had_engine = false;
matched_engine = false;
} }
else if (strcmp(name, "Signatures") == 0) else if (strcmp(name, "Signatures") == 0)
{ {
@ -167,25 +166,12 @@ SMCResult CGameConfig::ReadSMC_NewSection(const SMCStates *states, const char *n
} }
else if (strcmp(name, "CRC") == 0) else if (strcmp(name, "CRC") == 0)
{ {
#if 0
m_ParseState = PSTATE_GAMEDEFS_CRC; m_ParseState = PSTATE_GAMEDEFS_CRC;
bShouldBeReadingDefault = false; bShouldBeReadingDefault = false;
#endif
} }
else else
{ {
#if 0 m_IgnoreLevel++;
ITextListener_SMC **pListen = g_GameConfigs.m_customHandlers.retrieve(name);
if (pListen != NULL)
{
m_CustomLevel = 0;
m_ParseState = PSTATE_GAMEDEFS_CUSTOM;
m_CustomHandler = *pListen;
m_CustomHandler->ReadSMC_ParseStart();
break;
}
#endif
} }
break; break;
} }
@ -193,19 +179,17 @@ SMCResult CGameConfig::ReadSMC_NewSection(const SMCStates *states, const char *n
{ {
m_Prop[0] = '\0'; m_Prop[0] = '\0';
m_Class[0] = '\0'; m_Class[0] = '\0';
tempOffset = new Offset(); strncopy(m_offset, name, sizeof(m_offset));
tempOffset->setName(name);
m_ParseState = PSTATE_GAMEDEFS_OFFSETS_OFFSET; m_ParseState = PSTATE_GAMEDEFS_OFFSETS_OFFSET;
break; break;
} }
case PSTATE_GAMEDEFS_SIGNATURES: case PSTATE_GAMEDEFS_SIGNATURES:
{ {
tempSig = new Sig(); strncopy(m_offset, name, sizeof(m_offset));
tempSig->setName(name); s_TempSig.Reset();
m_ParseState = PSTATE_GAMEDEFS_SIGNATURES_SIG; m_ParseState = PSTATE_GAMEDEFS_SIGNATURES_SIG;
break; break;
} }
#if 0
case PSTATE_GAMEDEFS_CRC: case PSTATE_GAMEDEFS_CRC:
{ {
char error[255]; char error[255];
@ -236,26 +220,18 @@ SMCResult CGameConfig::ReadSMC_NewSection(const SMCStates *states, const char *n
s_ServerBinCRC = UTIL_CRC32(buffer, size); s_ServerBinCRC = UTIL_CRC32(buffer, size);
free(buffer); free(buffer);
s_ServerBinCRC_Ok = true; s_ServerBinCRC_Ok = true;
fclose(fp);
} }
} }
if (error[0] != '\0') if (error[0] != '\0')
{ {
m_IgnoreLevel = 1; m_IgnoreLevel = 1;
g_Logger.LogError("[SM] Error while parsing CRC section for \"%s\" (%s):", m_Game, m_CurFile); g_Logger.LogError("[SM] Error while parsing CRC section for \"%s\" (%s):", m_Game, m_pFile);
g_Logger.LogError("[SM] %s", error); g_Logger.LogError("[SM] %s", error);
} else { } else {
m_ParseState = PSTATE_GAMEDEFS_CRC_BINARY; m_ParseState = PSTATE_GAMEDEFS_CRC_BINARY;
} }
break; break;
} }
case PSTATE_GAMEDEFS_CUSTOM:
{
m_CustomLevel++;
return m_CustomHandler->ReadSMC_NewSection(states, name);
break;
}
#endif
/* No sub-sections allowed: /* No sub-sections allowed:
case PSTATE_GAMEDEFS_OFFSETS_OFFSET: case PSTATE_GAMEDEFS_OFFSETS_OFFSET:
case PSTATE_GAMEDEFS_KEYS: case PSTATE_GAMEDEFS_KEYS:
@ -288,46 +264,29 @@ SMCResult CGameConfig::ReadSMC_KeyValue(const SMCStates *states, const char *key
strncopy(m_Class, value, sizeof(m_Class)); strncopy(m_Class, value, sizeof(m_Class));
} else if (strcmp(key, "prop") == 0) { } else if (strcmp(key, "prop") == 0) {
strncopy(m_Prop, value, sizeof(m_Prop)); strncopy(m_Prop, value, sizeof(m_Prop));
} else /*if (strcmp(key, PLATFORM_NAME) == 0) */ { } else if (strcmp(key, PLATFORM_NAME) == 0) {
int val = atoi(value); int val = atoi(value);
// sm_trie_replace(m_pOffsets, m_offset, (void *)val); sm_trie_replace(m_pOffsets, m_offset, (void *)val);
if (strcmp(key, "windows") == 0) tempOffset->setWin(val);
else if (strcmp(key, "linux") == 0) tempOffset->setLin(val);
} }
} else if (m_ParseState == PSTATE_GAMEDEFS_KEYS) { } else if (m_ParseState == PSTATE_GAMEDEFS_KEYS) {
m_Keys[key] = value; int id = m_pStrings->AddString(value);
// printf("Inserting %s - %s\n", key, value); sm_trie_replace(m_pKeys, key, (void *)id);
// int id = m_pStrings->AddString(value);
// sm_trie_replace(m_pKeys, key, (void *)id);
} else if (m_ParseState == PSTATE_GAMEDEFS_SUPPORTED) { } else if (m_ParseState == PSTATE_GAMEDEFS_SUPPORTED) {
if (strcmp(key, "game") == 0) if (strcmp(key, "game") == 0
{ && (strcasecmp(value, g_Game) == 0
had_game = true; || strcasecmp(value, g_GameDesc) == 0
if (DoesGameMatch(value)) || strcasecmp(value, g_GameName) == 0)
{ )
matched_game = true;
}
if ((!had_engine && matched_game) || (matched_engine && matched_game))
{ {
bShouldBeReadingDefault = true; bShouldBeReadingDefault = true;
} }
}
else if (strcmp(key, "engine") == 0)
{
had_engine = true;
if (DoesEngineMatch(value))
{
matched_engine = true;
}
if ((!had_game && matched_engine) || (matched_game && matched_engine))
{
bShouldBeReadingDefault = true;
}
}
} else if (m_ParseState == PSTATE_GAMEDEFS_SIGNATURES_SIG) { } else if (m_ParseState == PSTATE_GAMEDEFS_SIGNATURES_SIG) {
if (strcmp(key, "windows") == 0) tempSig->setWin(value); if (strcmp(key, PLATFORM_NAME) == 0)
else if (strcmp(key, "linux") == 0) tempSig->setLin(value); {
else if (strcmp(key, "library") == 0) tempSig->setLib(value); 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) { } else if (m_ParseState == PSTATE_GAMEDEFS_CRC_BINARY) {
if (strcmp(key, PLATFORM_NAME) == 0 if (strcmp(key, PLATFORM_NAME) == 0
&& s_ServerBinCRC_Ok && s_ServerBinCRC_Ok
@ -340,8 +299,6 @@ SMCResult CGameConfig::ReadSMC_KeyValue(const SMCStates *states, const char *key
bShouldBeReadingDefault = true; bShouldBeReadingDefault = true;
} }
} }
} else if (m_ParseState == PSTATE_GAMEDEFS_CUSTOM) {
return m_CustomHandler->ReadSMC_KeyValue(states, key, value);
} }
return SMCResult_Continue; return SMCResult_Continue;
@ -355,13 +312,6 @@ SMCResult CGameConfig::ReadSMC_LeavingSection(const SMCStates *states)
return SMCResult_Continue; return SMCResult_Continue;
} }
if (m_CustomLevel)
{
m_CustomLevel--;
m_CustomHandler->ReadSMC_LeavingSection(states);
return SMCResult_Continue;
}
switch (m_ParseState) switch (m_ParseState)
{ {
case PSTATE_GAMES: case PSTATE_GAMES:
@ -374,12 +324,6 @@ SMCResult CGameConfig::ReadSMC_LeavingSection(const SMCStates *states)
m_ParseState = PSTATE_GAMES; m_ParseState = PSTATE_GAMES;
break; break;
} }
case PSTATE_GAMEDEFS_CUSTOM:
{
m_ParseState = PSTATE_GAMEDEFS;
m_CustomHandler->ReadSMC_ParseEnd(false, false);
break;
}
case PSTATE_GAMEDEFS_KEYS: case PSTATE_GAMEDEFS_KEYS:
case PSTATE_GAMEDEFS_OFFSETS: case PSTATE_GAMEDEFS_OFFSETS:
{ {
@ -388,8 +332,6 @@ SMCResult CGameConfig::ReadSMC_LeavingSection(const SMCStates *states)
} }
case PSTATE_GAMEDEFS_OFFSETS_OFFSET: case PSTATE_GAMEDEFS_OFFSETS_OFFSET:
{ {
m_Offsets.push_back(*tempOffset);
#if 0
/* Parse the offset... */ /* Parse the offset... */
if (m_Class[0] != '\0' if (m_Class[0] != '\0'
&& m_Prop[0] != '\0') && m_Prop[0] != '\0')
@ -408,12 +350,11 @@ SMCResult CGameConfig::ReadSMC_LeavingSection(const SMCStates *states)
g_Logger.LogError("[SM] Unable to find property %s.%s (file \"%s\") (mod \"%s\")", g_Logger.LogError("[SM] Unable to find property %s.%s (file \"%s\") (mod \"%s\")",
m_Class, m_Class,
m_Prop, m_Prop,
m_CurFile, m_pFile,
m_Game); m_Game);
} }
} }
} }
#endif
m_ParseState = PSTATE_GAMEDEFS_OFFSETS; m_ParseState = PSTATE_GAMEDEFS_OFFSETS;
break; break;
} }
@ -442,8 +383,6 @@ SMCResult CGameConfig::ReadSMC_LeavingSection(const SMCStates *states)
} }
case PSTATE_GAMEDEFS_SIGNATURES_SIG: case PSTATE_GAMEDEFS_SIGNATURES_SIG:
{ {
m_Sigs.push_back(*tempSig);
#if 0
if (s_TempSig.library[0] == '\0') if (s_TempSig.library[0] == '\0')
{ {
/* assume server */ /* assume server */
@ -461,7 +400,7 @@ SMCResult CGameConfig::ReadSMC_LeavingSection(const SMCStates *states)
{ {
g_Logger.LogError("[SM] Unrecognized library \"%s\" (gameconf \"%s\")", g_Logger.LogError("[SM] Unrecognized library \"%s\" (gameconf \"%s\")",
s_TempSig.library, s_TempSig.library,
m_CurFile); m_pFile);
} else { } else {
#if defined PLATFORM_LINUX #if defined PLATFORM_LINUX
if (s_TempSig.sig[0] == '@') if (s_TempSig.sig[0] == '@')
@ -478,12 +417,12 @@ SMCResult CGameConfig::ReadSMC_LeavingSection(const SMCStates *states)
} else { } else {
g_Logger.LogError("[SM] Unable to load library \"%s\" (gameconf \"%s\")", g_Logger.LogError("[SM] Unable to load library \"%s\" (gameconf \"%s\")",
s_TempSig.library, s_TempSig.library,
m_File); m_pFile);
} }
} else { } else {
g_Logger.LogError("[SM] Unable to find library \"%s\" in memory (gameconf \"%s\")", g_Logger.LogError("[SM] Unable to find library \"%s\" in memory (gameconf \"%s\")",
s_TempSig.library, s_TempSig.library,
m_File); m_pFile);
} }
} }
if (final_addr) if (final_addr)
@ -538,7 +477,6 @@ SMCResult CGameConfig::ReadSMC_LeavingSection(const SMCStates *states)
skip_find: skip_find:
#endif #endif
sm_trie_replace(m_pSigs, m_offset, final_addr); sm_trie_replace(m_pSigs, m_offset, final_addr);
#endif
m_ParseState = PSTATE_GAMEDEFS_SIGNATURES; m_ParseState = PSTATE_GAMEDEFS_SIGNATURES;
break; break;
@ -548,220 +486,48 @@ skip_find:
return SMCResult_Continue; return SMCResult_Continue;
} }
#define MSTATE_NONE 0
#define MSTATE_MAIN 1
#define MSTATE_FILE 2
class MasterReader : public ITextListener_SMC
{
public:
virtual void ReadSMC_ParseStart()
{
state = MSTATE_NONE;
ignoreLevel = 0;
}
virtual SMCResult ReadSMC_NewSection(const SMCStates *states, const char *name)
{
if (ignoreLevel)
{
return SMCResult_Continue;
}
if (state == MSTATE_NONE)
{
if (strcmp(name, "Game Master") == 0)
{
state = MSTATE_MAIN;
}
else
{
ignoreLevel++;
}
}
else if (state == MSTATE_MAIN)
{
strncopy(cur_file, name, sizeof(cur_file));
had_engine = false;
matched_engine = false;
had_game = false;
matched_game = false;
state = MSTATE_FILE;
}
else if (state == MSTATE_FILE)
{
ignoreLevel++;
}
return SMCResult_Continue;
}
virtual SMCResult ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value)
{
if (ignoreLevel || state != MSTATE_FILE)
{
return SMCResult_Continue;
}
if (strcmp(key, "engine") == 0)
{
had_engine = true;
if (DoesEngineMatch(value))
{
matched_engine = true;
}
}
else if (strcmp(key, "game") == 0)
{
had_game = true;
if (DoesGameMatch(value))
{
matched_game = true;
}
}
return SMCResult_Continue;
}
virtual SMCResult ReadSMC_LeavingSection(const SMCStates *states)
{
if (ignoreLevel)
{
ignoreLevel--;
return SMCResult_Continue;
}
if (state == MSTATE_FILE)
{
/* The four success conditions:
* 1. Needed nothing.
* 2. Needed game only.
* 3. Needed engine only.
* 4. Needed both engine and game.
* Final result is minimized via k-map.
*/
#if 0
if ((!had_engine && !had_game) ||
(!had_engine && (had_game && matched_game)) ||
(!had_game && (had_engine && matched_engine)) ||
((had_game && had_engine) && (matched_game && matched_engine)))
#endif
if ((!had_engine && !had_game) ||
(!had_engine && matched_game) ||
(!had_game && matched_engine) ||
(matched_engine && matched_game))
{
fileList->push_back(cur_file);
}
state = MSTATE_MAIN;
}
else if (state == MSTATE_MAIN)
{
state = MSTATE_NONE;
}
return SMCResult_Continue;
}
public:
list<char*> *fileList;
unsigned int state;
unsigned int ignoreLevel;
char cur_file[PLATFORM_MAX_PATH];
bool had_engine;
bool matched_engine;
bool had_game;
bool matched_game;
};
static MasterReader master_reader;
bool CGameConfig::Reparse(char *error, size_t maxlength) bool CGameConfig::Reparse(char *error, size_t maxlength)
{ {
/* Reset cached data */ SMCError err;
// m_pStrings->Reset(); SMCStates state = {0, 0};
m_Offsets.clear();
m_Sigs.clear();
char path[PLATFORM_MAX_PATH]; char path[PLATFORM_MAX_PATH];
g_SourceMod.BuildPath(Path_SM, path, sizeof(path), "gamedata/%s.txt", m_pFile);
/* See if we can use the extended gamedata format. */ /* Backwards compatibility */
//TODO pass in path to gamedata somehow if (!g_LibSys.PathExists(path))
// g_SourceMod.BuildPath(Path_SM, path, sizeof(path), "gamedata/%s/master.games.txt", m_File);
/* Otherwise, it's time to parse the master. */
SMCError err;
SMCStates state = {0, 0};
list<char*> fileList;
master_reader.fileList = &fileList;
err = textparsers->ParseSMCFile(path, &master_reader, &state, error, maxlength);
if (err != SMCError_Okay)
{ {
const char *msg = textparsers->GetSMCErrorString(err); g_SourceMod.BuildPath(Path_SM, path, sizeof(path), "configs/gamedata/%s.txt", m_pFile);
printf("[SM] Error parsing master gameconf file \"%s\":", path);
printf("[SM] Error %d on line %d, col %d: %s",
err,
state.line,
state.col,
msg ? msg : "Unknown error");
exit(PARSE_ERROR);
} }
/* Go through each file we found and parse it. */
list<char*>::iterator iter;
for (iter = fileList.begin(); iter != fileList.end(); iter++)
{
UTIL_Format(path, sizeof(path), "%s/%s", m_File, *iter);
if (!EnterFile(path, error, maxlength))
{
return false;
}
}
return true;
}
bool CGameConfig::EnterFile(const char *file, char *error, size_t maxlength)
{
SMCError err;
SMCStates state = {0, 0};
/* Initialize parse states */ /* Initialize parse states */
m_IgnoreLevel = 0; m_IgnoreLevel = 0;
bShouldBeReadingDefault = true; bShouldBeReadingDefault = true;
m_ParseState = PSTATE_NONE; 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(file, this, &state, error, maxlength)) if ((err=textparsers->ParseSMCFile(path, this, &state, error, maxlength))
!= SMCError_Okay) != SMCError_Okay)
{ {
const char *msg; const char *msg;
msg = textparsers->GetSMCErrorString(err); msg = textparsers->GetSMCErrorString(err);
printf("[SM] Error parsing gameconfig file \"%s\":\n", file); g_Logger.LogError("[SM] Error parsing gameconfig file \"%s\":", path);
printf("[SM] Error %d on line %d, col %d: %s\n", g_Logger.LogError("[SM] Error %d on line %d, col %d: %s",
err, err,
state.line, state.line,
state.col, state.col,
msg ? msg : "Unknown error"); msg ? msg : "Unknown error");
return false;
if (m_ParseState == PSTATE_GAMEDEFS_CUSTOM)
{
//error occurred while parsing a custom section
m_CustomHandler->ReadSMC_ParseEnd(true, true);
m_CustomHandler = NULL;
m_CustomLevel = 0;
}
exit(PARSE_ERROR);
} }
return true; return true;
} }
#if 0
bool CGameConfig::GetOffset(const char *key, int *value) bool CGameConfig::GetOffset(const char *key, int *value)
{ {
void *obj; void *obj;
@ -813,16 +579,108 @@ unsigned int CGameConfig::DecRefCount()
m_RefCount--; m_RefCount--;
return m_RefCount; return m_RefCount;
} }
#endif
const char *CGameConfig::GetKeyValue(const char *key) GameConfigManager::GameConfigManager()
{ {
map<const char*,const char*,cmp_str>::iterator it = m_Keys.find(key); m_pLookup = sm_trie_create();
if (it == m_Keys.end()) return NULL;
return it->second;
} }
list<Offset> CGameConfig::GetOffsets() { return m_Offsets; } GameConfigManager::~GameConfigManager()
list<Sig> CGameConfig::GetSigs() { return m_Sigs; } {
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 (pGameInfo->LoadFromFile(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)
{
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,8 +1,8 @@
/** /**
* vim: set ts=4 sw=4 tw=99 noet: * vim: set ts=4 :
* ============================================================================= * =============================================================================
* SourceMod * SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
* ============================================================================= * =============================================================================
* *
* This program is free software; you can redistribute it and/or modify it under * This program is free software; you can redistribute it and/or modify it under
@ -32,31 +32,28 @@
#ifndef _INCLUDE_SOURCEMOD_CGAMECONFIGS_H_ #ifndef _INCLUDE_SOURCEMOD_CGAMECONFIGS_H_
#define _INCLUDE_SOURCEMOD_CGAMECONFIGS_H_ #define _INCLUDE_SOURCEMOD_CGAMECONFIGS_H_
#include "common_logic.h"
#include <IGameConfigs.h> #include <IGameConfigs.h>
#include <ITextParsers.h> #include <ITextParsers.h>
#include <am-refcounting.h> #include <sh_list.h>
#include <sm_stringhashmap.h> #include "sm_trie.h"
#include <sm_namehashset.h> #include "sm_globals.h"
#include "sm_memtable.h"
using namespace SourceMod; using namespace SourceMod;
using namespace SourceHook;
class SendProp; class SendProp;
class CGameConfig : class CGameConfig :
public ITextListener_SMC, public ITextListener_SMC,
public IGameConfig, public IGameConfig
public ke::Refcounted<CGameConfig>
{ {
friend class GameConfigManager; friend class GameConfigManager;
public: public:
CGameConfig(const char *file, const char *engine = NULL); CGameConfig(const char *file);
~CGameConfig(); ~CGameConfig();
public: public:
bool Reparse(char *error, size_t maxlength); bool Reparse(char *error, size_t maxlength);
bool EnterFile(const char *file, char *error, size_t maxlength);
void SetBaseEngine(const char *engine);
void SetParseEngine(const char *engine);
public: //ITextListener_SMC public: //ITextListener_SMC
SMCResult ReadSMC_NewSection(const SMCStates *states, const char *name); SMCResult ReadSMC_NewSection(const SMCStates *states, const char *name);
SMCResult ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value); SMCResult ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value);
@ -66,23 +63,17 @@ public: //IGameConfig
bool GetOffset(const char *key, int *value); bool GetOffset(const char *key, int *value);
SendProp *GetSendProp(const char *key); SendProp *GetSendProp(const char *key);
bool GetMemSig(const char *key, void **addr); bool GetMemSig(const char *key, void **addr);
bool GetAddress(const char *key, void **addr); public:
public: //NameHashSet void IncRefCount();
static inline bool matches(const char *key, const CGameConfig *value) unsigned int DecRefCount();
{
return strcmp(key, value->m_File) == 0;
}
static inline uint32_t hash(const detail::CharsAndLength &key)
{
return key.hash();
}
private: private:
char m_File[PLATFORM_MAX_PATH]; BaseStringTable *m_pStrings;
char m_CurFile[PLATFORM_MAX_PATH]; char *m_pFile;
StringHashMap<int> m_Offsets; Trie *m_pOffsets;
StringHashMap<SendProp *> m_Props; Trie *m_pProps;
StringHashMap<ke::AString> m_Keys; Trie *m_pKeys;
StringHashMap<void *> m_Sigs; Trie *m_pSigs;
unsigned int m_RefCount;
/* Parse states */ /* Parse states */
int m_ParseState; int m_ParseState;
unsigned int m_IgnoreLevel; unsigned int m_IgnoreLevel;
@ -90,39 +81,7 @@ private:
char m_Prop[64]; char m_Prop[64];
char m_offset[64]; char m_offset[64];
char m_Game[256]; char m_Game[256];
char m_Key[64];
bool bShouldBeReadingDefault; bool bShouldBeReadingDefault;
bool had_game;
bool matched_game;
bool had_engine;
bool matched_engine;
bool matched_platform;
/* Custom Sections */
unsigned int m_CustomLevel;
ITextListener_SMC *m_CustomHandler;
/* Support for reading Addresses */
struct AddressConf
{
char signatureName[64];
int readCount;
int read[8];
bool lastIsOffset;
AddressConf(char *sigName, unsigned sigLength, unsigned readCount, int *read, bool lastIsOffset);
AddressConf() {}
};
char m_Address[64];
char m_AddressSignature[64];
int m_AddressReadCount;
int m_AddressRead[8];
bool m_AddressLastIsOffset;
StringHashMap<AddressConf> m_Addresses;
const char *m_pEngine;
const char *m_pBaseEngine;
}; };
class GameConfigManager : class GameConfigManager :
@ -138,20 +97,13 @@ public: //IGameConfigManager
IGameConfig *ReadHandle(Handle_t hndl, IGameConfig *ReadHandle(Handle_t hndl,
IdentityToken_t *ident, IdentityToken_t *ident,
HandleError *err); HandleError *err);
void AddUserConfigHook(const char *sectionname, ITextListener_SMC *listener);
void RemoveUserConfigHook(const char *sectionname, ITextListener_SMC *listener);
void AcquireLock();
void ReleaseLock();
public: //SMGlobalClass public: //SMGlobalClass
void OnSourceModStartup(bool late); void OnSourceModStartup(bool late);
void OnSourceModAllInitialized(); void OnSourceModAllInitialized();
void OnSourceModAllShutdown(); void OnSourceModAllShutdown();
public:
void RemoveCachedConfig(CGameConfig *config);
private: private:
NameHashSet<CGameConfig *> m_Lookup; List<CGameConfig *> m_cfgs;
public: Trie *m_pLookup;
StringHashMap<ITextListener_SMC *> m_customHandlers;
}; };
extern GameConfigManager g_GameConfigs; extern GameConfigManager g_GameConfigs;

View File

@ -1,171 +0,0 @@
// vim: set ts=4 sw=4 tw=99 noet :
// =============================================================================
// SourceMod
// Copyright (C) 2004-2015 AlliedModders LLC. All rights reserved.
// =============================================================================
//
// This program is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License, version 3.0, as published by the
// Free Software Foundation.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
// details.
//
// You should have received a copy of the GNU General Public License along with
// this program. If not, see <http://www.gnu.org/licenses/>.
//
// As a special exception, AlliedModders LLC gives you permission to link the
// code of this program (as well as its derivative works) to "Half-Life 2," the
// "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
// by the Valve Corporation. You must obey the GNU General Public License in
// all respects for all other code used. Additionally, AlliedModders LLC grants
// this exception to all derivative works. AlliedModders LLC defines further
// exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
// or <http://www.sourcemod.net/license.php>.
#include "GameHooks.h"
#include "sourcemod.h"
#include "ConVarManager.h"
#include "command_args.h"
#include "provider.h"
#if SOURCE_ENGINE >= SE_ORANGEBOX
SH_DECL_HOOK3_void(ICvar, CallGlobalChangeCallbacks, SH_NOATTRIB, false, ConVar *, const char *, float);
#else
SH_DECL_HOOK2_void(ICvar, CallGlobalChangeCallback, SH_NOATTRIB, false, ConVar *, const char *);
#endif
#if SOURCE_ENGINE != SE_DARKMESSIAH
SH_DECL_HOOK5_void(IServerGameDLL, OnQueryCvarValueFinished, SH_NOATTRIB, 0, QueryCvarCookie_t, edict_t *, EQueryCvarValueStatus, const char *, const char *);
SH_DECL_HOOK5_void(IServerPluginCallbacks, OnQueryCvarValueFinished, SH_NOATTRIB, 0, QueryCvarCookie_t, edict_t *, EQueryCvarValueStatus, const char *, const char *);
#endif
#if SOURCE_ENGINE >= SE_ORANGEBOX
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);
GameHooks::GameHooks()
: client_cvar_query_mode_(ClientCvarQueryMode::Unavailable),
last_command_client_(-1)
{
}
void GameHooks::Start()
{
// Hook ICvar::CallGlobalChangeCallbacks.
#if SOURCE_ENGINE >= SE_ORANGEBOX
hooks_ += SH_ADD_HOOK(ICvar, CallGlobalChangeCallbacks, icvar, SH_STATIC(OnConVarChanged), false);
#else
hooks_ += SH_ADD_HOOK(ICvar, CallGlobalChangeCallback, icvar, SH_STATIC(OnConVarChanged), false);
#endif
// Episode 2 has this function by default, but the older versions do not.
#if SOURCE_ENGINE == SE_EPISODEONE
if (g_SMAPI->GetGameDLLVersion() >= 6) {
hooks_ += SH_ADD_HOOK(IServerGameDLL, OnQueryCvarValueFinished, gamedll, SH_MEMBER(this, &GameHooks::OnQueryCvarValueFinished), false);
client_cvar_query_mode_ = ClientCvarQueryMode::DLL;
}
#endif
hooks_ += SH_ADD_HOOK(IServerGameClients, SetCommandClient, serverClients, SH_MEMBER(this, &GameHooks::SetCommandClient), false);
}
void GameHooks::OnVSPReceived()
{
if (client_cvar_query_mode_ != ClientCvarQueryMode::Unavailable)
return;
if (g_SMAPI->GetSourceEngineBuild() == SOURCE_ENGINE_ORIGINAL || vsp_version < 2)
return;
#if SOURCE_ENGINE != SE_DARKMESSIAH
hooks_ += SH_ADD_HOOK(IServerPluginCallbacks, OnQueryCvarValueFinished, vsp_interface, SH_MEMBER(this, &GameHooks::OnQueryCvarValueFinished), false);
client_cvar_query_mode_ = ClientCvarQueryMode::VSP;
#endif
}
void GameHooks::Shutdown()
{
for (size_t i = 0; i < hooks_.length(); i++)
SH_REMOVE_HOOK_ID(hooks_[i]);
hooks_.clear();
client_cvar_query_mode_ = ClientCvarQueryMode::Unavailable;
}
#if SOURCE_ENGINE >= SE_ORANGEBOX
void GameHooks::OnConVarChanged(ConVar *pConVar, const char *oldValue, float flOldValue)
#else
void GameHooks::OnConVarChanged(ConVar *pConVar, const char *oldValue)
#endif
{
#if SOURCE_ENGINE < SE_ORANGEBOX
float flOldValue = atof(oldValue);
#endif
g_ConVarManager.OnConVarChanged(pConVar, oldValue, flOldValue);
}
#if SOURCE_ENGINE != SE_DARKMESSIAH
void GameHooks::OnQueryCvarValueFinished(QueryCvarCookie_t cookie, edict_t *pPlayer, EQueryCvarValueStatus result,
const char *cvarName, const char *cvarValue){
int client = IndexOfEdict(pPlayer);
# if SOURCE_ENGINE == SE_CSGO
if (g_Players.HandleConVarQuery(cookie, client, result, cvarName, cvarValue))
return;
# endif
g_ConVarManager.OnClientQueryFinished(cookie, client, result, cvarName, cvarValue);
}
#endif
ke::RefPtr<CommandHook>
GameHooks::AddCommandHook(ConCommand *cmd, const CommandHook::Callback &callback)
{
return new CommandHook(cmd, callback, false);
}
ke::RefPtr<CommandHook>
GameHooks::AddPostCommandHook(ConCommand *cmd, const CommandHook::Callback &callback)
{
return new CommandHook(cmd, callback, true);
}
void GameHooks::SetCommandClient(int client)
{
last_command_client_ = client + 1;
}
CommandHook::CommandHook(ConCommand *cmd, const Callback &callback, bool post)
: hook_id_(0),
callback_(callback)
{
hook_id_ = SH_ADD_HOOK(ConCommand, Dispatch, cmd, SH_MEMBER(this, &CommandHook::Dispatch), post);
}
CommandHook::~CommandHook()
{
if (hook_id_)
SH_REMOVE_HOOK_ID(hook_id_);
}
void CommandHook::Dispatch(DISPATCH_ARGS)
{
DISPATCH_PROLOGUE;
EngineArgs args(command);
AddRef();
bool rval = callback_(sCoreProviderImpl.CommandClient(), &args);
Release();
if (rval)
RETURN_META(MRES_SUPERCEDE);
}
void CommandHook::Zap()
{
hook_id_ = 0;
}

View File

@ -1,133 +0,0 @@
// vim: set ts=4 sw=4 tw=99 noet :
// =============================================================================
// SourceMod
// Copyright (C) 2004-2015 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>.
#ifndef _INCLUDE_SOURCEMOD_PROVIDER_GAME_HOOKS_H_
#define _INCLUDE_SOURCEMOD_PROVIDER_GAME_HOOKS_H_
// Needed for CEntityIndex, edict_t, etc.
#include <stdint.h>
#include <stddef.h>
#include <eiface.h>
#include <iserverplugin.h>
#include <amtl/am-refcounting.h>
#include <amtl/am-vector.h>
#include <amtl/am-function.h>
class ConVar;
class CCommand;
struct CCommandContext;
#if SOURCE_ENGINE >= SE_ORANGEBOX
# define DISPATCH_ARGS const CCommand &command
# define DISPATCH_PROLOGUE
#else
# define DISPATCH_ARGS
# define DISPATCH_PROLOGUE CCommand command
#endif
namespace SourceMod {
// Describes the mechanism in which client cvar queries are implemented.
enum class ClientCvarQueryMode {
Unavailable,
DLL,
VSP
};
class ICommandArgs;
class CommandHook : public ke::Refcounted<CommandHook>
{
public:
// return false to RETURN_META(MRES_IGNORED), or true to SUPERCEDE.
typedef ke::Lambda<bool(int, const ICommandArgs *)> Callback;
public:
CommandHook(ConCommand *cmd, const Callback &callback, bool post);
~CommandHook();
void Dispatch(DISPATCH_ARGS);
void Zap();
private:
int hook_id_;
Callback callback_;
};
class GameHooks
{
public:
GameHooks();
void Start();
void Shutdown();
void OnVSPReceived();
ClientCvarQueryMode GetClientCvarQueryMode() const {
return client_cvar_query_mode_;
}
public:
ke::RefPtr<CommandHook> AddCommandHook(ConCommand *cmd, const CommandHook::Callback &callback);
ke::RefPtr<CommandHook> AddPostCommandHook(ConCommand *cmd, const CommandHook::Callback &callback);
int CommandClient() const {
return last_command_client_;
}
private:
// Static callback that Valve's ConVar object executes when the convar's value changes.
#if SOURCE_ENGINE >= SE_ORANGEBOX
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.
#if SOURCE_ENGINE != SE_DARKMESSIAH
void OnQueryCvarValueFinished(QueryCvarCookie_t cookie, edict_t *pPlayer, EQueryCvarValueStatus result,
const char *cvarName, const char *cvarValue);
#endif
void SetCommandClient(int client);
private:
class HookList : public ke::Vector<int>
{
public:
HookList &operator += (int hook_id) {
this->append(hook_id);
return *this;
}
};
HookList hooks_;
ClientCvarQueryMode client_cvar_query_mode_;
int last_command_client_;
};
} // namespace SourceMod
#endif // _INCLUDE_SOURCEMOD_PROVIDER_GAME_HOOKS_H_

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,8 @@
/** /**
* vim: set ts=4 sw=4 tw=99 noet : * vim: set ts=4 :
* ============================================================================= * =============================================================================
* SourceMod * SourceMod
* Copyright (C) 2004-2016 AlliedModders LLC. All rights reserved. * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
* ============================================================================= * =============================================================================
* *
* This program is free software; you can redistribute it and/or modify it under * This program is free software; you can redistribute it and/or modify it under
@ -35,24 +35,14 @@
#include <sh_list.h> #include <sh_list.h>
#include <sh_string.h> #include <sh_string.h>
#include <sh_tinyhash.h> #include <sh_tinyhash.h>
#include <am-utility.h> #include <sm_trie_tpl.h>
#include <am-hashset.h> #include "sm_trie.h"
#include <am-hashmap.h>
#include <sm_stringhashmap.h>
#include <sm_namehashset.h>
#include "sm_globals.h" #include "sm_globals.h"
#include "sm_queue.h" #include "sm_queue.h"
#include <IGameHelpers.h> #include <IGameHelpers.h>
#include <KeyValues.h> #include <KeyValues.h>
#include <server_class.h>
#include <datamap.h>
#include <ihandleentity.h>
#include <tier0/icommandline.h>
#include <string_t.h>
namespace SourceMod { class CCommand;
class ICommandArgs;
} // namespace SourceMod
using namespace SourceHook; using namespace SourceHook;
using namespace SourceMod; using namespace SourceMod;
@ -60,79 +50,18 @@ using namespace SourceMod;
#define HUD_PRINTTALK 3 #define HUD_PRINTTALK 3
#define HUD_PRINTCENTER 4 #define HUD_PRINTCENTER 4
#if defined _WIN32
#define SOURCE_BIN_PREFIX ""
#define SOURCE_BIN_SUFFIX ""
#define SOURCE_BIN_EXT ".dll"
#elif defined __APPLE__
#define SOURCE_BIN_PREFIX ""
#define SOURCE_BIN_SUFFIX ""
#define SOURCE_BIN_EXT ".dylib"
#elif defined __linux__
#if SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_TF2 \
|| SOURCE_ENGINE == SE_SDK2013 || SOURCE_ENGINE == SE_LEFT4DEAD2 || SOURCE_ENGINE == SE_NUCLEARDAWN \
|| SOURCE_ENGINE == SE_BMS || SOURCE_ENGINE == SE_INSURGENCY || SOURCE_ENGINE == SE_DOI
#define SOURCE_BIN_PREFIX "lib"
#define SOURCE_BIN_SUFFIX "_srv"
#elif SOURCE_ENGINE >= SE_LEFT4DEAD
#define SOURCE_BIN_PREFIX "lib"
#define SOURCE_BIN_SUFFIX ""
#else
#define SOURCE_BIN_PREFIX ""
#define SOURCE_BIN_SUFFIX "_i486"
#endif
#define SOURCE_BIN_EXT ".so"
#endif
#define FORMAT_SOURCE_BIN_NAME(basename) \
(SOURCE_BIN_PREFIX basename SOURCE_BIN_SUFFIX SOURCE_BIN_EXT)
struct DataTableInfo struct DataTableInfo
{ {
struct SendPropPolicy
{
static inline bool matches(const char *name, const sm_sendprop_info_t &info)
{
return strcmp(name, info.prop->GetName()) == 0;
}
static inline uint32_t hash(const detail::CharsAndLength &key)
{
return key.hash();
}
};
static inline bool matches(const char *name, const DataTableInfo *info)
{
return strcmp(name, info->sc->GetName()) == 0;
}
static inline uint32_t hash(const detail::CharsAndLength &key)
{
return key.hash();
}
DataTableInfo(ServerClass *sc)
: sc(sc)
{
}
ServerClass *sc; ServerClass *sc;
NameHashSet<sm_sendprop_info_t, SendPropPolicy> lookup; KTrie<sm_sendprop_info_t> lookup;
}; };
struct DataMapCachePolicy struct DataMapTrie
{ {
static inline bool matches(const char *name, const sm_datatable_info_t &info) DataMapTrie() : trie(NULL) {}
{ Trie *trie;
return strcmp(name, info.prop->fieldName) == 0;
}
static inline uint32_t hash(const detail::CharsAndLength &key)
{
return key.hash();
}
}; };
typedef NameHashSet<sm_datatable_info_t, DataMapCachePolicy> DataMapCache;
struct DelayedFakeCliCmd struct DelayedFakeCliCmd
{ {
String cmd; String cmd;
@ -142,153 +71,59 @@ struct DelayedFakeCliCmd
struct CachedCommandInfo struct CachedCommandInfo
{ {
const ICommandArgs *args; const CCommand *args;
#if SOURCE_ENGINE <= SE_DARKMESSIAH #if !defined ORANGEBOX_BUILD
char cmd[300]; char cmd[300];
#endif #endif
}; };
struct DelayedKickInfo
{
int userid;
int client;
char buffer[384];
};
// copy from game/shared/entitylist_base.h
class CEntInfo
{
public:
IHandleEntity *m_pEntity;
int m_SerialNumber;
CEntInfo *m_pPrev;
CEntInfo *m_pNext;
#if SOURCE_ENGINE >= SE_PORTAL2
string_t m_iName;
string_t m_iClassName;
#endif
};
// Corresponds to TF2's eFindMapResult in eiface.h
// Not yet in other games, but eventually in others on same branch.
enum class SMFindMapResult : cell_t {
Found,
NotFound,
FuzzyMatch,
NonCanonical,
PossiblyAvailable
};
class CHalfLife2 : class CHalfLife2 :
public SMGlobalClass, public SMGlobalClass,
public IGameHelpers public IGameHelpers
{ {
friend class AutoEnterCommand;
public: public:
CHalfLife2(); CHalfLife2();
~CHalfLife2(); ~CHalfLife2();
public: public:
void OnSourceModStartup(bool late); void OnSourceModStartup(bool late);
void OnSourceModAllInitialized(); void OnSourceModAllInitialized();
void OnSourceModAllInitialized_Post();
/*void OnSourceModAllShutdown();*/ /*void OnSourceModAllShutdown();*/
ConfigResult OnSourceModConfigChanged(const char *key, const char *value,
ConfigSource source, char *error, size_t maxlength) override;
public: //IGameHelpers public: //IGameHelpers
SendProp *FindInSendTable(const char *classname, const char *offset); SendProp *FindInSendTable(const char *classname, const char *offset);
bool FindSendPropInfo(const char *classname, const char *offset, sm_sendprop_info_t *info); bool FindSendPropInfo(const char *classname, const char *offset, sm_sendprop_info_t *info);
datamap_t *GetDataMap(CBaseEntity *pEntity); datamap_t *GetDataMap(CBaseEntity *pEntity);
ServerClass *FindServerClass(const char *classname); ServerClass *FindServerClass(const char *classname);
typedescription_t *FindInDataMap(datamap_t *pMap, const char *offset); typedescription_t *FindInDataMap(datamap_t *pMap, const char *offset);
bool FindDataMapInfo(datamap_t *pMap, const char *offset, sm_datatable_info_t *pDataTable);
void SetEdictStateChanged(edict_t *pEdict, unsigned short offset); void SetEdictStateChanged(edict_t *pEdict, unsigned short offset);
bool TextMsg(int client, int dest, const char *msg); bool TextMsg(int client, int dest, const char *msg);
bool HintTextMsg(int client, const char *msg); bool HintTextMsg(int client, const char *msg);
bool HintTextMsg(cell_t *players, int count, const char *msg);
bool ShowVGUIMenu(int client, const char *name, KeyValues *data, bool show); bool ShowVGUIMenu(int client, const char *name, KeyValues *data, bool show);
bool IsLANServer(); bool IsLANServer();
bool KVLoadFromFile(KeyValues *kv, IBaseFileSystem *filesystem, const char *resourceName, const char *pathID = NULL);
edict_t *EdictOfIndex(int index);
int IndexOfEdict(edict_t *pEnt);
edict_t *GetHandleEntity(CBaseHandle &hndl);
void SetHandleEntity(CBaseHandle &hndl, edict_t *pEnt);
const char *GetCurrentMap();
void ServerCommand(const char *buffer);
CBaseEntity *ReferenceToEntity(cell_t entRef);
cell_t EntityToReference(CBaseEntity *pEntity);
cell_t IndexToReference(int entIndex);
int ReferenceToIndex(cell_t entRef);
cell_t ReferenceToBCompatRef(cell_t entRef);
CEntInfo *LookupEntity(int entIndex);
cell_t EntityToBCompatRef(CBaseEntity *pEntity);
void *GetGlobalEntityList();
int GetSendPropOffset(SendProp *prop);
ICommandLine *GetValveCommandLine();
const char *GetEntityClassname(edict_t *pEdict);
const char *GetEntityClassname(CBaseEntity *pEntity);
bool IsMapValid(const char *map);
SMFindMapResult FindMap(char *pMapName, size_t nMapNameMax);
SMFindMapResult FindMap(const char *pMapName, char *pFoundMap = NULL, size_t nMapNameMax = 0);
bool GetMapDisplayName(const char *pMapName, char *pDisplayname, size_t nMapNameMax);
#if SOURCE_ENGINE >= SE_ORANGEBOX
string_t AllocPooledString(const char *pszValue);
#endif
bool GetServerSteam3Id(char *pszOut, size_t len) const override;
uint64_t GetServerSteamId64() const override;
public: public:
void AddToFakeCliCmdQueue(int client, int userid, const char *cmd); void AddToFakeCliCmdQueue(int client, int userid, const char *cmd);
void ProcessFakeCliCmdQueue(); void ProcessFakeCliCmdQueue();
public: public:
const ICommandArgs *PeekCommandStack(); void PushCommandStack(const CCommand *cmd);
const char *CurrentCommandName();
void AddDelayedKick(int client, int userid, const char *msg);
void ProcessDelayedKicks();
private:
void PushCommandStack(const ICommandArgs *cmd);
void PopCommandStack(); void PopCommandStack();
const CCommand *PeekCommandStack();
const char *CurrentCommandName();
#if !defined METAMOD_PLAPI_VERSION
bool IsOriginalEngine();
#endif
private:
DataTableInfo *_FindServerClass(const char *classname); DataTableInfo *_FindServerClass(const char *classname);
private: private:
void InitLogicalEntData(); Trie *m_pClasses;
void InitCommandLine(); List<DataTableInfo *> m_Tables;
private: THash<datamap_t *, DataMapTrie> m_Maps;
typedef ke::HashMap<datamap_t *, DataMapCache *, ke::PointerPolicy<datamap_t> > DataTableMap;
NameHashSet<DataTableInfo *> m_Classes;
DataTableMap m_Maps;
int m_MsgTextMsg; int m_MsgTextMsg;
int m_HinTextMsg; int m_HinTextMsg;
int m_SayTextMsg;
int m_VGUIMenu; int m_VGUIMenu;
Queue<DelayedFakeCliCmd *> m_CmdQueue; Queue<DelayedFakeCliCmd *> m_CmdQueue;
CStack<DelayedFakeCliCmd *> m_FreeCmds; CStack<DelayedFakeCliCmd *> m_FreeCmds;
CStack<CachedCommandInfo> m_CommandStack; CStack<CachedCommandInfo> m_CommandStack;
Queue<DelayedKickInfo> m_DelayedKicks;
void *m_pGetCommandLine;
#if SOURCE_ENGINE == SE_CSGO
public:
bool CanSetCSGOEntProp(const char *pszPropName)
{
return !m_bFollowCSGOServerGuidelines || !m_CSGOBadList.has(pszPropName);
}
private:
ke::HashSet<ke::AString, detail::StringHashMapPolicy> m_CSGOBadList;
bool m_bFollowCSGOServerGuidelines = true;
#endif
}; };
extern CHalfLife2 g_HL2; extern CHalfLife2 g_HL2;
bool IndexToAThings(cell_t, CBaseEntity **pEntData, edict_t **pEdictData);
class AutoEnterCommand
{
public:
AutoEnterCommand(const ICommandArgs *args) {
g_HL2.PushCommandStack(args);
}
~AutoEnterCommand() {
g_HL2.PopCommandStack();
}
};
#endif //_INCLUDE_SOURCEMOD_CHALFLIFE2_H_ #endif //_INCLUDE_SOURCEMOD_CHALFLIFE2_H_

View File

@ -1,8 +1,8 @@
/** /**
* vim: set ts=4 sw=4 : * vim: set ts=4 :
* ============================================================================= * =============================================================================
* SourceMod * SourceMod
* Copyright (C) 2004-2009 AlliedModders LLC. All rights reserved. * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
* ============================================================================= * =============================================================================
* *
* This program is free software; you can redistribute it and/or modify it under * This program is free software; you can redistribute it and/or modify it under
@ -34,37 +34,479 @@
#include "sourcemm_api.h" #include "sourcemm_api.h"
#include "sm_stringutil.h" #include "sm_stringutil.h"
#include "Logger.h" #include "Logger.h"
#include "systems/LibrarySys.h"
#include "TimerSys.h" #include "TimerSys.h"
#include "logic_bridge.h" #include "sm_version.h"
#include <sourcemod_version.h>
#include <bridge/include/IProviderCallbacks.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; bool g_in_game_log_hook = false;
static LoggerCore g_LoggerCore;
SH_DECL_HOOK1_void(IVEngineServer, LogPrint, SH_NOATTRIB, false, const char *);
static void HookLogPrint(const char *message)
{
g_in_game_log_hook = true;
bool stopped = logicore.callbacks->OnLogPrint(message);
g_in_game_log_hook = false;
if (stopped)
RETURN_META(MRES_SUPERCEDE);
}
void LoggerCore::OnSourceModStartup(bool late)
{
SH_ADD_HOOK(IVEngineServer, LogPrint, engine, SH_STATIC(HookLogPrint), false);
}
void LoggerCore::OnSourceModAllShutdown()
{
SH_REMOVE_HOOK(IVEngineServer, LogPrint, engine, SH_STATIC(HookLogPrint), false);
}
void Engine_LogPrintWrapper(const char *msg) void Engine_LogPrintWrapper(const char *msg)
{ {
if (g_in_game_log_hook) if (g_in_game_log_hook)

View File

@ -2,7 +2,7 @@
* vim: set ts=4 : * vim: set ts=4 :
* ============================================================================= * =============================================================================
* SourceMod * SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
* ============================================================================= * =============================================================================
* *
* This program is free software; you can redistribute it and/or modify it under * This program is free software; you can redistribute it and/or modify it under
@ -38,13 +38,69 @@
using namespace SourceHook; using namespace SourceHook;
class LoggerCore : public SMGlobalClass enum LogType
{ {
LogType_Normal,
LogType_Error
};
enum LoggingMode
{
LoggingMode_Daily,
LoggingMode_PerMap,
LoggingMode_Game
};
class Logger : public SMGlobalClass
{
public:
Logger() : m_Mode(LoggingMode_Daily), m_ErrMapStart(false),
m_Active(false), m_DelayedStart(false), m_DailyPrintHdr(false),
m_InitialState(true)
{
}
public: //SMGlobalClass public: //SMGlobalClass
ConfigResult OnSourceModConfigChanged(const char *key,
const char *value,
ConfigSource source,
char *error,
size_t maxlength);
void OnSourceModStartup(bool late); void OnSourceModStartup(bool late);
void OnSourceModAllShutdown(); 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); void Engine_LogPrintWrapper(const char *msg);
extern bool g_in_game_log_hook;
extern Logger g_Logger;
#endif // _INCLUDE_SOURCEMOD_CLOGGER_H_ #endif // _INCLUDE_SOURCEMOD_CLOGGER_H_

133
core/Makefile Normal file
View File

@ -0,0 +1,133 @@
#(C)2004-2008 Metamod:Source Development Team
# Makefile written by David "BAILOPAN" Anderson
#Local paths
HL2SDK_ORIG = ../../hl2sdk
HL2SDK_OB = ../../hl2sdk-ob
SOURCEMM14 = ../../sourcemm-1.4
SOURCEMM16 = ../../sourcemm-1.6
SRCDS_BASE = ~/srcds
SMSDK = ..
#Project options
OPT_FLAGS = -O3 -funroll-loops -s -pipe -fno-strict-aliasing
GCC4_FLAGS = -fvisibility=hidden
GCC4_CPP_FLAGS = -fvisibility-inlines-hidden
DEBUG_FLAGS = -g -ggdb3
CPP = gcc-4.1
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
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
OBJECTS += systems/ExtensionSys.cpp systems/ForwardSys.cpp systems/HandleSys.cpp \
systems/LibrarySys.cpp systems/PluginInfoDatabase.cpp systems/PluginSys.cpp \
systems/ShareSys.cpp vm/sp_vm_basecontext.cpp vm/sp_vm_function.cpp
OBJECTS += thread/ThreadWorker.cpp thread/BaseWorker.cpp thread/PosixThreads.cpp ThreadSupport.cpp
OBJECTS_C = zlib/adler32.c zlib/compress.c zlib/crc32.c zlib/deflate.c zlib/gzio.c \
zlib/infback.c zlib/inffast.c zlib/inflate.c zlib/inftrees.c zlib/trees.c \
zlib/uncompr.c zlib/zutil.c
OBJECTS_SM16 = vm/sp_vm_engine.cpp
ifeq "$(ENGINE)" "original"
HL2SDK = $(HL2SDK_ORIG)
HL2PUB = $(HL2SDK_ORIG)/public
HL2LIB = $(HL2SDK)/linux_sdk
METAMOD = $(SOURCEMM14)
INCLUDE += -I$(HL2PUB)/dlls
SRCDS = $(SRCDS_BASE)
BINARY = sourcemod.1.ep1.so
endif
ifeq "$(ENGINE)" "orangebox"
HL2SDK = $(HL2SDK_OB)
HL2PUB = $(HL2SDK_OB)/public
HL2LIB = $(HL2SDK)/linux_sdk
CFLAGS += -DORANGEBOX_BUILD
METAMOD = $(SOURCEMM16)
INCLUDE += -I$(HL2PUB)/game/server
SRCDS = $(SRCDS_BASE)/orangebox
BINARY = sourcemod.2.ep2.so
endif
ifeq "$(BINARY)" ""
echo "You must supply ENGINE=orangebox or ENGINE=original"
false
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 -I$(SMSDK)/public/extensions
INCLUDE += -I. -I.. -I$(HL2PUB) -I$(HL2PUB)/dlls -I$(HL2PUB)/engine -I$(HL2PUB)/tier0 -I$(HL2PUB)/tier1 \
-I$(HL2PUB)/vstdlib -I$(HL2SDK)/tier1 -I$(METAMOD) -I$(METAMOD)/sourcehook -I$(METAMOD)/sourcemm \
-I$(HL2PUB)/mathlib -Isystems $(INCLUDE_SMSDK)
SM16_INCLUDE = -I. -I.. -I$(SOURCEMM16)/sourcehook $(INCLUDE_SMSDK)
ifeq "$(DEBUG)" "true"
BIN_DIR = Debug.$(ENGINE)
CFLAGS += $(DEBUG_FLAGS)
else
BIN_DIR = Release.$(ENGINE)
CFLAGS += $(OPT_FLAGS)
endif
GCC_VERSION := $(shell $(CPP) -dumpversion >&1 | cut -b1)
CFLAGS += -D_LINUX -DNDEBUG -Dstricmp=strcasecmp -D_stricmp=strcasecmp -D_strnicmp=strncasecmp \
-Dstrnicmp=strncasecmp -D_snprintf=snprintf -D_vsnprintf=vsnprintf -D_alloca=alloca \
-Dstrcmpi=strcasecmp -Wall -Wno-uninitialized -Werror -mfpmath=sse -msse \
-DSOURCEMOD_BUILD -DSM_DEFAULT_THREADER -m32
CPPFLAGS = -Wno-non-virtual-dtor -fno-exceptions -fno-rtti
ifeq "$(GCC_VERSION)" "4"
CFLAGS += $(GCC4_FLAGS)
CPPFLAGS += $(GCC4_CPP_FLAGS)
endif
OBJ_LINUX := $(OBJECTS:%.cpp=$(BIN_DIR)/%.ox)
OBJ_LINUX_C := $(OBJECTS_C:%.c=$(BIN_DIR)/%.oc)
OBJ_LINUX_SM16 := $(OBJECTS_SM16:%.cpp=$(BIN_DIR)/%.ok)
$(BIN_DIR)/%.ox: %.cpp
$(CPP) $(INCLUDE) $(CFLAGS) $(CPPFLAGS) -o $@ -c $<
$(BIN_DIR)/%.oc: %.c
$(CPP) $(INCLUDE) $(CFLAGS) -o $@ -c $<
$(BIN_DIR)/%.ok: %.cpp
$(CPP) $(SM16_INCLUDE) $(CFLAGS) $(CPPFLAGS) -o $@ -c $<
all:
mkdir -p $(BIN_DIR)/systems
mkdir -p $(BIN_DIR)/vm
mkdir -p $(BIN_DIR)/zlib
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
sourcemod: $(OBJ_LINUX) $(OBJ_LINUX_C) $(OBJ_LINUX_SM16)
$(CPP) $(OBJ_LINUX) $(OBJ_LINUX_C) $(OBJ_LINUX_SM16) $(LINK) -m32 -shared -ldl -lm -o$(BIN_DIR)/$(BINARY)
default: all
clean:
rm -rf $(BIN_DIR)/*.ox
rm -rf $(BIN_DIR)/systems/*.ox
rm -rf $(BIN_DIR)/zlib/*.oc
rm -rf $(BIN_DIR)/vm/*.ox
rm -rf $(BIN_DIR)/thread/*.ox
rm -rf $(BIN_DIR)/$(BINARY)

220
core/MemoryUtils.cpp Normal file
View File

@ -0,0 +1,220 @@
/**
* vim: set ts=4 :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2007 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,8 +1,8 @@
/** /**
* vim: set ts=4 sw=4 tw=99 noet : * vim: set ts=4 :
* ============================================================================= * =============================================================================
* SourceMod * SourceMod
* Copyright (C) 2004-2011 AlliedModders LLC. All rights reserved. * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
* ============================================================================= * =============================================================================
* *
* This program is free software; you can redistribute it and/or modify it under * This program is free software; you can redistribute it and/or modify it under
@ -25,64 +25,34 @@
* this exception to all derivative works. AlliedModders LLC defines further * this exception to all derivative works. AlliedModders LLC defines further
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
* or <http://www.sourcemod.net/license.php>. * or <http://www.sourcemod.net/license.php>.
*
* Version: $Id$
*/ */
#ifndef _INCLUDE_SOURCEMOD_MEMORYUTILS_H_ #ifndef _INCLUDE_SOURCEMOD_MEMORYUTILS_H_
#define _INCLUDE_SOURCEMOD_MEMORYUTILS_H_ #define _INCLUDE_SOURCEMOD_MEMORYUTILS_H_
#include "common_logic.h"
#include <IMemoryUtils.h> #include <IMemoryUtils.h>
#if defined PLATFORM_LINUX || defined PLATFORM_APPLE #include "sm_globals.h"
#include <sh_vector.h>
#include "sm_symtable.h"
using namespace SourceHook;
#endif
using namespace SourceMod; using namespace SourceMod;
#ifdef PLATFORM_APPLE
#include <CoreServices/CoreServices.h>
#endif
struct DynLibInfo struct DynLibInfo
{ {
void *baseAddress; void *baseAddress;
size_t memorySize; size_t memorySize;
}; };
#if defined PLATFORM_LINUX || defined PLATFORM_APPLE
struct LibSymbolTable
{
SymbolTable table;
uintptr_t lib_base;
uint32_t last_pos;
};
#endif
class MemoryUtils : class MemoryUtils :
public IMemoryUtils, public IMemoryUtils,
public SMGlobalClass public SMGlobalClass
{ {
public:
MemoryUtils();
~MemoryUtils();
public: // SMGlobalClass public: // SMGlobalClass
void OnSourceModAllInitialized(); void OnSourceModAllInitialized();
public: // IMemoryUtils public: // IMemoryUtils
void *FindPattern(const void *libPtr, const char *pattern, size_t len); void *FindPattern(const void *libPtr, const char *pattern, size_t len);
void *ResolveSymbol(void *handle, const char *symbol);
public:
bool GetLibraryInfo(const void *libPtr, DynLibInfo &lib);
#if defined PLATFORM_LINUX || defined PLATFORM_APPLE
private: private:
CVector<LibSymbolTable *> m_SymTables; bool GetLibraryInfo(const void *libPtr, DynLibInfo &lib);
#ifdef PLATFORM_APPLE
struct dyld_all_image_infos *m_ImageList;
SInt32 m_OSXMajor;
SInt32 m_OSXMinor;
#endif
#endif
}; };
extern MemoryUtils g_MemUtils; extern MemoryUtils g_MemUtils;

View File

@ -2,7 +2,7 @@
* vim: set ts=4 : * vim: set ts=4 :
* ============================================================================= * =============================================================================
* SourceMod * SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
* ============================================================================= * =============================================================================
* *
* This program is free software; you can redistribute it and/or modify it under * This program is free software; you can redistribute it and/or modify it under
@ -38,8 +38,9 @@
#include "sourcemm_api.h" #include "sourcemm_api.h"
#include "PlayerManager.h" #include "PlayerManager.h"
#include "MenuStyle_Valve.h" #include "MenuStyle_Valve.h"
#include "ShareSys.h"
#include "HandleSys.h"
#include "sourcemm_api.h" #include "sourcemm_api.h"
#include "logic_bridge.h"
MenuManager g_Menus; MenuManager g_Menus;
VoteMenuHandler s_VoteHandler; VoteMenuHandler s_VoteHandler;
@ -54,24 +55,24 @@ MenuManager::MenuManager()
void MenuManager::OnSourceModAllInitialized() void MenuManager::OnSourceModAllInitialized()
{ {
sharesys->AddInterface(NULL, this); g_ShareSys.AddInterface(NULL, this);
HandleAccess access; HandleAccess access;
handlesys->InitAccessDefaults(NULL, &access); g_HandleSys.InitAccessDefaults(NULL, &access);
/* Deny cloning to menus */ /* Deny cloning to menus */
access.access[HandleAccess_Clone] = HANDLE_RESTRICT_OWNER|HANDLE_RESTRICT_IDENTITY; access.access[HandleAccess_Clone] = HANDLE_RESTRICT_OWNER|HANDLE_RESTRICT_IDENTITY;
m_MenuType = handlesys->CreateType("IBaseMenu", this, 0, NULL, &access, g_pCoreIdent, NULL); m_MenuType = g_HandleSys.CreateType("IBaseMenu", this, 0, NULL, &access, g_pCoreIdent, NULL);
/* Also deny deletion to styles */ /* Also deny deletion to styles */
access.access[HandleAccess_Delete] = HANDLE_RESTRICT_OWNER|HANDLE_RESTRICT_IDENTITY; access.access[HandleAccess_Delete] = HANDLE_RESTRICT_OWNER|HANDLE_RESTRICT_IDENTITY;
m_StyleType = handlesys->CreateType("IMenuStyle", this, 0, NULL, &access, g_pCoreIdent, NULL); m_StyleType = g_HandleSys.CreateType("IMenuStyle", this, 0, NULL, &access, g_pCoreIdent, NULL);
} }
void MenuManager::OnSourceModAllShutdown() void MenuManager::OnSourceModAllShutdown()
{ {
handlesys->RemoveType(m_MenuType, g_pCoreIdent); g_HandleSys.RemoveType(m_MenuType, g_pCoreIdent);
handlesys->RemoveType(m_StyleType, g_pCoreIdent); g_HandleSys.RemoveType(m_StyleType, g_pCoreIdent);
} }
void MenuManager::OnHandleDestroy(HandleType_t type, void *object) void MenuManager::OnHandleDestroy(HandleType_t type, void *object)
@ -110,7 +111,7 @@ Handle_t MenuManager::CreateMenuHandle(IBaseMenu *menu, IdentityToken_t *pOwner)
return BAD_HANDLE; return BAD_HANDLE;
} }
return handlesys->CreateHandle(m_MenuType, menu, pOwner, g_pCoreIdent, NULL); return g_HandleSys.CreateHandle(m_MenuType, menu, pOwner, g_pCoreIdent, NULL);
} }
Handle_t MenuManager::CreateStyleHandle(IMenuStyle *style) Handle_t MenuManager::CreateStyleHandle(IMenuStyle *style)
@ -120,7 +121,7 @@ Handle_t MenuManager::CreateStyleHandle(IMenuStyle *style)
return BAD_HANDLE; return BAD_HANDLE;
} }
return handlesys->CreateHandle(m_StyleType, style, g_pCoreIdent, g_pCoreIdent, NULL); return g_HandleSys.CreateHandle(m_StyleType, style, g_pCoreIdent, g_pCoreIdent, NULL);
} }
HandleError MenuManager::ReadMenuHandle(Handle_t handle, IBaseMenu **menu) HandleError MenuManager::ReadMenuHandle(Handle_t handle, IBaseMenu **menu)
@ -130,7 +131,7 @@ HandleError MenuManager::ReadMenuHandle(Handle_t handle, IBaseMenu **menu)
sec.pIdentity = g_pCoreIdent; sec.pIdentity = g_pCoreIdent;
sec.pOwner = NULL; sec.pOwner = NULL;
return handlesys->ReadHandle(handle, m_MenuType, &sec, (void **)menu); return g_HandleSys.ReadHandle(handle, m_MenuType, &sec, (void **)menu);
} }
HandleError MenuManager::ReadStyleHandle(Handle_t handle, IMenuStyle **style) HandleError MenuManager::ReadStyleHandle(Handle_t handle, IMenuStyle **style)
@ -140,7 +141,7 @@ HandleError MenuManager::ReadStyleHandle(Handle_t handle, IMenuStyle **style)
sec.pIdentity = g_pCoreIdent; sec.pIdentity = g_pCoreIdent;
sec.pOwner = g_pCoreIdent; sec.pOwner = g_pCoreIdent;
return handlesys->ReadHandle(handle, m_StyleType, &sec, (void **)style); return g_HandleSys.ReadHandle(handle, m_StyleType, &sec, (void **)style);
} }
bool MenuManager::SetDefaultStyle(IMenuStyle *style) bool MenuManager::SetDefaultStyle(IMenuStyle *style)
@ -229,7 +230,6 @@ IMenuPanel *MenuManager::RenderMenu(int client, menu_states_t &md, ItemOrder ord
unsigned int pgn = menu->GetPagination(); unsigned int pgn = menu->GetPagination();
unsigned int maxItems = style->GetMaxPageItems(); unsigned int maxItems = style->GetMaxPageItems();
bool exitButton = (menu->GetMenuOptionFlags() & MENUFLAG_BUTTON_EXIT) == MENUFLAG_BUTTON_EXIT; bool exitButton = (menu->GetMenuOptionFlags() & MENUFLAG_BUTTON_EXIT) == MENUFLAG_BUTTON_EXIT;
bool novoteButton = (menu->GetMenuOptionFlags() & MENUFLAG_BUTTON_NOVOTE) == MENUFLAG_BUTTON_NOVOTE;
if (pgn != MENU_NO_PAGINATION) if (pgn != MENU_NO_PAGINATION)
{ {
@ -240,11 +240,6 @@ IMenuPanel *MenuManager::RenderMenu(int client, menu_states_t &md, ItemOrder ord
maxItems--; maxItems--;
} }
if (novoteButton)
{
maxItems--;
}
/* This is very not allowed! */ /* This is very not allowed! */
if (maxItems < 2) if (maxItems < 2)
{ {
@ -308,7 +303,7 @@ IMenuPanel *MenuManager::RenderMenu(int client, menu_states_t &md, ItemOrder ord
{ {
ItemDrawInfo &dr = drawItems[foundItems].draw; ItemDrawInfo &dr = drawItems[foundItems].draw;
/* Is the item valid? */ /* Is the item valid? */
if (menu->GetItemInfo(i, &dr, client) != NULL) if (menu->GetItemInfo(i, &dr) != NULL)
{ {
/* Ask the user to change the style, if necessary */ /* Ask the user to change the style, if necessary */
mh->OnMenuDrawItem(menu, client, i, dr.style); mh->OnMenuDrawItem(menu, client, i, dr.style);
@ -398,7 +393,7 @@ IMenuPanel *MenuManager::RenderMenu(int client, menu_states_t &md, ItemOrder ord
} }
while (++lastItem < totalItems) while (++lastItem < totalItems)
{ {
if (menu->GetItemInfo(lastItem, &dr, client) != NULL) if (menu->GetItemInfo(lastItem, &dr) != NULL)
{ {
mh->OnMenuDrawItem(menu, client, lastItem, dr.style); mh->OnMenuDrawItem(menu, client, lastItem, dr.style);
if (IsSlotItem(panel, dr.style)) if (IsSlotItem(panel, dr.style))
@ -420,7 +415,7 @@ IMenuPanel *MenuManager::RenderMenu(int client, menu_states_t &md, ItemOrder ord
lastItem--; lastItem--;
while (lastItem != 0) while (lastItem != 0)
{ {
if (menu->GetItemInfo(lastItem, &dr, client) != NULL) if (menu->GetItemInfo(lastItem, &dr) != NULL)
{ {
mh->OnMenuDrawItem(menu, client, lastItem, dr.style); mh->OnMenuDrawItem(menu, client, lastItem, dr.style);
if (IsSlotItem(panel, dr.style)) if (IsSlotItem(panel, dr.style))
@ -440,20 +435,6 @@ skip_search:
/* Draw the item according to the order */ /* Draw the item according to the order */
menu_slots_t *slots = md.slots; menu_slots_t *slots = md.slots;
unsigned int position = 0; /* Keep track of the last position */ unsigned int position = 0; /* Keep track of the last position */
if (novoteButton)
{
char text[50];
if (!logicore.CoreTranslate(text, sizeof(text), "%T", 2, NULL, "No Vote", &client))
{
ke::SafeStrcpy(text, sizeof(text), "No Vote");
}
ItemDrawInfo dr(text, 0);
position = panel->DrawItem(dr);
slots[position].type = ItemSel_Exit;
position++;
}
if (order == ItemOrder_Ascending) if (order == ItemOrder_Ascending)
{ {
md.item_on_page = drawItems[0].position; md.item_on_page = drawItems[0].position;
@ -570,7 +551,7 @@ skip_search:
/* If there are no control options, /* If there are no control options,
* Instead just pad with invisible slots. * Instead just pad with invisible slots.
*/ */
if (!displayNext && !displayPrev) if (!displayPrev && !displayPrev)
{ {
padItem.style = ITEMDRAW_NOTEXT; padItem.style = ITEMDRAW_NOTEXT;
} }
@ -604,20 +585,14 @@ skip_search:
{ {
if (exitBackButton) if (exitBackButton)
{ {
if (!logicore.CoreTranslate(text, sizeof(text), "%T", 2, NULL, "Back", &client)) CorePlayerTranslate(client, text, sizeof(text), "Back", NULL);
{
ke::SafeStrcpy(text, sizeof(text), "Back");
}
dr.style = ITEMDRAW_CONTROL; dr.style = ITEMDRAW_CONTROL;
position = panel->DrawItem(dr); position = panel->DrawItem(dr);
slots[position].type = ItemSel_ExitBack; slots[position].type = ItemSel_ExitBack;
} }
else else
{ {
if (!logicore.CoreTranslate(text, sizeof(text), "%T", 2, NULL, "Previous", &client)) CorePlayerTranslate(client, text, sizeof(text), "Previous", NULL);
{
ke::SafeStrcpy(text, sizeof(text), "Previous");
}
dr.style = (displayPrev ? 0 : ITEMDRAW_DISABLED)|ITEMDRAW_CONTROL; dr.style = (displayPrev ? 0 : ITEMDRAW_DISABLED)|ITEMDRAW_CONTROL;
position = panel->DrawItem(dr); position = panel->DrawItem(dr);
slots[position].type = ItemSel_Back; slots[position].type = ItemSel_Back;
@ -635,10 +610,7 @@ skip_search:
/* NEXT */ /* NEXT */
if (displayNext || canDrawDisabled) if (displayNext || canDrawDisabled)
{ {
if (!logicore.CoreTranslate(text, sizeof(text), "%T", 2, NULL, "Next", &client)) CorePlayerTranslate(client, text, sizeof(text), "Next", NULL);
{
ke::SafeStrcpy(text, sizeof(text), "Next");
}
dr.style = (displayNext ? 0 : ITEMDRAW_DISABLED)|ITEMDRAW_CONTROL; dr.style = (displayNext ? 0 : ITEMDRAW_DISABLED)|ITEMDRAW_CONTROL;
position = panel->DrawItem(dr); position = panel->DrawItem(dr);
slots[position].type = ItemSel_Next; slots[position].type = ItemSel_Next;
@ -666,10 +638,7 @@ skip_search:
/* EXIT */ /* EXIT */
if (exitButton) if (exitButton)
{ {
if (!logicore.CoreTranslate(text, sizeof(text), "%T", 2, NULL, "Exit", &client)) CorePlayerTranslate(client, text, sizeof(text), "Exit", NULL);
{
ke::SafeStrcpy(text, sizeof(text), "Exit");
}
dr.style = ITEMDRAW_CONTROL; dr.style = ITEMDRAW_CONTROL;
position = panel->DrawItem(dr); position = panel->DrawItem(dr);
slots[position].type = ItemSel_Exit; slots[position].type = ItemSel_Exit;
@ -808,19 +777,3 @@ unsigned int MenuManager::GetRemainingVoteDelay()
{ {
return s_VoteHandler.GetRemainingVoteDelay(); return s_VoteHandler.GetRemainingVoteDelay();
} }
bool MenuManager::IsClientInVotePool(int client)
{
return s_VoteHandler.IsClientInVotePool(client);
}
bool MenuManager::RedrawClientVoteMenu(int client)
{
return RedrawClientVoteMenu2(client, true);
}
bool MenuManager::RedrawClientVoteMenu2(int client, bool revote)
{
return s_VoteHandler.RedrawToClient(client, revote);
}

View File

@ -2,7 +2,7 @@
* vim: set ts=4 : * vim: set ts=4 :
* ============================================================================= * =============================================================================
* SourceMod * SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
* ============================================================================= * =============================================================================
* *
* This program is free software; you can redistribute it and/or modify it under * This program is free software; you can redistribute it and/or modify it under
@ -37,6 +37,7 @@
#include <sh_stack.h> #include <sh_stack.h>
#include <sh_list.h> #include <sh_list.h>
#include <sh_string.h> #include <sh_string.h>
#include "sm_memtable.h"
#include "sm_globals.h" #include "sm_globals.h"
using namespace SourceMod; using namespace SourceMod;
@ -88,9 +89,6 @@ public:
bool IsVoteInProgress(); bool IsVoteInProgress();
void CancelVoting(); void CancelVoting();
unsigned int GetRemainingVoteDelay(); unsigned int GetRemainingVoteDelay();
bool IsClientInVotePool(int client);
bool RedrawClientVoteMenu(int client);
bool RedrawClientVoteMenu2(int client, bool revote);
public: //IHandleTypeDispatch public: //IHandleTypeDispatch
void OnHandleDestroy(HandleType_t type, void *object); void OnHandleDestroy(HandleType_t type, void *object);
bool GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize); bool GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize);

View File

@ -1,8 +1,8 @@
/** /**
* vim: set ts=4 sw=4 tw=99 noet : * vim: set ts=4 :
* ============================================================================= * =============================================================================
* SourceMod * SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
* ============================================================================= * =============================================================================
* *
* This program is free software; you can redistribute it and/or modify it under * This program is free software; you can redistribute it and/or modify it under
@ -34,12 +34,11 @@
#include "MenuStyle_Base.h" #include "MenuStyle_Base.h"
#include "PlayerManager.h" #include "PlayerManager.h"
#include "MenuManager.h" #include "MenuManager.h"
#include "HandleSys.h"
#include "CellRecipientFilter.h" #include "CellRecipientFilter.h"
#if defined MENU_DEBUG #if defined MENU_DEBUG
#include "Logger.h" #include "Logger.h"
#endif #endif
#include "logic_bridge.h"
#include "AutoHandleRooter.h"
BaseMenuStyle::BaseMenuStyle() : m_WatchList(256), m_hHandle(BAD_HANDLE) BaseMenuStyle::BaseMenuStyle() : m_WatchList(256), m_hHandle(BAD_HANDLE)
{ {
@ -315,7 +314,7 @@ void BaseMenuStyle::ClientPressedKey(int client, unsigned int key_press)
if (sound != NULL) if (sound != NULL)
{ {
edict_t *pEdict = PEntityOfEntIndex(client); edict_t *pEdict = engine->PEntityOfEntIndex(client);
if (pEdict) if (pEdict)
{ {
ICollideable *pCollideable = pEdict->GetCollideable(); ICollideable *pCollideable = pEdict->GetCollideable();
@ -323,25 +322,15 @@ void BaseMenuStyle::ClientPressedKey(int client, unsigned int key_press)
if (pCollideable) if (pCollideable)
{ {
const Vector & pos = pCollideable->GetCollisionOrigin(); const Vector & pos = pCollideable->GetCollisionOrigin();
enginesound->EmitSound(filter, enginesound->EmitSound(filter,
client, client,
CHAN_AUTO, CHAN_AUTO,
#if SOURCE_ENGINE >= SE_PORTAL2
sound,
-1,
#endif
sound, sound,
VOL_NORM, VOL_NORM,
ATTN_NORM, ATTN_NORM,
#if SOURCE_ENGINE >= SE_PORTAL2
0,
#endif
0, 0,
PITCH_NORM, PITCH_NORM,
#if SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS \
|| SOURCE_ENGINE == SE_SDK2013 || SOURCE_ENGINE == SE_BMS || SOURCE_ENGINE == SE_TF2
0,
#endif
&pos); &pos);
} }
} }
@ -388,9 +377,6 @@ void BaseMenuStyle::ClientPressedKey(int client, unsigned int key_press)
RemoveClientFromWatch(client); RemoveClientFromWatch(client);
} }
Handle_t hndl = menu ? menu->GetHandle() : BAD_HANDLE;
AutoHandleRooter ahr(hndl);
if (cancel) if (cancel)
{ {
mh->OnMenuCancel(menu, client, reason); mh->OnMenuCancel(menu, client, reason);
@ -605,7 +591,7 @@ bool BaseMenuStyle::RedoClientMenu(int client, ItemOrder order)
} }
CBaseMenu::CBaseMenu(IMenuHandler *pHandler, IMenuStyle *pStyle, IdentityToken_t *pOwner) : CBaseMenu::CBaseMenu(IMenuHandler *pHandler, IMenuStyle *pStyle, IdentityToken_t *pOwner) :
m_pStyle(pStyle), m_Pagination(7), m_bShouldDelete(false), m_bCancelling(false), m_pStyle(pStyle), m_Strings(512), m_Pagination(7), m_bShouldDelete(false), m_bCancelling(false),
m_pOwner(pOwner ? pOwner : g_pCoreIdent), m_bDeleting(false), m_bWillFreeHandle(false), m_pOwner(pOwner ? pOwner : g_pCoreIdent), m_bDeleting(false), m_bWillFreeHandle(false),
m_hHandle(BAD_HANDLE), m_pHandler(pHandler), m_nFlags(MENUFLAG_BUTTON_EXIT) m_hHandle(BAD_HANDLE), m_pHandler(pHandler), m_nFlags(MENUFLAG_BUTTON_EXIT)
{ {
@ -628,135 +614,94 @@ Handle_t CBaseMenu::GetHandle()
bool CBaseMenu::AppendItem(const char *info, const ItemDrawInfo &draw) bool CBaseMenu::AppendItem(const char *info, const ItemDrawInfo &draw)
{ {
if (m_Pagination == (unsigned)MENU_NO_PAGINATION if (m_Pagination == (unsigned)MENU_NO_PAGINATION
&& m_items.length() >= m_pStyle->GetMaxPageItems()) && m_items.size() >= m_pStyle->GetMaxPageItems())
{ {
return false; return false;
} }
CItem item(m_items.length()); CItem item;
item.info = info; item.infoString = m_Strings.AddString(info);
if (draw.display) if (draw.display)
item.display = new ke::AString(draw.display); {
item.displayString = m_Strings.AddString(draw.display);
}
item.style = draw.style; item.style = draw.style;
m_items.append(ke::Move(item)); m_items.push_back(item);
return true; return true;
} }
bool CBaseMenu::InsertItem(unsigned int position, const char *info, const ItemDrawInfo &draw) bool CBaseMenu::InsertItem(unsigned int position, const char *info, const ItemDrawInfo &draw)
{ {
if (m_Pagination == (unsigned)MENU_NO_PAGINATION && if (m_Pagination == (unsigned)MENU_NO_PAGINATION
m_items.length() >= m_pStyle->GetMaxPageItems()) && m_items.size() >= m_pStyle->GetMaxPageItems())
{ {
return false; return false;
} }
if (position >= m_items.length()) if (position >= m_items.size())
{
return false; return false;
}
CItem item(position); CItem item;
item.info = info; item.infoString = m_Strings.AddString(info);
if (draw.display) if (draw.display)
item.display = new ke::AString(draw.display); {
item.displayString = m_Strings.AddString(draw.display);
}
item.style = draw.style; item.style = draw.style;
m_items.insert(position, ke::Move(item)); CVector<CItem>::iterator iter = m_items.iterAt(position);
m_items.insert(iter, item);
return true; return true;
} }
bool CBaseMenu::RemoveItem(unsigned int position) bool CBaseMenu::RemoveItem(unsigned int position)
{ {
if (position >= m_items.length()) if (position >= m_items.size())
{
return false; return false;
}
m_items.erase(m_items.iterAt(position));
if (m_items.size() == 0)
{
m_Strings.Reset();
}
m_items.remove(position);
return true; return true;
} }
void CBaseMenu::RemoveAllItems() void CBaseMenu::RemoveAllItems()
{ {
m_items.clear(); m_items.clear();
m_Strings.Reset();
} }
const char *CBaseMenu::GetItemInfo(unsigned int position, ItemDrawInfo *draw/* =NULL */, int client/* =0 */) const char *CBaseMenu::GetItemInfo(unsigned int position, ItemDrawInfo *draw/* =NULL */)
{
if (position >= m_items.size())
{ {
if (position >= m_items.length())
return NULL; return NULL;
if (client > 0 && position < m_RandomMaps[client].length())
{
position = m_RandomMaps[client][position];
} }
if (draw) if (draw)
{ {
draw->display = m_items[position].display->chars(); draw->display = m_Strings.GetString(m_items[position].displayString);
draw->style = m_items[position].style; draw->style = m_items[position].style;
} }
return m_items[position].info.chars(); return m_Strings.GetString(m_items[position].infoString);
}
void CBaseMenu::ShufflePerClient(int start, int stop)
{
// limit map len to 255 items since it's using uint8
int length = MIN(GetItemCount(), 255);
if (stop >= 0)
length = MIN(length, stop);
for (int i = 1; i < SM_MAXPLAYERS + 1; i++)
{
// populate per-client map ...
m_RandomMaps[i].resize(length);
for (int j = 0; j < length; j++)
m_RandomMaps[i][j] = j;
// ... and random shuffle it
for (int j = length - 1; j > start; j--)
{
int x = rand() % (j - start + 1) + start;
uint8_t tmp = m_RandomMaps[i][x];
m_RandomMaps[i][x] = m_RandomMaps[i][j];
m_RandomMaps[i][j] = tmp;
}
}
}
void CBaseMenu::SetClientMapping(int client, int *array, int length)
{
length = MIN(length, 255);
m_RandomMaps[client].resize(length);
for (int i = 0; i < length; i++)
{
m_RandomMaps[client][i] = array[i];
}
}
bool CBaseMenu::IsPerClientShuffled()
{
for (int i = 1; i < SM_MAXPLAYERS + 1; i++)
{
if(m_RandomMaps[i].length() > 0)
return true;
}
return false;
}
unsigned int CBaseMenu::GetRealItemIndex(int client, unsigned int position)
{
if (client > 0 && position < m_RandomMaps[client].length())
{
position = m_RandomMaps[client][position];
return m_items[position].index;
}
return position;
} }
unsigned int CBaseMenu::GetItemCount() unsigned int CBaseMenu::GetItemCount()
{ {
return m_items.length(); return m_items.size();
} }
bool CBaseMenu::SetPagination(unsigned int itemsPerPage) bool CBaseMenu::SetPagination(unsigned int itemsPerPage)
@ -789,12 +734,12 @@ IMenuStyle *CBaseMenu::GetDrawStyle()
void CBaseMenu::SetDefaultTitle(const char *message) void CBaseMenu::SetDefaultTitle(const char *message)
{ {
m_Title = message; m_Title.assign(message);
} }
const char *CBaseMenu::GetDefaultTitle() const char *CBaseMenu::GetDefaultTitle()
{ {
return m_Title.chars(); return m_Title.c_str();
} }
void CBaseMenu::Cancel() void CBaseMenu::Cancel()
@ -861,7 +806,7 @@ void CBaseMenu::InternalDelete()
m_hHandle = BAD_HANDLE; m_hHandle = BAD_HANDLE;
m_bDeleting = true; m_bDeleting = true;
handlesys->FreeHandle(hndl, &sec); g_HandleSys.FreeHandle(hndl, &sec);
} }
m_pHandler->OnMenuDestroy(this); m_pHandler->OnMenuDestroy(this);
@ -886,5 +831,7 @@ IMenuHandler *CBaseMenu::GetHandler()
unsigned int CBaseMenu::GetBaseMemUsage() unsigned int CBaseMenu::GetBaseMemUsage()
{ {
return m_Title.length() + (m_items.length() * sizeof(CItem)); return m_Title.size()
+ m_Strings.GetMemTable()->GetMemUsage()
+ (m_items.size() * sizeof(CItem));
} }

View File

@ -1,8 +1,8 @@
/** /**
* vim: set ts=4 sw=4 tw=99 noet : * vim: set ts=4 :
* ============================================================================= * =============================================================================
* SourceMod * SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
* ============================================================================= * =============================================================================
* *
* This program is free software; you can redistribute it and/or modify it under * This program is free software; you can redistribute it and/or modify it under
@ -34,50 +34,29 @@
#include <IMenuManager.h> #include <IMenuManager.h>
#include <IPlayerHelpers.h> #include <IPlayerHelpers.h>
#include <am-autoptr.h> #include <sh_string.h>
#include <am-string.h> #include <sh_vector.h>
#include <am-vector.h> #include "sm_memtable.h"
#include "sm_fastlink.h" #include "sm_fastlink.h"
using namespace SourceMod; using namespace SourceMod;
using namespace SourceHook;
class CItem class CItem
{ {
public: public:
CItem(unsigned int index) CItem()
{ {
this->index = index; infoString = -1;
displayString = -1;
style = 0; style = 0;
access = 0; access = 0;
} }
CItem(CItem &&other)
: info(ke::Move(other.info)),
display(ke::Move(other.display))
{
index = other.index;
style = other.style;
access = other.access;
}
CItem & operator =(CItem &&other)
{
index = other.index;
info = ke::Move(other.info);
display = ke::Move(other.display);
style = other.style;
access = other.access;
return *this;
}
public: public:
unsigned int index; int infoString;
ke::AString info; int displayString;
ke::AutoPtr<ke::AString> display;
unsigned int style; unsigned int style;
unsigned int access; unsigned int access;
private:
CItem(const CItem &other) = delete;
CItem &operator =(const CItem &other) = delete;
}; };
class CBaseMenuPlayer class CBaseMenuPlayer
@ -142,7 +121,7 @@ public:
virtual bool InsertItem(unsigned int position, 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 bool RemoveItem(unsigned int position);
virtual void RemoveAllItems(); virtual void RemoveAllItems();
virtual const char *GetItemInfo(unsigned int position, ItemDrawInfo *draw=NULL, int client=0); virtual const char *GetItemInfo(unsigned int position, ItemDrawInfo *draw=NULL);
virtual unsigned int GetItemCount(); virtual unsigned int GetItemCount();
virtual bool SetPagination(unsigned int itemsPerPage); virtual bool SetPagination(unsigned int itemsPerPage);
virtual unsigned int GetPagination(); virtual unsigned int GetPagination();
@ -156,18 +135,15 @@ public:
virtual unsigned int GetMenuOptionFlags(); virtual unsigned int GetMenuOptionFlags();
virtual void SetMenuOptionFlags(unsigned int flags); virtual void SetMenuOptionFlags(unsigned int flags);
virtual IMenuHandler *GetHandler(); virtual IMenuHandler *GetHandler();
virtual void ShufflePerClient(int start, int stop);
virtual void SetClientMapping(int client, int *array, int length);
virtual bool IsPerClientShuffled();
virtual unsigned int GetRealItemIndex(int client, unsigned int position);
unsigned int GetBaseMemUsage(); unsigned int GetBaseMemUsage();
private: private:
void InternalDelete(); void InternalDelete();
protected: protected:
ke::AString m_Title; String m_Title;
IMenuStyle *m_pStyle; IMenuStyle *m_pStyle;
BaseStringTable m_Strings;
unsigned int m_Pagination; unsigned int m_Pagination;
ke::Vector<CItem> m_items; CVector<CItem> m_items;
bool m_bShouldDelete; bool m_bShouldDelete;
bool m_bCancelling; bool m_bCancelling;
IdentityToken_t *m_pOwner; IdentityToken_t *m_pOwner;
@ -176,7 +152,6 @@ protected:
Handle_t m_hHandle; Handle_t m_hHandle;
IMenuHandler *m_pHandler; IMenuHandler *m_pHandler;
unsigned int m_nFlags; unsigned int m_nFlags;
ke::Vector<uint8_t> m_RandomMaps[SM_MAXPLAYERS+1];
}; };
#endif //_INCLUDE_MENUSTYLE_BASE_H #endif //_INCLUDE_MENUSTYLE_BASE_H

View File

@ -2,7 +2,7 @@
* vim: set ts=4 : * vim: set ts=4 :
* ============================================================================= * =============================================================================
* SourceMod * SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
* ============================================================================= * =============================================================================
* *
* This program is free software; you can redistribute it and/or modify it under * This program is free software; you can redistribute it and/or modify it under
@ -32,20 +32,11 @@
#include "MenuStyle_Radio.h" #include "MenuStyle_Radio.h"
#include "sm_stringutil.h" #include "sm_stringutil.h"
#include "UserMessages.h" #include "UserMessages.h"
#include <IGameConfigs.h> #include "GameConfigs.h"
#include "PlayerManager.h" #include "PlayerManager.h"
#if defined MENU_DEBUG #if defined MENU_DEBUG
#include "Logger.h" #include "Logger.h"
#endif #endif
#include "logic_bridge.h"
#ifdef USE_PROTOBUF_USERMESSAGES
#include <google/protobuf/descriptor.h>
#endif
#if SOURCE_ENGINE == SE_CSGO
#include <game/shared/csgo/protobuf/cstrike15_usermessages.pb.h>
#endif
extern const char *g_RadioNumTable[]; extern const char *g_RadioNumTable[];
CRadioStyle g_RadioMenuStyle; CRadioStyle g_RadioMenuStyle;
@ -53,14 +44,6 @@ int g_ShowMenuId = -1;
bool g_bRadioInit = false; bool g_bRadioInit = false;
unsigned int g_RadioMenuTimeout = 0; unsigned int g_RadioMenuTimeout = 0;
// back, next, exit
#define MAX_PAGINATION_OPTIONS 3
#define MAX_MENUSLOT_KEYS 10
static unsigned int s_RadioMaxPageItems = MAX_MENUSLOT_KEYS;
CRadioStyle::CRadioStyle() CRadioStyle::CRadioStyle()
{ {
m_players = new CRadioMenuPlayer[256+1]; m_players = new CRadioMenuPlayer[256+1];
@ -83,10 +66,6 @@ void CRadioStyle::OnSourceModLevelChange(const char *mapName)
} }
g_bRadioInit = true; g_bRadioInit = true;
// Always register the style. Use IsSupported() to check for validity before use.
g_Menus.AddStyle(this);
const char *msg = g_pGameConf->GetKeyValue("HudRadioMenuMsg"); const char *msg = g_pGameConf->GetKeyValue("HudRadioMenuMsg");
if (!msg || msg[0] == '\0') if (!msg || msg[0] == '\0')
{ {
@ -110,18 +89,7 @@ void CRadioStyle::OnSourceModLevelChange(const char *mapName)
g_RadioMenuTimeout = 0; g_RadioMenuTimeout = 0;
} }
const char *items = g_pGameConf->GetKeyValue("RadioMenuMaxPageItems"); g_Menus.AddStyle(this);
if (items != NULL)
{
int value = atoi(items);
// Only override the mostly-safe default if it's a sane value
if (value > MAX_PAGINATION_OPTIONS && value <= MAX_MENUSLOT_KEYS)
{
s_RadioMaxPageItems = value;
}
}
g_Menus.SetDefaultStyle(this); g_Menus.SetDefaultStyle(this);
g_UserMsgs.HookUserMessage(g_ShowMenuId, this, false); g_UserMsgs.HookUserMessage(g_ShowMenuId, this, false);
@ -166,22 +134,13 @@ static unsigned int g_last_holdtime = 0;
static unsigned int g_last_client_count = 0; static unsigned int g_last_client_count = 0;
static int g_last_clients[256]; static int g_last_clients[256];
#ifdef USE_PROTOBUF_USERMESSAGES
void CRadioStyle::OnUserMessage(int msg_id, protobuf::Message &msg, IRecipientFilter *pFilter)
#else
void CRadioStyle::OnUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter) void CRadioStyle::OnUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter)
#endif
{ {
int count = pFilter->GetRecipientCount(); int count = pFilter->GetRecipientCount();
#if SOURCE_ENGINE == SE_CSGO
int c = ((CCSUsrMsg_ShowMenu &)msg).display_time();
#else
bf_read br(bf->GetBasePointer(), 3); bf_read br(bf->GetBasePointer(), 3);
br.ReadWord(); br.ReadWord();
int c = br.ReadChar(); int c = br.ReadChar();
#endif
g_last_holdtime = (c == -1) ? 0 : (unsigned)c; g_last_holdtime = (c == -1) ? 0 : (unsigned)c;
@ -229,7 +188,7 @@ IBaseMenu *CRadioStyle::CreateMenu(IMenuHandler *pHandler, IdentityToken_t *pOwn
unsigned int CRadioStyle::GetMaxPageItems() unsigned int CRadioStyle::GetMaxPageItems()
{ {
return s_RadioMaxPageItems; return 10;
} }
const char *CRadioStyle::GetStyleName() const char *CRadioStyle::GetStyleName()
@ -258,6 +217,15 @@ CRadioDisplay *CRadioStyle::MakeRadioDisplay(CRadioMenu *menu)
return display; 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) void CRadioStyle::FreeRadioDisplay(CRadioDisplay *display)
{ {
m_FreeDisplays.push(display); m_FreeDisplays.push(display);
@ -324,12 +292,11 @@ void CRadioDisplay::Reset()
keys = 0; keys = 0;
} }
bool CRadioDisplay::DirectSet(const char *str) void CRadioDisplay::DirectSet(const char *str, int keymap)
{ {
m_Title.clear(); m_Title.clear();
m_BufferText.assign(str); m_BufferText.assign(str);
keys = keymap;
return true;
} }
unsigned int CRadioDisplay::GetCurrentKey() unsigned int CRadioDisplay::GetCurrentKey()
@ -339,7 +306,7 @@ unsigned int CRadioDisplay::GetCurrentKey()
bool CRadioDisplay::SetCurrentKey(unsigned int key) bool CRadioDisplay::SetCurrentKey(unsigned int key)
{ {
if (key < m_NextPos || m_NextPos > s_RadioMaxPageItems) if (key < m_NextPos || m_NextPos > 10)
{ {
return false; return false;
} }
@ -375,7 +342,7 @@ void CRadioDisplay::DrawTitle(const char *text, bool onlyIfEmpty/* =false */)
unsigned int CRadioDisplay::DrawItem(const ItemDrawInfo &item) unsigned int CRadioDisplay::DrawItem(const ItemDrawInfo &item)
{ {
if (m_NextPos > s_RadioMaxPageItems || !CanDrawItem(item.style)) if (m_NextPos > 10 || !CanDrawItem(item.style))
{ {
return 0; return 0;
} }
@ -450,7 +417,7 @@ void CRadioMenuPlayer::Radio_Init(int keys, const char *title, const char *text)
{ {
if (title[0] != '\0') if (title[0] != '\0')
{ {
display_len = ke::SafeSprintf(display_pkt, display_len = UTIL_Format(display_pkt,
sizeof(display_pkt), sizeof(display_pkt),
"%s\n%s", "%s\n%s",
title, title,
@ -458,8 +425,9 @@ void CRadioMenuPlayer::Radio_Init(int keys, const char *title, const char *text)
} }
else else
{ {
display_len = ke::SafeStrcpy(display_pkt, display_len = UTIL_Format(display_pkt,
sizeof(display_pkt), sizeof(display_pkt),
"%s",
text); text);
} }
display_keys = keys; display_keys = keys;
@ -467,7 +435,7 @@ void CRadioMenuPlayer::Radio_Init(int keys, const char *title, const char *text)
void CRadioMenuPlayer::Radio_Refresh() void CRadioMenuPlayer::Radio_Refresh()
{ {
cell_t players[1] = { (cell_t)m_index }; cell_t players[1] = {m_index};
char *ptr = display_pkt; char *ptr = display_pkt;
char save = 0; char save = 0;
size_t len = display_len; size_t len = display_len;
@ -483,14 +451,6 @@ void CRadioMenuPlayer::Radio_Refresh()
time = menuHoldTime - (unsigned int)(gpGlobals->curtime - menuStartTime); time = menuHoldTime - (unsigned int)(gpGlobals->curtime - menuStartTime);
} }
#if SOURCE_ENGINE == SE_CSGO
// TODO: find what happens past 240 on CS:GO
CCSUsrMsg_ShowMenu *msg = (CCSUsrMsg_ShowMenu *)g_UserMsgs.StartProtobufMessage(g_ShowMenuId, players, 1, USERMSG_BLOCKHOOKS);
msg->set_bits_valid_slots(display_keys);
msg->set_display_time(time);
msg->set_menu_string(ptr);
g_UserMsgs.EndMessage();
#else
while (true) while (true)
{ {
if (len > 240) if (len > 240)
@ -498,8 +458,7 @@ void CRadioMenuPlayer::Radio_Refresh()
save = ptr[240]; save = ptr[240];
ptr[240] = '\0'; ptr[240] = '\0';
} }
bf_write *buffer = g_UserMsgs.StartMessage(g_ShowMenuId, players, 1, USERMSG_BLOCKHOOKS);
bf_write *buffer = g_UserMsgs.StartBitBufMessage(g_ShowMenuId, players, 1, USERMSG_BLOCKHOOKS);
buffer->WriteWord(display_keys); buffer->WriteWord(display_keys);
buffer->WriteChar(time ? time : -1); buffer->WriteChar(time ? time : -1);
buffer->WriteByte( (len > 240) ? 1 : 0 ); buffer->WriteByte( (len > 240) ? 1 : 0 );
@ -516,7 +475,6 @@ void CRadioMenuPlayer::Radio_Refresh()
break; break;
} }
} }
#endif
display_last_refresh = gpGlobals->curtime; display_last_refresh = gpGlobals->curtime;
} }
@ -552,7 +510,6 @@ unsigned int CRadioDisplay::GetApproxMemUsage()
CRadioMenu::CRadioMenu(IMenuHandler *pHandler, IdentityToken_t *pOwner) : CRadioMenu::CRadioMenu(IMenuHandler *pHandler, IdentityToken_t *pOwner) :
CBaseMenu(pHandler, &g_RadioMenuStyle, pOwner) CBaseMenu(pHandler, &g_RadioMenuStyle, pOwner)
{ {
m_Pagination = s_RadioMaxPageItems - MAX_PAGINATION_OPTIONS;
} }
bool CRadioMenu::SetExtOption(MenuOption option, const void *valuePtr) bool CRadioMenu::SetExtOption(MenuOption option, const void *valuePtr)
@ -586,7 +543,6 @@ bool CRadioMenu::DisplayAtItem(int client,
return false; return false;
} }
AutoHandleRooter ahr(this->GetHandle());
return g_RadioMenuStyle.DoClientMenu(client, return g_RadioMenuStyle.DoClientMenu(client,
this, this,
start_item, start_item,
@ -594,17 +550,6 @@ bool CRadioMenu::DisplayAtItem(int client,
time); time);
} }
bool CRadioMenu::SetPagination(unsigned int itemsPerPage)
{
const unsigned int maxPerPage = s_RadioMaxPageItems - MAX_PAGINATION_OPTIONS;
if (itemsPerPage > maxPerPage)
{
return false;
}
return CBaseMenu::SetPagination(itemsPerPage);
}
void CRadioMenu::Cancel_Finally() void CRadioMenu::Cancel_Finally()
{ {
g_RadioMenuStyle.CancelMenu(this); g_RadioMenuStyle.CancelMenu(this);

View File

@ -2,7 +2,7 @@
* vim: set ts=4 : * vim: set ts=4 :
* ============================================================================= * =============================================================================
* SourceMod * SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
* ============================================================================= * =============================================================================
* *
* This program is free software; you can redistribute it and/or modify it under * This program is free software; you can redistribute it and/or modify it under
@ -37,12 +37,10 @@
#include "MenuStyle_Base.h" #include "MenuStyle_Base.h"
#include "sourcemm_api.h" #include "sourcemm_api.h"
#include <IPlayerHelpers.h> #include <IPlayerHelpers.h>
#include "UserMessages.h" #include <IUserMessages.h>
#include "sm_fastlink.h" #include "sm_fastlink.h"
#include <sh_stack.h> #include <sh_stack.h>
#include <compat_wrappers.h> #include <compat_wrappers.h>
#include "logic/common_logic.h"
#include "AutoHandleRooter.h"
using namespace SourceMod; using namespace SourceMod;
@ -67,11 +65,7 @@ private:
class CRadioStyle : class CRadioStyle :
public BaseMenuStyle, public BaseMenuStyle,
public SMGlobalClass, public SMGlobalClass,
#ifdef USE_PROTOBUF_USERMESSAGES public IUserMessageListener
public IProtobufUserMessageListener
#else
public IBitBufUserMessageListener
#endif
{ {
public: public:
CRadioStyle(); CRadioStyle();
@ -90,11 +84,7 @@ public: //IMenuStyle
unsigned int GetMaxPageItems(); unsigned int GetMaxPageItems();
unsigned int GetApproxMemUsage(); unsigned int GetApproxMemUsage();
public: //IUserMessageListener public: //IUserMessageListener
#ifdef USE_PROTOBUF_USERMESSAGES
void OnUserMessage(int msg_id, protobuf::Message &msg, IRecipientFilter *pFilter);
#else
void OnUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter); void OnUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter);
#endif
void OnUserMessageSent(int msg_id); void OnUserMessageSent(int msg_id);
public: public:
bool IsSupported(); bool IsSupported();
@ -103,6 +93,7 @@ public:
CRadioDisplay *MakeRadioDisplay(CRadioMenu *menu=NULL); CRadioDisplay *MakeRadioDisplay(CRadioMenu *menu=NULL);
void FreeRadioDisplay(CRadioDisplay *display); void FreeRadioDisplay(CRadioDisplay *display);
CRadioMenuPlayer *GetRadioMenuPlayer(int client); CRadioMenuPlayer *GetRadioMenuPlayer(int client);
IMenuPanel *MakeRadioDisplay(const char *str, int keys);
private: private:
CRadioMenuPlayer *m_players; CRadioMenuPlayer *m_players;
CStack<CRadioDisplay *> m_FreeDisplays; CStack<CRadioDisplay *> m_FreeDisplays;
@ -130,7 +121,8 @@ public: //IMenuPanel
bool SetCurrentKey(unsigned int key); bool SetCurrentKey(unsigned int key);
int GetAmountRemaining(); int GetAmountRemaining();
unsigned int GetApproxMemUsage(); unsigned int GetApproxMemUsage();
bool DirectSet(const char *str); public:
void DirectSet(const char *str, int keymap);
private: private:
String m_BufferText; String m_BufferText;
String m_Title; String m_Title;
@ -150,7 +142,6 @@ public:
unsigned int time, unsigned int time,
unsigned int start_item, unsigned int start_item,
IMenuHandler *alt_handler/* =NULL */); IMenuHandler *alt_handler/* =NULL */);
bool SetPagination(unsigned int itemsPerPage);
void Cancel_Finally(); void Cancel_Finally();
unsigned int GetApproxMemUsage(); unsigned int GetApproxMemUsage();
}; };

View File

@ -1,8 +1,8 @@
/** /**
* vim: set ts=4 sw=4 tw=99 noet : * vim: set ts=4 :
* ============================================================================= * =============================================================================
* SourceMod * SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
* ============================================================================= * =============================================================================
* *
* This program is free software; you can redistribute it and/or modify it under * This program is free software; you can redistribute it and/or modify it under
@ -32,6 +32,7 @@
#include "sm_stringutil.h" #include "sm_stringutil.h"
#include "PlayerManager.h" #include "PlayerManager.h"
#include "MenuStyle_Valve.h" #include "MenuStyle_Valve.h"
#include "Translator.h"
#include "PlayerManager.h" #include "PlayerManager.h"
#include "ConCmdManager.h" #include "ConCmdManager.h"
@ -66,14 +67,14 @@ bool ValveMenuStyle::OnClientCommand(int client, const char *cmdname, const CCom
void ValveMenuStyle::OnSourceModAllInitialized() void ValveMenuStyle::OnSourceModAllInitialized()
{ {
g_Players.AddClientListener(this); g_Players.AddClientListener(this);
SH_ADD_HOOK(IServerPluginHelpers, CreateMessage, serverpluginhelpers, SH_MEMBER(this, &ValveMenuStyle::HookCreateMessage), false); SH_ADD_HOOK_MEMFUNC(IServerPluginHelpers, CreateMessage, serverpluginhelpers, this, &ValveMenuStyle::HookCreateMessage, false);
g_pSPHCC = SH_GET_CALLCLASS(serverpluginhelpers); g_pSPHCC = SH_GET_CALLCLASS(serverpluginhelpers);
} }
void ValveMenuStyle::OnSourceModShutdown() void ValveMenuStyle::OnSourceModShutdown()
{ {
SH_RELEASE_CALLCLASS(g_pSPHCC); SH_RELEASE_CALLCLASS(g_pSPHCC);
SH_REMOVE_HOOK(IServerPluginHelpers, CreateMessage, serverpluginhelpers, SH_MEMBER(this, &ValveMenuStyle::HookCreateMessage), false); SH_REMOVE_HOOK_MEMFUNC(IServerPluginHelpers, CreateMessage, serverpluginhelpers, this, &ValveMenuStyle::HookCreateMessage, false);
g_Players.RemoveClientListener(this); g_Players.RemoveClientListener(this);
} }
@ -87,7 +88,7 @@ void ValveMenuStyle::HookCreateMessage(edict_t *pEdict,
return; return;
} }
int client = IndexOfEdict(pEdict); int client = engine->IndexOfEdict(pEdict);
if (client < 1 || client > 256) if (client < 1 || client > 256)
{ {
return; return;
@ -293,7 +294,7 @@ unsigned int CValveMenuDisplay::DrawItem(const ItemDrawInfo &item)
} }
char buffer[255]; char buffer[255];
ke::SafeSprintf(buffer, sizeof(buffer), "%d. %s", m_NextPos, item.display); UTIL_Format(buffer, sizeof(buffer), "%d. %s", m_NextPos, item.display);
KeyValues *ki = m_pKv->FindKey(g_OptionNumTable[m_NextPos], true); KeyValues *ki = m_pKv->FindKey(g_OptionNumTable[m_NextPos], true);
ki->SetString("command", g_OptionCmdTable[m_NextPos]); ki->SetString("command", g_OptionCmdTable[m_NextPos]);
@ -324,7 +325,7 @@ void CValveMenuDisplay::SendRawDisplay(int client, int priority, unsigned int ti
m_pKv->SetInt("time", time ? time : 200); m_pKv->SetInt("time", time ? time : 200);
SH_CALL(g_pSPHCC, &IServerPluginHelpers::CreateMessage)( SH_CALL(g_pSPHCC, &IServerPluginHelpers::CreateMessage)(
PEntityOfEntIndex(client), engine->PEntityOfEntIndex(client),
DIALOG_MENU, DIALOG_MENU,
m_pKv, m_pKv,
vsp_interface); vsp_interface);
@ -378,7 +379,7 @@ bool CValveMenu::SetExtOption(MenuOption option, const void *valuePtr)
{ {
if (option == MenuOption_IntroMessage) if (option == MenuOption_IntroMessage)
{ {
ke::SafeStrcpy(m_IntroMsg, sizeof(m_IntroMsg), (const char *)valuePtr); strncopy(m_IntroMsg, (const char *)valuePtr, sizeof(m_IntroMsg));
return true; return true;
} else if (option == MenuOption_IntroColor) { } else if (option == MenuOption_IntroColor) {
unsigned int *array = (unsigned int *)valuePtr; unsigned int *array = (unsigned int *)valuePtr;
@ -404,7 +405,6 @@ bool CValveMenu::DisplayAtItem(int client,
return false; return false;
} }
AutoHandleRooter ahr(this->GetHandle());
return g_ValveMenuStyle.DoClientMenu(client, this, start_item, alt_handler ? alt_handler : m_pHandler, time); return g_ValveMenuStyle.DoClientMenu(client, this, start_item, alt_handler ? alt_handler : m_pHandler, time);
} }

View File

@ -2,7 +2,7 @@
* vim: set ts=4 : * vim: set ts=4 :
* ============================================================================= * =============================================================================
* SourceMod * SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
* ============================================================================= * =============================================================================
* *
* This program is free software; you can redistribute it and/or modify it under * This program is free software; you can redistribute it and/or modify it under
@ -39,8 +39,6 @@
#include "KeyValues.h" #include "KeyValues.h"
#include "sm_fastlink.h" #include "sm_fastlink.h"
#include <compat_wrappers.h> #include <compat_wrappers.h>
#include "logic/common_logic.h"
#include "AutoHandleRooter.h"
using namespace SourceMod; using namespace SourceMod;
@ -77,7 +75,6 @@ public: //IMenuStyle
IBaseMenu *CreateMenu(IMenuHandler *pHandler, IdentityToken_t *pOwner); IBaseMenu *CreateMenu(IMenuHandler *pHandler, IdentityToken_t *pOwner);
unsigned int GetMaxPageItems(); unsigned int GetMaxPageItems();
unsigned int GetApproxMemUsage(); unsigned int GetApproxMemUsage();
bool IsSupported() { return true; }
private: private:
void HookCreateMessage(edict_t *pEdict, DIALOG_TYPE type, KeyValues *kv, IServerPluginCallbacks *plugin); void HookCreateMessage(edict_t *pEdict, DIALOG_TYPE type, KeyValues *kv, IServerPluginCallbacks *plugin);
private: private:
@ -108,7 +105,6 @@ public:
bool SetCurrentKey(unsigned int key); bool SetCurrentKey(unsigned int key);
int GetAmountRemaining(); int GetAmountRemaining();
unsigned int GetApproxMemUsage(); unsigned int GetApproxMemUsage();
bool DirectSet(const char *str) { return false; }
private: private:
KeyValues *m_pKv; KeyValues *m_pKv;
unsigned int m_NextPos; unsigned int m_NextPos;

View File

@ -1,8 +1,8 @@
/** /**
* vim: set ts=4 sw=4 : * vim: set ts=4 :
* ============================================================================= * =============================================================================
* SourceMod * SourceMod
* Copyright (C) 2004-2009 AlliedModders LLC. All rights reserved. * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
* ============================================================================= * =============================================================================
* *
* This program is free software; you can redistribute it and/or modify it under * This program is free software; you can redistribute it and/or modify it under
@ -34,57 +34,10 @@
#include "MenuVoting.h" #include "MenuVoting.h"
#include "PlayerManager.h" #include "PlayerManager.h"
#include "sourcemm_api.h" #include "sourcemm_api.h"
#include <sourcemod.h>
#include <Logger.h>
#include <HalfLife2.h>
#include <mathlib.h>
#include <const.h>
#include <ITranslator.h>
#include "logic_bridge.h"
float g_next_vote = 0.0f; float g_next_vote = 0.0f;
#define VOTE_NOT_VOTING -2 #if defined ORANGEBOX_BUILD
#define VOTE_PENDING -1
ConVar sm_vote_hintbox("sm_vote_progress_hintbox",
"0",
0,
"Show current vote progress in a hint box",
true,
0.0,
true,
1.0);
ConVar sm_vote_chat("sm_vote_progress_chat",
"0",
0,
"Show current vote progress as chat messages",
true,
0.0,
true,
1.0);
ConVar sm_vote_console("sm_vote_progress_console",
"0",
0,
"Show current vote progress as console messages",
true,
0.0,
true,
1.0);
ConVar sm_vote_client_console("sm_vote_progress_client_console",
"0",
0,
"Show current vote progress as console messages to clients",
true,
0.0,
true,
1.0);
#if SOURCE_ENGINE >= SE_ORANGEBOX
void OnVoteDelayChange(IConVar *cvar, const char *value, float flOldValue); void OnVoteDelayChange(IConVar *cvar, const char *value, float flOldValue);
#else #else
void OnVoteDelayChange(ConVar *cvar, const char *value); void OnVoteDelayChange(ConVar *cvar, const char *value);
@ -99,7 +52,7 @@ ConVar sm_vote_delay("sm_vote_delay",
0.0, 0.0,
OnVoteDelayChange); OnVoteDelayChange);
#if SOURCE_ENGINE >= SE_ORANGEBOX #if defined ORANGEBOX_BUILD
void OnVoteDelayChange(IConVar *cvar, const char *value, float flOldValue) void OnVoteDelayChange(IConVar *cvar, const char *value, float flOldValue)
#else #else
void OnVoteDelayChange(ConVar *cvar, const char *value) void OnVoteDelayChange(ConVar *cvar, const char *value)
@ -160,19 +113,14 @@ void VoteMenuHandler::OnClientDisconnected(int client)
return; return;
} }
/* Wipe out their vote if they had one. We have to make sure the the the /* Wipe out their vote if they had one */
* newly connected client is not allowed to vote.
*/
int item; int item;
if ((item = m_ClientVotes[client]) >= VOTE_PENDING) if ((item = m_ClientVotes[client]) >= 0)
{
if (item >= 0)
{ {
assert((unsigned)item < m_Items); assert((unsigned)item < m_Items);
assert(m_Votes[item] > 0); assert(m_Votes[item] > 0);
m_Votes[item]--; m_Votes[item]--;
} m_ClientVotes[client] = -1;
m_ClientVotes[client] = VOTE_NOT_VOTING;
} }
} }
@ -181,28 +129,18 @@ bool VoteMenuHandler::IsVoteInProgress()
return (m_pCurMenu != NULL); return (m_pCurMenu != NULL);
} }
bool VoteMenuHandler::StartVote(IBaseMenu *menu, bool VoteMenuHandler::StartVote(IBaseMenu *menu, unsigned int num_clients, int clients[], unsigned int max_time, unsigned int flags/* =0 */)
unsigned int num_clients,
int clients[],
unsigned int max_time,
unsigned int flags/* =0 */)
{ {
if (!InitializeVoting(menu, menu->GetHandler(), max_time, flags)) if (!InitializeVoting(menu, menu->GetHandler(), max_time, flags))
{ {
return false; 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(); float fVoteDelay = sm_vote_delay.GetFloat();
if (fVoteDelay < 1.0) if (fVoteDelay < 1.0)
{ {
g_next_vote = 0.0; g_next_vote = 0.0;
} } else {
else
{
/* This little trick breaks for infinite votes! /* This little trick breaks for infinite votes!
* However, we just ignore that since those 1) shouldn't exist and * However, we just ignore that since those 1) shouldn't exist and
* 2) people must be checking IsVoteInProgress() beforehand anyway. * 2) people must be checking IsVoteInProgress() beforehand anyway.
@ -210,15 +148,8 @@ bool VoteMenuHandler::StartVote(IBaseMenu *menu,
g_next_vote = gpGlobals->curtime + fVoteDelay + (float)max_time; 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++) for (unsigned int i=0; i<num_clients; i++)
{ {
if (clients[i] < 1 || clients[i] > 256)
{
continue;
}
menu->Display(clients[i], max_time, this); menu->Display(clients[i], max_time, this);
} }
@ -227,72 +158,6 @@ bool VoteMenuHandler::StartVote(IBaseMenu *menu,
return true; return true;
} }
bool VoteMenuHandler::IsClientInVotePool(int client)
{
if (client < 1
|| client > g_Players.MaxClients()
|| m_pCurMenu == NULL)
{
return false;
}
return (m_ClientVotes[client] > VOTE_NOT_VOTING);
}
bool VoteMenuHandler::GetClientVoteChoice(int client, unsigned int *pItem)
{
if (!IsClientInVotePool(client)
|| m_ClientVotes[client] == VOTE_PENDING)
{
return false;
}
*pItem = m_ClientVotes[client];
return true;
}
bool VoteMenuHandler::RedrawToClient(int client, bool revotes)
{
unsigned int time_limit;
if (!IsClientInVotePool(client))
{
return false;
}
if (m_ClientVotes[client] >= 0)
{
if ((m_VoteFlags & VOTEFLAG_NO_REVOTES) == VOTEFLAG_NO_REVOTES || !revotes)
{
return false;
}
assert((unsigned)m_ClientVotes[client] < m_Items);
assert(m_Votes[m_ClientVotes[client]] > 0);
m_Votes[m_ClientVotes[client]]--;
m_ClientVotes[client] = VOTE_PENDING;
m_Revoting[client] = true;
m_NumVotes--;
}
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, bool VoteMenuHandler::InitializeVoting(IBaseMenu *menu,
IMenuHandler *handler, IMenuHandler *handler,
unsigned int time, unsigned int time,
@ -308,8 +173,7 @@ bool VoteMenuHandler::InitializeVoting(IBaseMenu *menu,
/* Mark all clients as not voting */ /* Mark all clients as not voting */
for (int i=1; i<=gpGlobals->maxClients; i++) for (int i=1; i<=gpGlobals->maxClients; i++)
{ {
m_ClientVotes[i] = VOTE_NOT_VOTING; m_ClientVotes[i] = -2;
m_Revoting[i] = false;
} }
m_Items = menu->GetItemCount(); m_Items = menu->GetItemCount();
@ -323,9 +187,7 @@ bool VoteMenuHandler::InitializeVoting(IBaseMenu *menu,
m_Votes[i] = 0; m_Votes[i] = 0;
} }
m_Votes.resize(m_Items, 0); m_Votes.resize(m_Items, 0);
} } else {
else
{
for (unsigned int i=0; i<m_Items; i++) for (unsigned int i=0; i<m_Items; i++)
{ {
m_Votes[i] = 0; m_Votes[i] = 0;
@ -353,8 +215,6 @@ void VoteMenuHandler::StartVoting()
m_pHandler->OnMenuVoteStart(m_pCurMenu); m_pHandler->OnMenuVoteStart(m_pCurMenu);
m_displayTimer = g_Timers.CreateTimer(this, 1.0, NULL, TIMER_FLAG_REPEAT|TIMER_FLAG_NO_MAPCHANGE);
/* By now we know how many clients were set. /* By now we know how many clients were set.
* If there are none, we should end IMMEDIATELY. * If there are none, we should end IMMEDIATELY.
*/ */
@ -362,8 +222,6 @@ void VoteMenuHandler::StartVoting()
{ {
EndVoting(); EndVoting();
} }
m_TotalClients = m_Clients;
} }
void VoteMenuHandler::DecrementPlayerCount() void VoteMenuHandler::DecrementPlayerCount()
@ -394,17 +252,10 @@ void VoteMenuHandler::EndVoting()
if (fVoteDelay < 1.0) if (fVoteDelay < 1.0)
{ {
g_next_vote = 0.0; g_next_vote = 0.0;
} } else {
else
{
g_next_vote = gpGlobals->curtime + fVoteDelay; g_next_vote = gpGlobals->curtime + fVoteDelay;
} }
if (m_displayTimer)
{
g_Timers.KillTimer(m_displayTimer);
}
if (m_bCancelled) if (m_bCancelled)
{ {
/* If we were cancelled, don't bother tabulating anything. /* If we were cancelled, don't bother tabulating anything.
@ -451,7 +302,7 @@ void VoteMenuHandler::EndVoting()
/* Build the client list */ /* Build the client list */
for (int i=1; i<=gpGlobals->maxClients; i++) for (int i=1; i<=gpGlobals->maxClients; i++)
{ {
if (m_ClientVotes[i] >= VOTE_PENDING) if (m_ClientVotes[i] >= -1)
{ {
client_vote[vote.num_clients].client = i; client_vote[vote.num_clients].client = i;
client_vote[vote.num_clients].item = m_ClientVotes[i]; client_vote[vote.num_clients].item = m_ClientVotes[i];
@ -495,7 +346,7 @@ void VoteMenuHandler::OnMenuCancel(IBaseMenu *menu, int client, MenuCancelReason
void VoteMenuHandler::OnMenuDisplay(IBaseMenu *menu, int client, IMenuPanel *display) void VoteMenuHandler::OnMenuDisplay(IBaseMenu *menu, int client, IMenuPanel *display)
{ {
m_ClientVotes[client] = VOTE_PENDING; m_ClientVotes[client] = -1;
m_pHandler->OnMenuDisplay(menu, client, display); m_pHandler->OnMenuDisplay(menu, client, display);
} }
@ -514,62 +365,9 @@ void VoteMenuHandler::OnMenuSelect(IBaseMenu *menu, int client, unsigned int ite
/* Check by our item count, NOT the vote array size */ /* Check by our item count, NOT the vote array size */
if (item < m_Items) if (item < m_Items)
{ {
unsigned int index = menu->GetRealItemIndex(client, item); m_ClientVotes[client] = item;
m_ClientVotes[client] = index; m_Votes[item]++;
m_Votes[index]++;
m_NumVotes++; m_NumVotes++;
if (sm_vote_chat.GetBool() || sm_vote_console.GetBool() || sm_vote_client_console.GetBool())
{
static char buffer[1024];
ItemDrawInfo dr;
menu->GetItemInfo(item, &dr, client);
if (sm_vote_console.GetBool())
{
int target = SOURCEMOD_SERVER_LANGUAGE;
logicore.CoreTranslate(buffer, sizeof(buffer), "[SM] %T", 4, NULL, "Voted For",
&target, g_Players.GetPlayerByIndex(client)->GetName(), dr.display);
Engine_LogPrintWrapper(buffer);
}
if (sm_vote_chat.GetBool() || sm_vote_client_console.GetBool())
{
int maxclients = g_Players.GetMaxClients();
for (int i=1; i<=maxclients; i++)
{
CPlayer *pPlayer = g_Players.GetPlayerByIndex(i);
assert(pPlayer);
if (pPlayer->IsInGame() && !pPlayer->IsFakeClient())
{
if (m_Revoting[client])
{
logicore.CoreTranslate(buffer, sizeof(buffer), "[SM] %T", 4, NULL, "Changed Vote",
&i, g_Players.GetPlayerByIndex(client)->GetName(), dr.display);
}
else
{
logicore.CoreTranslate(buffer, sizeof(buffer), "[SM] %T", 4, NULL, "Voted For",
&i, g_Players.GetPlayerByIndex(client)->GetName(), dr.display);
}
if (sm_vote_chat.GetBool())
{
g_HL2.TextMsg(i, HUD_PRINTTALK, buffer);
}
if (sm_vote_client_console.GetBool())
{
ClientConsolePrint(pPlayer->GetEdict(), buffer);
}
}
}
}
}
BuildVoteLeaders();
DrawHintProgress();
} }
m_pHandler->OnMenuSelect(menu, client, item); m_pHandler->OnMenuSelect(menu, client, item);
@ -592,9 +390,6 @@ void VoteMenuHandler::InternalReset()
m_NumVotes = 0; m_NumVotes = 0;
m_bCancelled = false; m_bCancelled = false;
m_pHandler = NULL; m_pHandler = NULL;
m_leaderList[0] = '\0';
m_displayTimer = NULL;
m_TotalClients = 0;
} }
void VoteMenuHandler::CancelVoting() void VoteMenuHandler::CancelVoting()
@ -616,87 +411,3 @@ bool VoteMenuHandler::IsCancelling()
{ {
return m_bCancelled; return m_bCancelled;
} }
void VoteMenuHandler::DrawHintProgress()
{
if (!sm_vote_hintbox.GetBool())
{
return;
}
static char buffer[1024];
float timeRemaining = (m_fStartTime + m_nMenuTime) - gpGlobals->curtime;
if (timeRemaining < 0)
{
timeRemaining = 0.0;
}
int iTimeRemaining = RoundFloatToInt(timeRemaining);
int maxclients = g_Players.GetMaxClients();
for (int i=1; i<=maxclients; i++)
{
if (g_Players.GetPlayerByIndex(i)->IsInGame())
{
logicore.CoreTranslate(buffer, sizeof(buffer), "%T%s", 6, NULL, "Vote Count",
&i, &m_NumVotes, &m_TotalClients, &iTimeRemaining, &m_leaderList);
g_HL2.HintTextMsg(i, buffer);
}
}
}
void VoteMenuHandler::BuildVoteLeaders()
{
if (m_NumVotes == 0 || !sm_vote_hintbox.GetBool())
{
return;
}
menu_vote_result_t vote;
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;
assert(vote.num_votes);
/* Sort the item list descending */
qsort(item_vote,
vote.num_items,
sizeof(menu_vote_result_t::menu_item_vote_t),
SortVoteItems);
/* Take the top 3 (if applicable) and draw them */
int len = 0;
for (unsigned int i=0; i<vote.num_items && i<3; i++)
{
int curItem = vote.item_list[i].item;
ItemDrawInfo dr;
m_pCurMenu->GetItemInfo(curItem, &dr);
len += g_SourceMod.Format(m_leaderList + len, sizeof(m_leaderList) - len, "\n%i. %s: (%i)", i+1, dr.display, vote.item_list[i].count);
}
}
SourceMod::ResultType VoteMenuHandler::OnTimer(ITimer *pTimer, void *pData)
{
DrawHintProgress();
return Pl_Continue;
}
void VoteMenuHandler::OnTimerEnd(ITimer *pTimer, void *pData)
{
m_displayTimer = NULL;
}

View File

@ -2,7 +2,7 @@
* vim: set ts=4 : * vim: set ts=4 :
* ============================================================================= * =============================================================================
* SourceMod * SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
* ============================================================================= * =============================================================================
* *
* This program is free software; you can redistribute it and/or modify it under * This program is free software; you can redistribute it and/or modify it under
@ -36,7 +36,6 @@
#include <IPlayerHelpers.h> #include <IPlayerHelpers.h>
#include <sh_vector.h> #include <sh_vector.h>
#include "sm_globals.h" #include "sm_globals.h"
#include <TimerSys.h>
using namespace SourceHook; using namespace SourceHook;
using namespace SourceMod; using namespace SourceMod;
@ -44,8 +43,7 @@ using namespace SourceMod;
class VoteMenuHandler : class VoteMenuHandler :
public IMenuHandler, public IMenuHandler,
public SMGlobalClass, public SMGlobalClass,
public IClientListener, public IClientListener
public ITimedEvent
{ {
public: //SMGlobalClass public: //SMGlobalClass
void OnSourceModAllInitialized(); void OnSourceModAllInitialized();
@ -63,9 +61,6 @@ public: //IMenuHandler
void OnMenuEnd(IBaseMenu *menu, MenuEndReason reason); void OnMenuEnd(IBaseMenu *menu, MenuEndReason reason);
void OnMenuDrawItem(IBaseMenu *menu, int client, unsigned int item, unsigned int &style); 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); unsigned int OnMenuDisplayItem(IBaseMenu *menu, int client, IMenuPanel *panel, unsigned int item, const ItemDrawInfo &dr);
public: //ITimedEvent
ResultType OnTimer(ITimer *pTimer, void *pData);
void OnTimerEnd(ITimer *pTimer, void *pData);
public: public:
bool StartVote(IBaseMenu *menu, bool StartVote(IBaseMenu *menu,
unsigned int num_clients, unsigned int num_clients,
@ -77,9 +72,6 @@ public:
IBaseMenu *GetCurrentMenu(); IBaseMenu *GetCurrentMenu();
bool IsCancelling(); bool IsCancelling();
unsigned int GetRemainingVoteDelay(); unsigned int GetRemainingVoteDelay();
bool IsClientInVotePool(int client);
bool GetClientVoteChoice(int client, unsigned int *pItem);
bool RedrawToClient(int client, bool revote);
private: private:
void Reset(IMenuHandler *mh); void Reset(IMenuHandler *mh);
void DecrementPlayerCount(); void DecrementPlayerCount();
@ -90,12 +82,9 @@ private:
unsigned int time, unsigned int time,
unsigned int flags); unsigned int flags);
void StartVoting(); void StartVoting();
void DrawHintProgress();
void BuildVoteLeaders();
private: private:
IMenuHandler *m_pHandler; IMenuHandler *m_pHandler;
unsigned int m_Clients; unsigned int m_Clients;
unsigned int m_TotalClients;
unsigned int m_Items; unsigned int m_Items;
CVector<unsigned int> m_Votes; CVector<unsigned int> m_Votes;
IBaseMenu *m_pCurMenu; IBaseMenu *m_pCurMenu;
@ -104,13 +93,7 @@ private:
unsigned int m_NumVotes; unsigned int m_NumVotes;
unsigned int m_VoteTime; unsigned int m_VoteTime;
unsigned int m_VoteFlags; unsigned int m_VoteFlags;
float m_fStartTime;
unsigned int m_nMenuTime;
int m_ClientVotes[256+1]; int m_ClientVotes[256+1];
bool m_Revoting[256+1];
char m_leaderList[1024];
ITimer *m_displayTimer;
}; };
#endif //_INCLUDE_SOURCEMOD_MENUVOTING_H_ #endif //_INCLUDE_SOURCEMOD_MENUVOTING_H_

View File

@ -1,227 +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 "HalfLife2.h"
#include "sourcemm_api.h"
#include "sm_stringutil.h"
#include "sourcehook.h"
#include "logic_bridge.h"
#include "compat_wrappers.h"
#include <time.h>
#include <bridge/include/ILogger.h>
NextMapManager g_NextMap;
#if SOURCE_ENGINE != SE_DARKMESSIAH
SH_DECL_HOOK2_void(IVEngineServer, ChangeLevel, SH_NOATTRIB, 0, const char *, const char *);
#else
SH_DECL_HOOK4_void(IVEngineServer, ChangeLevel, SH_NOATTRIB, 0, const char *, const char *, const char *, bool);
#endif
#if SOURCE_ENGINE >= SE_ORANGEBOX
SH_DECL_EXTERN1_void(ConCommand, Dispatch, SH_NOATTRIB, false, const CCommand &);
#else
SH_DECL_EXTERN0_void(ConCommand, Dispatch, SH_NOATTRIB, false);
#endif
ConCommand *changeLevelCmd = NULL;
ConVar sm_nextmap("sm_nextmap", "", FCVAR_NOTIFY);
ConVar sm_maphistory_size("sm_maphistory_size", "20");
bool g_forcedChange = false;
void NextMapManager::OnSourceModAllInitialized_Post()
{
#if SOURCE_ENGINE >= SE_ORANGEBOX
SH_ADD_HOOK(IVEngineServer, ChangeLevel, engine, SH_MEMBER(this, &NextMapManager::HookChangeLevel), false);
#else
SH_ADD_HOOK(IVEngineServer, ChangeLevel, engine, SH_MEMBER(this, &NextMapManager::HookChangeLevel), false);
#endif
ConCommand *pCmd = FindCommand("changelevel");
if (pCmd != NULL)
{
SH_ADD_HOOK(ConCommand, Dispatch, pCmd, SH_STATIC(CmdChangeLevelCallback), false);
changeLevelCmd = pCmd;
}
}
void NextMapManager::OnSourceModShutdown()
{
#if SOURCE_ENGINE >= SE_ORANGEBOX
SH_REMOVE_HOOK(IVEngineServer, ChangeLevel, engine, SH_MEMBER(this, &NextMapManager::HookChangeLevel), false);
#else
SH_REMOVE_HOOK(IVEngineServer, ChangeLevel, engine, SH_MEMBER(this, &NextMapManager::HookChangeLevel), false);
#endif
if (changeLevelCmd != NULL)
{
SH_REMOVE_HOOK(ConCommand, Dispatch, changeLevelCmd, SH_STATIC(CmdChangeLevelCallback), false);
}
SourceHook::List<MapChangeData *>::iterator iter;
iter = m_mapHistory.begin();
while (iter != m_mapHistory.end())
{
delete (MapChangeData *)*iter;
iter = m_mapHistory.erase(iter);
}
}
const char *NextMapManager::GetNextMap()
{
return sm_nextmap.GetString();
}
bool NextMapManager::SetNextMap(const char *map)
{
if (!g_HL2.IsMapValid(map))
{
return false;
}
sm_nextmap.SetValue(map);
return true;
}
#if SOURCE_ENGINE != SE_DARKMESSIAH
void NextMapManager::HookChangeLevel(const char *map, const char *unknown)
#else
void NextMapManager::HookChangeLevel(const char *map, const char *unknown, const char *video, bool bLongLoading)
#endif
{
if (g_forcedChange)
{
logger->LogMessage("[SM] Changed map to \"%s\"", map);
RETURN_META(MRES_IGNORED);
}
const char *newmap = sm_nextmap.GetString();
if (newmap[0] == 0 || !g_HL2.IsMapValid(newmap))
{
RETURN_META(MRES_IGNORED);
}
logger->LogMessage("[SM] Changed map to \"%s\"", newmap);
ke::SafeStrcpy(m_tempChangeInfo.m_mapName, sizeof(m_tempChangeInfo.m_mapName), newmap);
ke::SafeStrcpy(m_tempChangeInfo.m_changeReason, sizeof(m_tempChangeInfo.m_changeReason), "Normal level change");
#if SOURCE_ENGINE != SE_DARKMESSIAH
RETURN_META_NEWPARAMS(MRES_IGNORED, &IVEngineServer::ChangeLevel, (newmap, unknown));
#else
RETURN_META_NEWPARAMS(MRES_IGNORED, &IVEngineServer::ChangeLevel, (newmap, unknown, video, bLongLoading));
#endif
}
void NextMapManager::OnSourceModLevelChange( const char *mapName )
{
/* Skip the first 'mapchange' when the server starts up */
if (m_tempChangeInfo.startTime != 0)
{
if (strcmp(mapName, m_tempChangeInfo.m_mapName) == 0)
{
/* The map change was as we expected */
m_mapHistory.push_back(new MapChangeData(lastMap, m_tempChangeInfo.m_changeReason, m_tempChangeInfo.startTime));
}
else
{
/* Something intercepted the mapchange */
char newReason[255];
ke::SafeSprintf(newReason, sizeof(newReason), "%s (Map overridden)", m_tempChangeInfo.m_changeReason);
m_mapHistory.push_back(new MapChangeData(lastMap, newReason, m_tempChangeInfo.startTime));
}
int historydiff = sm_maphistory_size.GetInt();
if (historydiff > 0)
{
historydiff -= m_mapHistory.size();
} else if (historydiff < 0)
{
historydiff = (m_mapHistory.size() * -1);
}
for (SourceHook::List<MapChangeData *>::iterator iter = m_mapHistory.begin(); historydiff++ < 0; iter = m_mapHistory.erase(iter))
{
delete (MapChangeData *)*iter;
}
}
m_tempChangeInfo.m_mapName[0] ='\0';
m_tempChangeInfo.m_changeReason[0] = '\0';
m_tempChangeInfo.startTime = time(NULL);
ke::SafeStrcpy(lastMap, sizeof(lastMap), mapName);
}
void NextMapManager::ForceChangeLevel( const char *mapName, const char* changeReason )
{
/* Store the mapname and reason */
ke::SafeStrcpy(m_tempChangeInfo.m_mapName, sizeof(m_tempChangeInfo.m_mapName), mapName);
ke::SafeStrcpy(m_tempChangeInfo.m_changeReason, sizeof(m_tempChangeInfo.m_changeReason), changeReason);
/* Change level and skip our hook */
g_forcedChange = true;
engine->ChangeLevel(mapName, NULL);
g_forcedChange = false;
}
NextMapManager::NextMapManager()
{
m_tempChangeInfo = MapChangeData();
m_mapHistory = SourceHook::List<MapChangeData *>();
}
#if SOURCE_ENGINE >= SE_ORANGEBOX
void CmdChangeLevelCallback(const CCommand &command)
{
#else
void CmdChangeLevelCallback()
{
CCommand command;
#endif
if (command.ArgC() < 2)
{
return;
}
if (g_NextMap.m_tempChangeInfo.m_mapName[0] == '\0')
{
ke::SafeStrcpy(g_NextMap.m_tempChangeInfo.m_mapName, sizeof(g_NextMap.m_tempChangeInfo.m_mapName), command.Arg(1));
ke::SafeStrcpy(g_NextMap.m_tempChangeInfo.m_changeReason, sizeof(g_NextMap.m_tempChangeInfo.m_changeReason), "changelevel Command");
}
}

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_NEXTMAP_H_
#define _INCLUDE_SOURCEMOD_NEXTMAP_H_
#include "sm_globals.h"
#include <eiface.h>
#include "sh_list.h"
#include "sm_stringutil.h"
#include <amtl/am-string.h>
struct MapChangeData
{
MapChangeData(const char *mapName, const char *changeReason, time_t time)
{
ke::SafeStrcpy(m_mapName, sizeof(m_mapName), mapName);
ke::SafeStrcpy(m_changeReason, sizeof(m_changeReason), changeReason);
startTime = time;
}
MapChangeData()
{
m_mapName[0] = '\0';
m_changeReason[0] = '\0';
startTime = 0;
}
char m_mapName[PLATFORM_MAX_PATH];
char m_changeReason[100];
time_t startTime;
};
#if SOURCE_ENGINE >= SE_ORANGEBOX
void CmdChangeLevelCallback(const CCommand &command);
#else
void CmdChangeLevelCallback();
#endif
class NextMapManager : public SMGlobalClass
{
public:
NextMapManager();
#if SOURCE_ENGINE >= SE_ORANGEBOX
friend void CmdChangeLevelCallback(const CCommand &command);
#else
friend void CmdChangeLevelCallback();
#endif
void OnSourceModAllInitialized_Post();
void OnSourceModShutdown();
void OnSourceModLevelChange(const char *mapName);
const char *GetNextMap();
bool SetNextMap(const char *map);
void ForceChangeLevel(const char *mapName, const char* changeReason);
#if SOURCE_ENGINE != SE_DARKMESSIAH
void HookChangeLevel(const char *map, const char *unknown);
#else
void HookChangeLevel(const char *map, const char *unknown, const char *video, bool bLongLoading);
#endif
public:
SourceHook::List<MapChangeData *> m_mapHistory;
private:
MapChangeData m_tempChangeInfo;
char lastMap[32];
};
extern NextMapManager g_NextMap;
#endif //_INCLUDE_SOURCEMOD_NEXTMAP_H_

File diff suppressed because it is too large Load Diff

View File

@ -2,7 +2,7 @@
* vim: set ts=4 : * vim: set ts=4 :
* ============================================================================= * =============================================================================
* SourceMod * SourceMod
* Copyright (C) 2004-2015 AlliedModders LLC. All rights reserved. * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
* ============================================================================= * =============================================================================
* *
* This program is free software; you can redistribute it and/or modify it under * This program is free software; you can redistribute it and/or modify it under
@ -38,36 +38,18 @@
#include <IForwardSys.h> #include <IForwardSys.h>
#include <IPlayerHelpers.h> #include <IPlayerHelpers.h>
#include <IAdminSystem.h> #include <IAdminSystem.h>
#include <ITranslator.h>
#include <sh_string.h> #include <sh_string.h>
#include <sh_list.h> #include <sh_list.h>
#include <sh_vector.h> #include <sh_vector.h>
#include <am-string.h>
#include <am-deque.h>
#include "ConVarManager.h"
#include <steam/steamclientpublic.h>
using namespace SourceHook; using namespace SourceHook;
class IClient;
#define PLAYER_LIFE_UNKNOWN 0 #define PLAYER_LIFE_UNKNOWN 0
#define PLAYER_LIFE_ALIVE 1 #define PLAYER_LIFE_ALIVE 1
#define PLAYER_LIFE_DEAD 2 #define PLAYER_LIFE_DEAD 2
#define MIN_API_FOR_ADMINCALLS 7 #define MIN_API_FOR_ADMINCALLS 7
union serial_t
{
uint32_t value;
struct
{
uint32_t index : 8;
uint32_t serial : 24;
} bits;
};
class CPlayer : public IGamePlayer class CPlayer : public IGamePlayer
{ {
friend class PlayerManager; friend class PlayerManager;
@ -76,126 +58,86 @@ public:
public: public:
const char *GetName(); const char *GetName();
const char *GetIPAddress(); const char *GetIPAddress();
const char *GetAuthString(bool validated = true); const char *GetAuthString();
unsigned int GetSteamAccountID(bool validated = true);
const CSteamID &GetSteamId(bool validated = true);
uint64_t GetSteamId64(bool validated = true) { return GetSteamId(validated).ConvertToUint64(); }
const char *GetSteam2Id(bool validated = true);
const char *GetSteam3Id(bool validated = true);
edict_t *GetEdict(); edict_t *GetEdict();
bool IsInGame(); bool IsInGame();
bool WasCountedAsInGame(); bool WasCountedAsInGame();
bool IsConnected(); bool IsConnected();
bool IsAuthorized(); bool IsAuthorized();
bool IsFakeClient(); bool IsFakeClient();
bool IsSourceTV() const;
bool IsReplay() const;
void SetAdminId(AdminId id, bool temporary); void SetAdminId(AdminId id, bool temporary);
AdminId GetAdminId(); AdminId GetAdminId();
void Kick(const char *str); void Kick(const char *str);
bool IsInKickQueue();
IPlayerInfo *GetPlayerInfo(); IPlayerInfo *GetPlayerInfo();
unsigned int GetLanguageId(); unsigned int GetLanguageId();
void SetLanguageId(unsigned int id);
int GetUserId(); int GetUserId();
bool RunAdminCacheChecks(); bool RunAdminCacheChecks();
void NotifyPostAdminChecks(); void NotifyPostAdminChecks();
unsigned int GetSerial();
int GetIndex() const;
void PrintToConsole(const char *pMsg);
void ClearAdmin();
public: public:
void DoBasicAdminChecks(); void DoBasicAdminChecks();
bool IsInKickQueue();
void MarkAsBeingKicked(); void MarkAsBeingKicked();
int GetLifeState(); int GetLifeState();
// This can be NULL for fakeclients due to limitations in our impl
IClient *GetIClient() const;
private: private:
void Initialize(const char *name, const char *ip, edict_t *pEntity); void Initialize(const char *name, const char *ip, edict_t *pEntity);
void Connect(); void Connect();
void Disconnect(); void Disconnect();
void SetName(const char *name); void SetName(const char *name);
void DumpAdmin(bool deleting); void DumpAdmin(bool deleting);
void UpdateAuthIds(); void Authorize(const char *auth);
void Authorize();
void Authorize_Post(); void Authorize_Post();
void DoPostConnectAuthorization(); void DoPostConnectAuthorization();
bool IsAuthStringValidated();
bool SetEngineString();
bool SetCSteamID();
void ClearNetchannelQueue(void);
private: private:
bool m_IsConnected = false; bool m_IsConnected;
bool m_IsInGame = false; bool m_IsInGame;
bool m_IsAuthorized = false; bool m_IsAuthorized;
bool m_bIsInKickQueue = false; bool m_bIsInKickQueue;
String m_Name; String m_Name;
String m_Ip; String m_Ip;
String m_IpNoPort; String m_IpNoPort;
ke::AString m_AuthID; String m_AuthID;
ke::AString m_Steam2Id; AdminId m_Admin;
ke::AString m_Steam3Id; bool m_TempAdmin;
AdminId m_Admin = INVALID_ADMIN_ID; edict_t *m_pEdict;
bool m_TempAdmin = false; IPlayerInfo *m_Info;
edict_t *m_pEdict = nullptr;
IPlayerInfo *m_Info = nullptr;
IClient *m_pIClient = nullptr;
String m_LastPassword; String m_LastPassword;
bool m_bAdminCheckSignalled = false; bool m_bAdminCheckSignalled;
int m_iIndex; int m_iIndex;
unsigned int m_LangId = SOURCEMOD_LANGUAGE_ENGLISH; unsigned int m_LangId;
int m_UserId = -1; int m_UserId;
bool m_bFakeClient = false;
bool m_bIsSourceTV = false;
bool m_bIsReplay = false;
serial_t m_Serial;
CSteamID m_SteamId;
#if SOURCE_ENGINE == SE_CSGO
QueryCvarCookie_t m_LanguageCookie = InvalidQueryCvarCookie;
#endif
ke::Deque<ke::AString> m_PrintfBuffer;
}; };
class PlayerManager : class PlayerManager :
public SMGlobalClass, public SMGlobalClass,
public IPlayerManager, public IPlayerManager
public IGameEventListener2
{ {
friend class CPlayer; friend class CPlayer;
public: public:
PlayerManager(); PlayerManager();
~PlayerManager(); ~PlayerManager();
public: //SMGlobalClass public: //SMGlobalClass
void OnSourceModStartup(bool late) override;
void OnSourceModAllInitialized(); void OnSourceModAllInitialized();
void OnSourceModShutdown(); void OnSourceModShutdown();
void OnSourceModLevelEnd(); void OnSourceModLevelEnd();
ConfigResult OnSourceModConfigChanged(const char *key, const char *value, ConfigSource source, char *error, size_t maxlength); ConfigResult OnSourceModConfigChanged(const char *key, const char *value, ConfigSource source, char *error, size_t maxlength);
void OnSourceModMaxPlayersChanged(int newvalue);
public: public:
CPlayer *GetPlayerByIndex(int client) const; CPlayer *GetPlayerByIndex(int client) const;
void RunAuthChecks(); void RunAuthChecks();
void ClearAdminId(AdminId id);
void ClearAllAdmins();
public: public:
bool OnClientConnect(edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen); 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); 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 OnClientPutInServer(edict_t *pEntity, char const *playername);
void OnClientDisconnect(edict_t *pEntity); void OnClientDisconnect(edict_t *pEntity);
void OnClientDisconnect_Post(edict_t *pEntity); void OnClientDisconnect_Post(edict_t *pEntity);
#if SOURCE_ENGINE >= SE_ORANGEBOX #if defined ORANGEBOX_BUILD
void OnClientCommand(edict_t *pEntity, const CCommand &args); void OnClientCommand(edict_t *pEntity, const CCommand &args);
#if SOURCE_ENGINE >= SE_EYE
void OnClientCommandKeyValues(edict_t *pEntity, KeyValues *pCommand);
void OnClientCommandKeyValues_Post(edict_t *pEntity, KeyValues *pCommand);
#endif
#else #else
void OnClientCommand(edict_t *pEntity); void OnClientCommand(edict_t *pEntity);
#endif #endif
void OnClientSettingsChanged(edict_t *pEntity); void OnClientSettingsChanged(edict_t *pEntity);
//void OnClientSettingsChanged_Pre(edict_t *pEntity); //void OnClientSettingsChanged_Pre(edict_t *pEntity);
void OnServerHibernationUpdate(bool bHibernating);
void OnClientPrintf(edict_t *pEdict, const char *szMsg);
void OnPrintfFrameAction(unsigned int serial);
public: //IPlayerManager public: //IPlayerManager
void AddClientListener(IClientListener *listener); void AddClientListener(IClientListener *listener);
void RemoveClientListener(IClientListener *listener); void RemoveClientListener(IClientListener *listener);
@ -203,7 +145,6 @@ public: //IPlayerManager
IGamePlayer *GetGamePlayer(edict_t *pEdict); IGamePlayer *GetGamePlayer(edict_t *pEdict);
int GetMaxClients(); int GetMaxClients();
int GetNumPlayers(); int GetNumPlayers();
int GetNumClients();
int GetClientOfUserId(int userid); int GetClientOfUserId(int userid);
bool IsServerActivated(); bool IsServerActivated();
int FilterCommandTarget(IGamePlayer *pAdmin, IGamePlayer *pTarget, int flags); int FilterCommandTarget(IGamePlayer *pAdmin, IGamePlayer *pTarget, int flags);
@ -211,11 +152,6 @@ public: //IPlayerManager
void RegisterCommandTargetProcessor(ICommandTargetProcessor *pHandler); void RegisterCommandTargetProcessor(ICommandTargetProcessor *pHandler);
void UnregisterCommandTargetProcessor(ICommandTargetProcessor *pHandler); void UnregisterCommandTargetProcessor(ICommandTargetProcessor *pHandler);
void ProcessCommandTarget(cmd_target_info_t *info); void ProcessCommandTarget(cmd_target_info_t *info);
int GetClientFromSerial(unsigned int serial);
void ClearAdminId(AdminId id);
void RecheckAnyAdmins();
public: // IGameEventListener2
void FireGameEvent(IGameEvent *pEvent);
public: public:
inline int MaxClients() inline int MaxClients()
{ {
@ -225,36 +161,21 @@ public:
{ {
return m_PlayerCount; return m_PlayerCount;
} }
inline int ListenClient()
{
return m_ListenClient;
}
bool CheckSetAdmin(int index, CPlayer *pPlayer, AdminId id); bool CheckSetAdmin(int index, CPlayer *pPlayer, AdminId id);
bool CheckSetAdminName(int index, CPlayer *pPlayer, AdminId id); bool CheckSetAdminName(int index, CPlayer *pPlayer, AdminId id);
const char *GetPassInfoVar(); const char *GetPassInfoVar();
void RecheckAnyAdmins();
unsigned int GetReplyTo(); unsigned int GetReplyTo();
unsigned int SetReplyTo(unsigned int reply); unsigned int SetReplyTo(unsigned int reply);
void MaxPlayersChanged(int newvalue = -1);
inline bool InClientCommandKeyValuesHook()
{
return m_bInCCKVHook;
}
#if SOURCE_ENGINE == SE_CSGO
bool HandleConVarQuery(QueryCvarCookie_t cookie, int client, EQueryCvarValueStatus result, const char *cvarName, const char *cvarValue);
#endif
private: private:
void OnServerActivate(edict_t *pEdictList, int edictCount, int clientMax); void OnServerActivate(edict_t *pEdictList, int edictCount, int clientMax);
void InvalidatePlayer(CPlayer *pPlayer);
private: private:
List<IClientListener *> m_hooks; List<IClientListener *> m_hooks;
IForward *m_clconnect; IForward *m_clconnect;
IForward *m_clconnect_post;
IForward *m_cldisconnect; IForward *m_cldisconnect;
IForward *m_cldisconnect_post; IForward *m_cldisconnect_post;
IForward *m_clputinserver; IForward *m_clputinserver;
IForward *m_clcommand; IForward *m_clcommand;
IForward *m_clcommandkv;
IForward *m_clcommandkv_post;
IForward *m_clinfochanged; IForward *m_clinfochanged;
IForward *m_clauth; IForward *m_clauth;
IForward *m_onActivate; IForward *m_onActivate;
@ -263,33 +184,12 @@ private:
int *m_UserIdLookUp; int *m_UserIdLookUp;
int m_maxClients; int m_maxClients;
int m_PlayerCount; int m_PlayerCount;
int m_PlayersSinceActive; bool m_FirstPass;
bool m_bServerActivated;
unsigned int *m_AuthQueue; unsigned int *m_AuthQueue;
String m_PassInfoVar; String m_PassInfoVar;
bool m_QueryLang; bool m_QueryLang;
bool m_bAuthstringValidation; // are we validating admins with steam before authorizing?
bool m_bIsListenServer;
int m_ListenClient;
bool m_bIsSourceTVActive;
bool m_bIsReplayActive;
int m_SourceTVUserId;
int m_ReplayUserId;
bool m_bInCCKVHook;
int m_ClientCount;
private:
static const int NETMSG_TYPE_BITS = 5; // SVC_Print overhead for netmsg type
static const int SVC_Print_BufferSize = 2048 - 1; // -1 for terminating \0
}; };
#if SOURCE_ENGINE >= SE_ORANGEBOX
void CmdMaxplayersCallback(const CCommand &command);
#else
void CmdMaxplayersCallback();
#endif
extern void ClientConsolePrint(edict_t *e, const char *fmt, ...);
extern PlayerManager g_Players; extern PlayerManager g_Players;
extern bool g_OnMapStarted; extern bool g_OnMapStarted;
extern const unsigned int *g_NumPlayersToAuth; extern const unsigned int *g_NumPlayersToAuth;

487
core/Profiler.cpp Normal file
View File

@ -0,0 +1,487 @@
/**
* vim: set ts=4 :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2007 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;
}
}

131
core/Profiler.h Normal file
View File

@ -0,0 +1,131 @@
/**
* vim: set ts=4 :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2007 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_

View File

@ -2,7 +2,7 @@
* vim: set ts=4 : * vim: set ts=4 :
* ============================================================================= * =============================================================================
* SourceMod * SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
* ============================================================================= * =============================================================================
* *
* This program is free software; you can redistribute it and/or modify it under * This program is free software; you can redistribute it and/or modify it under
@ -36,9 +36,9 @@
#include <stdlib.h> #include <stdlib.h>
#include <assert.h> #include <assert.h>
#include "TextParsers.h" #include "TextParsers.h"
//#include "ShareSys.h" #include "ShareSys.h"
//#include "sm_stringutil.h" #include "sm_stringutil.h"
//#include "LibrarySys.h" #include "LibrarySys.h"
TextParsers g_TextParser; TextParsers g_TextParser;
ITextParsers *textparsers = &g_TextParser; ITextParsers *textparsers = &g_TextParser;
@ -69,6 +69,11 @@ TextParsers::TextParsers()
g_ws_chartable[(unsigned)' '] = 1; g_ws_chartable[(unsigned)' '] = 1;
} }
void TextParsers::OnSourceModAllInitialized()
{
g_ShareSys.AddInterface(NULL, this);
}
unsigned int TextParsers::GetUTF8CharBytes(const char *stream) unsigned int TextParsers::GetUTF8CharBytes(const char *stream)
{ {
return _GetUTF8CharBytes(stream); return _GetUTF8CharBytes(stream);
@ -169,7 +174,7 @@ SMCError TextParsers::ParseSMCFile(const char *file,
states->line = 0; states->line = 0;
states->col = 0; states->col = 0;
} }
//g_LibSys.GetPlatformError(error, sizeof(error)); g_LibSys.GetPlatformError(error, sizeof(error));
UTIL_Format(buffer, maxsize, "File could not be opened: %s", error); UTIL_Format(buffer, maxsize, "File could not be opened: %s", error);
return SMCError_StreamOpen; return SMCError_StreamOpen;
} }

View File

@ -2,7 +2,7 @@
* vim: set ts=4 : * vim: set ts=4 :
* ============================================================================= * =============================================================================
* SourceMod * SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
* ============================================================================= * =============================================================================
* *
* This program is free software; you can redistribute it and/or modify it under * This program is free software; you can redistribute it and/or modify it under
@ -32,8 +32,8 @@
#ifndef _INCLUDE_SOURCEMOD_TEXTPARSERS_H_ #ifndef _INCLUDE_SOURCEMOD_TEXTPARSERS_H_
#define _INCLUDE_SOURCEMOD_TEXTPARSERS_H_ #define _INCLUDE_SOURCEMOD_TEXTPARSERS_H_
#include "ITextParsers.h" #include <ITextParsers.h>
#include "main.h" #include "sm_globals.h"
using namespace SourceMod; using namespace SourceMod;
@ -46,10 +46,14 @@ using namespace SourceMod;
*/ */
typedef bool (*STREAMREADER)(void *, char *, size_t, unsigned int *); typedef bool (*STREAMREADER)(void *, char *, size_t, unsigned int *);
class TextParsers : public ITextParsers class TextParsers :
public ITextParsers,
public SMGlobalClass
{ {
public: public:
TextParsers(); TextParsers();
public: //SMGlobalClass
void OnSourceModAllInitialized();
public: public:
bool ParseFile_INI(const char *file, bool ParseFile_INI(const char *file,
ITextListener_INI *ini_listener, ITextListener_INI *ini_listener,

View File

@ -1,8 +1,8 @@
/** /**
* vim: set ts=4 sw=4 : * vim: set ts=4 :
* ============================================================================= * =============================================================================
* SourceMod * SourceMod
* Copyright (C) 2004-2009 AlliedModders LLC. All rights reserved. * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
* ============================================================================= * =============================================================================
* *
* This program is free software; you can redistribute it and/or modify it under * This program is free software; you can redistribute it and/or modify it under
@ -28,9 +28,10 @@
* *
* Version: $Id$ * Version: $Id$
*/ */
#include <sm_platform.h>
#include "ThreadSupport.h" #include "ThreadSupport.h"
#include "common_logic.h" #include "sm_globals.h"
#include "ShareSys.h"
#if defined PLATFORM_POSIX #if defined PLATFORM_POSIX
#include "thread/PosixThreads.h" #include "thread/PosixThreads.h"
@ -46,7 +47,6 @@ class RegThreadStuff : public SMGlobalClass
public: public:
void OnSourceModAllInitialized() void OnSourceModAllInitialized()
{ {
sharesys->AddInterface(NULL, g_pThreader); g_ShareSys.AddInterface(NULL, g_pThreader);
} }
} s_RegThreadStuff; } s_RegThreadStuff;

View File

@ -2,7 +2,7 @@
* vim: set ts=4 : * vim: set ts=4 :
* ============================================================================= * =============================================================================
* SourceMod * SourceMod
* Copyright (C) 2004-2018 AlliedModders LLC. All rights reserved. * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
* ============================================================================= * =============================================================================
* *
* This program is free software; you can redistribute it and/or modify it under * This program is free software; you can redistribute it and/or modify it under
@ -29,10 +29,13 @@
* Version: $Id$ * Version: $Id$
*/ */
#pragma once #ifndef _INCLUDE_SOURCEMOD_THREAD_SUPPORT_H
#define _INCLUDE_SOURCEMOD_THREAD_SUPPORT_H
#define protected public #include <IThreader.h>
#define private public
#include <tier1/convar.h> using namespace SourceMod;
#undef protected
#undef private extern IThreader *g_pThreader;
#endif //_INCLUDE_SOURCEMOD_THREAD_SUPPORT_H

View File

@ -2,7 +2,7 @@
* vim: set ts=4 : * vim: set ts=4 :
* ============================================================================= * =============================================================================
* SourceMod * SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
* ============================================================================= * =============================================================================
* *
* This program is free software; you can redistribute it and/or modify it under * This program is free software; you can redistribute it and/or modify it under
@ -31,10 +31,10 @@
#include <time.h> #include <time.h>
#include "TimerSys.h" #include "TimerSys.h"
#include "ForwardSys.h"
#include "sourcemm_api.h" #include "sourcemm_api.h"
#include "frame_hooks.h" #include "frame_hooks.h"
#include "ConVarManager.h" #include "ConVarManager.h"
#include "logic_bridge.h"
#define TIMER_MIN_ACCURACY 0.1 #define TIMER_MIN_ACCURACY 0.1
@ -180,9 +180,9 @@ TimerSystem::~TimerSystem()
void TimerSystem::OnSourceModAllInitialized() void TimerSystem::OnSourceModAllInitialized()
{ {
sharesys->AddInterface(NULL, this); g_ShareSys.AddInterface(NULL, this);
m_pOnGameFrame = forwardsys->CreateForward("OnGameFrame", ET_Ignore, 0, NULL); m_pOnGameFrame = g_Forwards.CreateForward("OnGameFrame", ET_Ignore, 0, NULL);
m_pOnMapTimeLeftChanged = forwardsys->CreateForward("OnMapTimeLeftChanged", ET_Ignore, 0, NULL); m_pOnMapTimeLeftChanged = g_Forwards.CreateForward("OnMapTimeLeftChanged", ET_Ignore, 0, NULL);
} }
void TimerSystem::OnSourceModGameInitialized() void TimerSystem::OnSourceModGameInitialized()
@ -198,8 +198,8 @@ void TimerSystem::OnSourceModGameInitialized()
void TimerSystem::OnSourceModShutdown() void TimerSystem::OnSourceModShutdown()
{ {
SetMapTimer(NULL); SetMapTimer(NULL);
forwardsys->ReleaseForward(m_pOnGameFrame); g_Forwards.ReleaseForward(m_pOnGameFrame);
forwardsys->ReleaseForward(m_pOnMapTimeLeftChanged); g_Forwards.ReleaseForward(m_pOnMapTimeLeftChanged);
} }
void TimerSystem::OnSourceModLevelEnd() void TimerSystem::OnSourceModLevelEnd()

View File

@ -2,7 +2,7 @@
* vim: set ts=4 : * vim: set ts=4 :
* ============================================================================= * =============================================================================
* SourceMod * SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
* ============================================================================= * =============================================================================
* *
* This program is free software; you can redistribute it and/or modify it under * This program is free software; you can redistribute it and/or modify it under
@ -32,11 +32,11 @@
#ifndef _INCLUDE_SOURCEMOD_CTIMERSYS_H_ #ifndef _INCLUDE_SOURCEMOD_CTIMERSYS_H_
#define _INCLUDE_SOURCEMOD_CTIMERSYS_H_ #define _INCLUDE_SOURCEMOD_CTIMERSYS_H_
#include "ShareSys.h"
#include <ITimerSystem.h> #include <ITimerSystem.h>
#include <sh_stack.h> #include <sh_stack.h>
#include <sh_list.h> #include <sh_list.h>
#include "sourcemm_api.h" #include "sourcemm_api.h"
#include "sm_globals.h"
using namespace SourceHook; using namespace SourceHook;
using namespace SourceMod; using namespace SourceMod;
@ -78,11 +78,11 @@ public: //ITimerSystem
float GetTickedTime(); float GetTickedTime();
void NotifyOfGameStart(float offset /* = 0.0f */); void NotifyOfGameStart(float offset /* = 0.0f */);
bool GetMapTimeLeft(float *pTime); bool GetMapTimeLeft(float *pTime);
IMapTimer *GetMapTimer();
public: public:
void RunFrame(); void RunFrame();
void RemoveMapChangeTimers(); void RemoveMapChangeTimers();
void GameFrame(bool simulating); void GameFrame(bool simulating);
IMapTimer *GetMapTimer();
private: private:
List<ITimer *> m_SingleTimers; List<ITimer *> m_SingleTimers;
List<ITimer *> m_LoopTimers; List<ITimer *> m_LoopTimers;

View File

@ -1,8 +1,8 @@
/** /**
* vim: set ts=4 sw=4 tw=99 noet: * vim: set ts=4 :
* ============================================================================= * =============================================================================
* SourceMod * SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
* ============================================================================= * =============================================================================
* *
* This program is free software; you can redistribute it and/or modify it under * This program is free software; you can redistribute it and/or modify it under
@ -29,28 +29,20 @@
* Version: $Id$ * Version: $Id$
*/ */
#include "common_logic.h"
#include <stdarg.h> #include <stdarg.h>
#include <stdlib.h> #include <stdlib.h>
#include <ctype.h> #include <ctype.h>
#include <sm_platform.h>
#include "Translator.h" #include "Translator.h"
#include <IPlayerHelpers.h> #include "Logger.h"
#include <ISourceMod.h> #include "LibrarySys.h"
#include <ILibrarySys.h> #include "sm_stringutil.h"
#include "PhraseCollection.h" #include "sourcemod.h"
#include "stringutil.h" #include "PlayerManager.h"
#include "sprintf.h"
#include <am-string.h>
#include <bridge/include/ILogger.h>
#include <bridge/include/CoreProvider.h>
Translator g_Translator; Translator g_Translator;
IPhraseCollection *g_pCorePhrases = NULL; CPhraseFile *g_pCorePhrases = NULL;
unsigned int g_pCorePhraseID = 0; unsigned int g_pCorePhraseID = 0;
using namespace SourceMod;
struct trans_t struct trans_t
{ {
int stridx; int stridx;
@ -73,10 +65,15 @@ CPhraseFile::CPhraseFile(Translator *pTranslator, const char *file)
m_LangCount = pTranslator->GetLanguageCount(); m_LangCount = pTranslator->GetLanguageCount();
m_File.assign(file); m_File.assign(file);
m_pTranslator = pTranslator; m_pTranslator = pTranslator;
m_pPhraseLookup = NULL;
} }
CPhraseFile::~CPhraseFile() CPhraseFile::~CPhraseFile()
{ {
if (m_pPhraseLookup)
{
sm_trie_destroy(m_pPhraseLookup);
}
} }
void CPhraseFile::ParseError(const char *message, ...) void CPhraseFile::ParseError(const char *message, ...)
@ -100,16 +97,20 @@ void CPhraseFile::ParseWarning(const char *message, ...)
if (!m_FileLogged) if (!m_FileLogged)
{ {
logger->LogError("[SM] Warning(s) encountered in translation file \"%s\"", m_File.c_str()); g_Logger.LogError("[SM] Warning(s) encountered in translation file \"%s\"", m_File.c_str());
m_FileLogged = true; m_FileLogged = true;
} }
logger->LogError("[SM] %s", buffer); g_Logger.LogError("[SM] %s", message);
} }
void CPhraseFile::ReparseFile() void CPhraseFile::ReparseFile()
{ {
m_PhraseLookup.clear(); if (m_pPhraseLookup)
{
sm_trie_destroy(m_pPhraseLookup);
}
m_pPhraseLookup = sm_trie_create();
m_LangCount = m_pTranslator->GetLanguageCount(); m_LangCount = m_pTranslator->GetLanguageCount();
@ -120,19 +121,19 @@ void CPhraseFile::ReparseFile()
SMCError err; SMCError err;
char path[PLATFORM_MAX_PATH]; char path[PLATFORM_MAX_PATH];
g_pSM->BuildPath(Path_SM, path, PLATFORM_MAX_PATH, "translations/%s", m_File.c_str()); g_SourceMod.BuildPath(Path_SM, path, PLATFORM_MAX_PATH, "translations/%s", m_File.c_str());
//backwards compatibility shim //backwards compatibility shim
/* :HACKHACK: Change .cfg/.txt and vice versa for compatibility */ /* :HACKHACK: Change .cfg/.txt and vice versa for compatibility */
if (!libsys->PathExists(path)) if (!g_LibSys.PathExists(path))
{ {
if (m_File.compare("common.cfg") == 0) if (m_File.compare("common.cfg") == 0)
{ {
UTIL_ReplaceAll(path, sizeof(path), "common.cfg", "common.phrases.txt", true); UTIL_ReplaceAll(path, sizeof(path), "common.cfg", "common.phrases.txt");
} else if (strstr(path, ".cfg")) { } else if (strstr(path, ".cfg")) {
UTIL_ReplaceAll(path, sizeof(path), ".cfg", ".txt", true); UTIL_ReplaceAll(path, sizeof(path), ".cfg", ".txt");
} else if (strstr(path, ".txt")) { } else if (strstr(path, ".txt")) {
UTIL_ReplaceAll(path, sizeof(path), ".txt", ".cfg", true); UTIL_ReplaceAll(path, sizeof(path), ".txt", ".cfg");
} }
} }
@ -146,47 +147,8 @@ void CPhraseFile::ReparseFile()
msg = m_ParseError.c_str(); msg = m_ParseError.c_str();
} }
logger->LogError("[SM] Fatal error encountered parsing translation file \"%s\"", m_File.c_str()); g_Logger.LogError("[SM] Fatal error encountered parsing translation file \"%s\"", m_File.c_str());
logger->LogError("[SM] Error (line %d, column %d): %s", states.line, states.col, msg); g_Logger.LogError("[SM] Error (line %d, column %d): %s", states.line, states.col, msg);
}
const char *code;
for (unsigned int i = 1; i < m_LangCount; i++)
{
if (!m_pTranslator->GetLanguageInfo(i, &code, NULL))
{
continue;
}
g_pSM->BuildPath(Path_SM,
path,
PLATFORM_MAX_PATH,
"translations/%s/%s",
code,
m_File.c_str());
/* Speculatively load these. */
if (!libsys->PathExists(path))
{
continue;
}
if ((err=textparsers->ParseFile_SMC(path, this, &states)) != SMCError_Okay)
{
const char *msg = textparsers->GetSMCErrorString(err);
if (!msg)
{
msg = m_ParseError.c_str();
}
logger->LogError("[SM] Fatal error encountered parsing translation file \"%s/%s\"",
code,
m_File.c_str());
logger->LogError("[SM] Error (line %d, column %d): %s",
states.line,
states.col,
msg);
}
} }
} }
@ -214,13 +176,18 @@ SMCResult CPhraseFile::ReadSMC_NewSection(const SMCStates *states, const char *n
m_ParseState = PPS_InPhrase; m_ParseState = PPS_InPhrase;
recognized = true; recognized = true;
if (!m_PhraseLookup.retrieve(name, &m_CurPhrase))
{
phrase_t *pPhrase; phrase_t *pPhrase;
m_CurPhrase = m_pMemory->CreateMem(sizeof(phrase_t), (void **)&pPhrase); m_CurPhrase = m_pMemory->CreateMem(sizeof(phrase_t), (void **)&pPhrase);
m_PhraseLookup.insert(name, m_CurPhrase);
/* Create the reverse lookup */
if (!sm_trie_insert(m_pPhraseLookup, name, reinterpret_cast<void *>(m_CurPhrase)))
{
ParseWarning("Skipping duplicate phrase \"%s\" on line %d.", name, states->line);
/* :IDEA: prevent memory waste by seeking backwards in memtable? */
m_CurPhrase = -1;
}
else
{
/* Initialize new phrase */ /* Initialize new phrase */
trans_t *pTrans; trans_t *pTrans;
@ -238,10 +205,9 @@ SMCResult CPhraseFile::ReadSMC_NewSection(const SMCStates *states, const char *n
{ {
pTrans[i].stridx = -1; pTrans[i].stridx = -1;
} }
}
m_LastPhraseString.assign(name); m_LastPhraseString.assign(name);
} }
}
else if (m_ParseState == PPS_InPhrase) else if (m_ParseState == PPS_InPhrase)
{ {
ParseError("Phrase sections may not have sub-sections"); ParseError("Phrase sections may not have sub-sections");
@ -266,11 +232,14 @@ SMCResult CPhraseFile::ReadSMC_KeyValue(const SMCStates *states, const char *key
phrase_t *pPhrase = (phrase_t *)m_pMemory->GetAddress(m_CurPhrase); phrase_t *pPhrase = (phrase_t *)m_pMemory->GetAddress(m_CurPhrase);
/* Duplicate format keys get silently ignored. */ if (key[0] == '#' && strcmp(key, "#format") == 0)
if (key[0] == '#'
&& strcmp(key, "#format") == 0
&& pPhrase->fmt_list == -1)
{ {
if (pPhrase->fmt_list != -1)
{
ParseWarning("Ignoring duplicated #format property on line %d", states->line);
return SMCResult_Continue;
}
if (pPhrase->translations > 0) if (pPhrase->translations > 0)
{ {
ParseWarning("#format property should come before translations on line %d, ignoring", states->line); ParseWarning("#format property should come before translations on line %d, ignoring", states->line);
@ -478,6 +447,13 @@ SMCResult CPhraseFile::ReadSMC_KeyValue(const SMCStates *states, const char *key
} }
else else
{ {
size_t len = strlen(key);
if (len != 2)
{
ParseWarning("Ignoring translation to invalid language \"%s\" on line %d.", key, states->line);
return SMCResult_Continue;
}
unsigned int lang; unsigned int lang;
if (!m_pTranslator->GetLanguageByCode(key, &lang)) if (!m_pTranslator->GetLanguageByCode(key, &lang))
{ {
@ -490,7 +466,7 @@ SMCResult CPhraseFile::ReadSMC_KeyValue(const SMCStates *states, const char *key
/* See how many bytes we need for this string, then allocate. /* See how many bytes we need for this string, then allocate.
* NOTE: THIS SHOULD GUARANTEE THAT WE DO NOT NEED TO NEED TO SIZE CHECK * NOTE: THIS SHOULD GUARANTEE THAT WE DO NOT NEED TO NEED TO SIZE CHECK
*/ */
size_t len = strlen(value) + pPhrase->fmt_bytes + 1; len = strlen(value) + pPhrase->fmt_bytes + 1;
char *out_buf; char *out_buf;
int out_idx; int out_idx;
@ -624,7 +600,9 @@ SMCResult CPhraseFile::ReadSMC_LeavingSection(const SMCStates *states)
if (m_ParseState == PPS_InPhrase) if (m_ParseState == PPS_InPhrase)
{ {
if (m_CurPhrase == -1 && m_LastPhraseString.size()) if (m_CurPhrase == -1 && m_LastPhraseString.size())
m_PhraseLookup.remove(m_LastPhraseString.c_str()); {
sm_trie_delete(m_pPhraseLookup, m_LastPhraseString.c_str());
}
m_CurPhrase = -1; m_CurPhrase = -1;
m_ParseState = PPS_Phrases; m_ParseState = PPS_Phrases;
m_LastPhraseString.assign(""); m_LastPhraseString.assign("");
@ -641,7 +619,9 @@ void CPhraseFile::ReadSMC_ParseEnd(bool halted, bool failed)
{ {
/* Check to see if we have any dangling phrases that weren't completed, and scrap them */ /* Check to see if we have any dangling phrases that weren't completed, and scrap them */
if ((halted || failed) && m_LastPhraseString.size()) if ((halted || failed) && m_LastPhraseString.size())
m_PhraseLookup.remove(m_LastPhraseString.c_str()); {
sm_trie_delete(m_pPhraseLookup, m_LastPhraseString.c_str());
}
} }
TransError CPhraseFile::GetTranslation(const char *szPhrase, unsigned int lang_id, Translation *pTrans) TransError CPhraseFile::GetTranslation(const char *szPhrase, unsigned int lang_id, Translation *pTrans)
@ -651,11 +631,13 @@ TransError CPhraseFile::GetTranslation(const char *szPhrase, unsigned int lang_i
return Trans_BadLanguage; return Trans_BadLanguage;
} }
int address; void *object;
if (!m_PhraseLookup.retrieve(szPhrase, &address)) if (!sm_trie_retrieve(m_pPhraseLookup, szPhrase, &object))
{
return Trans_BadPhrase; return Trans_BadPhrase;
}
phrase_t *pPhrase = (phrase_t *)m_pMemory->GetAddress(address); phrase_t *pPhrase = (phrase_t *)m_pMemory->GetAddress(reinterpret_cast<int>(object));
trans_t *trans = (trans_t *)m_pMemory->GetAddress(pPhrase->trans_tbl); trans_t *trans = (trans_t *)m_pMemory->GetAddress(pPhrase->trans_tbl);
trans = &trans[lang_id]; trans = &trans[lang_id];
@ -672,12 +654,6 @@ TransError CPhraseFile::GetTranslation(const char *szPhrase, unsigned int lang_i
return Trans_Okay; return Trans_Okay;
} }
bool CPhraseFile::TranslationPhraseExists(const char *phrase)
{
int address;
return m_PhraseLookup.retrieve(phrase, &address);
}
const char *CPhraseFile::GetFilename() const char *CPhraseFile::GetFilename()
{ {
return m_File.c_str(); return m_File.c_str();
@ -687,9 +663,10 @@ const char *CPhraseFile::GetFilename()
** MAIN TRANSLATOR CODE ** ** MAIN TRANSLATOR CODE **
**************************/ **************************/
Translator::Translator() : m_ServerLang(SOURCEMOD_LANGUAGE_ENGLISH) Translator::Translator() : m_ServerLang(LANGUAGE_ENGLISH)
{ {
m_pStringTab = new BaseStringTable(2048); m_pStringTab = new BaseStringTable(2048);
m_pLCodeLookup = sm_trie_create();
strncopy(m_InitialLang, "en", sizeof(m_InitialLang)); strncopy(m_InitialLang, "en", sizeof(m_InitialLang));
} }
@ -705,6 +682,8 @@ Translator::~Translator()
delete m_Languages[i]; delete m_Languages[i];
} }
sm_trie_destroy(m_pLCodeLookup);
delete m_pStringTab; delete m_pStringTab;
} }
@ -721,7 +700,7 @@ ConfigResult Translator::OnSourceModConfigChanged(const char *key,
unsigned int index; unsigned int index;
if (!GetLanguageByCode(value, &index)) if (!GetLanguageByCode(value, &index))
{ {
ke::SafeSprintf(error, maxlength, "Language code \"%s\" is not registered", value); UTIL_Format(error, maxlength, "Language code \"%s\" is not registered", value);
return ConfigResult_Reject; return ConfigResult_Reject;
} }
@ -738,57 +717,64 @@ ConfigResult Translator::OnSourceModConfigChanged(const char *key,
void Translator::OnSourceModLevelChange(const char *mapName) void Translator::OnSourceModLevelChange(const char *mapName)
{ {
RebuildLanguageDatabase(); /* Refresh language stuff */
char path[PLATFORM_MAX_PATH];
g_SourceMod.BuildPath(Path_SM, path, sizeof(path), "configs/languages.cfg");
RebuildLanguageDatabase(path);
} }
void Translator::OnSourceModAllInitialized() void Translator::OnSourceModAllInitialized()
{ {
AddLanguage("en", "English"); AddLanguage("en", "English");
const char* lang = bridge->GetCoreConfigValue("ServerLang"); unsigned int id;
if (lang)
{
strncpy(m_InitialLang, lang, sizeof(m_InitialLang));
}
g_pCorePhrases = CreatePhraseCollection(); id = FindOrAddPhraseFile("core.phrases.txt");
g_pCorePhrases->AddPhraseFile("core.phrases"); g_pCorePhraseID = id;
g_pCorePhrases = GetFileByIndex(id);
sharesys->AddInterface(NULL, this);
auto sm_reload_translations = [this] (int client, const ICommandArgs *args) -> bool {
RebuildLanguageDatabase();
return true;
};
bridge->DefineCommand("sm_reload_translations", "Reparses all loaded translation files",
sm_reload_translations);
}
void Translator::OnSourceModShutdown()
{
g_pCorePhrases->Destroy();
} }
bool Translator::GetLanguageByCode(const char *code, unsigned int *index) bool Translator::GetLanguageByCode(const char *code, unsigned int *index)
{ {
return m_LCodeLookup.retrieve(code, index); void *_index;
if (!sm_trie_retrieve(m_pLCodeLookup, code, &_index))
{
return false;
}
if (index)
{
*index = reinterpret_cast<unsigned int>(_index);
}
return true;
} }
bool Translator::GetLanguageByName(const char *name, unsigned int *index) bool Translator::GetLanguageByName(const char *name, unsigned int *index)
{ {
char lower[256]; CVector<Language *>::iterator iter;
size_t len = strlen(name); unsigned int id = 0;
if (len > 255) len = 255;
for (size_t i = 0; i < len; i++)
{
if (name[i] >= 'A' && name[i] <= 'Z')
lower[i] = tolower(name[i]);
else
lower[i] = name[i];
}
lower[len] = '\0';
return m_LAliases.retrieve(lower, index); for (iter=m_Languages.begin(); iter!=m_Languages.end(); iter++, id++)
{
if (strcasecmp(m_pStringTab->GetString((*iter)->m_FullName), name) == 0)
{
break;
}
}
if (iter == m_Languages.end())
{
return false;
}
if (index)
{
*index = id;
}
return true;
} }
unsigned int Translator::GetLanguageCount() unsigned int Translator::GetLanguageCount()
@ -821,11 +807,11 @@ unsigned int Translator::FindOrAddPhraseFile(const char *phrase_file)
return idx; return idx;
} }
void Translator::RebuildLanguageDatabase() void Translator::RebuildLanguageDatabase(const char *lang_header_file)
{ {
/* Erase everything we have */ /* Erase everything we have */
m_LCodeLookup.clear(); sm_trie_destroy(m_pLCodeLookup);
m_LAliases.clear(); m_pLCodeLookup = sm_trie_create();
m_pStringTab->Reset(); m_pStringTab->Reset();
for (size_t i=0; i<m_Languages.size(); i++) for (size_t i=0; i<m_Languages.size(); i++)
@ -835,12 +821,9 @@ void Translator::RebuildLanguageDatabase()
m_Languages.clear(); m_Languages.clear();
/* Start anew */ /* Start anew */
char path[PLATFORM_MAX_PATH];
g_pSM->BuildPath(Path_SM, path, sizeof(path), "configs/languages.cfg");
SMCError err; SMCError err;
SMCStates states; SMCStates states;
if ((err=textparsers->ParseFile_SMC(path, this, &states)) != SMCError_Okay) if ((err=textparsers->ParseFile_SMC(lang_header_file, this, &states)) != SMCError_Okay)
{ {
const char *str_err = textparsers->GetSMCErrorString(err); const char *str_err = textparsers->GetSMCErrorString(err);
if (!str_err) if (!str_err)
@ -848,21 +831,25 @@ void Translator::RebuildLanguageDatabase()
str_err = m_CustomError.c_str(); str_err = m_CustomError.c_str();
} }
logger->LogError("[SM] Failed to parse language header file: \"%s\"", path); g_Logger.LogError("[SM] Failed to parse language header file: \"%s\"", lang_header_file);
logger->LogError("[SM] Parse error (line %d, column %d): %s", states.line, states.col, str_err); g_Logger.LogError("[SM] Parse error (line %d, column %d): %s", states.line, states.col, str_err);
} }
if (!m_LCodeLookup.retrieve(m_InitialLang, &m_ServerLang)) void *serverLang;
if (!sm_trie_retrieve(m_pLCodeLookup, m_InitialLang, &serverLang))
{ {
logger->LogError("Server language was set to bad language \"%s\" -- reverting to English", m_InitialLang); g_Logger.LogError("Server language was set to bad language \"%s\" -- reverting to English", m_InitialLang);
strncopy(m_InitialLang, "en", sizeof(m_InitialLang)); strncopy(m_InitialLang, "en", sizeof(m_InitialLang));
m_ServerLang = SOURCEMOD_LANGUAGE_ENGLISH; m_ServerLang = LANGUAGE_ENGLISH;
} }
m_ServerLang = reinterpret_cast<unsigned int>(serverLang);
if (!m_Languages.size()) if (!m_Languages.size())
{ {
logger->LogError("[SM] Fatal error, no languages found! Translation will not work."); g_Logger.LogError("[SM] Fatal error, no languages found! Translation will not work.");
} }
for (size_t i=0; i<m_Files.size(); i++) for (size_t i=0; i<m_Files.size(); i++)
@ -889,7 +876,7 @@ SMCResult Translator::ReadSMC_NewSection(const SMCStates *states, const char *na
if (!m_InLanguageSection) if (!m_InLanguageSection)
{ {
logger->LogError("[SM] Warning: Unrecognized section \"%s\" in languages.cfg", name); g_Logger.LogError("[SM] Warning: Unrecognized section \"%s\" in languages.cfg", name);
} }
return SMCResult_Continue; return SMCResult_Continue;
@ -906,10 +893,10 @@ SMCResult Translator::ReadSMC_KeyValue(const SMCStates *states, const char *key,
{ {
size_t len = strlen(key); size_t len = strlen(key);
if (len >= sizeof(((Language *)0)->m_code2)) if (len != 2)
{ {
logger->LogError("[SM] Warning encountered parsing languages.cfg file."); g_Logger.LogError("[SM] Warning encountered parsing languages.cfg file.");
logger->LogError("[SM] Invalid language code \"%s\" is too long.", key); g_Logger.LogError("[SM] Invalid language code \"%s\" is being ignored.", key);
} }
AddLanguage(key, value); AddLanguage(key, value);
@ -919,36 +906,22 @@ SMCResult Translator::ReadSMC_KeyValue(const SMCStates *states, const char *key,
bool Translator::AddLanguage(const char *langcode, const char *description) bool Translator::AddLanguage(const char *langcode, const char *description)
{ {
char lower[256]; if (sm_trie_retrieve(m_pLCodeLookup, langcode, NULL))
size_t len = strlen(description);
if (len > 255) len = 255;
for (size_t i = 0; i < len; i++)
{ {
if (description[i] >= 'A' && description[i] <= 'Z')
lower[i] = tolower(description[i]);
else
lower[i] = description[i];
}
lower[len] = '\0';
if (m_LAliases.contains(lower))
return false; return false;
}
unsigned int idx;
if (!m_LCodeLookup.retrieve(langcode, &idx))
{
Language *pLanguage = new Language; Language *pLanguage = new Language;
idx = m_Languages.size(); unsigned int idx = m_Languages.size();
ke::SafeStrcpy(pLanguage->m_code2, sizeof(pLanguage->m_code2), langcode); pLanguage->m_code2[0] = langcode[0];
pLanguage->m_CanonicalName = m_pStringTab->AddString(lower); pLanguage->m_code2[1] = langcode[1];
pLanguage->m_code2[2] = langcode[2];
pLanguage->m_FullName = m_pStringTab->AddString(description);
m_LCodeLookup.insert(langcode, idx); sm_trie_insert(m_pLCodeLookup, langcode, reinterpret_cast<void *>(idx));
m_Languages.push_back(pLanguage); m_Languages.push_back(pLanguage);
}
m_LAliases.insert(lower, idx);
return true; return true;
} }
@ -963,6 +936,61 @@ CPhraseFile *Translator::GetFileByIndex(unsigned int index)
return m_Files[index]; return m_Files[index];
} }
size_t Translator::Translate(char *buffer, size_t maxlength, void **params, const Translation *pTrans)
{
void *new_params[MAX_TRANSLATE_PARAMS];
/* Rewrite the parameter order */
for (unsigned int i=0; i<pTrans->fmt_count; i++)
{
new_params[i] = params[pTrans->fmt_order[i]];
}
return gnprintf(buffer, maxlength, pTrans->szPhrase, new_params);
}
TransError Translator::CoreTransEx(CPhraseFile *pFile,
int client,
char *buffer,
size_t maxlength,
const char *phrase,
void **params,
size_t *outlen)
{
Translation trans;
TransError err;
/* Using server lang temporarily until client lang stuff is implemented */
if ((err = pFile->GetTranslation(phrase, m_ServerLang, &trans)) != Trans_Okay)
{
return err;
}
size_t len = Translate(buffer, maxlength, params, &trans);
if (outlen)
{
*outlen = len;
}
return Trans_Okay;
}
TransError Translator::CoreTrans(int client,
char *buffer,
size_t maxlength,
const char *phrase,
void **params,
size_t *outlen)
{
if (!g_pCorePhrases)
{
return Trans_BadPhraseFile;
}
return CoreTransEx(g_pCorePhrases, client, buffer, maxlength, phrase, params, outlen);
}
unsigned int Translator::GetServerLanguage() unsigned int Translator::GetServerLanguage()
{ {
return m_ServerLang; return m_ServerLang;
@ -970,7 +998,7 @@ unsigned int Translator::GetServerLanguage()
unsigned int Translator::GetClientLanguage(int client) unsigned int Translator::GetClientLanguage(int client)
{ {
IGamePlayer *pPlayer = playerhelpers->GetGamePlayer(client); CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
return pPlayer->GetLanguageId(); return pPlayer->GetLanguageId();
} }
@ -988,105 +1016,7 @@ bool Translator::GetLanguageInfo(unsigned int number, const char **code, const c
} }
if (name) if (name)
{ {
*name = m_pStringTab->GetString(l->m_CanonicalName); *name = m_pStringTab->GetString(l->m_FullName);
}
return true;
}
const char *Translator::GetInterfaceName()
{
return SMINTERFACE_TRANSLATOR_NAME;
}
unsigned int Translator::GetInterfaceVersion()
{
return SMINTERFACE_TRANSLATOR_VERSION;
}
CPhraseCollection *Translator::CreatePhraseCollection()
{
return new CPhraseCollection();
}
int Translator::SetGlobalTarget(int index)
{
return g_pSM->SetGlobalTarget(index);
}
int Translator::GetGlobalTarget() const
{
return g_pSM->GetGlobalTarget();
}
bool CoreTranslate(char *buffer, size_t maxlength, const char *format, unsigned int numparams,
size_t *pOutLength, ...)
{
va_list ap;
unsigned int i;
const char *fail_phrase;
void *params[MAX_TRANSLATE_PARAMS];
if (numparams > MAX_TRANSLATE_PARAMS)
{
assert(false);
return false;
}
va_start(ap, pOutLength);
for (i = 0; i < numparams; i++)
{
params[i] = va_arg(ap, void *);
}
va_end(ap);
if (!g_pCorePhrases->FormatString(buffer,
maxlength,
format,
params,
numparams,
pOutLength,
&fail_phrase))
{
if (fail_phrase != NULL)
{
logger->LogError("[SM] Could not find core phrase: %s", fail_phrase);
}
else
{
logger->LogError("[SM] Unknown fatal error while translating a core phrase.");
}
return false;
}
return true;
}
bool Translator::FormatString(char *buffer,
size_t maxlength,
const char *format,
IPhraseCollection *pPhrases,
void **params,
unsigned int numparams,
size_t *pOutLength,
const char **pFailPhrase)
{
unsigned int arg;
arg = 0;
if (!gnprintf(buffer, maxlength, format, pPhrases, params, numparams, arg, pOutLength, pFailPhrase))
{
return false;
}
if (arg != numparams)
{
if (pFailPhrase != NULL)
{
*pFailPhrase = NULL;
}
return false;
} }
return true; return true;

View File

@ -2,7 +2,7 @@
* vim: set ts=4 : * vim: set ts=4 :
* ============================================================================= * =============================================================================
* SourceMod * SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
* ============================================================================= * =============================================================================
* *
* This program is free software; you can redistribute it and/or modify it under * This program is free software; you can redistribute it and/or modify it under
@ -32,18 +32,18 @@
#ifndef _INCLUDE_SOURCEMOD_TRANSLATOR_H_ #ifndef _INCLUDE_SOURCEMOD_TRANSLATOR_H_
#define _INCLUDE_SOURCEMOD_TRANSLATOR_H_ #define _INCLUDE_SOURCEMOD_TRANSLATOR_H_
#include "common_logic.h" #include "sm_trie.h"
#include <sm_stringhashmap.h>
#include <sh_string.h> #include <sh_string.h>
#include <sh_vector.h> #include <sh_vector.h>
#include "sm_globals.h"
#include "sm_memtable.h" #include "sm_memtable.h"
#include "ITextParsers.h" #include "ITextParsers.h"
#include <ITranslator.h>
#include "PhraseCollection.h" #define MAX_TRANSLATE_PARAMS 32
#define CORELANG_ENGLISH 0
/* :TODO: write a templatized version of tries? */ /* :TODO: write a templatized version of tries? */
using namespace SourceMod;
using namespace SourceHook; using namespace SourceHook;
class Translator; class Translator;
@ -56,13 +56,29 @@ enum PhraseParseState
struct Language struct Language
{ {
char m_code2[32]; char m_code2[3];
int m_CanonicalName; int m_FullName;
}; };
class CPhraseFile : struct Translation
public ITextListener_SMC, {
public IPhraseFile const char *szPhrase; /**< Translated phrase. */
unsigned int fmt_count; /**< Number of format parameters. */
int *fmt_order; /**< Format phrase order. */
};
#define LANGUAGE_ENGLISH 0
enum TransError
{
Trans_Okay = 0,
Trans_BadLanguage = 1,
Trans_BadPhrase = 2,
Trans_BadPhraseLanguage = 3,
Trans_BadPhraseFile = 4,
};
class CPhraseFile : public ITextListener_SMC
{ {
public: public:
CPhraseFile(Translator *pTranslator, const char *file); CPhraseFile(Translator *pTranslator, const char *file);
@ -71,7 +87,6 @@ public:
void ReparseFile(); void ReparseFile();
const char *GetFilename(); const char *GetFilename();
TransError GetTranslation(const char *szPhrase, unsigned int lang_id, Translation *pTrans); TransError GetTranslation(const char *szPhrase, unsigned int lang_id, Translation *pTrans);
bool TranslationPhraseExists(const char *phrase);
public: //ITextListener_SMC public: //ITextListener_SMC
void ReadSMC_ParseStart(); void ReadSMC_ParseStart();
SMCResult ReadSMC_NewSection(const SMCStates *states, const char *name); SMCResult ReadSMC_NewSection(const SMCStates *states, const char *name);
@ -82,7 +97,7 @@ private:
void ParseError(const char *message, ...); void ParseError(const char *message, ...);
void ParseWarning(const char *message, ...); void ParseWarning(const char *message, ...);
private: private:
StringHashMap<int> m_PhraseLookup; Trie *m_pPhraseLookup;
String m_File; String m_File;
Translator *m_pTranslator; Translator *m_pTranslator;
PhraseParseState m_ParseState; PhraseParseState m_ParseState;
@ -97,8 +112,7 @@ private:
class Translator : class Translator :
public ITextListener_SMC, public ITextListener_SMC,
public SMGlobalClass, public SMGlobalClass
public ITranslator
{ {
public: public:
Translator(); Translator();
@ -111,69 +125,51 @@ public: // SMGlobalClass
size_t maxlength); size_t maxlength);
void OnSourceModAllInitialized(); void OnSourceModAllInitialized();
void OnSourceModLevelChange(const char *mapName); void OnSourceModLevelChange(const char *mapName);
void OnSourceModShutdown();
public: // ITextListener_SMC public: // ITextListener_SMC
void ReadSMC_ParseStart(); void ReadSMC_ParseStart();
SMCResult ReadSMC_NewSection(const SMCStates *states, const char *name); SMCResult ReadSMC_NewSection(const SMCStates *states, const char *name);
SMCResult ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value); SMCResult ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value);
SMCResult ReadSMC_LeavingSection(const SMCStates *states); SMCResult ReadSMC_LeavingSection(const SMCStates *states);
public: public:
void RebuildLanguageDatabase(const char *lang_header_file);
unsigned int FindOrAddPhraseFile(const char *phrase_file); unsigned int FindOrAddPhraseFile(const char *phrase_file);
BaseStringTable *GetStringTable(); BaseStringTable *GetStringTable();
unsigned int GetLanguageCount(); unsigned int GetLanguageCount();
bool GetLanguageInfo(unsigned int number, const char **code, const char **name);
bool GetLanguageByCode(const char *code, unsigned int *index); bool GetLanguageByCode(const char *code, unsigned int *index);
bool GetLanguageByName(const char *name, unsigned int *index); bool GetLanguageByName(const char *name, unsigned int *index);
size_t Translate(char *buffer, size_t maxlength, void **params, const Translation *pTrans);
CPhraseFile *GetFileByIndex(unsigned int index); CPhraseFile *GetFileByIndex(unsigned int index);
public: //ITranslator TransError CoreTransEx(CPhraseFile *pFile,
int client,
char *buffer,
size_t maxlength,
const char *phrase,
void **params,
size_t *outlen=NULL);
TransError CoreTrans(int client,
char *buffer,
size_t maxlength,
const char *phrase,
void **params,
size_t *outlen=NULL);
unsigned int GetServerLanguage(); unsigned int GetServerLanguage();
unsigned int GetClientLanguage(int client); unsigned int GetClientLanguage(int client);
const char *GetInterfaceName();
unsigned int GetInterfaceVersion();
CPhraseCollection *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);
bool GetLanguageInfo(unsigned int number, const char **code, const char **name);
void RebuildLanguageDatabase();
private: private:
bool AddLanguage(const char *langcode, const char *description); bool AddLanguage(const char *langcode, const char *description);
private: private:
CVector<Language *> m_Languages; CVector<Language *> m_Languages;
CVector<CPhraseFile *> m_Files; CVector<CPhraseFile *> m_Files;
BaseStringTable *m_pStringTab; BaseStringTable *m_pStringTab;
StringHashMap<unsigned int> m_LCodeLookup; Trie *m_pLCodeLookup;
StringHashMap<unsigned int> m_LAliases;
bool m_InLanguageSection; bool m_InLanguageSection;
String m_CustomError; String m_CustomError;
unsigned int m_ServerLang; unsigned int m_ServerLang;
char m_InitialLang[4]; char m_InitialLang[3];
}; };
/* Nice little wrapper to handle error logging and whatnot */ extern CPhraseFile *g_pCorePhrases;
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 unsigned int g_pCorePhraseID;
extern Translator g_Translator; extern Translator g_Translator;
#endif //_INCLUDE_SOURCEMOD_TRANSLATOR_H_ #endif //_INCLUDE_SOURCEMOD_TRANSLATOR_H_

File diff suppressed because it is too large Load Diff

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