Merge branch 'master' into override-fix

This commit is contained in:
Michael Flaherty 2018-08-13 17:10:20 -07:00 committed by GitHub
commit f471b6fcfb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
452 changed files with 138845 additions and 49866 deletions

74
.github/CONTRIBUTING.md vendored Normal file
View File

@ -0,0 +1,74 @@
# 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.

26
.github/ISSUE_TEMPLATE.md vendored Normal file
View File

@ -0,0 +1,26 @@
# 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.

View File

@ -1,27 +1,118 @@
git:
depth: 3
sudo: false
language: cpp
os: linux
dist: trusty
addons:
apt:
packages:
- clang-3.5
- lib32stdc++6
- lib32z1-dev
- libc6-dev-i386
- linux-libc-dev
- g++-multilib
- g++4.8
sources:
- llvm-toolchain-precise-3.5
- ubuntu-toolchain-r-test
cache:
directories:
- ../mysql-5.0
language: cpp
sudo: false
compiler:
- clang
- 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"
- CC=clang-3.5 CXX=clang-3.5 python ../configure.py --enable-optimize --sdks=episode1,tf2,l4d2,csgo,dota
- ambuild
- eval "${MATRIX_EVAL}"
- python ../configure.py --enable-optimize --sdks=episode1,tf2,l4d2,csgo,dota
- ambuild

View File

@ -11,13 +11,32 @@ class SDK(object):
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', '1.ep1', '1', 'EPISODEONE', WinLinux, 'episode1'),
'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'),
@ -31,13 +50,13 @@ PossibleSDKs = {
'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', '20', 'CSGO', WinLinuxMac, 'csgo'),
'dota': SDK('HL2SDKDOTA', '2.dota', '21', 'DOTA', [], 'dota'),
'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):
@ -60,6 +79,28 @@ def ResolveEnvPath(env, folder):
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):
@ -68,10 +109,12 @@ class SMConfig(object):
self.extensions = []
self.generated_headers = None
self.mms_root = None
self.mysql_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':
@ -105,7 +148,7 @@ class SMConfig(object):
for sdk_name in PossibleSDKs:
sdk = PossibleSDKs[sdk_name]
if builder.target_platform in sdk.platform:
if sdk.shouldBuild(builder.target, self.archs):
if builder.options.hl2sdk_root:
sdk_path = os.path.join(builder.options.hl2sdk_root, sdk.folder)
else:
@ -118,8 +161,9 @@ class SMConfig(object):
sdk.path = Normalize(sdk_path)
self.sdks[sdk_name] = sdk
if len(self.sdks) < 1:
raise Exception('At least one SDK must be available.')
if 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
@ -136,24 +180,43 @@ class SMConfig(object):
if builder.options.hasMySql:
if builder.options.mysql_path:
self.mysql_root = builder.options.mysql_path
self.mysql_root['x86'] = builder.options.mysql_path
else:
for i in range(7):
self.mysql_root = ResolveEnvPath('MYSQL5', 'mysql-5.' + str(i))
if self.mysql_root:
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 or not os.path.isdir(self.mysql_root):
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 = Normalize(self.mysql_root)
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.DetectCompilers()
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.vendor == 'msvc':
elif cxx.family == 'msvc':
self.configure_msvc(cxx)
# Optimizaiton
@ -165,11 +228,11 @@ class SMConfig(object):
cxx.defines += ['DEBUG', '_DEBUG']
# Platform-specifics
if builder.target_platform == 'linux':
if builder.target.platform == 'linux':
self.configure_linux(cxx)
elif builder.target_platform == 'mac':
elif builder.target.platform == 'mac':
self.configure_mac(cxx)
elif builder.target_platform == 'windows':
elif builder.target.platform == 'windows':
self.configure_windows(cxx)
# Finish up.
@ -205,7 +268,6 @@ class SMConfig(object):
'-Wno-switch',
'-Wno-array-bounds',
'-msse',
'-m32',
'-fvisibility=hidden',
]
cxx.cxxflags += [
@ -216,12 +278,17 @@ class SMConfig(object):
'-Wno-overloaded-virtual',
'-fvisibility-inlines-hidden',
]
cxx.linkflags += ['-m32']
have_gcc = cxx.vendor == 'gcc'
have_clang = cxx.vendor == 'clang'
if cxx.version >= 'clang-3.6':
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'):
@ -239,6 +306,7 @@ class SMConfig(object):
if have_gcc:
cxx.cflags += ['-mfpmath=sse']
cxx.cflags += ['-Wno-maybe-uninitialized']
if builder.options.opt == '1':
cxx.cflags += ['-O3']
@ -264,7 +332,6 @@ class SMConfig(object):
'/TP',
]
cxx.linkflags += [
'/MACHINE:X86',
'kernel32.lib',
'user32.lib',
'gdi32.lib',
@ -291,19 +358,18 @@ class SMConfig(object):
cxx.cflags += ['/Oy-']
def configure_linux(self, cxx):
cxx.defines += ['_LINUX', 'POSIX']
cxx.defines += ['_LINUX', 'POSIX', '_FILE_OFFSET_BITS=64']
cxx.linkflags += ['-lm']
if cxx.vendor == 'gcc':
if cxx.family == 'gcc':
cxx.linkflags += ['-static-libgcc']
elif cxx.vendor == 'clang':
elif cxx.family == 'clang':
cxx.linkflags += ['-lgcc_eh']
def configure_mac(self, cxx):
cxx.defines += ['OSX', '_OSX', 'POSIX']
cxx.defines += ['OSX', '_OSX', 'POSIX', 'KE_ABSOLUTELY_NO_STL']
cxx.cflags += ['-mmacosx-version-min=10.5']
cxx.linkflags += [
'-mmacosx-version-min=10.5',
'-arch', 'i386',
'-lstdc++',
'-stdlib=libstdc++',
]
@ -312,8 +378,8 @@ class SMConfig(object):
def configure_windows(self, cxx):
cxx.defines += ['WIN32', '_WINDOWS']
def AddVersioning(self, binary):
if builder.target_platform == 'windows':
def AddVersioning(self, binary, arch):
if builder.target.platform == 'windows':
binary.sources += ['version.rc']
binary.compiler.rcdefines += [
'BINARY_NAME="{0}"'.format(binary.outputFile),
@ -321,28 +387,58 @@ class SMConfig(object):
]
if self.use_auto_versioning():
binary.compiler.rcdefines += ['SM_GENERATED_BUILD']
elif builder.target_platform == 'mac':
elif builder.target.platform == 'mac':
if binary.type == 'library':
binary.compiler.postlink += [
'-compatibility_version', '1.0.0',
'-current_version', self.productVersion
]
if self.use_auto_versioning():
binary.compiler.linkflags += [self.versionlib]
binary.compiler.linkflags += [self.versionlib[arch]]
binary.compiler.sourcedeps += SM.generated_headers
return binary
def Library(self, context, name):
binary = context.compiler.Library(name)
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 self.AddVersioning(binary)
return binary
def Program(self, context, name):
binary = context.compiler.Program(name)
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++']
if binary.compiler.like('msvc'):
binary.compiler.linkflags += ['/SUBSYSTEM:CONSOLE']
return self.AddVersioning(binary)
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 += [
@ -355,22 +451,19 @@ class SMConfig(object):
]
return compiler
def ExtLibrary(self, context, name):
binary = context.compiler.Library(name)
def ExtLibrary(self, context, name, arch):
binary = self.Library(context, name, arch)
self.ConfigureForExtension(context, binary.compiler)
return self.AddVersioning(binary)
return binary
def ConfigureForHL2(self, binary, sdk):
def ConfigureForHL2(self, binary, sdk, arch):
compiler = binary.compiler
if sdk.name == 'episode1':
mms_path = os.path.join(self.mms_root, 'core-legacy')
else:
mms_path = os.path.join(self.mms_root, 'core')
SetArchFlags(compiler, arch, builder.target.platform)
compiler.cxxincludes += [
os.path.join(mms_path),
os.path.join(mms_path, 'sourcehook'),
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]
@ -404,39 +497,49 @@ class SMConfig(object):
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', 'csgo', 'dota']:
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', 'dota']:
if builder.target_platform in ['linux', 'mac']:
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':
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 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':
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']:
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'))
@ -447,25 +550,28 @@ class SMConfig(object):
compiler.Dep(os.path.join(lib_folder, 'mathlib_i486.a'))
]
if sdk.name in ['blade', 'insurgency', 'csgo', 'dota']:
compiler.postlink += [compiler.Dep(os.path.join(lib_folder, 'interfaces_i486.a'))]
self.AddVersioning(binary)
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']:
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 sdk.name in ['l4d', 'blade', 'insurgency', 'csgo', 'dota']:
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':
elif builder.target.platform == 'mac':
compiler.linkflags.append('-liconv')
dynamic_libs = ['libtier0.dylib', 'libvstdlib.dylib']
elif builder.target_platform == 'windows':
elif builder.target.platform == 'windows':
libs = ['tier0', 'tier1', 'vstdlib', 'mathlib']
if sdk.name in ['swarm', 'blade', 'insurgency', 'csgo', 'dota']:
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'
@ -486,19 +592,21 @@ class SMConfig(object):
return binary
def HL2Library(self, context, name, sdk):
binary = context.compiler.Library(name)
def HL2Library(self, context, name, sdk, arch):
binary = self.Library(context, name, arch)
self.ConfigureForExtension(context, binary.compiler)
return self.ConfigureForHL2(binary, sdk)
return self.ConfigureForHL2(binary, sdk, arch)
def HL2Project(self, context, name):
project = context.compiler.LibraryProject(name)
project = context.cxx.LibraryProject(name)
self.ConfigureForExtension(context, project.compiler)
return project
def HL2Config(self, project, name, sdk):
def HL2Config(self, project, name, sdk, arch):
binary = project.Configure(name, '{0} - {1}'.format(self.tag, sdk.name))
return self.ConfigureForHL2(binary, sdk)
AppendArchSuffix(binary, name, arch)
self.AddVersioning(binary, arch)
return self.ConfigureForHL2(binary, sdk, arch)
SM = SMConfig()
SM.detectProductVersion()
@ -506,26 +614,30 @@ SM.detectSDKs()
SM.configure()
if SM.use_auto_versioning():
SM.generated_headers = builder.RunScript(
SM.generated_headers = builder.Build(
'tools/buildbot/Versioning',
{ 'SM': SM }
)
SM.versionlib = builder.RunScript(
SM.versionlib = builder.Build(
'versionlib/AMBuilder',
{ 'SM': SM }
)
# Build SourcePawn externally.
SourcePawn = builder.RunScript('sourcepawn/AMBuildScript', {})
SP = SourcePawn(
root = SM,
amtl = os.path.join(builder.sourcePath, 'public', 'amtl'),
)
SP.BuildCore()
SM.spcomp = SP.spcomp
SM.binaries += [
SP.libsourcepawn
]
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',
@ -552,7 +664,7 @@ if builder.backend == 'amb2':
'tools/buildbot/PackageScript',
]
builder.RunBuildScripts(BuildScripts, { 'SM': SM })
builder.Build(BuildScripts, { 'SM': SM })
if builder.options.breakpad_dump:
builder.RunScript('tools/buildbot/BreakpadSymbols', { 'SM': SM })
builder.Build('tools/buildbot/BreakpadSymbols', { 'SM': SM })

View File

@ -6,12 +6,18 @@ General
- [SourceMod website](http://www.sourcemod.net): Source Engine scripting and server administration
- [Forum](https://forums.alliedmods.net/forumdisplay.php?f=52): Discussion forum including plugin/extension development
- [General documentation](https://wiki.alliedmods.net/Category:SourceMod_Documentation): Miscellaneous information about SourceMod
- [Latest release](http://www.sourcemod.net/downloads.php): The latest stable SourceMod release
- [Build snapshots](http://www.sourcemod.net/snapshots.php): Builds of recent development versions
- [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://bugs.alliedmods.net): Issues that require back and forth communication
- [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

View File

@ -35,7 +35,7 @@ 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 - 54;
static const uint32_t SM_LOGIC_MAGIC = 0x0F47C0DE - 57;
} // namespace SourceMod

View File

@ -50,7 +50,7 @@ class IProviderCallbacks;
class IExtensionSys;
class ITextParsers;
class ILogger;
class IDataPack;
class ICellArray;
struct sm_logic_t
{
@ -69,8 +69,10 @@ struct sm_logic_t
void (*GenerateError)(IPluginContext *, cell_t, int, const char *, ...);
void (*AddNatives)(sp_nativeinfo_t *natives);
void (*RegisterProfiler)(IProfilingTool *tool);
IDataPack * (*CreateDataPack)();
void (*FreeDataPack)(IDataPack *pack);
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;

View File

@ -65,6 +65,10 @@ sm_flood_time 0.75
// no reserved slot access (spectator players are selected first) is kicked to make room. Thus, the reserved
// slots always remains free. The only situation where the reserved slot(s) can become properly occupied is
// if the server is full with reserve slot access clients.
// 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
// Default: 0

View File

@ -30,12 +30,12 @@
"ServerLang" "en"
/**
* String to use as the public chat trigger. Set an empty string to disable.
* List of characters to use for public chat triggers. Set an empty list to disable.
*/
"PublicChatTrigger" "!"
/**
* String to use as the silent chat trigger. Set an empty string to disable.
* List of characters to use for silent chat triggers. Set an empty list to disable.
*/
"SilentChatTrigger" "/"
@ -132,5 +132,18 @@
* 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

@ -1,7 +1,7 @@
# vim: set ts=2 sw=2 tw=99 noet:
import sys
try:
from ambuild2 import run
from ambuild2 import run, util
except:
try:
import ambuild
@ -12,25 +12,31 @@ except:
sys.stderr.write('http://www.alliedmods.net/ambuild\n')
sys.exit(1)
run = run.PrepareBuild(sourcePath=sys.path[0])
run.default_build_folder = 'obj-' + run.target_platform
run.options.add_option('--hl2sdk-root', type=str, dest='hl2sdk_root', default=None,
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')
run.options.add_option('--mysql-path', type=str, dest='mysql_path', default=None,
parser.options.add_option('--mysql-path', type=str, dest='mysql_path', default=None,
help='Path to MySQL 5')
run.options.add_option('--mms-path', type=str, dest='mms_path', default=None,
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')
run.options.add_option('--enable-debug', action='store_const', const='1', dest='debug',
parser.options.add_option('--enable-debug', action='store_const', const='1', dest='debug',
help='Enable debugging symbols')
run.options.add_option('--enable-optimize', action='store_const', const='1', dest='opt',
parser.options.add_option('--enable-optimize', action='store_const', const='1', dest='opt',
help='Enable optimization')
run.options.add_option('--no-mysql', action='store_false', default=True, dest='hasMySql',
parser.options.add_option('--no-mysql', action='store_false', default=True, dest='hasMySql',
help='Disable building MySQL extension')
run.options.add_option('-s', '--sdks', default='all', dest='sdks',
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)')
run.options.add_option('--breakpad-dump', action='store_true', dest='breakpad_dump',
parser.options.add_option('--breakpad-dump', action='store_true', dest='breakpad_dump',
default=False, help='Dump and upload breakpad symbols')
run.options.add_option('--disable-auto-versioning', action='store_true', dest='disable_auto_versioning',
parser.options.add_option('--disable-auto-versioning', action='store_true', dest='disable_auto_versioning',
default=False, help='Disable the auto versioning script')
run.Configure()
parser.Configure()

View File

@ -1,4 +1,4 @@
# vim: set sts=2 ts=8 sw=2 tw=99 et ft=python:
# vim: set sts=2 ts=8 sw=2 tw=99 et ft=python:
import os
project = SM.HL2Project(builder, 'sourcemod')
@ -44,73 +44,70 @@ project.sources += [
for sdk_name in SM.sdks:
sdk = SM.sdks[sdk_name]
binary_name = 'sourcemod.' + sdk.ext
for arch in SM.archs:
if not arch in sdk.platformSpec[builder.target.platform]:
continue
binary = SM.HL2Config(project, binary_name, sdk)
compiler = binary.compiler
binary_name = 'sourcemod.' + sdk.ext
compiler.cxxincludes += [
builder.sourcePath
]
binary = SM.HL2Config(project, binary_name, sdk, arch)
compiler = binary.compiler
if sdk.name == 'csgo':
compiler.cxxincludes += [
os.path.join(sdk.path, 'common', 'protobuf-2.5.0', 'src'),
os.path.join(sdk.path, 'public', 'engine', 'protobuf'),
os.path.join(sdk.path, 'public', 'game', 'shared', 'csgo', 'protobuf')
]
elif sdk.name == 'dota':
compiler.cxxincludes += [
os.path.join(sdk.path, 'common', 'protobuf-2.6.1', 'src'),
os.path.join(sdk.path, 'public', 'engine', 'protobuf'),
os.path.join(sdk.path, 'public', 'game', 'shared', 'protobuf'),
os.path.join(sdk.path, 'public', 'game', 'shared', 'dota', 'protobuf')
builder.sourcePath
]
if builder.target_platform == 'linux':
compiler.postlink += ['-lpthread', '-lrt']
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 sdk.name == 'csgo' or sdk.name == 'dota':
if builder.target_platform == 'linux':
lib_path = os.path.join(sdk.path, 'lib', 'linux32', 'release', 'libprotobuf.a')
elif builder.target_platform == 'mac':
lib_path = os.path.join(sdk.path, 'lib', 'osx32', 'release', 'libprotobuf.a')
elif builder.target_platform == 'windows':
msvc_ver = compiler.version
vs_year = ''
if msvc_ver == 1800:
vs_year = '2013'
else:
raise Exception('Cannot find libprotobuf for MSVC version "' + str(compiler.version) + '"')
if compiler.like('msvc'):
compiler.defines += ['_ALLOW_KEYWORD_MACROS']
if builder.target.platform == 'linux':
compiler.postlink += ['-lpthread', '-lrt']
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':
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 in ['csgo', 'dota']:
binary.sources += ['smn_protobuf.cpp']
else:
binary.sources += ['smn_bitbuffer.cpp']
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'),
]
elif sdk.name == 'dota':
binary.sources += [
os.path.join(sdk.path, 'public', 'engine', 'protobuf', 'networkbasetypes.pb.cc'),
os.path.join(sdk.path, 'public', 'engine', 'protobuf', 'netmessages.pb.cc'),
os.path.join(sdk.path, 'public', 'engine', 'protobuf', 'network_connection.pb.cc'),
os.path.join(sdk.path, 'public', 'game', 'shared', 'protobuf', 'ai_activity.pb.cc'),
os.path.join(sdk.path, 'public', 'game', 'shared', 'protobuf', 'usermessages.pb.cc'),
os.path.join(sdk.path, 'public', 'game', 'shared', 'dota', 'protobuf', 'dota_commonmessages.pb.cc'),
os.path.join(sdk.path, 'public', 'game', 'shared', 'dota', 'protobuf', 'dota_usermessages.pb.cc'),
os.path.join(sdk.path, 'public', 'game', 'shared', 'dota', 'protobuf', 'dota_usermessage_helpers.cpp'),
]
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)

View File

@ -44,11 +44,7 @@ public: //IRecipientFilter
bool IsReliable() const;
bool IsInitMessage() const;
int GetRecipientCount() const;
#if SOURCE_ENGINE == SE_DOTA
CEntityIndex GetRecipientIndex(int slot) const;
#else
int GetRecipientIndex(int slot) const;
#endif
public:
void Initialize(const cell_t *ptr, size_t count);
void SetToReliable(bool isreliable);
@ -83,11 +79,7 @@ inline int CellRecipientFilter::GetRecipientCount() const
return m_Size;
}
#if SOURCE_ENGINE == SE_DOTA
inline CEntityIndex CellRecipientFilter::GetRecipientIndex(int slot) const
#else
inline int CellRecipientFilter::GetRecipientIndex(int slot) const
#endif
{
int ret;
if ((slot < 0) || (slot >= GetRecipientCount()))
@ -99,11 +91,7 @@ inline int CellRecipientFilter::GetRecipientIndex(int slot) const
ret = static_cast<int>(m_Players[slot]);
}
#if SOURCE_ENGINE == SE_DOTA
return CEntityIndex(ret);
#else
return ret;
#endif
}
inline void CellRecipientFilter::SetToInit(bool isinitmsg)

View File

@ -8,7 +8,7 @@
* 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
@ -38,12 +38,13 @@
#include "logic_bridge.h"
#include "sourcemod.h"
#include "provider.h"
#include <bridge/include/ILogger.h>
#include <amtl/am-string.h>
ChatTriggers g_ChatTriggers;
bool g_bSupressSilentFails = false;
ChatTriggers::ChatTriggers() : m_bWillProcessInPost(false),
ChatTriggers::ChatTriggers() : m_bWillProcessInPost(false),
m_ReplyTo(SM_REPLY_CONSOLE), m_ArgSBackup(NULL)
{
m_PubTrigger = "!";
@ -61,20 +62,43 @@ ChatTriggers::~ChatTriggers()
m_ArgSBackup = NULL;
}
ConfigResult ChatTriggers::OnSourceModConfigChanged(const char *key,
const char *value,
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,
const char *value,
ConfigSource source,
char *error,
char *error,
size_t maxlength)
{
if (strcmp(key, "PublicChatTrigger") == 0)
{
m_PubTrigger = value;
SetChatTrigger(ChatTrigger_Public, value);
return ConfigResult_Accept;
}
else if (strcmp(key, "SilentChatTrigger") == 0)
{
m_PrivTrigger = value;
SetChatTrigger(ChatTrigger_Private, value);
return ConfigResult_Accept;
}
else if (strcmp(key, "SilentFailSuppress") == 0)
@ -156,7 +180,7 @@ bool ChatTriggers::OnSayCommand_Pre(int client, const ICommandArgs *command)
if (!args)
return false;
/* Save these off for post hook as the command data returned from the engine in older engine versions
/* 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);
@ -182,7 +206,7 @@ bool ChatTriggers::OnSayCommand_Pre(int client, const ICommandArgs *command)
if (
#if SOURCE_ENGINE == SE_EPISODEONE
!m_bIsINS &&
!m_bIsINS &&
#endif
client != 0 && args[0] == '"' && args[len-1] == '"')
{
@ -250,17 +274,17 @@ bool ChatTriggers::OnSayCommand_Pre(int client, const ICommandArgs *command)
bool is_trigger = false;
bool is_silent = false;
/* Check for either trigger */
if (m_PubTrigger.length() && strncmp(m_ArgSBackup, m_PubTrigger.chars(), m_PubTrigger.length()) == 0)
{
is_trigger = true;
args = &m_ArgSBackup[m_PubTrigger.length()];
}
else if (m_PrivTrigger.length() && strncmp(m_ArgSBackup, m_PrivTrigger.chars(), m_PrivTrigger.length()) == 0)
{
// Prefer the silent trigger in case of clashes.
if (strchr(m_PrivTrigger.chars(), m_ArgSBackup[0])) {
is_trigger = true;
is_silent = true;
args = &m_ArgSBackup[m_PrivTrigger.length()];
} else if (strchr(m_PubTrigger.chars(), m_ArgSBackup[0])) {
is_trigger = true;
}
if (is_trigger) {
// Bump the args past the chat trigger - we only support single-character triggers now.
args = &m_ArgSBackup[1];
}
/**
@ -295,11 +319,7 @@ bool ChatTriggers::OnSayCommand_Post(int client, const ICommandArgs *command)
/* Execute the cached command */
unsigned int old = SetReplyTo(SM_REPLY_CHAT);
#if SOURCE_ENGINE == SE_DOTA
engine->ClientCommand(client, "%s", m_ToExecute);
#else
serverpluginhelpers->ClientCommand(PEntityOfEntIndex(client), m_ToExecute);
#endif
SetReplyTo(old);
}
@ -322,8 +342,8 @@ bool ChatTriggers::PreProcessTrigger(edict_t *pEdict, const char *args)
char cmd_buf[64];
size_t cmd_len = 0;
const char *inptr = args;
while (*inptr != '\0'
&& !textparsers->IsWhitespace(inptr)
while (*inptr != '\0'
&& !textparsers->IsWhitespace(inptr)
&& *inptr != '"'
&& cmd_len < sizeof(cmd_buf) - 1)
{
@ -346,7 +366,7 @@ bool ChatTriggers::PreProcessTrigger(edict_t *pEdict, const char *args)
return false;
}
/* Now, prepend. Don't worry about the buffers. This will
/* Now, prepend. Don't worry about the buffers. This will
* work because the sizes are limited from earlier.
*/
char new_buf[80];

View File

@ -8,7 +8,7 @@
* 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
@ -50,10 +50,10 @@ public: //SMGlobalClass
void OnSourceModAllInitialized_Post();
void OnSourceModGameInitialized();
void OnSourceModShutdown();
ConfigResult OnSourceModConfigChanged(const char *key,
const char *value,
ConfigResult OnSourceModConfigChanged(const char *key,
const char *value,
ConfigSource source,
char *error,
char *error,
size_t maxlength);
private: //ConCommand
bool OnSayCommand_Pre(int client, const ICommandArgs *args);
@ -64,11 +64,16 @@ public:
bool IsChatTrigger();
bool WasFloodedMessage();
private:
enum ChatTriggerType {
ChatTrigger_Public,
ChatTrigger_Private,
};
void SetChatTrigger(ChatTriggerType type, const char *value);
bool PreProcessTrigger(edict_t *pEdict, const char *args);
bool ClientIsFlooding(int client);
cell_t CallOnClientSayCommand(int client);
private:
ke::Vector<ke::Ref<CommandHook>> hooks_;
ke::Vector<ke::RefPtr<CommandHook>> hooks_;
ke::AString m_PubTrigger;
ke::AString m_PrivTrigger;
bool m_bWillProcessInPost;

View File

@ -317,7 +317,7 @@ bool ConCmdManager::CheckAccess(int client, const char *cmd, AdminCmdInfo *pAdmi
char buffer[128];
if (!logicore.CoreTranslate(buffer, sizeof(buffer), "%T", 2, NULL, "No Access", &client))
{
ke::SafeSprintf(buffer, sizeof(buffer), "You do not have access to this command");
ke::SafeStrcpy(buffer, sizeof(buffer), "You do not have access to this command");
}
unsigned int replyto = g_ChatTriggers.GetReplyTo();
@ -342,9 +342,10 @@ bool ConCmdManager::AddAdminCommand(IPluginFunction *pFunction,
const char *group,
int adminflags,
const char *description,
int flags)
int flags,
IPlugin *pPlugin)
{
ConCmdInfo *pInfo = AddOrFindCommand(name, description, flags);
ConCmdInfo *pInfo = AddOrFindCommand(name, description, flags, pPlugin);
if (!pInfo)
return false;
@ -356,7 +357,7 @@ bool ConCmdManager::AddAdminCommand(IPluginFunction *pFunction,
return false;
i->value = new CommandGroup();
}
Ref<CommandGroup> cmdgroup = i->value;
RefPtr<CommandGroup> cmdgroup = i->value;
CmdHook *pHook = new CmdHook(CmdHook::Client, pInfo, pFunction, description);
pHook->admin = new AdminCmdInfo(cmdgroup, adminflags);
@ -391,10 +392,10 @@ bool ConCmdManager::AddAdminCommand(IPluginFunction *pFunction,
bool ConCmdManager::AddServerCommand(IPluginFunction *pFunction,
const char *name,
const char *description,
int flags)
int flags,
IPlugin *pPlugin)
{
ConCmdInfo *pInfo = AddOrFindCommand(name, description, flags);
ConCmdInfo *pInfo = AddOrFindCommand(name, description, flags, pPlugin);
if (!pInfo)
return false;
@ -491,7 +492,7 @@ void ConCmdManager::UpdateAdminCmdFlags(const char *cmd, OverrideType type, Flag
if (!r.found())
return;
Ref<CommandGroup> group(r->value);
RefPtr<CommandGroup> group(r->value);
for (PluginHookList::iterator iter = group->hooks.begin(); iter != group->hooks.end(); iter++)
{
@ -558,7 +559,7 @@ bool ConCmdManager::LookForCommandAdminFlags(const char *cmd, FlagBits *pFlags)
return true;
}
ConCmdInfo *ConCmdManager::AddOrFindCommand(const char *name, const char *description, int flags)
ConCmdInfo *ConCmdManager::AddOrFindCommand(const char *name, const char *description, int flags, IPlugin *pPlugin)
{
ConCmdInfo *pInfo;
if (!m_Cmds.retrieve(name, &pInfo))
@ -583,6 +584,7 @@ ConCmdInfo *ConCmdManager::AddOrFindCommand(const char *name, const char *descri
char *new_name = sm_strdup(name);
char *new_help = sm_strdup(description);
pCmd = new ConCommand(new_name, CommandCallback, new_help, flags);
pInfo->pPlugin = pPlugin;
pInfo->sourceMod = true;
}
else

View File

@ -41,6 +41,7 @@
#include <IAdminSystem.h>
#include "concmd_cleaner.h"
#include "GameHooks.h"
#include <am-autoptr.h>
#include <sm_stringhashmap.h>
#include <am-utility.h>
#include <am-inlinelist.h>
@ -59,13 +60,13 @@ struct CommandGroup : public ke::Refcounted<CommandGroup>
struct AdminCmdInfo
{
AdminCmdInfo(const ke::Ref<CommandGroup> &group, FlagBits flags)
AdminCmdInfo(const ke::RefPtr<CommandGroup> &group, FlagBits flags)
: group(group),
flags(flags),
eflags(0)
{
}
ke::Ref<CommandGroup> group;
ke::RefPtr<CommandGroup> group;
FlagBits flags; /* default flags */
FlagBits eflags; /* effective flags */
};
@ -98,15 +99,17 @@ struct ConCmdInfo
{
ConCmdInfo()
{
pPlugin = nullptr;
sourceMod = false;
pCmd = NULL;
pCmd = nullptr;
eflags = 0;
}
bool sourceMod; /**< Determines whether or not concmd was created by a SourceMod plugin */
ConCommand *pCmd; /**< Pointer to the command itself */
CmdHookList hooks; /**< Hook list */
FlagBits eflags; /**< Effective admin flags */
ke::Ref<CommandHook> sh_hook; /**< SourceHook hook, if any. */
ke::RefPtr<CommandHook> sh_hook; /**< SourceHook hook, if any. */
IPlugin *pPlugin; /**< Owning plugin handle. */
};
typedef List<ConCmdInfo *> ConCmdList;
@ -131,13 +134,14 @@ public: //IRootConsoleCommand
public: //IConCommandTracker
void OnUnlinkConCommandBase(ConCommandBase *pBase, const char *name) override;
public:
bool AddServerCommand(IPluginFunction *pFunction, const char *name, const char *description, int flags);
bool AddServerCommand(IPluginFunction *pFunction, const char *name, const char *description, int flags, IPlugin *pPlugin);
bool AddAdminCommand(IPluginFunction *pFunction,
const char *name,
const char *group,
int adminflags,
const char *description,
int flags);
int flags,
IPlugin *pPlugin);
ResultType DispatchClientCommand(int client, const char *cmd, int args, ResultType type);
void UpdateAdminCmdFlags(const char *cmd, OverrideType type, FlagBits bits, bool remove);
bool LookForSourceModCommand(const char *cmd);
@ -145,7 +149,7 @@ public:
private:
bool InternalDispatch(int client, const ICommandArgs *args);
ResultType RunAdminCommand(ConCmdInfo *pInfo, int client, int args);
ConCmdInfo *AddOrFindCommand(const char *name, const char *description, int flags);
ConCmdInfo *AddOrFindCommand(const char *name, const char *description, int flags, IPlugin *pPlugin);
void AddToCmdList(ConCmdInfo *info);
void RemoveConCmd(ConCmdInfo *info, const char *cmd, bool untrack);
bool CheckAccess(int client, const char *cmd, AdminCmdInfo *pAdmin);
@ -161,7 +165,7 @@ public:
return m_CmdList;
}
private:
typedef StringHashMap<ke::Ref<CommandGroup> > GroupMap;
typedef StringHashMap<ke::RefPtr<CommandGroup> > GroupMap;
StringHashMap<ConCmdInfo *> m_Cmds; /* command lookup */
GroupMap m_CmdGrps; /* command group map */

View File

@ -43,6 +43,7 @@
#include <compat_wrappers.h>
#include "concmd_cleaner.h"
#include "PlayerManager.h"
#include <sm_stringhashmap.h>
using namespace SourceHook;
@ -67,6 +68,10 @@ struct ConVarInfo
{
return strcmp(name, info->pVar->GetName()) == 0;
}
static inline uint32_t hash(const detail::CharsAndLength &key)
{
return key.hash();
}
};
/**

View File

@ -62,18 +62,10 @@
# include <unistd.h>
#endif
#if SH_IMPL_VERSION >= 5
# if SOURCE_ENGINE == SE_DOTA
SH_DECL_EXTERN2_void(ConCommand, Dispatch, SH_NOATTRIB, false, const CCommandContext &, const CCommand &);
# elif SOURCE_ENGINE >= SE_ORANGEBOX
#if SOURCE_ENGINE >= SE_ORANGEBOX
SH_DECL_EXTERN1_void(ConCommand, Dispatch, SH_NOATTRIB, false, const CCommand &);
# else
SH_DECL_EXTERN0_void(ConCommand, Dispatch, SH_NOATTRIB, false);
# endif
#else
extern int __SourceHook_FHVPAddConCommandDispatch(void *,bool,class fastdelegate::FastDelegate0<void>,bool);
extern int __SourceHook_FHAddConCommandDispatch(void *, bool, class fastdelegate::FastDelegate0<void>);
extern bool __SourceHook_FHRemoveConCommandDispatch(void *, bool, class fastdelegate::FastDelegate0<void>);
SH_DECL_EXTERN0_void(ConCommand, Dispatch, SH_NOATTRIB, false);
#endif
class GenericCommandHooker : public IConCommandLinkListener
@ -131,9 +123,7 @@ class GenericCommandHooker : public IConCommandLinkListener
}
}
#if SOURCE_ENGINE == SE_DOTA
void Dispatch(const CCommandContext &context, const CCommand& args)
#elif SOURCE_ENGINE >= SE_ORANGEBOX
#if SOURCE_ENGINE >= SE_ORANGEBOX
void Dispatch(const CCommand& args)
#else
void Dispatch()
@ -317,13 +307,13 @@ bool ConsoleDetours::AddListener(IPluginFunction *fun, const char *command)
}
else
{
ke::AutoArray<char> str(UTIL_ToLowerCase(command));
ke::AutoPtr<char[]> str(UTIL_ToLowerCase(command));
IChangeableForward *forward;
if (!m_Listeners.retrieve(str, &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, forward);
m_Listeners.insert(str.get(), forward);
}
forward->AddFunction(fun);
}
@ -339,9 +329,9 @@ bool ConsoleDetours::RemoveListener(IPluginFunction *fun, const char *command)
}
else
{
ke::AutoArray<char> str(UTIL_ToLowerCase(command));
ke::AutoPtr<char[]> str(UTIL_ToLowerCase(command));
IChangeableForward *forward;
if (!m_Listeners.retrieve(str, &forward))
if (!m_Listeners.retrieve(str.get(), &forward))
return false;
return forward->RemoveFunction(fun);
}

View File

@ -67,18 +67,11 @@ ConVar *g_ServerCfgFile = NULL;
void CheckAndFinalizeConfigs();
#if SOURCE_ENGINE == SE_DOTA
SH_DECL_EXTERN2_void(ConCommand, Dispatch, SH_NOATTRIB, false, const CCommandContext &, const CCommand &);
void Hook_ExecDispatchPre(const CCommandContext &context, const CCommand &cmd)
#elif SOURCE_ENGINE >= SE_ORANGEBOX
#if SOURCE_ENGINE >= SE_ORANGEBOX
SH_DECL_EXTERN1_void(ConCommand, Dispatch, SH_NOATTRIB, false, const CCommand &);
void Hook_ExecDispatchPre(const CCommand &cmd)
#elif SOURCE_ENGINE == SE_DARKMESSIAH
SH_DECL_EXTERN0_void(ConCommand, Dispatch, SH_NOATTRIB, false);
void Hook_ExecDispatchPre()
#else
extern int __SourceHook_FHAddConCommandDispatch(void *,bool,class fastdelegate::FastDelegate0<void>);
extern bool __SourceHook_FHRemoveConCommandDispatch(void *,bool,class fastdelegate::FastDelegate0<void>);
SH_DECL_EXTERN0_void(ConCommand, Dispatch, SH_NOATTRIB, false);
void Hook_ExecDispatchPre()
#endif
{
@ -94,9 +87,7 @@ void Hook_ExecDispatchPre()
}
}
#if SOURCE_ENGINE == SE_DOTA
void Hook_ExecDispatchPost(const CCommandContext &context, const CCommand &cmd)
#elif SOURCE_ENGINE >= SE_ORANGEBOX
#if SOURCE_ENGINE >= SE_ORANGEBOX
void Hook_ExecDispatchPost(const CCommand &cmd)
#else
void Hook_ExecDispatchPost()
@ -286,7 +277,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 result;
ConfigResult result = ConfigResult_Ignore;
/* Notify! */
SMGlobalClass *pBase = SMGlobalClass::head;
@ -294,7 +285,7 @@ ConfigResult CoreConfig::SetConfigOption(const char *option, const char *value,
{
if ((result = pBase->OnSourceModConfigChanged(option, value, source, error, maxlength)) != ConfigResult_Ignore)
{
return result;
break;
}
pBase = pBase->m_pGlobalClassNext;
}
@ -302,7 +293,7 @@ ConfigResult CoreConfig::SetConfigOption(const char *option, const char *value,
ke::AString vstr(value);
m_KeyValues.replace(option, ke::Move(vstr));
return ConfigResult_Ignore;
return result;
}
const char *CoreConfig::GetCoreConfigValue(const char *key)
@ -421,8 +412,11 @@ bool SM_ExecuteConfig(IPlugin *pl, AutoConfig *cfg, bool can_create)
for (iter = convars->begin(); iter != convars->end(); iter++)
{
const ConVar *cvar = (*iter);
if ((cvar->GetFlags() & FCVAR_DONTRECORD) == FCVAR_DONTRECORD)
#if SOURCE_ENGINE >= SE_ORANGEBOX
if (cvar->IsFlagSet(FCVAR_DONTRECORD))
#else
if (cvar->IsBitSet(FCVAR_DONTRECORD))
#endif
{
continue;
}

View File

@ -31,6 +31,8 @@
#include "EventManager.h"
#include "sm_stringutil.h"
#include "PlayerManager.h"
#include "logic_bridge.h"
#include <bridge/include/IScriptManager.h>
@ -156,7 +158,7 @@ void EventManager::FireGameEvent(IGameEvent *pEvent)
Just need to add ourselves as a listener to make our hook on IGameEventManager2::FireEvent work */
}
#if SOURCE_ENGINE >= SE_LEFT4DEAD && SOURCE_ENGINE != SE_DOTA
#if SOURCE_ENGINE >= SE_LEFT4DEAD
int EventManager::GetEventDebugID()
{
return EVENT_DEBUG_ID_INIT;
@ -360,6 +362,13 @@ void EventManager::FireEvent(EventInfo *pInfo, bool bDontBroadcast)
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)
{
/* Free event from IGameEventManager2 */
@ -424,7 +433,7 @@ bool EventManager::OnFireEvent(IGameEvent *pEvent, bool bDontBroadcast)
m_EventCopies.push(gameevents->DuplicateEvent(pEvent));
}
if (res)
if (res >= Pl_Handled)
{
gameevents->FreeEvent(pEvent);
RETURN_META_VALUE(MRES_SUPERCEDE, false);

View File

@ -41,6 +41,8 @@
#include <IForwardSys.h>
#include <IPluginSys.h>
class IClient;
using namespace SourceHook;
struct EventInfo
@ -75,6 +77,10 @@ struct EventHook
{
return strcmp(name, hook->name.chars()) == 0;
}
static inline uint32_t hash(const detail::CharsAndLength &key)
{
return key.hash();
}
};
enum EventHookMode
@ -110,7 +116,7 @@ public: // IPluginsListener
void OnPluginUnloaded(IPlugin *plugin);
public: // IGameEventListener2
void FireGameEvent(IGameEvent *pEvent);
#if SOURCE_ENGINE >= SE_LEFT4DEAD && SOURCE_ENGINE != SE_DOTA
#if SOURCE_ENGINE >= SE_LEFT4DEAD
int GetEventDebugID();
#endif
public:
@ -126,6 +132,7 @@ public:
EventHookError UnhookEvent(const char *name, IPluginFunction *pFunction, EventHookMode mode=EventHookMode_Post);
EventInfo *CreateEvent(IPluginContext *pContext, const char *name, bool force=false);
void FireEvent(EventInfo *pInfo, bool bDontBroadcast=false);
void FireEventToClient(EventInfo *pInfo, IClient *pClient);
void CancelCreatedEvent(EventInfo *pInfo);
private: // IGameEventManager2 hooks
bool OnFireEvent(IGameEvent *pEvent, bool bDontBroadcast);

View File

@ -36,17 +36,12 @@ SH_DECL_HOOK3_void(ICvar, CallGlobalChangeCallbacks, SH_NOATTRIB, false, ConVar
SH_DECL_HOOK2_void(ICvar, CallGlobalChangeCallback, SH_NOATTRIB, false, ConVar *, const char *);
#endif
#if SOURCE_ENGINE == SE_DOTA
SH_DECL_HOOK5_void(IServerGameDLL, OnQueryCvarValueFinished, SH_NOATTRIB, 0, QueryCvarCookie_t, CEntityIndex, EQueryCvarValueStatus, const char *, const char *);
SH_DECL_HOOK5_void(IServerPluginCallbacks, OnQueryCvarValueFinished, SH_NOATTRIB, 0, QueryCvarCookie_t, CEntityIndex, EQueryCvarValueStatus, const char *, const char *);
#elif SOURCE_ENGINE != SE_DARKMESSIAH
#if SOURCE_ENGINE != SE_DARKMESSIAH
SH_DECL_HOOK5_void(IServerGameDLL, OnQueryCvarValueFinished, SH_NOATTRIB, 0, QueryCvarCookie_t, edict_t *, EQueryCvarValueStatus, const char *, const char *);
SH_DECL_HOOK5_void(IServerPluginCallbacks, OnQueryCvarValueFinished, SH_NOATTRIB, 0, QueryCvarCookie_t, edict_t *, EQueryCvarValueStatus, const char *, const char *);
#endif
#if SOURCE_ENGINE == SE_DOTA
SH_DECL_HOOK2_void(ConCommand, Dispatch, SH_NOATTRIB, false, const CCommandContext &, const CCommand &);
#elif SOURCE_ENGINE >= SE_ORANGEBOX
#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);
@ -88,7 +83,7 @@ void GameHooks::OnVSPReceived()
if (g_SMAPI->GetSourceEngineBuild() == SOURCE_ENGINE_ORIGINAL || vsp_version < 2)
return;
#if SOURCE_ENGINE != SE_DARKMESSIAH && SOURCE_ENGINE != SE_DOTA
#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
@ -116,19 +111,9 @@ void GameHooks::OnConVarChanged(ConVar *pConVar, const char *oldValue)
}
#if SOURCE_ENGINE != SE_DARKMESSIAH
# if SOURCE_ENGINE == SE_DOTA
void GameHooks::OnQueryCvarValueFinished(QueryCvarCookie_t cookie, CEntityIndex player, EQueryCvarValueStatus result,
const char *cvarName, const char *cvarValue)
# else
void GameHooks::OnQueryCvarValueFinished(QueryCvarCookie_t cookie, edict_t *pPlayer, EQueryCvarValueStatus result,
const char *cvarName, const char *cvarValue)
# endif
{
# if SOURCE_ENGINE == SE_DOTA
int client = player.Get();
# else
const char *cvarName, const char *cvarValue){
int client = IndexOfEdict(pPlayer);
# endif
# if SOURCE_ENGINE == SE_CSGO
if (g_Players.HandleConVarQuery(cookie, client, result, cvarName, cvarValue))
@ -138,13 +123,13 @@ void GameHooks::OnQueryCvarValueFinished(QueryCvarCookie_t cookie, edict_t *pPla
}
#endif
ke::PassRef<CommandHook>
ke::RefPtr<CommandHook>
GameHooks::AddCommandHook(ConCommand *cmd, const CommandHook::Callback &callback)
{
return new CommandHook(cmd, callback, false);
}
ke::PassRef<CommandHook>
ke::RefPtr<CommandHook>
GameHooks::AddPostCommandHook(ConCommand *cmd, const CommandHook::Callback &callback)
{
return new CommandHook(cmd, callback, true);

View File

@ -40,10 +40,7 @@ class ConVar;
class CCommand;
struct CCommandContext;
#if SOURCE_ENGINE == SE_DOTA
# define DISPATCH_ARGS const CCommandContext &context, const CCommand &command
# define DISPATCH_PROLOGUE
#elif SOURCE_ENGINE >= SE_ORANGEBOX
#if SOURCE_ENGINE >= SE_ORANGEBOX
# define DISPATCH_ARGS const CCommand &command
# define DISPATCH_PROLOGUE
#else
@ -93,8 +90,8 @@ public:
}
public:
ke::PassRef<CommandHook> AddCommandHook(ConCommand *cmd, const CommandHook::Callback &callback);
ke::PassRef<CommandHook> AddPostCommandHook(ConCommand *cmd, const CommandHook::Callback &callback);
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_;
@ -109,10 +106,7 @@ private:
#endif
// Callback for when StartQueryCvarValue() has finished.
#if SOURCE_ENGINE == SE_DOTA
void OnQueryCvarValueFinished(QueryCvarCookie_t cookie, CEntityIndex player, EQueryCvarValueStatus result,
const char *cvarName, const char *cvarValue);
#elif SOURCE_ENGINE != SE_DARKMESSIAH
#if SOURCE_ENGINE != SE_DARKMESSIAH
void OnQueryCvarValueFinished(QueryCvarCookie_t cookie, edict_t *pPlayer, EQueryCvarValueStatus result,
const char *cvarName, const char *cvarValue);
#endif

View File

@ -2,7 +2,7 @@
* vim: set ts=4 sw=4 tw=99 noet :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
* Copyright (C) 2004-2016 AlliedModders LLC. All rights reserved.
* =============================================================================
*
* This program is free software; you can redistribute it and/or modify it under
@ -43,35 +43,15 @@
#include <tier0/mem.h>
#include <bridge/include/ILogger.h>
#if SOURCE_ENGINE == SE_DOTA
#include <game/shared/protobuf/usermessages.pb.h>
#elif SOURCE_ENGINE == SE_CSGO
#if SOURCE_ENGINE == SE_CSGO
#include <cstrike15_usermessages.pb.h>
#endif
typedef ICommandLine *(*FakeGetCommandLine)();
#if defined _WIN32
#define TIER0_NAME "tier0.dll"
#define VSTDLIB_NAME "vstdlib.dll"
#elif defined __APPLE__
#define TIER0_NAME "libtier0.dylib"
#define VSTDLIB_NAME "libvstdlib.dylib"
#elif defined __linux__
#if SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_TF2 \
|| SOURCE_ENGINE == SE_SDK2013 || SOURCE_ENGINE == SE_LEFT4DEAD2 || SOURCE_ENGINE == SE_NUCLEARDAWN \
|| SOURCE_ENGINE == SE_BMS
#define TIER0_NAME "libtier0_srv.so"
#define VSTDLIB_NAME "libvstdlib_srv.so"
#elif SOURCE_ENGINE >= SE_LEFT4DEAD
#define TIER0_NAME "libtier0.so"
#define VSTDLIB_NAME "libvstdlib.so"
#else
#define TIER0_NAME "tier0_i486.so"
#define VSTDLIB_NAME "vstdlib_i486.so"
#endif
#endif
#define TIER0_NAME SOURCE_BIN_PREFIX "tier0" SOURCE_BIN_SUFFIX SOURCE_BIN_EXT
#define VSTDLIB_NAME SOURCE_BIN_PREFIX "vstdlib" SOURCE_BIN_SUFFIX SOURCE_BIN_EXT
CHalfLife2 g_HL2;
ConVar *sv_lan = NULL;
@ -137,6 +117,59 @@ void CHalfLife2::OnSourceModAllInitialized_Post()
{
InitLogicalEntData();
InitCommandLine();
#if SOURCE_ENGINE == SE_CSGO
m_CSGOBadList.init();
m_CSGOBadList.add("m_iItemDefinitionIndex");
m_CSGOBadList.add("m_iEntityLevel");
m_CSGOBadList.add("m_iItemIDHigh");
m_CSGOBadList.add("m_iItemIDLow");
m_CSGOBadList.add("m_iAccountID");
m_CSGOBadList.add("m_iEntityQuality");
m_CSGOBadList.add("m_bInitialized");
m_CSGOBadList.add("m_szCustomName");
m_CSGOBadList.add("m_iAttributeDefinitionIndex");
m_CSGOBadList.add("m_iRawValue32");
m_CSGOBadList.add("m_iRawInitialValue32");
m_CSGOBadList.add("m_nRefundableCurrency");
m_CSGOBadList.add("m_bSetBonus");
m_CSGOBadList.add("m_OriginalOwnerXuidLow");
m_CSGOBadList.add("m_OriginalOwnerXuidHigh");
m_CSGOBadList.add("m_nFallbackPaintKit");
m_CSGOBadList.add("m_nFallbackSeed");
m_CSGOBadList.add("m_flFallbackWear");
m_CSGOBadList.add("m_nFallbackStatTrak");
m_CSGOBadList.add("m_iCompetitiveRanking");
m_CSGOBadList.add("m_iCompetitiveRankType");
m_CSGOBadList.add("m_nActiveCoinRank");
m_CSGOBadList.add("m_nMusicID");
#endif
}
ConfigResult CHalfLife2::OnSourceModConfigChanged(const char *key, const char *value,
ConfigSource source, char *error, size_t maxlength)
{
if (strcasecmp(key, "FollowCSGOServerGuidelines") == 0)
{
#if SOURCE_ENGINE == SE_CSGO
if (strcasecmp(value, "no") == 0)
{
m_bFollowCSGOServerGuidelines = false;
return ConfigResult_Accept;
}
else if (strcasecmp(value, "yes") == 0)
{
m_bFollowCSGOServerGuidelines = true;
return ConfigResult_Accept;
}
else
{
ke::SafeStrcpy(error, maxlength, "Invalid value: must be \"yes\" or \"no\"");
return ConfigResult_Reject;
}
#endif
}
return ConfigResult_Ignore;
}
void CHalfLife2::InitLogicalEntData()
@ -146,7 +179,8 @@ void CHalfLife2::InitLogicalEntData()
|| SOURCE_ENGINE == SE_HL2DM \
|| SOURCE_ENGINE == SE_CSS \
|| SOURCE_ENGINE == SE_SDK2013 \
|| SOURCE_ENGINE == SE_BMS
|| SOURCE_ENGINE == SE_BMS \
|| SOURCE_ENGINE == SE_NUCLEARDAWN
if (g_SMAPI->GetServerFactory(false)("VSERVERTOOLS003", nullptr))
{
@ -194,7 +228,12 @@ void CHalfLife2::InitLogicalEntData()
return;
}
#ifdef PLATFORM_X86
g_EntList = *reinterpret_cast<void **>(addr + offset);
#elif defined PLATFORM_X64
int32_t varOffset = *reinterpret_cast<int32_t *>(addr + offset);
g_EntList = reinterpret_cast<void *>(addr + offset + sizeof(int32_t) + varOffset);
#endif
}
}
@ -226,7 +265,7 @@ void CHalfLife2::InitCommandLine()
#if SOURCE_ENGINE != SE_DARKMESSIAH
if (g_SMAPI->GetSourceEngineBuild() != SOURCE_ENGINE_ORIGINAL)
{
ke::Ref<ke::SharedLib> lib = ke::SharedLib::Open(TIER0_NAME, error, sizeof(error));
ke::RefPtr<ke::SharedLib> lib = ke::SharedLib::Open(TIER0_NAME, error, sizeof(error));
if (!lib) {
logger->LogError("Could not load %s: %s", TIER0_NAME, error);
return;
@ -243,7 +282,7 @@ void CHalfLife2::InitCommandLine()
else
#endif
{
ke::Ref<ke::SharedLib> lib = ke::SharedLib::Open(VSTDLIB_NAME, error, sizeof(error));
ke::RefPtr<ke::SharedLib> lib = ke::SharedLib::Open(VSTDLIB_NAME, error, sizeof(error));
if (!lib) {
logger->LogError("Could not load %s: %s", VSTDLIB_NAME, error);
return;
@ -269,11 +308,7 @@ ICommandLine *CHalfLife2::GetValveCommandLine()
#if SOURCE_ENGINE != SE_DARKMESSIAH
IChangeInfoAccessor *CBaseEdict::GetChangeAccessor()
{
#if SOURCE_ENGINE == SE_DOTA
return engine->GetChangeAccessor( IndexOfEdict((const edict_t *)this) );
#else
return engine->GetChangeAccessor( (const edict_t *)this );
#endif
}
#endif
@ -481,17 +516,7 @@ bool CHalfLife2::TextMsg(int client, int dest, const char *msg)
char buffer[253];
ke::SafeSprintf(buffer, sizeof(buffer), "%s\1\n", msg);
#if SOURCE_ENGINE == SE_DOTA
CUserMsg_SayText *pMsg;
if ((pMsg = (CUserMsg_SayText *)g_UserMsgs.StartProtobufMessage(m_SayTextMsg, players, 1, USERMSG_RELIABLE)) == NULL)
{
return false;
}
pMsg->set_client(0);
pMsg->set_text(buffer);
pMsg->set_chat(false);
#elif SOURCE_ENGINE == SE_CSGO
#if SOURCE_ENGINE == SE_CSGO
CCSUsrMsg_SayText *pMsg;
if ((pMsg = (CCSUsrMsg_SayText *)g_UserMsgs.StartProtobufMessage(m_SayTextMsg, players, 1, USERMSG_RELIABLE)) == NULL)
{
@ -518,16 +543,7 @@ bool CHalfLife2::TextMsg(int client, int dest, const char *msg)
}
}
#if SOURCE_ENGINE == SE_DOTA
CUserMsg_TextMsg *pMsg;
if ((pMsg = (CUserMsg_TextMsg *)g_UserMsgs.StartProtobufMessage(m_MsgTextMsg, players, 1, USERMSG_RELIABLE)) == NULL)
{
return false;
}
pMsg->set_dest(dest);
pMsg->add_param(msg);
#elif SOURCE_ENGINE == SE_CSGO
#if SOURCE_ENGINE == SE_CSGO
CCSUsrMsg_TextMsg *pMsg;
if ((pMsg = (CCSUsrMsg_TextMsg *)g_UserMsgs.StartProtobufMessage(m_MsgTextMsg, players, 1, USERMSG_RELIABLE)) == NULL)
{
@ -549,6 +565,10 @@ bool CHalfLife2::TextMsg(int client, int dest, const char *msg)
pBitBuf->WriteByte(dest);
pBitBuf->WriteString(msg);
pBitBuf->WriteString("");
pBitBuf->WriteString("");
pBitBuf->WriteString("");
pBitBuf->WriteString("");
#endif
g_UserMsgs.EndMessage();
@ -560,15 +580,7 @@ bool CHalfLife2::HintTextMsg(int client, const char *msg)
{
cell_t players[] = {client};
#if SOURCE_ENGINE == SE_DOTA
CUserMsg_HintText *pMsg;
if ((pMsg = (CUserMsg_HintText *)g_UserMsgs.StartProtobufMessage(m_HinTextMsg, players, 1, USERMSG_RELIABLE)) == NULL)
{
return false;
}
pMsg->set_message(msg);
#elif SOURCE_ENGINE == SE_CSGO
#if SOURCE_ENGINE == SE_CSGO
CCSUsrMsg_HintText *pMsg;
if ((pMsg = (CCSUsrMsg_HintText *)g_UserMsgs.StartProtobufMessage(m_HinTextMsg, players, 1, USERMSG_RELIABLE)) == NULL)
{
@ -598,15 +610,7 @@ bool CHalfLife2::HintTextMsg(int client, const char *msg)
bool CHalfLife2::HintTextMsg(cell_t *players, int count, const char *msg)
{
#if SOURCE_ENGINE == SE_DOTA
CUserMsg_HintText *pMsg;
if ((pMsg = (CUserMsg_HintText *)g_UserMsgs.StartProtobufMessage(m_HinTextMsg, players, count, USERMSG_RELIABLE)) == NULL)
{
return false;
}
pMsg->set_message(msg);
#elif SOURCE_ENGINE == SE_CSGO
#if SOURCE_ENGINE == SE_CSGO
CCSUsrMsg_HintText *pMsg;
if ((pMsg = (CCSUsrMsg_HintText *)g_UserMsgs.StartProtobufMessage(m_HinTextMsg, players, count, USERMSG_RELIABLE)) == NULL)
{
@ -641,13 +645,7 @@ bool CHalfLife2::ShowVGUIMenu(int client, const char *name, KeyValues *data, boo
int count = 0;
cell_t players[] = {client};
#if SOURCE_ENGINE == SE_DOTA
CUserMsg_VGUIMenu *pMsg;
if ((pMsg = (CUserMsg_VGUIMenu *)g_UserMsgs.StartProtobufMessage(m_VGUIMenu, players, 1, USERMSG_RELIABLE)) == NULL)
{
return false;
}
#elif SOURCE_ENGINE == SE_CSGO
#if SOURCE_ENGINE == SE_CSGO
CCSUsrMsg_VGUIMenu *pMsg;
if ((pMsg = (CCSUsrMsg_VGUIMenu *)g_UserMsgs.StartProtobufMessage(m_VGUIMenu, players, 1, USERMSG_RELIABLE)) == NULL)
{
@ -672,18 +670,7 @@ bool CHalfLife2::ShowVGUIMenu(int client, const char *name, KeyValues *data, boo
SubKey = data->GetFirstSubKey();
}
#if SOURCE_ENGINE == SE_DOTA
pMsg->set_name(name);
pMsg->set_show(show);
while (SubKey)
{
CUserMsg_VGUIMenu_Keys *key = pMsg->add_keys();
key->set_name(SubKey->GetName());
key->set_value(SubKey->GetString());
SubKey = SubKey->GetNextKey();
}
#elif SOURCE_ENGINE == SE_CSGO
#if SOURCE_ENGINE == SE_CSGO
pMsg->set_name(name);
pMsg->set_show(show);
@ -739,11 +726,7 @@ void CHalfLife2::ProcessFakeCliCmdQueue()
if (g_Players.GetClientOfUserId(pFake->userid) == pFake->client)
{
CPlayer *pPlayer = g_Players.GetPlayerByIndex(pFake->client);
#if SOURCE_ENGINE == SE_DOTA
engine->ClientCommand(pPlayer->GetIndex(), "%s", pFake->cmd.c_str());
#else
serverpluginhelpers->ClientCommand(pPlayer->GetEdict(), pFake->cmd.c_str());
#endif
}
m_CmdQueue.pop();
@ -850,7 +833,7 @@ void CHalfLife2::AddDelayedKick(int client, int userid, const char *msg)
kick.client = client;
kick.userid = userid;
ke::SafeSprintf(kick.buffer, sizeof(kick.buffer), "%s", msg);
ke::SafeStrcpy(kick.buffer, sizeof(kick.buffer), msg);
m_DelayedKicks.push(kick);
}
@ -1187,8 +1170,58 @@ SMFindMapResult CHalfLife2::FindMap(char *pMapName, size_t nMapNameMax)
return this->FindMap(pMapName, pMapName, nMapNameMax);
}
#ifdef PLATFORM_WINDOWS
bool CheckReservedFilename(const char *in, const char *reservedName)
{
size_t nameLen = strlen(reservedName);
for (size_t i = 0; i < nameLen; ++i)
{
if (reservedName[i] != tolower(in[i]))
{
return false;
}
}
if (in[nameLen] == '\0' || in[nameLen] == '.')
{
return true;
}
return false;
}
bool IsWindowsReservedDeviceName(const char *pMapname)
{
static const char * const reservedDeviceNames[] = {
"con", "prn", "aux", "clock$", "nul", "com1",
"com2", "com3", "com4", "com5", "com6", "com7",
"com8", "com9", "lpt1", "lpt2", "lpt3", "lpt4",
"lpt5", "lpt6", "lpt7", "lpt8", "lpt9"
};
size_t reservedCount = sizeof(reservedDeviceNames) / sizeof(reservedDeviceNames[0]);
for (int i = 0; i < reservedCount; ++i)
{
if (CheckReservedFilename(pMapname, reservedDeviceNames[i]))
{
return true;
}
}
return false;
}
#endif
SMFindMapResult CHalfLife2::FindMap(const char *pMapName, char *pFoundMap, size_t nMapNameMax)
{
/* We need to ensure user input does not contain reserved device names on windows */
#ifdef PLATFORM_WINDOWS
if (IsWindowsReservedDeviceName(pMapName))
{
return SMFindMapResult::NotFound;
}
#endif
ke::SafeStrcpy(pFoundMap, nMapNameMax, pMapName);
#if SOURCE_ENGINE >= SE_LEFT4DEAD
@ -1233,7 +1266,7 @@ SMFindMapResult CHalfLife2::FindMap(const char *pMapName, char *pFoundMap, size_
return SMFindMapResult::FuzzyMatch;
}
#elif SOURCE_ENGINE == SE_TF2
#elif SOURCE_ENGINE == SE_TF2 || SOURCE_ENGINE == SE_BMS
static char szTemp[PLATFORM_MAX_PATH];
if (pFoundMap == NULL)
{
@ -1256,29 +1289,14 @@ bool CHalfLife2::GetMapDisplayName(const char *pMapName, char *pDisplayname, siz
SMFindMapResult result = FindMap(pMapName, pDisplayname, nMapNameMax);
if (result == SMFindMapResult::NotFound)
{
return false;
}
#if SOURCE_ENGINE == SE_CSGO
char *lastSlashPos;
// In CSGO, workshop maps show up as workshop/123456789/mapname
if (strncmp(pDisplayname, "workshop/", 9) == 0 && (lastSlashPos = strrchr(pDisplayname, '/')) != NULL)
{
ke::SafeSprintf(pDisplayname, nMapNameMax, "%s", &lastSlashPos[1]);
return true;
}
#elif SOURCE_ENGINE == SE_TF2
char *ugcPos;
// In TF2, workshop maps show up as workshop/mapname.ugc123456789
if (strncmp(pDisplayname, "workshop/", 9) == 0 && (ugcPos = strstr(pDisplayname, ".ugc")) != NULL)
{
// Overwrite the . with a nul and SafeSprintf will handle the rest
ugcPos[0] = '\0';
ke::SafeSprintf(pDisplayname, nMapNameMax, "%s", &pDisplayname[9]);
return true;
}
#endif
char *pPos;
if ((pPos = strrchr(pDisplayname, '/')) != NULL || (pPos = strrchr(pDisplayname, '\\')) != NULL)
ke::SafeStrcpy(pDisplayname, nMapNameMax, &pPos[1]);
if ((pPos = strstr(pDisplayname, ".ugc")) != NULL)
pPos[0] = '\0';
return true;
}
@ -1324,3 +1342,76 @@ string_t CHalfLife2::AllocPooledString(const char *pszValue)
return newString;
}
#endif
bool CHalfLife2::GetServerSteam3Id(char *pszOut, size_t len) const
{
CSteamID sid((uint64)GetServerSteamId64());
switch (sid.GetEAccountType())
{
case k_EAccountTypeAnonGameServer:
ke::SafeSprintf(pszOut, len, "[A:%u:%u:%u]", sid.GetEUniverse(), sid.GetAccountID(), sid.GetUnAccountInstance());
break;
case k_EAccountTypeGameServer:
ke::SafeSprintf(pszOut, len, "[G:%u:%u]", sid.GetEUniverse(), sid.GetAccountID());
break;
case k_EAccountTypeInvalid:
ke::SafeSprintf(pszOut, len, "[I:%u:%u]", sid.GetEUniverse(), sid.GetAccountID());
break;
default:
return false;
}
return true;
}
#if defined( PLATFORM_WINDOWS )
#define STEAM_LIB_PREFIX
#define STEAM_LIB_SUFFIX
#elif defined( PLATFORM_LINUX )
#define STEAM_LIB_PREFIX "lib"
#define STEAM_LIB_SUFFIX ".so"
#elif defined( PLATFORM_APPLE )
#define STEAM_LIB_PREFIX "lib"
#define STEAM_LIB_SUFFIX ".dylib"
#endif
uint64_t CHalfLife2::GetServerSteamId64() const
{
#if SOURCE_ENGINE == SE_BLADE \
|| SOURCE_ENGINE == SE_BMS \
|| SOURCE_ENGINE == SE_CSGO \
|| SOURCE_ENGINE == SE_CSS \
|| SOURCE_ENGINE == SE_DODS \
|| SOURCE_ENGINE == SE_EYE \
|| SOURCE_ENGINE == SE_HL2DM \
|| SOURCE_ENGINE == SE_INSURGENCY \
|| SOURCE_ENGINE == SE_DOI \
|| SOURCE_ENGINE == SE_SDK2013 \
|| SOURCE_ENGINE == SE_ALIENSWARM \
|| SOURCE_ENGINE == SE_TF2
const CSteamID *sid = engine->GetGameServerSteamID();
if (sid)
{
return sid->ConvertToUint64();
}
#else
typedef uint64_t(* GetServerSteamIdFn)(void);
static GetServerSteamIdFn fn = nullptr;
if (!fn)
{
ke::SharedLib steam_api(STEAM_LIB_PREFIX "steam_api" STEAM_LIB_SUFFIX);
if (steam_api.valid())
{
fn = (GetServerSteamIdFn)steam_api.lookup("SteamGameServer_GetSteamID");
}
}
if (fn)
{
return fn();
}
#endif
return 1ULL;
}

View File

@ -2,7 +2,7 @@
* vim: set ts=4 sw=4 tw=99 noet :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
* Copyright (C) 2004-2016 AlliedModders LLC. All rights reserved.
* =============================================================================
*
* This program is free software; you can redistribute it and/or modify it under
@ -36,6 +36,7 @@
#include <sh_string.h>
#include <sh_tinyhash.h>
#include <am-utility.h>
#include <am-hashset.h>
#include <am-hashmap.h>
#include <sm_stringhashmap.h>
#include <sm_namehashset.h>
@ -59,6 +60,30 @@ using namespace SourceMod;
#define HUD_PRINTTALK 3
#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
struct DataTableInfo
{
struct SendPropPolicy
@ -67,13 +92,21 @@ struct DataTableInfo
{
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)
{
@ -89,6 +122,10 @@ struct DataMapCachePolicy
{
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;
@ -123,7 +160,7 @@ public:
int m_SerialNumber;
CEntInfo *m_pPrev;
CEntInfo *m_pNext;
#if (SOURCE_ENGINE >= SE_PORTAL2) && (SOURCE_ENGINE != SE_DOTA)
#if SOURCE_ENGINE >= SE_PORTAL2
string_t m_iName;
string_t m_iClassName;
#endif
@ -152,6 +189,8 @@ public:
void OnSourceModAllInitialized();
void OnSourceModAllInitialized_Post();
/*void OnSourceModAllShutdown();*/
ConfigResult OnSourceModConfigChanged(const char *key, const char *value,
ConfigSource source, char *error, size_t maxlength) override;
public: //IGameHelpers
SendProp *FindInSendTable(const char *classname, const char *offset);
bool FindSendPropInfo(const char *classname, const char *offset, sm_sendprop_info_t *info);
@ -191,6 +230,8 @@ public: //IGameHelpers
#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:
void AddToFakeCliCmdQueue(int client, int userid, const char *cmd);
void ProcessFakeCliCmdQueue();
@ -220,6 +261,16 @@ private:
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;

View File

@ -570,7 +570,7 @@ skip_search:
/* If there are no control options,
* Instead just pad with invisible slots.
*/
if (!displayPrev && !displayPrev)
if (!displayNext && !displayPrev)
{
padItem.style = ITEMDRAW_NOTEXT;
}

View File

@ -34,6 +34,7 @@
#include <IMenuManager.h>
#include <IPlayerHelpers.h>
#include <am-autoptr.h>
#include <am-string.h>
#include <am-vector.h>
#include "sm_fastlink.h"

View File

@ -141,11 +141,7 @@ void CRadioStyle::OnSourceModShutdown()
bool CRadioStyle::IsSupported()
{
#if SOURCE_ENGINE == SE_DOTA
return false;
#else
return (g_ShowMenuId != -1);
#endif
}
bool CRadioStyle::OnClientCommand(int client, const char *cmdname, const CCommand &cmd)
@ -176,10 +172,9 @@ void CRadioStyle::OnUserMessage(int msg_id, protobuf::Message &msg, IRecipientFi
void CRadioStyle::OnUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter)
#endif
{
#if SOURCE_ENGINE != SE_DOTA
int count = pFilter->GetRecipientCount();
#ifdef USE_PROTOBUF_USERMESSAGES
#if SOURCE_ENGINE == SE_CSGO
int c = ((CCSUsrMsg_ShowMenu &)msg).display_time();
#else
bf_read br(bf->GetBasePointer(), 3);
@ -194,7 +189,6 @@ void CRadioStyle::OnUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFil
{
g_last_clients[g_last_client_count++] = pFilter->GetRecipientIndex(i);
}
#endif
}
void CRadioStyle::OnUserMessageSent(int msg_id)
@ -464,9 +458,8 @@ void CRadioMenuPlayer::Radio_Init(int keys, const char *title, const char *text)
}
else
{
display_len = ke::SafeSprintf(display_pkt,
display_len = ke::SafeStrcpy(display_pkt,
sizeof(display_pkt),
"%s",
text);
}
display_keys = keys;
@ -474,7 +467,6 @@ void CRadioMenuPlayer::Radio_Init(int keys, const char *title, const char *text)
void CRadioMenuPlayer::Radio_Refresh()
{
#if SOURCE_ENGINE != SE_DOTA
cell_t players[1] = { (cell_t)m_index };
char *ptr = display_pkt;
char save = 0;
@ -491,8 +483,7 @@ void CRadioMenuPlayer::Radio_Refresh()
time = menuHoldTime - (unsigned int)(gpGlobals->curtime - menuStartTime);
}
#ifdef USE_PROTOBUF_USERMESSAGES
// If or when we need to support multiple games per engine with this, we can switch to reflection
#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);
@ -528,7 +519,6 @@ void CRadioMenuPlayer::Radio_Refresh()
#endif
display_last_refresh = gpGlobals->curtime;
#endif // !DOTA
}
int CRadioDisplay::GetAmountRemaining()

View File

@ -65,20 +65,16 @@ bool ValveMenuStyle::OnClientCommand(int client, const char *cmdname, const CCom
void ValveMenuStyle::OnSourceModAllInitialized()
{
#if SOURCE_ENGINE != SE_DOTA
g_Players.AddClientListener(this);
SH_ADD_HOOK(IServerPluginHelpers, CreateMessage, serverpluginhelpers, SH_MEMBER(this, &ValveMenuStyle::HookCreateMessage), false);
g_pSPHCC = SH_GET_CALLCLASS(serverpluginhelpers);
#endif
}
void ValveMenuStyle::OnSourceModShutdown()
{
#if SOURCE_ENGINE != SE_DOTA
SH_RELEASE_CALLCLASS(g_pSPHCC);
SH_REMOVE_HOOK(IServerPluginHelpers, CreateMessage, serverpluginhelpers, SH_MEMBER(this, &ValveMenuStyle::HookCreateMessage), false);
g_Players.RemoveClientListener(this);
#endif
}
void ValveMenuStyle::HookCreateMessage(edict_t *pEdict,

View File

@ -48,15 +48,10 @@ SH_DECL_HOOK2_void(IVEngineServer, ChangeLevel, SH_NOATTRIB, 0, const char *, co
SH_DECL_HOOK4_void(IVEngineServer, ChangeLevel, SH_NOATTRIB, 0, const char *, const char *, const char *, bool);
#endif
#if SOURCE_ENGINE == SE_DOTA
SH_DECL_EXTERN2_void(ConCommand, Dispatch, SH_NOATTRIB, false, const CCommandContext &, const CCommand &);
#elif SOURCE_ENGINE >= SE_ORANGEBOX
#if SOURCE_ENGINE >= SE_ORANGEBOX
SH_DECL_EXTERN1_void(ConCommand, Dispatch, SH_NOATTRIB, false, const CCommand &);
#elif SOURCE_ENGINE == SE_DARKMESSIAH
SH_DECL_EXTERN0_void(ConCommand, Dispatch, SH_NOATTRIB, false);
#else
extern int __SourceHook_FHAddConCommandDispatch(void *,bool,class fastdelegate::FastDelegate0<void>);
extern bool __SourceHook_FHRemoveConCommandDispatch(void *,bool,class fastdelegate::FastDelegate0<void>);
SH_DECL_EXTERN0_void(ConCommand, Dispatch, SH_NOATTRIB, false);
#endif
ConCommand *changeLevelCmd = NULL;
@ -143,8 +138,8 @@ void NextMapManager::HookChangeLevel(const char *map, const char *unknown, const
logger->LogMessage("[SM] Changed map to \"%s\"", newmap);
ke::SafeSprintf(m_tempChangeInfo.m_mapName, sizeof(m_tempChangeInfo.m_mapName), newmap);
ke::SafeSprintf(m_tempChangeInfo.m_changeReason, sizeof(m_tempChangeInfo.m_changeReason), "Normal level change");
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));
@ -189,14 +184,14 @@ void NextMapManager::OnSourceModLevelChange( const char *mapName )
m_tempChangeInfo.m_mapName[0] ='\0';
m_tempChangeInfo.m_changeReason[0] = '\0';
m_tempChangeInfo.startTime = time(NULL);
ke::SafeSprintf(lastMap, sizeof(lastMap), "%s", mapName);
ke::SafeStrcpy(lastMap, sizeof(lastMap), mapName);
}
void NextMapManager::ForceChangeLevel( const char *mapName, const char* changeReason )
{
/* Store the mapname and reason */
ke::SafeSprintf(m_tempChangeInfo.m_mapName, sizeof(m_tempChangeInfo.m_mapName), "%s", mapName);
ke::SafeSprintf(m_tempChangeInfo.m_changeReason, sizeof(m_tempChangeInfo.m_changeReason), "%s", changeReason);
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;
@ -210,10 +205,7 @@ NextMapManager::NextMapManager()
m_mapHistory = SourceHook::List<MapChangeData *>();
}
#if SOURCE_ENGINE == SE_DOTA
void CmdChangeLevelCallback(const CCommandContext &context, const CCommand &command)
{
#elif SOURCE_ENGINE >= SE_ORANGEBOX
#if SOURCE_ENGINE >= SE_ORANGEBOX
void CmdChangeLevelCallback(const CCommand &command)
{
#else
@ -229,7 +221,7 @@ void CmdChangeLevelCallback()
if (g_NextMap.m_tempChangeInfo.m_mapName[0] == '\0')
{
ke::SafeSprintf(g_NextMap.m_tempChangeInfo.m_mapName, sizeof(g_NextMap.m_tempChangeInfo.m_mapName), command.Arg(1));
ke::SafeSprintf(g_NextMap.m_tempChangeInfo.m_changeReason, sizeof(g_NextMap.m_tempChangeInfo.m_changeReason), "changelevel Command");
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

@ -59,9 +59,7 @@ struct MapChangeData
time_t startTime;
};
#if SOURCE_ENGINE == SE_DOTA
void CmdChangeLevelCallback(const CCommandContext &context, const CCommand &command);
#elif SOURCE_ENGINE >= SE_ORANGEBOX
#if SOURCE_ENGINE >= SE_ORANGEBOX
void CmdChangeLevelCallback(const CCommand &command);
#else
void CmdChangeLevelCallback();
@ -72,9 +70,7 @@ class NextMapManager : public SMGlobalClass
public:
NextMapManager();
#if SOURCE_ENGINE == SE_DOTA
friend void CmdChangeLevelCallback(const CCommandContext &context, const CCommand &command);
#elif SOURCE_ENGINE >= SE_ORANGEBOX
#if SOURCE_ENGINE >= SE_ORANGEBOX
friend void CmdChangeLevelCallback(const CCommand &command);
#else
friend void CmdChangeLevelCallback();

View File

@ -42,13 +42,13 @@
#include "HalfLife2.h"
#include <inetchannel.h>
#include <iclient.h>
#include <iserver.h>
#include <IGameConfigs.h>
#include "ConsoleDetours.h"
#include "logic_bridge.h"
#include <sourcemod_version.h>
#include "smn_keyvalues.h"
#include "command_args.h"
#include <ITranslator.h>
#include <bridge/include/IExtensionBridge.h>
#include <bridge/include/IScriptManager.h>
#include <bridge/include/ILogger.h>
@ -63,15 +63,8 @@ const unsigned int *g_NumPlayersToAuth = NULL;
int lifestate_offset = -1;
List<ICommandTargetProcessor *> target_processors;
ConVar sm_debug_connect("sm_debug_connect", "0", 0, "Log Debug information about potential connection issues.");
ConVar sm_debug_connect("sm_debug_connect", "1", 0, "Log Debug information about potential connection issues.");
#if SOURCE_ENGINE == SE_DOTA
SH_DECL_HOOK5(IServerGameClients, ClientConnect, SH_NOATTRIB, 0, bool, CEntityIndex, const char *, const char *, char *, int);
SH_DECL_HOOK2_void(IServerGameClients, ClientPutInServer, SH_NOATTRIB, 0, CEntityIndex, const char *);
SH_DECL_HOOK2_void(IServerGameClients, ClientDisconnect, SH_NOATTRIB, 0, CEntityIndex, int);
SH_DECL_HOOK2_void(IServerGameClients, ClientCommand, SH_NOATTRIB, 0, CEntityIndex, const CCommand &);
SH_DECL_HOOK1_void(IServerGameClients, ClientSettingsChanged, SH_NOATTRIB, 0, CEntityIndex);
#else
SH_DECL_HOOK5(IServerGameClients, ClientConnect, SH_NOATTRIB, 0, bool, edict_t *, const char *, const char *, char *, int);
SH_DECL_HOOK2_void(IServerGameClients, ClientPutInServer, SH_NOATTRIB, 0, edict_t *, const char *);
SH_DECL_HOOK1_void(IServerGameClients, ClientDisconnect, SH_NOATTRIB, 0, edict_t *);
@ -81,32 +74,23 @@ SH_DECL_HOOK2_void(IServerGameClients, ClientCommand, SH_NOATTRIB, 0, edict_t *,
SH_DECL_HOOK1_void(IServerGameClients, ClientCommand, SH_NOATTRIB, 0, edict_t *);
#endif
SH_DECL_HOOK1_void(IServerGameClients, ClientSettingsChanged, SH_NOATTRIB, 0, edict_t *);
#endif // SE_DOTA
#if SOURCE_ENGINE >= SE_EYE && SOURCE_ENGINE != SE_DOTA
#if SOURCE_ENGINE >= SE_EYE
SH_DECL_HOOK2_void(IServerGameClients, ClientCommandKeyValues, SH_NOATTRIB, 0, edict_t *, KeyValues *);
#endif
#if SOURCE_ENGINE == SE_DOTA
SH_DECL_HOOK0_void(IServerGameDLL, ServerActivate, SH_NOATTRIB, 0);
#else
SH_DECL_HOOK3_void(IServerGameDLL, ServerActivate, SH_NOATTRIB, 0, edict_t *, int, int);
#endif
#if SOURCE_ENGINE >= SE_LEFT4DEAD && SOURCE_ENGINE != SE_DOTA
#if SOURCE_ENGINE >= SE_LEFT4DEAD
SH_DECL_HOOK1_void(IServerGameDLL, ServerHibernationUpdate, SH_NOATTRIB, 0, bool);
#elif SOURCE_ENGINE > SE_EYE // 2013/orangebox, but not original orangebox. +dota
#elif SOURCE_ENGINE > SE_EYE // 2013/orangebox, but not original orangebox.
SH_DECL_HOOK1_void(IServerGameDLL, SetServerHibernation, SH_NOATTRIB, 0, bool);
#endif
#if SOURCE_ENGINE == SE_DOTA
SH_DECL_EXTERN2_void(ConCommand, Dispatch, SH_NOATTRIB, false, const CCommandContext &, const CCommand &);
#elif SOURCE_ENGINE >= SE_ORANGEBOX
#if SOURCE_ENGINE >= SE_ORANGEBOX
SH_DECL_EXTERN1_void(ConCommand, Dispatch, SH_NOATTRIB, false, const CCommand &);
#elif SOURCE_ENGINE == SE_DARKMESSIAH
SH_DECL_EXTERN0_void(ConCommand, Dispatch, SH_NOATTRIB, false);
#else
extern int __SourceHook_FHAddConCommandDispatch(void *,bool,class fastdelegate::FastDelegate0<void>);
extern bool __SourceHook_FHRemoveConCommandDispatch(void *,bool,class fastdelegate::FastDelegate0<void>);
SH_DECL_EXTERN0_void(ConCommand, Dispatch, SH_NOATTRIB, false);
#endif
ConCommand *maxplayersCmd = NULL;
@ -118,7 +102,7 @@ class KickPlayerTimer : public ITimedEvent
public:
ResultType OnTimer(ITimer *pTimer, void *pData)
{
int userid = (int)pData;
int userid = (int)(intptr_t)pData;
int client = g_Players.GetClientOfUserId(userid);
if (client)
{
@ -177,15 +161,15 @@ void PlayerManager::OnSourceModAllInitialized()
SH_ADD_HOOK(IServerGameClients, ClientDisconnect, serverClients, SH_MEMBER(this, &PlayerManager::OnClientDisconnect), false);
SH_ADD_HOOK(IServerGameClients, ClientDisconnect, serverClients, SH_MEMBER(this, &PlayerManager::OnClientDisconnect_Post), true);
SH_ADD_HOOK(IServerGameClients, ClientCommand, serverClients, SH_MEMBER(this, &PlayerManager::OnClientCommand), false);
#if SOURCE_ENGINE >= SE_EYE && SOURCE_ENGINE != SE_DOTA
#if SOURCE_ENGINE >= SE_EYE
SH_ADD_HOOK(IServerGameClients, ClientCommandKeyValues, serverClients, SH_MEMBER(this, &PlayerManager::OnClientCommandKeyValues), false);
SH_ADD_HOOK(IServerGameClients, ClientCommandKeyValues, serverClients, SH_MEMBER(this, &PlayerManager::OnClientCommandKeyValues_Post), true);
#endif
SH_ADD_HOOK(IServerGameClients, ClientSettingsChanged, serverClients, SH_MEMBER(this, &PlayerManager::OnClientSettingsChanged), true);
SH_ADD_HOOK(IServerGameDLL, ServerActivate, gamedll, SH_MEMBER(this, &PlayerManager::OnServerActivate), true);
#if SOURCE_ENGINE >= SE_LEFT4DEAD && SOURCE_ENGINE != SE_DOTA
#if SOURCE_ENGINE >= SE_LEFT4DEAD
SH_ADD_HOOK(IServerGameDLL, ServerHibernationUpdate, gamedll, SH_MEMBER(this, &PlayerManager::OnServerHibernationUpdate), true);
#elif SOURCE_ENGINE > SE_EYE // 2013/orangebox, but not original orangebox. +dota
#elif SOURCE_ENGINE > SE_EYE // 2013/orangebox, but not original orangebox.
SH_ADD_HOOK(IServerGameDLL, SetServerHibernation, gamedll, SH_MEMBER(this, &PlayerManager::OnServerHibernationUpdate), true);
#endif
@ -230,15 +214,15 @@ void PlayerManager::OnSourceModShutdown()
SH_REMOVE_HOOK(IServerGameClients, ClientDisconnect, serverClients, SH_MEMBER(this, &PlayerManager::OnClientDisconnect), false);
SH_REMOVE_HOOK(IServerGameClients, ClientDisconnect, serverClients, SH_MEMBER(this, &PlayerManager::OnClientDisconnect_Post), true);
SH_REMOVE_HOOK(IServerGameClients, ClientCommand, serverClients, SH_MEMBER(this, &PlayerManager::OnClientCommand), false);
#if SOURCE_ENGINE >= SE_EYE && SOURCE_ENGINE != SE_DOTA
#if SOURCE_ENGINE >= SE_EYE
SH_REMOVE_HOOK(IServerGameClients, ClientCommandKeyValues, serverClients, SH_MEMBER(this, &PlayerManager::OnClientCommandKeyValues), false);
SH_REMOVE_HOOK(IServerGameClients, ClientCommandKeyValues, serverClients, SH_MEMBER(this, &PlayerManager::OnClientCommandKeyValues_Post), true);
#endif
SH_REMOVE_HOOK(IServerGameClients, ClientSettingsChanged, serverClients, SH_MEMBER(this, &PlayerManager::OnClientSettingsChanged), true);
SH_REMOVE_HOOK(IServerGameDLL, ServerActivate, gamedll, SH_MEMBER(this, &PlayerManager::OnServerActivate), true);
#if SOURCE_ENGINE >= SE_LEFT4DEAD && SOURCE_ENGINE != SE_DOTA
#if SOURCE_ENGINE >= SE_LEFT4DEAD
SH_REMOVE_HOOK(IServerGameDLL, ServerHibernationUpdate, gamedll, SH_MEMBER(this, &PlayerManager::OnServerHibernationUpdate), true);
#elif SOURCE_ENGINE > SE_EYE // 2013/orangebox, but not original orangebox. +dota
#elif SOURCE_ENGINE > SE_EYE // 2013/orangebox, but not original orangebox.
SH_REMOVE_HOOK(IServerGameDLL, SetServerHibernation, gamedll, SH_MEMBER(this, &PlayerManager::OnServerHibernationUpdate), true);
#endif
@ -288,7 +272,7 @@ ConfigResult PlayerManager::OnSourceModConfigChanged(const char *key,
} else if (strcasecmp(value, "off") == 0) {
m_QueryLang = false;
} else {
ke::SafeSprintf(error, maxlength, "Invalid value: must be \"on\" or \"off\"");
ke::SafeStrcpy(error, maxlength, "Invalid value: must be \"on\" or \"off\"");
return ConfigResult_Reject;
}
return ConfigResult_Accept;
@ -299,7 +283,7 @@ ConfigResult PlayerManager::OnSourceModConfigChanged(const char *key,
} else if ( strcasecmp(value, "no") == 0) {
m_bAuthstringValidation = false;
} else {
ke::SafeSprintf(error, maxlength, "Invalid value: must be \"yes\" or \"no\"");
ke::SafeStrcpy(error, maxlength, "Invalid value: must be \"yes\" or \"no\"");
return ConfigResult_Reject;
}
return ConfigResult_Accept;
@ -307,11 +291,7 @@ ConfigResult PlayerManager::OnSourceModConfigChanged(const char *key,
return ConfigResult_Ignore;
}
#if SOURCE_ENGINE == SE_DOTA
void PlayerManager::OnServerActivate()
#else
void PlayerManager::OnServerActivate(edict_t *pEdictList, int edictCount, int clientMax)
#endif
{
static ConVar *tv_enable = icvar->FindVar("tv_enable");
#if SOURCE_ENGINE == SE_TF2
@ -329,11 +309,7 @@ void PlayerManager::OnServerActivate(edict_t *pEdictList, int edictCount, int cl
g_OnMapStarted = true;
m_bServerActivated = true;
#if SOURCE_ENGINE == SE_DOTA
extsys->CallOnCoreMapStart(gpGlobals->pEdicts, gpGlobals->maxEntities, gpGlobals->maxClients);
#else
extsys->CallOnCoreMapStart(pEdictList, edictCount, m_maxClients);
#endif
m_onActivate->Execute(NULL);
m_onActivate2->Execute(NULL);
@ -499,16 +475,9 @@ void PlayerManager::RunAuthChecks()
}
}
#if SOURCE_ENGINE == SE_DOTA
bool PlayerManager::OnClientConnect(CEntityIndex index, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen)
{
int client = index.Get();
edict_t *pEntity = PEntityOfEntIndex(client);
#else
bool PlayerManager::OnClientConnect(edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen)
{
int client = IndexOfEdict(pEntity);
#endif
CPlayer *pPlayer = &m_Players[client];
++m_PlayersSinceActive;
@ -525,13 +494,8 @@ bool PlayerManager::OnClientConnect(edict_t *pEntity, const char *pszName, const
logger->LogMessage("\"%s<%d><%s><>\" was already connected to the server.", pPlayer->GetName(), pPlayer->GetUserId(), pAuth);
}
#if SOURCE_ENGINE == SE_DOTA
OnClientDisconnect(pPlayer->GetIndex(), 0);
OnClientDisconnect_Post(pPlayer->GetIndex(), 0);
#else
OnClientDisconnect(pPlayer->GetEdict());
OnClientDisconnect_Post(pPlayer->GetEdict());
#endif
}
pPlayer->Initialize(pszName, pszAddress, pEntity);
@ -578,7 +542,7 @@ bool PlayerManager::OnClientConnect(edict_t *pEntity, const char *pszName, const
m_AuthQueue[++m_AuthQueue[0]] = client;
}
m_UserIdLookUp[GetPlayerUserId(pEntity)] = client;
m_UserIdLookUp[engine->GetPlayerUserId(pEntity)] = client;
}
else
{
@ -591,17 +555,9 @@ bool PlayerManager::OnClientConnect(edict_t *pEntity, const char *pszName, const
return true;
}
#if SOURCE_ENGINE == SE_DOTA
bool PlayerManager::OnClientConnect_Post(CEntityIndex index, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen)
{
int client = index.Get();
edict_t *pEntity = PEntityOfEntIndex(client);
#else
bool PlayerManager::OnClientConnect_Post(edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen)
{
int client = IndexOfEdict(pEntity);
#endif
bool orig_value = META_RESULT_ORIG_RET(bool);
CPlayer *pPlayer = &m_Players[client];
@ -638,18 +594,10 @@ bool PlayerManager::OnClientConnect_Post(edict_t *pEntity, const char *pszName,
return true;
}
#if SOURCE_ENGINE == SE_DOTA
void PlayerManager::OnClientPutInServer(CEntityIndex index, const char *playername)
{
int client = index.Get();
edict_t *pEntity = PEntityOfEntIndex(client);
#else
void PlayerManager::OnClientPutInServer(edict_t *pEntity, const char *playername)
{
int client = IndexOfEdict(pEntity);
#endif
cell_t res;
int client = IndexOfEdict(pEntity);
CPlayer *pPlayer = &m_Players[client];
/* If they're not connected, they're a bot */
@ -682,8 +630,9 @@ void PlayerManager::OnClientPutInServer(edict_t *pEntity, const char *playername
// This doesn't actually get incremented until OnClientConnect. Fake it to check.
int newCount = m_PlayersSinceActive + 1;
int userId = GetPlayerUserId(pEntity);
#if (SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_TF2 || SOURCE_ENGINE == SE_NUCLEARDAWN || SOURCE_ENGINE == SE_LEFT4DEAD2)
int userId = engine->GetPlayerUserId(pEntity);
#if (SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_TF2 || SOURCE_ENGINE == SE_SDK2013 \
|| SOURCE_ENGINE == SE_BMS || SOURCE_ENGINE == SE_NUCLEARDAWN || SOURCE_ENGINE == SE_LEFT4DEAD2)
static ConVar *tv_name = icvar->FindVar("tv_name");
#endif
#if SOURCE_ENGINE == SE_TF2
@ -708,7 +657,8 @@ void PlayerManager::OnClientPutInServer(edict_t *pEntity, const char *playername
&& (m_SourceTVUserId == userId
#if SOURCE_ENGINE == SE_CSGO
|| strcmp(playername, "GOTV") == 0
#elif (SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_TF2 || SOURCE_ENGINE == SE_NUCLEARDAWN)
#elif (SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_TF2 || SOURCE_ENGINE == SE_SDK2013 \
|| SOURCE_ENGINE == SE_BMS || SOURCE_ENGINE == SE_NUCLEARDAWN || SOURCE_ENGINE == SE_LEFT4DEAD2)
|| (tv_name && strcmp(playername, tv_name->GetString()) == 0) || (tv_name && tv_name->GetString()[0] == 0 && strcmp(playername, "unnamed") == 0)
#else
|| strcmp(playername, "SourceTV") == 0
@ -720,11 +670,7 @@ void PlayerManager::OnClientPutInServer(edict_t *pEntity, const char *playername
m_SourceTVUserId = userId;
}
#if SOURCE_ENGINE == SE_DOTA
if (!OnClientConnect(client, playername, "127.0.0.1", error, sizeof(error)))
#else
if (!OnClientConnect(pEntity, playername, "127.0.0.1", error, sizeof(error)))
#endif
{
/* :TODO: kick the bot if it's rejected */
return;
@ -767,7 +713,7 @@ void PlayerManager::OnClientPutInServer(edict_t *pEntity, const char *playername
pPlayer->Authorize_Post();
}
#if SOURCE_ENGINE == SE_CSGO
else
else if(m_QueryLang)
{
// Not a bot
pPlayer->m_LanguageCookie = g_ConVarManager.QueryClientConVar(pEntity, "cl_language", NULL, 0);
@ -806,13 +752,8 @@ void PlayerManager::OnSourceModLevelEnd()
{
if (m_Players[i].IsConnected())
{
#if SOURCE_ENGINE == SE_DOTA
OnClientDisconnect(m_Players[i].GetIndex(), 0);
OnClientDisconnect_Post(m_Players[i].GetIndex(), 0);
#else
OnClientDisconnect(m_Players[i].GetEdict());
OnClientDisconnect_Post(m_Players[i].GetEdict());
#endif
}
}
m_PlayerCount = 0;
@ -836,30 +777,17 @@ void PlayerManager::OnServerHibernationUpdate(bool bHibernating)
if (pPlayer->IsSourceTV() || pPlayer->IsReplay())
continue;
#endif
#if SOURCE_ENGINE == SE_DOTA
OnClientDisconnect(m_Players[i].GetIndex(), 0);
OnClientDisconnect_Post(m_Players[i].GetIndex(), 0);
#else
OnClientDisconnect(m_Players[i].GetEdict());
OnClientDisconnect_Post(m_Players[i].GetEdict());
#endif
}
}
}
}
#if SOURCE_ENGINE == SE_DOTA
void PlayerManager::OnClientDisconnect(CEntityIndex index, int reason)
{
int client = index.Get();
edict_t *pEntity = PEntityOfEntIndex(client);
#else
void PlayerManager::OnClientDisconnect(edict_t *pEntity)
{
int client = IndexOfEdict(pEntity);
#endif
cell_t res;
int client = IndexOfEdict(pEntity);
CPlayer *pPlayer = &m_Players[client];
if (pPlayer->IsConnected())
@ -887,16 +815,9 @@ void PlayerManager::OnClientDisconnect(edict_t *pEntity)
}
}
#if SOURCE_ENGINE == SE_DOTA
void PlayerManager::OnClientDisconnect_Post(CEntityIndex index, int reason)
{
int client = index.Get();
edict_t *pEntity = PEntityOfEntIndex(client);
#else
void PlayerManager::OnClientDisconnect_Post(edict_t *pEntity)
{
int client = IndexOfEdict(pEntity);
#endif
CPlayer *pPlayer = &m_Players[client];
if (!pPlayer->IsConnected())
{
@ -1112,24 +1033,17 @@ void ListPluginsToClient(CPlayer *player, const CCommand &args)
}
}
#if SOURCE_ENGINE == SE_DOTA
void PlayerManager::OnClientCommand(CEntityIndex index, const CCommand &args)
{
int client = index.Get();
edict_t *pEntity = PEntityOfEntIndex(client);
#elif SOURCE_ENGINE >= SE_ORANGEBOX
#if SOURCE_ENGINE >= SE_ORANGEBOX
void PlayerManager::OnClientCommand(edict_t *pEntity, const CCommand &args)
{
int client = IndexOfEdict(pEntity);
#else
void PlayerManager::OnClientCommand(edict_t *pEntity)
{
CCommand args;
int client = IndexOfEdict(pEntity);
#endif
cell_t res = Pl_Continue;
int client = IndexOfEdict(pEntity);
CPlayer *pPlayer = &m_Players[client];
if (!pPlayer->IsConnected())
@ -1234,7 +1148,7 @@ void PlayerManager::OnClientCommand(edict_t *pEntity)
}
}
#if SOURCE_ENGINE >= SE_EYE && SOURCE_ENGINE != SE_DOTA
#if SOURCE_ENGINE >= SE_EYE
static bool s_LastCCKVAllowed = true;
void PlayerManager::OnClientCommandKeyValues(edict_t *pEntity, KeyValues *pCommand)
@ -1314,18 +1228,10 @@ void PlayerManager::OnClientCommandKeyValues_Post(edict_t *pEntity, KeyValues *p
}
#endif
#if SOURCE_ENGINE == SE_DOTA
void PlayerManager::OnClientSettingsChanged(CEntityIndex index)
{
int client = index.Get();
edict_t *pEntity = PEntityOfEntIndex(client);
#else
void PlayerManager::OnClientSettingsChanged(edict_t *pEntity)
{
int client = IndexOfEdict(pEntity);
#endif
cell_t res;
int client = IndexOfEdict(pEntity);
CPlayer *pPlayer = &m_Players[client];
if (!pPlayer->IsConnected())
@ -1445,7 +1351,7 @@ int PlayerManager::GetClientOfUserId(int userid)
CPlayer *player = GetPlayerByIndex(client);
if (player && player->IsConnected())
{
int realUserId = GetPlayerUserId(player->GetEdict());
int realUserId = engine->GetPlayerUserId(player->GetEdict());
if (realUserId == userid)
{
return client;
@ -1462,7 +1368,7 @@ int PlayerManager::GetClientOfUserId(int userid)
{
continue;
}
if (GetPlayerUserId(player->GetEdict()) == userid)
if (engine->GetPlayerUserId(player->GetEdict()) == userid)
{
m_UserIdLookUp[userid] = i;
return i;
@ -1568,7 +1474,7 @@ void PlayerManager::InvalidatePlayer(CPlayer *pPlayer)
}
}
m_UserIdLookUp[GetPlayerUserId(pPlayer->m_pEdict)] = 0;
m_UserIdLookUp[engine->GetPlayerUserId(pPlayer->m_pEdict)] = 0;
pPlayer->Disconnect();
}
@ -1993,10 +1899,7 @@ int PlayerManager::GetClientFromSerial(unsigned int serial)
return 0;
}
#if SOURCE_ENGINE == SE_DOTA
void CmdMaxplayersCallback(const CCommandContext &context, const CCommand &command)
{
#elif SOURCE_ENGINE >= SE_ORANGEBOX
#if SOURCE_ENGINE >= SE_ORANGEBOX
void CmdMaxplayersCallback(const CCommand &command)
{
#else
@ -2032,31 +1935,13 @@ bool PlayerManager::HandleConVarQuery(QueryCvarCookie_t cookie, int client, EQue
CPlayer::CPlayer()
{
m_IsConnected = false;
m_IsInGame = false;
m_IsAuthorized = false;
m_pEdict = NULL;
m_Admin = INVALID_ADMIN_ID;
m_TempAdmin = false;
m_Info = NULL;
m_bAdminCheckSignalled = false;
m_UserId = -1;
m_bIsInKickQueue = false;
m_LastPassword.clear();
m_LangId = SOURCEMOD_LANGUAGE_ENGLISH;
m_bFakeClient = false;
m_bIsSourceTV = false;
m_bIsReplay = false;
m_Serial.value = -1;
#if SOURCE_ENGINE == SE_CSGO
m_LanguageCookie = InvalidQueryCvarCookie;
#endif
}
void CPlayer::Initialize(const char *name, const char *ip, edict_t *pEntity)
{
m_IsConnected = true;
m_Name.assign(name);
m_Ip.assign(ip);
m_pEdict = pEntity;
m_iIndex = IndexOfEdict(pEntity);
@ -2065,6 +1950,8 @@ void CPlayer::Initialize(const char *name, const char *ip, edict_t *pEntity)
m_Serial.bits.index = m_iIndex;
m_Serial.bits.serial = g_PlayerSerialCount++;
SetName(name);
char ip2[24], *ptr;
ke::SafeStrcpy(ip2, sizeof(ip2), ip);
if ((ptr = strchr(ip2, ':')) != NULL)
@ -2073,6 +1960,33 @@ void CPlayer::Initialize(const char *name, const char *ip, edict_t *pEntity)
}
m_IpNoPort.assign(ip2);
#if SOURCE_ENGINE == SE_TF2 \
|| SOURCE_ENGINE == SE_CSS \
|| SOURCE_ENGINE == SE_DODS \
|| SOURCE_ENGINE == SE_HL2DM \
|| SOURCE_ENGINE == SE_BMS \
|| SOURCE_ENGINE == SE_INSURGENCY \
|| SOURCE_ENGINE == SE_DOI
m_pIClient = engine->GetIServer()->GetClient(m_iIndex - 1);
#else
#if SOURCE_ENGINE == SE_SDK2013
// Source SDK 2013 mods that ship on Steam can be using older engine binaries
static IVEngineServer *engine22 = (IVEngineServer *)(g_SMAPI->GetEngineFactory()("VEngineServer022", nullptr));
if (engine22)
{
m_pIClient = engine22->GetIServer()->GetClient(m_iIndex - 1);
}
else
#endif
{
INetChannel *pNetChan = static_cast<INetChannel *>(engine->GetPlayerNetInfo(m_iIndex));
if (pNetChan)
{
m_pIClient = static_cast<IClient *>(pNetChan->GetMsgHandler());
}
}
#endif
UpdateAuthIds();
}
@ -2100,61 +2014,8 @@ void CPlayer::Connect()
void CPlayer::UpdateAuthIds()
{
if (m_IsAuthorized)
{
if (m_IsAuthorized || (!SetEngineString() && !SetCSteamID()))
return;
}
// First cache engine networkid
const char *authstr;
#if SOURCE_ENGINE == SE_DOTA
authstr = engine->GetPlayerNetworkIDString(m_iIndex - 1);
#else
authstr = engine->GetPlayerNetworkIDString(m_pEdict);
#endif
if (!authstr)
{
// engine doesn't have the client's auth string just yet, we can't do anything
return;
}
if (m_AuthID.compare(authstr) == 0)
{
return;
}
m_AuthID = authstr;
// Then, cache SteamId
if (IsFakeClient())
{
m_SteamId = k_steamIDNil;
}
else
{
#if SOURCE_ENGINE < SE_ORANGEBOX
const char * pAuth = GetAuthString();
/* STEAM_0:1:123123 | STEAM_ID_LAN | STEAM_ID_PENDING */
if (pAuth && (strlen(pAuth) > 10) && pAuth[8] != '_')
{
m_SteamId = CSteamID(atoi(&pAuth[8]) | (atoi(&pAuth[10]) << 1),
k_unSteamUserDesktopInstance, k_EUniversePublic, k_EAccountTypeIndividual);
}
#else
const CSteamID *steamId;
#if SOURCE_ENGINE == SE_DOTA
steamId = engine->GetClientSteamID(m_iIndex);
#else
steamId = engine->GetClientSteamID(m_pEdict);
#endif
if (steamId)
{
m_SteamId = (*steamId);
}
#endif
}
// Now cache Steam2/3 rendered ids
if (IsFakeClient())
@ -2189,23 +2050,70 @@ void CPlayer::UpdateAuthIds()
}
char szAuthBuffer[64];
snprintf(szAuthBuffer, sizeof(szAuthBuffer), "STEAM_%u:%u:%u", steam2universe, m_SteamId.GetAccountID() & 1, m_SteamId.GetAccountID() >> 1);
ke::SafeSprintf(szAuthBuffer, sizeof(szAuthBuffer), "STEAM_%u:%u:%u", steam2universe, m_SteamId.GetAccountID() & 1, m_SteamId.GetAccountID() >> 1);
m_Steam2Id = szAuthBuffer;
// TODO: make sure all hl2sdks' steamclientpublic.h have k_unSteamUserDesktopInstance.
if (m_SteamId.GetUnAccountInstance() == 1 /* k_unSteamUserDesktopInstance */)
{
snprintf(szAuthBuffer, sizeof(szAuthBuffer), "[U:%u:%u]", m_SteamId.GetEUniverse(), m_SteamId.GetAccountID());
ke::SafeSprintf(szAuthBuffer, sizeof(szAuthBuffer), "[U:%u:%u]", m_SteamId.GetEUniverse(), m_SteamId.GetAccountID());
}
else
{
snprintf(szAuthBuffer, sizeof(szAuthBuffer), "[U:%u:%u:%u]", m_SteamId.GetEUniverse(), m_SteamId.GetAccountID(), m_SteamId.GetUnAccountInstance());
ke::SafeSprintf(szAuthBuffer, sizeof(szAuthBuffer), "[U:%u:%u:%u]", m_SteamId.GetEUniverse(), m_SteamId.GetAccountID(), m_SteamId.GetUnAccountInstance());
}
m_Steam3Id = szAuthBuffer;
}
bool CPlayer::SetEngineString()
{
const char *authstr = engine->GetPlayerNetworkIDString(m_pEdict);
if (!authstr || m_AuthID.compare(authstr) == 0)
return false;
m_AuthID = authstr;
SetCSteamID();
return true;
}
bool CPlayer::SetCSteamID()
{
if (IsFakeClient())
{
m_SteamId = k_steamIDNil;
return true; /* This is the default value. There's a bug-out branch in the caller function. */
}
#if SOURCE_ENGINE < SE_ORANGEBOX
const char *pAuth = GetAuthString();
/* STEAM_0:1:123123 | STEAM_ID_LAN | STEAM_ID_PENDING */
if (pAuth && (strlen(pAuth) > 10) && pAuth[8] != '_')
{
CSteamID sid = CSteamID(atoi(&pAuth[8]) | (atoi(&pAuth[10]) << 1),
k_unSteamUserDesktopInstance, k_EUniversePublic, k_EAccountTypeIndividual);
if (m_SteamId != sid)
{
m_SteamId = sid;
return true;
}
}
#else
const CSteamID *steamId = engine->GetClientSteamID(m_pEdict);
if (steamId)
{
if (m_SteamId != (*steamId))
{
m_SteamId = (*steamId);
return true;
}
}
#endif
return false;
}
// Ensure a valid AuthString is set before calling.
void CPlayer::Authorize()
{
@ -2226,6 +2134,7 @@ void CPlayer::Disconnect()
m_Steam3Id = "";
m_pEdict = NULL;
m_Info = NULL;
m_pIClient = NULL;
m_bAdminCheckSignalled = false;
m_UserId = -1;
m_bIsInKickQueue = false;
@ -2240,7 +2149,30 @@ void CPlayer::Disconnect()
void CPlayer::SetName(const char *name)
{
m_Name.assign(name);
// Player names from Steam can get truncated in the engine, leaving
// a partial, invalid UTF-8 char at the end. Strip it off.
char szNewName[MAX_PLAYER_NAME_LENGTH];
ke::SafeStrcpy(szNewName, sizeof(szNewName), name);
size_t i = 0;
while (i < sizeof(szNewName))
{
if (szNewName[i] == 0)
break;
unsigned int cCharBytes = _GetUTF8CharBytes(&szNewName[i]);
size_t newPos = i + cCharBytes;
if (newPos > (sizeof(szNewName) - 1))
{
szNewName[i] = 0;
break;
}
i = newPos;
}
m_Name.assign(szNewName);
}
const char *CPlayer::GetName()
@ -2346,11 +2278,7 @@ bool CPlayer::IsAuthStringValidated()
#if SOURCE_ENGINE >= SE_ORANGEBOX
if (!IsFakeClient() && g_Players.m_bAuthstringValidation && !g_HL2.IsLANServer())
{
#if SOURCE_ENGINE == SE_DOTA
return engine->IsClientFullyAuthenticated(m_iIndex);
#else
return engine->IsClientFullyAuthenticated(m_pEdict);
#endif
}
#endif
@ -2421,10 +2349,9 @@ void CPlayer::DumpAdmin(bool deleting)
void CPlayer::Kick(const char *str)
{
MarkAsBeingKicked();
INetChannel *pNetChan = static_cast<INetChannel *>(engine->GetPlayerNetInfo(m_iIndex));
if (pNetChan == NULL)
IClient *pClient = GetIClient();
if (pClient == nullptr)
{
/* What does this even mean? Hell if I know. */
int userid = GetUserId();
if (userid > 0)
{
@ -2435,13 +2362,7 @@ void CPlayer::Kick(const char *str)
}
else
{
IClient *pClient = static_cast<IClient *>(pNetChan->GetMsgHandler());
#if SOURCE_ENGINE == SE_DOTA
// Including network_connection.pb.h (and .cpp) is overkill for just this. -p
// Copied from ENetworkDisconnectionReason enum
const int NETWORK_DISCONNECT_KICKED = 39;
pClient->Disconnect(NETWORK_DISCONNECT_KICKED);
#elif SOURCE_ENGINE == SE_CSGO
#if SOURCE_ENGINE == SE_CSGO
pClient->Disconnect(str);
#else
pClient->Disconnect("%s", str);
@ -2558,8 +2479,8 @@ void CPlayer::DoBasicAdminChecks()
{
if (!g_Players.CheckSetAdminName(client, this, id))
{
int userid = GetPlayerUserId(m_pEdict);
g_Timers.CreateTimer(&s_KickPlayerTimer, 0.1f, (void *)userid, 0);
int userid = engine->GetPlayerUserId(m_pEdict);
g_Timers.CreateTimer(&s_KickPlayerTimer, 0.1f, (void *)(intptr_t)userid, 0);
}
return;
}
@ -2597,7 +2518,7 @@ int CPlayer::GetUserId()
{
if (m_UserId == -1)
{
m_UserId = GetPlayerUserId(GetEdict());
m_UserId = engine->GetPlayerUserId(GetEdict());
}
return m_UserId;
@ -2655,6 +2576,11 @@ int CPlayer::GetLifeState()
}
}
IClient *CPlayer::GetIClient() const
{
return m_pIClient;
}
unsigned int CPlayer::GetSerial()
{
return m_Serial.value;
@ -2673,9 +2599,5 @@ void CPlayer::PrintToConsole(const char *pMsg)
return;
}
#if SOURCE_ENGINE == SE_DOTA
engine->ClientPrintf(m_iIndex, pMsg);
#else
engine->ClientPrintf(m_pEdict, pMsg);
#endif
}

View File

@ -38,6 +38,7 @@
#include <IForwardSys.h>
#include <IPlayerHelpers.h>
#include <IAdminSystem.h>
#include <ITranslator.h>
#include <sh_string.h>
#include <sh_list.h>
#include <sh_vector.h>
@ -48,6 +49,8 @@
using namespace SourceHook;
class IClient;
#define PLAYER_LIFE_UNKNOWN 0
#define PLAYER_LIFE_ALIVE 1
#define PLAYER_LIFE_DEAD 2
@ -104,6 +107,9 @@ public:
void DoBasicAdminChecks();
void MarkAsBeingKicked();
int GetLifeState();
// This can be NULL for fakeclients due to limitations in our impl
IClient *GetIClient() const;
private:
void Initialize(const char *name, const char *ip, edict_t *pEntity);
void Connect();
@ -115,33 +121,36 @@ private:
void Authorize_Post();
void DoPostConnectAuthorization();
bool IsAuthStringValidated();
bool SetEngineString();
bool SetCSteamID();
private:
bool m_IsConnected;
bool m_IsInGame;
bool m_IsAuthorized;
bool m_bIsInKickQueue;
bool m_IsConnected = false;
bool m_IsInGame = false;
bool m_IsAuthorized = false;
bool m_bIsInKickQueue = false;
String m_Name;
String m_Ip;
String m_IpNoPort;
ke::AString m_AuthID;
ke::AString m_Steam2Id;
ke::AString m_Steam3Id;
AdminId m_Admin;
bool m_TempAdmin;
edict_t *m_pEdict;
IPlayerInfo *m_Info;
AdminId m_Admin = INVALID_ADMIN_ID;
bool m_TempAdmin = false;
edict_t *m_pEdict = nullptr;
IPlayerInfo *m_Info = nullptr;
IClient *m_pIClient = nullptr;
String m_LastPassword;
bool m_bAdminCheckSignalled;
bool m_bAdminCheckSignalled = false;
int m_iIndex;
unsigned int m_LangId;
int m_UserId;
bool m_bFakeClient;
bool m_bIsSourceTV;
bool m_bIsReplay;
unsigned int m_LangId = SOURCEMOD_LANGUAGE_ENGLISH;
int m_UserId = -1;
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;
QueryCvarCookie_t m_LanguageCookie = InvalidQueryCvarCookie;
#endif
};
@ -164,16 +173,6 @@ public:
CPlayer *GetPlayerByIndex(int client) const;
void RunAuthChecks();
public:
#if SOURCE_ENGINE == SE_DOTA
bool OnClientConnect(CEntityIndex index, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen);
bool OnClientConnect_Post(CEntityIndex index, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen);
void OnClientPutInServer(CEntityIndex index, char const *playername);
void OnClientDisconnect(CEntityIndex index, int reason);
void OnClientDisconnect_Post(CEntityIndex index, int reason);
void OnClientCommand(CEntityIndex index, const CCommand &args);
void OnClientSettingsChanged(CEntityIndex index);
//void OnClientSettingsChanged_Pre(CEntityIndex client);
#else
bool OnClientConnect(edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen);
bool OnClientConnect_Post(edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen);
void OnClientPutInServer(edict_t *pEntity, char const *playername);
@ -181,7 +180,7 @@ public:
void OnClientDisconnect_Post(edict_t *pEntity);
#if SOURCE_ENGINE >= SE_ORANGEBOX
void OnClientCommand(edict_t *pEntity, const CCommand &args);
#if SOURCE_ENGINE >= SE_EYE && SOURCE_ENGINE != SE_DOTA
#if SOURCE_ENGINE >= SE_EYE
void OnClientCommandKeyValues(edict_t *pEntity, KeyValues *pCommand);
void OnClientCommandKeyValues_Post(edict_t *pEntity, KeyValues *pCommand);
#endif
@ -190,7 +189,6 @@ public:
#endif
void OnClientSettingsChanged(edict_t *pEntity);
//void OnClientSettingsChanged_Pre(edict_t *pEntity);
#endif
void OnServerHibernationUpdate(bool bHibernating);
public: //IPlayerManager
void AddClientListener(IClientListener *listener);
@ -236,11 +234,7 @@ public:
bool HandleConVarQuery(QueryCvarCookie_t cookie, int client, EQueryCvarValueStatus result, const char *cvarName, const char *cvarValue);
#endif
private:
#if SOURCE_ENGINE == SE_DOTA
void OnServerActivate();
#else
void OnServerActivate(edict_t *pEdictList, int edictCount, int clientMax);
#endif
void InvalidatePlayer(CPlayer *pPlayer);
private:
List<IClientListener *> m_hooks;
@ -275,9 +269,7 @@ private:
bool m_bInCCKVHook;
};
#if SOURCE_ENGINE == SE_DOTA
void CmdMaxplayersCallback(const CCommandContext &context, const CCommand &command);
#elif SOURCE_ENGINE >= SE_ORANGEBOX
#if SOURCE_ENGINE >= SE_ORANGEBOX
void CmdMaxplayersCallback(const CCommand &command);
#else
void CmdMaxplayersCallback();

View File

@ -118,6 +118,13 @@ public:
return msg;
}
inline bool HasField(const char *pszFieldName)
{
GETCHECK_FIELD();
CHECK_FIELD_NOT_REPEATED();
return msg->GetReflection()->HasField(*msg, field);
}
inline bool GetInt32(const char *pszFieldName, int32 *out)
{
GETCHECK_FIELD();

View File

@ -33,16 +33,14 @@
#include "sm_stringutil.h"
#include "logic_bridge.h"
#if SOURCE_ENGINE == SE_DOTA
#include <dota_usermessage_helpers.h>
#elif SOURCE_ENGINE == SE_CSGO
#if SOURCE_ENGINE == SE_CSGO
#include <cstrike15_usermessage_helpers.h>
#endif
#include <amtl/am-string.h>
UserMessages g_UserMsgs;
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
#if SOURCE_ENGINE == SE_CSGO
SH_DECL_HOOK3_void(IVEngineServer, SendUserMessage, SH_NOATTRIB, 0, IRecipientFilter &, int, const protobuf::Message &);
#else
#if SOURCE_ENGINE >= SE_LEFT4DEAD
@ -95,7 +93,7 @@ void UserMessages::OnSourceModAllShutdown()
{
if (m_HookCount)
{
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
#if SOURCE_ENGINE == SE_CSGO
SH_REMOVE_HOOK(IVEngineServer, SendUserMessage, engine, SH_MEMBER(this, &UserMessages::OnSendUserMessage_Pre), false);
SH_REMOVE_HOOK(IVEngineServer, SendUserMessage, engine, SH_MEMBER(this, &UserMessages::OnSendUserMessage_Post), true);
#else
@ -110,10 +108,7 @@ void UserMessages::OnSourceModAllShutdown()
int UserMessages::GetMessageIndex(const char *msg)
{
#if SOURCE_ENGINE == SE_DOTA
// Can split this per engine and/or game later
return g_DotaUsermessageHelpers.GetIndex(msg);
#elif SOURCE_ENGINE == SE_CSGO
#if SOURCE_ENGINE == SE_CSGO
// Can split this per engine and/or game later
return g_Cstrike15UsermessageHelpers.GetIndex(msg);
#else
@ -151,9 +146,7 @@ int UserMessages::GetMessageIndex(const char *msg)
bool UserMessages::GetMessageName(int msgid, char *buffer, size_t maxlength) const
{
#ifdef USE_PROTOBUF_USERMESSAGES
#if SOURCE_ENGINE == SE_DOTA
const char *pszName = g_DotaUsermessageHelpers.GetName(msgid);
#elif SOURCE_ENGINE == SE_CSGO
#if SOURCE_ENGINE == SE_CSGO
const char *pszName = g_Cstrike15UsermessageHelpers.GetName(msgid);
#endif
if (!pszName)
@ -304,7 +297,7 @@ bool UserMessages::EndMessage()
return false;
}
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
#if SOURCE_ENGINE == SE_CSGO
if (m_CurFlags & USERMSG_BLOCKHOOKS)
{
ENGINE_CALL(SendUserMessage)(static_cast<IRecipientFilter &>(m_CellRecFilter), m_CurId, *m_FakeEngineBuffer);
@ -334,7 +327,7 @@ bool UserMessages::EndMessage()
} else {
engine->MessageEnd();
}
#endif // SE_CSGO || SE_DOTA
#endif // SE_CSGO
m_InExec = false;
m_CurFlags = 0;
@ -419,7 +412,7 @@ bool UserMessages::InternalHook(int msg_id, IBitBufUserMessageListener *pListene
if (!m_HookCount++)
{
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
#if SOURCE_ENGINE == SE_CSGO
SH_ADD_HOOK(IVEngineServer, SendUserMessage, engine, SH_MEMBER(this, &UserMessages::OnSendUserMessage_Pre), false);
SH_ADD_HOOK(IVEngineServer, SendUserMessage, engine, SH_MEMBER(this, &UserMessages::OnSendUserMessage_Post), true);
#else
@ -443,9 +436,7 @@ bool UserMessages::InternalHook(int msg_id, IBitBufUserMessageListener *pListene
#ifdef USE_PROTOBUF_USERMESSAGES
const protobuf::Message *UserMessages::GetMessagePrototype(int msg_type)
{
#if SOURCE_ENGINE == SE_DOTA
return g_DotaUsermessageHelpers.GetPrototype(msg_type);
#elif SOURCE_ENGINE == SE_CSGO
#if SOURCE_ENGINE == SE_CSGO
return g_Cstrike15UsermessageHelpers.GetPrototype(msg_type);
#endif
}
@ -496,7 +487,7 @@ void UserMessages::_DecRefCounter()
{
if (--m_HookCount == 0)
{
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
#if SOURCE_ENGINE == SE_CSGO
SH_REMOVE_HOOK(IVEngineServer, SendUserMessage, engine, SH_MEMBER(this, &UserMessages::OnSendUserMessage_Pre), false);
SH_REMOVE_HOOK(IVEngineServer, SendUserMessage, engine, SH_MEMBER(this, &UserMessages::OnSendUserMessage_Post), true);
#else
@ -508,12 +499,10 @@ void UserMessages::_DecRefCounter()
}
}
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
#if SOURCE_ENGINE == SE_CSGO
void UserMessages::OnSendUserMessage_Pre(IRecipientFilter &filter, int msg_type, const protobuf::Message &msg)
{
#if SOURCE_ENGINE == SE_DOTA
OnStartMessage_Pre(&filter, msg_type, g_DotaUsermessageHelpers.GetName(msg_type));
#elif SOURCE_ENGINE == SE_CSGO
#if SOURCE_ENGINE == SE_CSGO
OnStartMessage_Pre(&filter, msg_type, g_Cstrike15UsermessageHelpers.GetName(msg_type));
#endif
if (m_FakeMetaRes == MRES_SUPERCEDE)
@ -528,9 +517,7 @@ void UserMessages::OnSendUserMessage_Pre(IRecipientFilter &filter, int msg_type,
m_FakeEngineBuffer = &const_cast<protobuf::Message &>(msg);
}
#if SOURCE_ENGINE == SE_DOTA
OnStartMessage_Post(&filter, msg_type, g_DotaUsermessageHelpers.GetName(msg_type));
#elif SOURCE_ENGINE == SE_CSGO
#if SOURCE_ENGINE == SE_CSGO
OnStartMessage_Post(&filter, msg_type, g_Cstrike15UsermessageHelpers.GetName(msg_type));
#endif
@ -564,7 +551,7 @@ void UserMessages::OnSendUserMessage_Post(IRecipientFilter &filter, int msg_type
RETURN_META(res)
#endif
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
#if SOURCE_ENGINE == SE_CSGO
protobuf::Message *UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_type, const char *msg_name)
#elif SOURCE_ENGINE >= SE_LEFT4DEAD
bf_write *UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_type, const char *msg_name)
@ -604,7 +591,7 @@ bf_write *UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_typ
UM_RETURN_META_VALUE(MRES_IGNORED, NULL);
}
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
#if SOURCE_ENGINE == SE_CSGO
protobuf::Message *UserMessages::OnStartMessage_Post(IRecipientFilter *filter, int msg_type, const char *msg_name)
#elif SOURCE_ENGINE >= SE_LEFT4DEAD
bf_write *UserMessages::OnStartMessage_Post(IRecipientFilter *filter, int msg_type, const char *msg_name)
@ -769,7 +756,7 @@ void UserMessages::OnMessageEnd_Pre()
if (!handled && intercepted)
{
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
#if SOURCE_ENGINE == SE_CSGO
ENGINE_CALL(SendUserMessage)(static_cast<IRecipientFilter &>(*m_CurRecFilter), m_CurId, *m_InterceptBuffer);
#else
bf_write *engine_bfw;
@ -781,11 +768,11 @@ void UserMessages::OnMessageEnd_Pre()
m_ReadBuffer.StartReading(m_InterceptBuffer.GetBasePointer(), m_InterceptBuffer.GetNumBytesWritten());
engine_bfw->WriteBitsFromBuffer(&m_ReadBuffer, m_InterceptBuffer.GetNumBitsWritten());
ENGINE_CALL(MessageEnd)();
#endif // SE_CSGO || SE_DOTA
#endif // SE_CSGO
}
{
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
#if SOURCE_ENGINE == SE_CSGO
int size = m_OrigBuffer->ByteSize();
uint8 *data = (uint8 *)stackalloc(size);
m_OrigBuffer->SerializePartialToArray(data, size);
@ -815,7 +802,7 @@ void UserMessages::OnMessageEnd_Pre()
iter++;
}
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
#if SOURCE_ENGINE == SE_CSGO
delete pTempMsg;
#endif
}

View File

@ -44,7 +44,7 @@
using namespace SourceHook;
using namespace SourceMod;
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
#if SOURCE_ENGINE == SE_CSGO
#define USE_PROTOBUF_USERMESSAGES
#endif
@ -102,12 +102,12 @@ public: //IUserMessages
bool intercept=false);
UserMessageType GetUserMessageType() const;
public:
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
#if SOURCE_ENGINE == SE_CSGO
void OnSendUserMessage_Pre(IRecipientFilter &filter, int msg_type, const protobuf::Message &msg);
void OnSendUserMessage_Post(IRecipientFilter &filter, int msg_type, const protobuf::Message &msg);
#endif
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
#if SOURCE_ENGINE == SE_CSGO
protobuf::Message *OnStartMessage_Pre(IRecipientFilter *filter, int msg_type, const char *msg_name);
protobuf::Message *OnStartMessage_Post(IRecipientFilter *filter, int msg_type, const char *msg_name);
#elif SOURCE_ENGINE >= SE_LEFT4DEAD

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -1,90 +1,98 @@
# vim: set sts=2 ts=8 sw=2 tw=99 et ft=python:
import os
binary = SM.Library(builder, 'sourcemod.logic')
binary.compiler.cxxincludes += [
builder.sourcePath,
os.path.join(builder.sourcePath, 'core', 'logic'),
os.path.join(builder.sourcePath, 'public'),
os.path.join(builder.sourcePath, 'sourcepawn', 'include'),
os.path.join(builder.sourcePath, 'public', 'amtl', 'amtl'),
os.path.join(builder.sourcePath, 'public', 'amtl'),
os.path.join(SM.mms_root, 'core', 'sourcehook')
]
binary.compiler.defines += [
'SM_DEFAULT_THREADER',
'SM_LOGIC'
]
for arch in SM.archs:
binary = SM.Library(builder, 'sourcemod.logic', arch)
binary.compiler.cxxincludes += [
builder.sourcePath,
os.path.join(builder.sourcePath, 'core', 'logic'),
os.path.join(builder.sourcePath, 'public'),
os.path.join(builder.sourcePath, 'sourcepawn', 'include'),
os.path.join(builder.sourcePath, 'public', 'amtl', 'amtl'),
os.path.join(builder.sourcePath, 'public', 'amtl'),
os.path.join(SM.mms_root, 'core', 'sourcehook')
]
binary.compiler.defines += [
'SM_DEFAULT_THREADER',
'SM_LOGIC'
]
if builder.target_platform == 'linux':
binary.compiler.postlink += ['-lpthread', '-lrt']
elif builder.target_platform == 'mac':
binary.compiler.cflags += ['-Wno-deprecated-declarations']
binary.compiler.postlink += ['-framework', 'CoreServices']
if builder.target.platform == 'linux':
binary.compiler.postlink += ['-lpthread', '-lrt']
elif builder.target.platform == 'mac':
binary.compiler.cflags += ['-Wno-deprecated-declarations']
binary.compiler.postlink += ['-framework', 'CoreServices']
if binary.compiler.vendor == 'gcc' or binary.compiler.vendor == 'clang':
binary.compiler.cxxflags += ['-fno-rtti']
elif binary.compiler.vendor == 'msvc':
binary.compiler.cxxflags += ['/GR-']
if binary.compiler.family == 'gcc' or binary.compiler.family == 'clang':
binary.compiler.cxxflags += ['-fno-rtti']
elif binary.compiler.family == 'msvc':
binary.compiler.cxxflags += ['/GR-']
binary.sources += [
'common_logic.cpp',
'smn_adt_array.cpp',
'smn_sorting.cpp',
'smn_maplists.cpp',
'ADTFactory.cpp',
'smn_adt_stack.cpp',
'thread/ThreadWorker.cpp',
'thread/BaseWorker.cpp',
'ThreadSupport.cpp',
'smn_float.cpp',
'TextParsers.cpp',
'smn_textparse.cpp',
'smn_adt_trie.cpp',
'smn_functions.cpp',
'smn_timers.cpp',
'smn_players.cpp',
'MemoryUtils.cpp',
'smn_admin.cpp',
'smn_banning.cpp',
'smn_filesystem.cpp',
'stringutil.cpp',
'Translator.cpp',
'PhraseCollection.cpp',
'smn_lang.cpp',
'smn_string.cpp',
'smn_handles.cpp',
'smn_datapacks.cpp',
'smn_gameconfigs.cpp',
'smn_fakenatives.cpp',
'GameConfigs.cpp',
'sm_crc32.cpp',
'smn_profiler.cpp',
'ShareSys.cpp',
'PluginSys.cpp',
'HandleSys.cpp',
'NativeOwner.cpp',
'ExtensionSys.cpp',
'DebugReporter.cpp',
'Database.cpp',
'smn_database.cpp',
'ForwardSys.cpp',
'AdminCache.cpp',
'sm_trie.cpp',
'smn_console.cpp',
'ProfileTools.cpp',
'Logger.cpp',
'smn_core.cpp',
'smn_menus.cpp',
'sprintf.cpp',
'LibrarySys.cpp',
'RootConsoleMenu.cpp',
'CDataPack.cpp',
'frame_tasks.cpp',
]
if builder.target_platform == 'windows':
binary.sources += ['thread/WinThreads.cpp']
else:
binary.sources += ['thread/PosixThreads.cpp']
binary.sources += [
'common_logic.cpp',
'smn_adt_array.cpp',
'smn_sorting.cpp',
'smn_maplists.cpp',
'ADTFactory.cpp',
'smn_adt_stack.cpp',
'thread/ThreadWorker.cpp',
'thread/BaseWorker.cpp',
'ThreadSupport.cpp',
'smn_float.cpp',
'TextParsers.cpp',
'smn_textparse.cpp',
'smn_adt_trie.cpp',
'smn_functions.cpp',
'smn_timers.cpp',
'smn_players.cpp',
'MemoryUtils.cpp',
'smn_admin.cpp',
'smn_banning.cpp',
'smn_filesystem.cpp',
'stringutil.cpp',
'Translator.cpp',
'PhraseCollection.cpp',
'smn_lang.cpp',
'smn_string.cpp',
'smn_handles.cpp',
'smn_datapacks.cpp',
'smn_gameconfigs.cpp',
'smn_fakenatives.cpp',
'GameConfigs.cpp',
'sm_crc32.cpp',
'smn_profiler.cpp',
'ShareSys.cpp',
'PluginSys.cpp',
'HandleSys.cpp',
'NativeOwner.cpp',
'ExtensionSys.cpp',
'DebugReporter.cpp',
'Database.cpp',
'smn_database.cpp',
'ForwardSys.cpp',
'AdminCache.cpp',
'sm_trie.cpp',
'smn_console.cpp',
'ProfileTools.cpp',
'Logger.cpp',
'smn_core.cpp',
'smn_menus.cpp',
'sprintf.cpp',
'LibrarySys.cpp',
'RootConsoleMenu.cpp',
'CDataPack.cpp',
'frame_tasks.cpp',
'smn_halflife.cpp',
'FrameIterator.cpp',
'DatabaseConfBuilder.cpp',
]
SM.binaries += [builder.Add(binary)]
if arch == 'x64':
binary.sources += ['PseudoAddrManager.cpp']
if builder.target.platform == 'windows':
binary.sources += ['thread/WinThreads.cpp']
else:
binary.sources += ['thread/PosixThreads.cpp']
SM.binaries += [builder.Add(binary)]

View File

@ -1090,14 +1090,14 @@ bool AdminCache::GetUnifiedSteamIdentity(const char *ident, char *out, size_t ma
else if (len >= 11 && !strncmp(ident, "STEAM_", 6) && ident[8] != '_')
{
// non-bot/lan Steam2 Id, strip off the STEAM_* part
snprintf(out, maxlen, "%s", &ident[8]);
ke::SafeStrcpy(out, maxlen, &ident[8]);
return true;
}
else if (len >= 7 && !strncmp(ident, "[U:", 3) && ident[len-1] == ']')
{
// Steam3 Id, replicate the Steam2 Post-"STEAM_" part
uint32_t accountId = strtoul(&ident[5], nullptr, 10);
snprintf(out, maxlen, "%u:%u", accountId & 1, accountId >> 1);
ke::SafeSprintf(out, maxlen, "%u:%u", accountId & 1, accountId >> 1);
return true;
}
else
@ -1124,7 +1124,7 @@ bool AdminCache::GetUnifiedSteamIdentity(const char *ident, char *out, size_t ma
&& accountType == k_EAccountTypeIndividual && accountInstance <= k_unSteamUserWebInstance
)
{
snprintf(out, maxlen, "%u:%u", accountId & 1, accountId >> 1);
ke::SafeSprintf(out, maxlen, "%u:%u", accountId & 1, accountId >> 1);
return true;
}
}

View File

@ -82,6 +82,10 @@ struct AuthMethod
{
return strcmp(name, method->name.c_str()) == 0;
}
static inline uint32_t hash(const detail::CharsAndLength &key)
{
return key.hash();
}
};
struct UserAuth

View File

@ -32,28 +32,21 @@
#include <stdlib.h>
#include <string.h>
#include "CDataPack.h"
#include <am-utility.h>
#include <am-vector.h>
using namespace ke;
#define DATAPACK_INITIAL_SIZE 64
#include <amtl/am-autoptr.h>
CDataPack::CDataPack()
{
m_pBase = (char *)malloc(DATAPACK_INITIAL_SIZE);
m_capacity = DATAPACK_INITIAL_SIZE;
Initialize();
}
CDataPack::~CDataPack()
{
free(m_pBase);
Initialize();
}
static Vector<AutoPtr<CDataPack>> sDataPackCache;
static ke::Vector<ke::AutoPtr<CDataPack>> sDataPackCache;
IDataPack * CDataPack::New()
CDataPack *CDataPack::New()
{
if (sDataPackCache.empty())
return new CDataPack();
@ -65,293 +58,187 @@ IDataPack * CDataPack::New()
}
void
CDataPack::Free(IDataPack *pack)
CDataPack::Free(CDataPack *pack)
{
sDataPackCache.append(static_cast<CDataPack *>(pack));
}
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;
} while (pos + typesize > m_capacity);
m_pBase = (char *)realloc(m_pBase, m_capacity);
m_curptr = m_pBase + pos;
} while (this->RemoveItem());
elements.clear();
position = 0;
}
void CDataPack::ResetSize()
{
m_size = 0;
Initialize();
}
size_t CDataPack::CreateMemory(size_t size, void **addr)
{
CheckSize(sizeof(char) + sizeof(size_t) + size);
size_t pos = m_curptr - m_pBase;
InternalPack val;
val.type = CDataPackType::Raw;
val.pData.vval = new uint8_t[size + sizeof(size)];
reinterpret_cast<size_t *>(val.pData.vval)[0] = size;
elements.insert(position, val);
*(char *)m_curptr = Raw;
m_curptr += sizeof(char);
*(size_t *)m_curptr = size;
m_curptr += sizeof(size_t);
if (addr)
{
*addr = m_curptr;
}
m_curptr += size;
m_size += sizeof(char) + sizeof(size_t) + size;
return pos;
return position++;
}
void CDataPack::PackCell(cell_t cell)
{
CheckSize(sizeof(char) + sizeof(size_t) + sizeof(cell_t));
*(char *)m_curptr = Cell;
m_curptr += sizeof(char);
*(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(char) + sizeof(size_t) + sizeof(cell_t);
InternalPack val;
val.type = CDataPackType::Cell;
val.pData.cval = cell;
elements.insert(position++, val);
}
void CDataPack::PackFloat(float val)
void CDataPack::PackFunction(cell_t function)
{
CheckSize(sizeof(char) + sizeof(size_t) + sizeof(float));
InternalPack val;
val.type = CDataPackType::Function;
val.pData.cval = function;
elements.insert(position++, val);
}
*(char *)m_curptr = Float;
m_curptr += sizeof(char);
*(size_t *)m_curptr = sizeof(float);
m_curptr += sizeof(size_t);
*(float *)m_curptr = val;
m_curptr += sizeof(float);
m_size += sizeof(char) + sizeof(size_t) + sizeof(float);
void CDataPack::PackFloat(float floatval)
{
InternalPack val;
val.type = CDataPackType::Float;
val.pData.fval = floatval;
elements.insert(position++, val);
}
void CDataPack::PackString(const char *string)
{
size_t len = strlen(string);
size_t maxsize = sizeof(char) + sizeof(size_t) + len + 1;
CheckSize(maxsize);
*(char *)m_curptr = String;
m_curptr += sizeof(char);
// Pack the string length first for buffer overrun checking.
*(size_t *)m_curptr = len;
m_curptr += sizeof(size_t);
// Now pack the string.
memcpy(m_curptr, string, len);
m_curptr[len] = '\0';
m_curptr += len + 1;
m_size += maxsize;
InternalPack val;
val.type = CDataPackType::String;
ke::AString *sval = new ke::AString(string);
val.pData.sval = sval;
elements.insert(position++, val);
}
void CDataPack::Reset() const
{
m_curptr = m_pBase;
position = 0;
}
size_t CDataPack::GetPosition() const
{
return static_cast<size_t>(m_curptr - m_pBase);
return position;
}
bool CDataPack::SetPosition(size_t pos) const
{
if (pos > m_size-1)
{
if (pos > elements.length())
return false;
}
m_curptr = m_pBase + pos;
position = pos;
return true;
}
cell_t CDataPack::ReadCell() const
{
if (!IsReadable(sizeof(char) + sizeof(size_t) + sizeof(cell_t)))
{
if (!IsReadable() || elements[position].type != CDataPackType::Cell)
return 0;
}
if (*reinterpret_cast<char *>(m_curptr) != Cell)
{
return 0;
}
m_curptr += sizeof(char);
if (*reinterpret_cast<size_t *>(m_curptr) != sizeof(cell_t))
{
return 0;
}
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(char) + sizeof(size_t) + sizeof(float)))
{
return 0;
}
if (*reinterpret_cast<char *>(m_curptr) != Float)
{
return 0;
}
m_curptr += sizeof(char);
if (*reinterpret_cast<size_t *>(m_curptr) != sizeof(float))
{
return 0;
}
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(char) + sizeof(size_t)))
{
return NULL;
}
if (*reinterpret_cast<char *>(m_curptr) != String)
{
return NULL;
}
m_curptr += sizeof(char);
size_t real_len = *(size_t *)m_curptr;
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;
}
if (*reinterpret_cast<char *>(m_curptr) != Raw)
{
return NULL;
}
m_curptr += sizeof(char);
size_t bytecount = *(size_t *)m_curptr;
m_curptr += sizeof(size_t);
if (!IsReadable(bytecount))
{
return NULL;
}
void *ptr = m_curptr;
if (size)
{
*size = bytecount;
}
m_curptr += bytecount;
return ptr;
}
void CDataPack::PackFunction(cell_t function)
{
CheckSize(sizeof(char) + sizeof(size_t) + sizeof(cell_t));
*(char *)m_curptr = Function;
m_curptr += sizeof(char);
*(size_t *)m_curptr = sizeof(cell_t);
m_curptr += sizeof(size_t);
*(cell_t *)m_curptr = function;
m_curptr += sizeof(cell_t);
m_size += sizeof(char) + sizeof(size_t) + sizeof(cell_t);
return elements[position++].pData.cval;
}
cell_t CDataPack::ReadFunction() const
{
if (!IsReadable(sizeof(char) + sizeof(size_t) + sizeof(cell_t)))
{
if (!IsReadable() || elements[position].type != CDataPackType::Function)
return 0;
}
if (*reinterpret_cast<char *>(m_curptr) != Function)
{
return 0;
}
m_curptr += sizeof(char);
if (*reinterpret_cast<size_t *>(m_curptr) != sizeof(cell_t))
{
return 0;
}
m_curptr += sizeof(size_t);
cell_t val = *reinterpret_cast<cell_t *>(m_curptr);
m_curptr += sizeof(cell_t);
return val;
return elements[position++].pData.cval;
}
float CDataPack::ReadFloat() const
{
if (!IsReadable() || elements[position].type != CDataPackType::Float)
return 0;
return elements[position++].pData.fval;
}
bool CDataPack::IsReadable(size_t bytes) const
{
return (position < elements.length());
}
const char *CDataPack::ReadString(size_t *len) const
{
if (!IsReadable() || elements[position].type != CDataPackType::String)
{
if (len)
*len = 0;
return nullptr;
}
const ke::AString &val = *elements[position++].pData.sval;
if (len)
*len = val.length();
return val.chars();
}
void *CDataPack::ReadMemory(size_t *size) const
{
void *ptr = nullptr;
if (!IsReadable() || elements[position].type != CDataPackType::Raw)
return ptr;
size_t *val = reinterpret_cast<size_t *>(elements[position].pData.vval);
ptr = &(val[1]);
++position;
if (size)
*size = val[0]; /* Egor!!!! */
return ptr;
}
bool CDataPack::RemoveItem(size_t pos)
{
if (!elements.length())
{
return false;
}
if (pos == static_cast<size_t>(-1))
{
pos = position;
}
if (pos >= elements.length())
{
return false;
}
if (pos < position) // we're deleting under us, step back
{
--position;
}
switch (elements[pos].type)
{
case CDataPackType::Raw:
{
delete elements[pos].pData.vval;
break;
}
case CDataPackType::String:
{
delete elements[pos].pData.sval;
break;
}
}
elements.remove(pos);
return true;
}

View File

@ -32,54 +32,165 @@
#ifndef _INCLUDE_SOURCEMOD_CDATAPACK_H_
#define _INCLUDE_SOURCEMOD_CDATAPACK_H_
#include <IDataPack.h>
#include <ISourceMod.h>
#include <amtl/am-vector.h>
#include <amtl/am-string.h>
using namespace SourceMod;
class CDataPack : public IDataPack
enum CDataPackType {
Raw,
Cell,
Float,
String,
Function
};
class CDataPack
{
public:
CDataPack();
~CDataPack();
static IDataPack *New();
static void Free(IDataPack *pack);
public: //IDataReader
static CDataPack *New();
static void Free(CDataPack *pack);
public: // Originally IDataReader
/**
* @brief Resets the position in the data stream to the beginning.
*/
void Reset() const;
/**
* @brief Retrieves the current stream position.
*
* @return Index into the stream.
*/
size_t GetPosition() const;
/**
* @brief Sets the current stream position.
*
* @param pos Index to set the stream at.
* @return True if succeeded, false if out of bounds.
*/
bool SetPosition(size_t pos) const;
/**
* @brief Reads one cell from the data stream.
*
* @return A cell read from the current position.
*/
cell_t ReadCell() const;
/**
* @brief Reads one float from the data stream.
*
* @return A float read from the current position.
*/
float ReadFloat() const;
bool IsReadable(size_t bytes) const;
/**
* @brief Returns whether or not a specified number of bytes from the current stream
* position to the end can be read.
*
* @param bytes Number of bytes to simulate reading.
* @return True if can be read, false otherwise.
*/
bool IsReadable(size_t bytes = 0) const;
/**
* @brief Reads a string from the data stream.
*
* @param len Optional pointer to store the string length.
* @return Pointer to the string, or NULL if out of bounds.
*/
const char *ReadString(size_t *len) const;
void *GetMemory() const;
/**
* @brief Reads the current position as a generic data type.
*
* @param size Optional pointer to store the size of the data type.
* @return Pointer to the data, or NULL if out of bounds.
*/
void *ReadMemory(size_t *size) const;
/**
* @brief Reads a function pointer from the data stream.
*
* @return A function pointer read from the current position.
*/
cell_t ReadFunction() const;
public: //IDataPack
public: // Originally IDataPack
/**
* @brief Resets the used size of the stream back to zero.
*/
void ResetSize();
/**
* @brief Packs one cell into the data stream.
*
* @param cell Cell value to write.
*/
void PackCell(cell_t cell);
/**
* @brief Packs one float into the data stream.
*
* @param val Float value to write.
*/
void PackFloat(float val);
/**
* @brief Packs one string into the data stream.
* The length is recorded as well for buffer overrun protection.
*
* @param string String to write.
*/
void PackString(const char *string);
/**
* @brief Creates a generic block of memory in the stream.
*
* Note that the pointer it returns can be invalidated on further
* writing, since the stream size may grow. You may need to double back
* and fetch the pointer again.
*
* @param size Size of the memory to create in the stream.
* @param addr Optional pointer to store the relocated memory address.
* @return Current position of the stream beforehand.
*/
size_t CreateMemory(size_t size, void **addr);
/**
* @brief Packs one function pointer into the data stream.
*
* @param function The function pointer to write.
*/
void PackFunction(cell_t function);
public:
void Initialize();
inline size_t GetCapacity() const { return m_capacity; }
private:
void CheckSize(size_t sizetype);
private:
char *m_pBase;
mutable char *m_curptr;
size_t m_capacity;
size_t m_size;
inline size_t GetCapacity() const { return this->elements.length(); };
inline CDataPackType GetCurrentType(void) const { return this->elements[this->position].type; };
bool RemoveItem(size_t pos = -1);
enum DataPackType {
Raw,
Cell,
Float,
String,
Function
};
private:
typedef union {
cell_t cval;
float fval;
uint8_t *vval;
ke::AString *sval;
} InternalPackValue;
typedef struct {
InternalPackValue pData;
CDataPackType type;
} InternalPack;
ke::Vector<InternalPack> elements;
mutable size_t position;
};
#endif //_INCLUDE_SOURCEMOD_CDATAPACK_H_

View File

@ -34,10 +34,11 @@
#include <stdlib.h>
#include <string.h>
#include <ICellArray.h>
extern HandleType_t htCellArray;
class CellArray
class CellArray : public ICellArray
{
public:
CellArray(size_t blocksize) : m_Data(NULL), m_BlockSize(blocksize), m_AllocSize(0), m_Size(0)
@ -49,6 +50,31 @@ public:
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
{
return m_Size;
@ -154,12 +180,18 @@ public:
return true;
}
CellArray *clone()
ICellArray *clone()
{
CellArray *array = new CellArray(m_BlockSize);
array->m_AllocSize = m_AllocSize;
array->m_Size = m_Size;
array->m_Data = (cell_t *)malloc(sizeof(cell_t) * m_BlockSize * m_AllocSize);
if (!array->m_Data)
{
delete array;
return NULL;
}
memcpy(array->m_Data, m_Data, sizeof(cell_t) * m_BlockSize * m_Size);
return array;
}

View File

@ -47,8 +47,6 @@ static bool s_OneTimeThreaderErrorMsg = false;
DBManager::DBManager()
: m_Terminate(false),
m_ParseLevel(0),
m_ParseState(0),
m_pDefault(NULL)
{
}
@ -72,7 +70,8 @@ void DBManager::OnSourceModAllInitialized()
g_ShareSys.AddInterface(NULL, this);
g_pSM->BuildPath(Path_SM, m_Filename, sizeof(m_Filename), "configs/databases.cfg");
m_Builder.SetPath(m_Filename);
g_PluginSys.AddPluginsListener(this);
g_pSM->AddGameFrameHook(&FrameHook);
@ -80,23 +79,7 @@ void DBManager::OnSourceModAllInitialized()
void DBManager::OnSourceModLevelChange(const char *mapName)
{
SMCError err;
SMCStates states = {0, 0};
/* We lock and don't give up the lock until we're done.
* This way the thread's search won't be searching through a
* potentially empty/corrupt list, which would be very bad.
*/
ke::AutoLock lock(&m_ConfigLock);
if ((err = textparsers->ParseFile_SMC(m_Filename, this, &states)) != SMCError_Okay)
{
logger->LogError("[SM] Detected parse error(s) in file \"%s\"", m_Filename);
if (err != SMCError_Custom)
{
const char *txt = textparsers->GetSMCErrorString(err);
logger->LogError("[SM] Line %d: %s", states.line, txt);
}
}
m_Builder.StartParse();
}
void DBManager::OnSourceModShutdown()
@ -106,7 +89,6 @@ void DBManager::OnSourceModShutdown()
g_PluginSys.RemovePluginsListener(this);
g_HandleSys.RemoveType(m_DatabaseType, g_pCoreIdent);
g_HandleSys.RemoveType(m_DriverType, g_pCoreIdent);
ClearConfigs();
}
unsigned int DBManager::GetInterfaceVersion()
@ -134,136 +116,10 @@ void DBManager::OnHandleDestroy(HandleType_t type, void *object)
}
}
void DBManager::ReadSMC_ParseStart()
{
ClearConfigs();
m_ParseLevel = 0;
m_ParseState = DBPARSE_LEVEL_NONE;
m_DefDriver.clear();
}
void DBManager::ClearConfigs()
{
List<ConfDbInfo *>::iterator iter;
for (iter=m_confs.begin(); iter!=m_confs.end(); iter++)
delete (*iter);
m_confs.clear();
}
ConfDbInfo s_CurInfo;
SMCResult DBManager::ReadSMC_NewSection(const SMCStates *states, const char *name)
{
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 = 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 = value;
}
} else if (strcmp(key, "database") == 0) {
s_CurInfo.database = value;
} else if (strcmp(key, "host") == 0) {
s_CurInfo.host = value;
} else if (strcmp(key, "user") == 0) {
s_CurInfo.user = value;
} else if (strcmp(key, "pass") == 0) {
s_CurInfo.pass = 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;
}
SMCResult DBManager::ReadSMC_LeavingSection(const SMCStates *states)
{
if (m_ParseLevel)
{
m_ParseLevel--;
return SMCResult_Continue;
}
if (m_ParseState == DBPARSE_LEVEL_DATABASE)
{
ConfDbInfo *cdb = new ConfDbInfo();
cdb->name = s_CurInfo.name;
cdb->driver = s_CurInfo.driver;
cdb->host = s_CurInfo.host;
cdb->user = s_CurInfo.user;
cdb->pass = s_CurInfo.pass;
cdb->database = s_CurInfo.database;
cdb->realDriver = s_CurInfo.realDriver;
cdb->info.maxTimeout = s_CurInfo.info.maxTimeout;
cdb->info.port = s_CurInfo.info.port;
cdb->info.driver = cdb->driver.c_str();
cdb->info.database = cdb->database.c_str();
cdb->info.host = cdb->host.c_str();
cdb->info.user = cdb->user.c_str();
cdb->info.pass = cdb->pass.c_str();
/* Save it.. */
m_confs.push_back(cdb);
/* 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;
}
void DBManager::ReadSMC_ParseEnd(bool halted, bool failed)
{
}
bool DBManager::Connect(const char *name, IDBDriver **pdr, IDatabase **pdb, bool persistent, char *error, size_t maxlength)
{
ConfDbInfo *pInfo = GetDatabaseConf(name);
ConfDbInfoList *list = m_Builder.GetConfigList();
ke::RefPtr<ConfDbInfo> pInfo = list->GetDatabaseConf(name);
if (!pInfo)
{
@ -282,11 +138,12 @@ bool DBManager::Connect(const char *name, IDBDriver **pdr, IDatabase **pdb, bool
/* Try to assign a real driver pointer */
if (pInfo->info.driver[0] == '\0')
{
if (!m_pDefault && m_DefDriver.size() > 0)
ke::AString defaultDriver = list->GetDefaultDriver();
if (!m_pDefault && defaultDriver.length() > 0)
{
m_pDefault = FindOrLoadDriver(m_DefDriver.c_str());
m_pDefault = FindOrLoadDriver(defaultDriver.chars());
}
dname = m_DefDriver.size() ? m_DefDriver.c_str() : "default";
dname = defaultDriver.length() ? defaultDriver.chars() : "default";
pInfo->realDriver = m_pDefault;
} else {
pInfo->realDriver = FindOrLoadDriver(pInfo->info.driver);
@ -310,7 +167,6 @@ bool DBManager::Connect(const char *name, IDBDriver **pdr, IDatabase **pdb, bool
*pdb = NULL;
g_pSM->Format(error, maxlength, "Driver \"%s\" not found", dname);
return false;
}
@ -323,7 +179,7 @@ void DBManager::AddDriver(IDBDriver *pDriver)
*/
KillWorkerThread();
m_drivers.push_back(pDriver);
m_drivers.push_back(pDriver);
}
void DBManager::RemoveDriver(IDBDriver *pDriver)
@ -343,17 +199,17 @@ void DBManager::RemoveDriver(IDBDriver *pDriver)
}
}
/* Make sure NOTHING references this! */
List<ConfDbInfo *>::iterator iter;
for (iter=m_confs.begin(); iter!=m_confs.end(); iter++)
ConfDbInfoList *list = m_Builder.GetConfigList();
for (size_t i = 0; i < list->length(); i++)
{
ConfDbInfo &db = *(*iter);
if (db.realDriver == pDriver)
ke::RefPtr<ConfDbInfo> current = list->at(i);
if (current->realDriver == pDriver)
{
db.realDriver = NULL;
current->realDriver = NULL;
}
}
/* Someone unloaded the default driver? Silly.. */
if (pDriver == m_pDefault)
{
@ -389,9 +245,11 @@ void DBManager::RemoveDriver(IDBDriver *pDriver)
IDBDriver *DBManager::GetDefaultDriver()
{
if (!m_pDefault && m_DefDriver.size() > 0)
ConfDbInfoList *list = m_Builder.GetConfigList();
ke::AString defaultDriver = list->GetDefaultDriver();
if (!m_pDefault && defaultDriver.length() > 0)
{
m_pDefault = FindOrLoadDriver(m_DefDriver.c_str());
m_pDefault = FindOrLoadDriver(defaultDriver.chars());
}
return m_pDefault;
@ -454,10 +312,16 @@ IDBDriver *DBManager::GetDriver(unsigned int index)
const DatabaseInfo *DBManager::FindDatabaseConf(const char *name)
{
ConfDbInfo *info = GetDatabaseConf(name);
ConfDbInfoList *list = m_Builder.GetConfigList();
ke::RefPtr<ConfDbInfo> info = list->GetDatabaseConf(name);
if (!info)
{
return NULL;
// couldn't find requested conf, return default if exists
info = list->GetDefaultConfiguration();
if (!info)
{
return NULL;
}
}
return &info->info;
@ -465,18 +329,9 @@ const DatabaseInfo *DBManager::FindDatabaseConf(const char *name)
ConfDbInfo *DBManager::GetDatabaseConf(const char *name)
{
List<ConfDbInfo *>::iterator iter;
for (iter=m_confs.begin(); iter!=m_confs.end(); iter++)
{
ConfDbInfo &conf = *(*iter);
if (conf.name == name)
{
return &conf;
}
}
return NULL;
ConfDbInfoList *list = m_Builder.GetConfigList();
ke::RefPtr<ConfDbInfo> info(list->GetDatabaseConf(name));
return info;
}
IDBDriver *DBManager::FindOrLoadDriver(const char *name)
@ -520,7 +375,7 @@ void DBManager::KillWorkerThread()
m_QueueEvent.Notify();
}
m_Worker->Join();
m_Worker = NULL;
m_Worker = nullptr;
s_OneTimeThreaderErrorMsg = false;
m_Terminate = false;
}
@ -537,7 +392,9 @@ bool DBManager::AddToThreadQueue(IDBThreadOperation *op, PrioQueueLevel prio)
if (!m_Worker)
{
m_Worker = new ke::Thread(this, "SM SQL Worker");
m_Worker = new ke::Thread([this]() -> void {
Run();
}, "SM SQL Worker");
if (!m_Worker->Succeeded())
{
if (!s_OneTimeThreaderErrorMsg)
@ -545,7 +402,7 @@ bool DBManager::AddToThreadQueue(IDBThreadOperation *op, PrioQueueLevel prio)
logger->LogError("[SM] Unable to create db threader (error unknown)");
s_OneTimeThreaderErrorMsg = true;
}
m_Worker = NULL;
m_Worker = nullptr;
return false;
}
}
@ -727,19 +584,10 @@ void DBManager::OnPluginWillUnload(IPlugin *plugin)
}
}
void DBManager::LockConfig()
ke::AString DBManager::GetDefaultDriverName()
{
m_ConfigLock.Lock();
}
void DBManager::UnlockConfig()
{
m_ConfigLock.Unlock();
}
const char *DBManager::GetDefaultDriverName()
{
return m_DefDriver.c_str();
ConfDbInfoList *list = m_Builder.GetConfigList();
return list->GetDefaultDriver();
}
void DBManager::AddDependency(IExtension *myself, IDBDriver *driver)

View File

@ -32,41 +32,25 @@
#ifndef _INCLUDE_DATABASE_MANAGER_H_
#define _INCLUDE_DATABASE_MANAGER_H_
#include <IDBDriver.h>
#include "common_logic.h"
#include <sh_vector.h>
#include <sh_string.h>
#include <am-string.h>
#include <sh_list.h>
#include <ITextParsers.h>
#include <IThreader.h>
#include <IPluginSys.h>
#include <am-thread-utils.h>
#include "sm_simple_prioqueue.h"
#include <am-refcounting.h>
#include "DatabaseConfBuilder.h"
using namespace SourceHook;
struct ConfDbInfo
{
ConfDbInfo() : realDriver(NULL)
{
}
String name;
String driver;
String host;
String user;
String pass;
String database;
IDBDriver *realDriver;
DatabaseInfo info;
};
class DBManager :
public IDBManager,
public SMGlobalClass,
public IHandleTypeDispatch,
public ITextListener_SMC,
public IPluginsListener,
public ke::IRunnable
public IPluginsListener
{
public:
DBManager();
@ -84,6 +68,7 @@ public: //IDBManager
void AddDriver(IDBDriver *pDrivera);
void RemoveDriver(IDBDriver *pDriver);
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);
unsigned int GetDriverCount();
IDBDriver *GetDriver(unsigned int index);
@ -91,25 +76,16 @@ public: //IDBManager
HandleError ReadHandle(Handle_t hndl, DBHandleType type, void **ptr);
HandleError ReleaseHandle(Handle_t hndl, DBHandleType type, IdentityToken_t *token);
void AddDependency(IExtension *myself, IDBDriver *driver);
public: //ITextListener_SMC
void ReadSMC_ParseStart();
SMCResult ReadSMC_NewSection(const SMCStates *states, const char *name);
SMCResult ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value);
SMCResult ReadSMC_LeavingSection(const SMCStates *states);
void ReadSMC_ParseEnd(bool halted, bool failed);
public: //ke::IRunnable
void Run();
void ThreadMain();
public: //IPluginsListener
void OnPluginWillUnload(IPlugin *plugin);
public:
ConfDbInfo *GetDatabaseConf(const char *name);
IDBDriver *FindOrLoadDriver(const char *name);
IDBDriver *GetDefaultDriver();
const char *GetDefaultDriverName();
ke::AString GetDefaultDriverName();
bool AddToThreadQueue(IDBThreadOperation *op, PrioQueueLevel prio);
void LockConfig();
void UnlockConfig();
void RunFrame();
inline HandleType_t GetDatabaseType()
{
@ -127,17 +103,13 @@ private:
CVector<bool> m_drSafety; /* which drivers are safe? */
ke::AutoPtr<ke::Thread> m_Worker;
ke::ConditionVariable m_QueueEvent;
ke::Mutex m_ConfigLock;
ke::Mutex m_ThinkLock;
bool m_Terminate;
List<ConfDbInfo *> m_confs;
DatabaseConfBuilder m_Builder;
HandleType_t m_DriverType;
HandleType_t m_DatabaseType;
String m_DefDriver;
char m_Filename[PLATFORM_MAX_PATH];
unsigned int m_ParseLevel;
unsigned int m_ParseState;
IDBDriver *m_pDefault;
};

View File

@ -0,0 +1,184 @@
/**
* vim: set ts=4 sw=4 tw=99 noet :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2018 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 "DatabaseConfBuilder.h"
#include <bridge/include/ILogger.h>
#define DBPARSE_LEVEL_NONE 0
#define DBPARSE_LEVEL_MAIN 1
#define DBPARSE_LEVEL_DATABASE 2
DatabaseConfBuilder::DatabaseConfBuilder()
: m_ParseList(nullptr),
m_InfoList(new ConfDbInfoList())
{
}
void DatabaseConfBuilder::SetPath(char *str)
{
m_Filename = str;
}
DatabaseConfBuilder::~DatabaseConfBuilder()
{
}
ConfDbInfoList *DatabaseConfBuilder::GetConfigList()
{
return m_InfoList;
}
void DatabaseConfBuilder::StartParse()
{
SMCError err;
SMCStates states = {0, 0};
if ((err = textparsers->ParseFile_SMC(m_Filename.chars(), this, &states)) != SMCError_Okay)
{
logger->LogError("[SM] Detected parse error(s) in file \"%s\"", m_Filename.chars());
if (err != SMCError_Custom)
{
const char *txt = textparsers->GetSMCErrorString(err);
logger->LogError("[SM] Line %d: %s", states.line, txt);
}
}
}
void DatabaseConfBuilder::ReadSMC_ParseStart()
{
m_ParseLevel = 0;
m_ParseState = DBPARSE_LEVEL_NONE;
m_ParseList = new ConfDbInfoList();
}
SMCResult DatabaseConfBuilder::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) {
m_ParseCurrent = new ConfDbInfo();
m_ParseCurrent->name = name;
m_ParseState = DBPARSE_LEVEL_DATABASE;
} else if (m_ParseState == DBPARSE_LEVEL_DATABASE) {
m_ParseLevel++;
}
return SMCResult_Continue;
}
SMCResult DatabaseConfBuilder::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_ParseList->SetDefaultDriver(value);
}
} else if (m_ParseState == DBPARSE_LEVEL_DATABASE) {
if (strcmp(key, "driver") == 0)
{
if (strcmp(value, "default") != 0)
{
m_ParseCurrent->driver = value;
}
} else if (strcmp(key, "database") == 0) {
m_ParseCurrent->database = value;
} else if (strcmp(key, "host") == 0) {
m_ParseCurrent->host = value;
} else if (strcmp(key, "user") == 0) {
m_ParseCurrent->user = value;
} else if (strcmp(key, "pass") == 0) {
m_ParseCurrent->pass = value;
} else if (strcmp(key, "timeout") == 0) {
m_ParseCurrent->info.maxTimeout = atoi(value);
} else if (strcmp(key, "port") == 0) {
m_ParseCurrent->info.port = atoi(value);
}
}
return SMCResult_Continue;
}
SMCResult DatabaseConfBuilder::ReadSMC_LeavingSection(const SMCStates *states)
{
if (m_ParseLevel)
{
m_ParseLevel--;
return SMCResult_Continue;
}
if (m_ParseState == DBPARSE_LEVEL_DATABASE)
{
m_ParseCurrent->info.driver = m_ParseCurrent->driver.chars();
m_ParseCurrent->info.database = m_ParseCurrent->database.chars();
m_ParseCurrent->info.host = m_ParseCurrent->host.chars();
m_ParseCurrent->info.user = m_ParseCurrent->user.chars();
m_ParseCurrent->info.pass = m_ParseCurrent->pass.chars();
/* Save it.. */
m_ParseCurrent->AddRef();
m_ParseList->append(m_ParseCurrent);
m_ParseCurrent = nullptr;
/* 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;
}
void DatabaseConfBuilder::ReadSMC_ParseEnd(bool halted, bool failed)
{
m_InfoList->ReleaseMembers();
delete m_InfoList;
m_InfoList = m_ParseList;
m_ParseList = nullptr;
}

View File

@ -0,0 +1,129 @@
/**
* vim: set ts=4 sw=4 tw=99 noet :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2018 AlliedModders LLC. All rights reserved.
* =============================================================================
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 3.0, as published by the
* Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
* As a special exception, AlliedModders LLC gives you permission to link the
* code of this program (as well as its derivative works) to "Half-Life 2," the
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
* by the Valve Corporation. You must obey the GNU General Public License in
* all respects for all other code used. Additionally, AlliedModders LLC grants
* this exception to all derivative works. AlliedModders LLC defines further
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
* or <http://www.sourcemod.net/license.php>.
*
* Version: $Id$
*/
#ifndef _INCLUDE_DATABASE_CONF_BUILDER_H_
#define _INCLUDE_DATABASE_CONF_BUILDER_H_
#include <IDBDriver.h>
#include <ITextParsers.h>
#include "common_logic.h"
#include <am-vector.h>
#include <am-string.h>
#include <am-refcounting-threadsafe.h>
class ConfDbInfo : public ke::RefcountedThreadsafe<ConfDbInfo>
{
public:
ConfDbInfo() : realDriver(NULL)
{
}
ke::AString name;
ke::AString driver;
ke::AString host;
ke::AString user;
ke::AString pass;
ke::AString database;
IDBDriver *realDriver;
DatabaseInfo info;
};
class ConfDbInfoList : public ke::Vector<ConfDbInfo *>
{
/* Allow internal usage of ConfDbInfoList */
friend class DBManager;
friend class DatabaseConfBuilder;
private:
ke::AString& GetDefaultDriver() {
return m_DefDriver;
}
ConfDbInfo *GetDatabaseConf(const char *name) {
for (size_t i = 0; i < this->length(); i++)
{
ConfDbInfo *current = this->at(i);
/* If we run into the default configuration, then we'll save it
* for the next call to GetDefaultConfiguration */
if (strcmp(current->name.chars(), "default") == 0)
{
m_DefaultConfig = current;
}
if (strcmp(current->name.chars(), name) == 0)
{
return current;
}
}
return nullptr;
}
ConfDbInfo *GetDefaultConfiguration() {
return m_DefaultConfig;
}
void SetDefaultDriver(const char *input) {
m_DefDriver = ke::AString(input);
}
void ReleaseMembers() {
for (size_t i = 0; i < this->length(); i++) {
ConfDbInfo *current = this->at(i);
current->Release();
}
}
private:
ConfDbInfo *m_DefaultConfig;
ke::AString m_DefDriver;
};
class DatabaseConfBuilder : public ITextListener_SMC
{
public:
DatabaseConfBuilder();
~DatabaseConfBuilder();
void StartParse();
void SetPath(char* path);
ConfDbInfoList *GetConfigList();
public: //ITextListener_SMC
void ReadSMC_ParseStart();
SMCResult ReadSMC_NewSection(const SMCStates *states, const char *name);
SMCResult ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value);
SMCResult ReadSMC_LeavingSection(const SMCStates *states);
void ReadSMC_ParseEnd(bool halted, bool failed);
private:
unsigned int m_ParseLevel;
unsigned int m_ParseState;
ConfDbInfo *m_ParseCurrent;
ConfDbInfoList *m_ParseList;
private:
ke::AString m_Filename;
ConfDbInfoList *m_InfoList;
};
#endif //_INCLUDE_DATABASE_CONF_BUILDER_H_

View File

@ -29,11 +29,11 @@
* Version: $Id$
*/
#include <ISourceMod.h>
#include <IPluginSys.h>
#include <stdarg.h>
#include "DebugReporter.h"
#include "Logger.h"
#include <am-string.h>
DebugReport g_DbgReporter;
@ -157,44 +157,90 @@ int DebugReport::_GetPluginIndex(IPluginContext *ctx)
void DebugReport::ReportError(const IErrorReport &report, IFrameIterator &iter)
{
// Find the nearest plugin to blame.
// 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;
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;
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 plugin: %s", blame);
g_Logger.LogError("[SM] Call stack trace:");
for (int index = 0; !iter.Done(); iter.Next(), index++) {
const char *fn = iter.FunctionName();
if (!fn)
fn = "<unknown function>";
if (blame)
{
g_Logger.LogError("[SM] Blaming: %s", blame);
}
if (iter.IsNativeFrame()) {
g_Logger.LogError("[SM] [%d] %s", index, fn);
continue;
}
if (iter.IsScriptedFrame()) {
const char *file = iter.FilePath();
if (!file)
file = "<unknown>";
g_Logger.LogError("[SM] [%d] Line %d, %s::%s()",
index,
iter.LineNumber(),
file,
fn);
}
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

@ -34,6 +34,8 @@
#include "sp_vm_api.h"
#include "common_logic.h"
#include <am-vector.h>
#include <am-string.h>
class DebugReport :
public SMGlobalClass,
@ -48,6 +50,7 @@ public:
void GenerateError(IPluginContext *ctx, cell_t func_idx, int err, const char *message, ...);
void GenerateErrorVA(IPluginContext *ctx, cell_t func_idx, int err, const char *message, va_list ap);
void GenerateCodeError(IPluginContext *ctx, uint32_t code_addr, int err, const char *message, ...);
ke::Vector<ke::AString> GetStackTrace(IFrameIterator *iter);
private:
int _GetPluginIndex(IPluginContext *ctx);
};

View File

@ -43,8 +43,9 @@
CExtensionManager g_Extensions;
IdentityType_t g_ExtType;
void CExtension::Initialize(const char *filename, const char *path)
void CExtension::Initialize(const char *filename, const char *path, bool bRequired)
{
m_bRequired = bRequired;
m_pAPI = NULL;
m_pIdentToken = NULL;
unload_code = 0;
@ -62,7 +63,7 @@ CRemoteExtension::CRemoteExtension(IExtensionInterface *pAPI, const char *filena
m_pAPI = pAPI;
}
CLocalExtension::CLocalExtension(const char *filename)
CLocalExtension::CLocalExtension(const char *filename, bool bRequired)
{
m_PlId = 0;
m_pLib = NULL;
@ -72,74 +73,69 @@ CLocalExtension::CLocalExtension(const char *filename)
/* Special case for new bintools binary */
if (strcmp(filename, "bintools.ext") == 0)
{
goto normal;
}
/* Zeroth, see if there is an engine specific build in the new place. */
g_pSM->BuildPath(Path_SM,
path,
PLATFORM_MAX_PATH,
"extensions/%s.%s." PLATFORM_LIB_EXT,
filename,
bridge->gamesuffix);
if (libsys->IsPathFile(path))
{
goto found;
}
/* COMPAT HACK: One-halfth, if ep2v, see if there is an engine specific build in the new place with old naming */
if (strcmp(bridge->gamesuffix, "2.tf2") == 0
|| strcmp(bridge->gamesuffix, "2.dods") == 0
|| strcmp(bridge->gamesuffix, "2.hl2dm") == 0
)
{
g_pSM->BuildPath(Path_SM,
path,
PLATFORM_MAX_PATH,
"extensions/%s.2.ep2v." PLATFORM_LIB_EXT,
filename);
if (libsys->IsPathFile(path))
{
goto found;
}
}
else if (strcmp(bridge->gamesuffix, "2.nd") == 0)
{
g_pSM->BuildPath(Path_SM,
path,
PLATFORM_MAX_PATH,
"extensions/%s.2.l4d2." PLATFORM_LIB_EXT,
filename);
if (libsys->IsPathFile(path))
{
goto found;
}
}
/* First see if there is an engine specific build! */
g_pSM->BuildPath(Path_SM,
path,
PLATFORM_MAX_PATH,
"extensions/auto.%s/%s." PLATFORM_LIB_EXT,
filename,
bridge->gamesuffix);
/* Try the "normal" version */
if (!libsys->IsPathFile(path))
{
normal:
g_pSM->BuildPath(Path_SM,
path,
PLATFORM_MAX_PATH,
"extensions/%s." PLATFORM_LIB_EXT,
filename);
}
else
{
/* Zeroth, see if there is an engine specific build in the new place. */
g_pSM->BuildPath(Path_SM,
path,
PLATFORM_MAX_PATH,
"extensions/%s.%s." PLATFORM_LIB_EXT,
filename,
bridge->gamesuffix);
found:
Initialize(filename, path);
if (!libsys->IsPathFile(path))
{
/* COMPAT HACK: One-halfth, if ep2v, see if there is an engine specific build in the new place with old naming */
if (strcmp(bridge->gamesuffix, "2.tf2") == 0
|| strcmp(bridge->gamesuffix, "2.dods") == 0
|| strcmp(bridge->gamesuffix, "2.hl2dm") == 0
)
{
g_pSM->BuildPath(Path_SM,
path,
PLATFORM_MAX_PATH,
"extensions/%s.2.ep2v." PLATFORM_LIB_EXT,
filename);
}
else if (strcmp(bridge->gamesuffix, "2.nd") == 0)
{
g_pSM->BuildPath(Path_SM,
path,
PLATFORM_MAX_PATH,
"extensions/%s.2.l4d2." PLATFORM_LIB_EXT,
filename);
}
//Try further
if (!libsys->IsPathFile(path))
{
/* First see if there is an engine specific build! */
g_pSM->BuildPath(Path_SM,
path,
PLATFORM_MAX_PATH,
"extensions/auto.%s/%s." PLATFORM_LIB_EXT,
filename,
bridge->gamesuffix);
/* Try the "normal" version */
if (!libsys->IsPathFile(path))
{
g_pSM->BuildPath(Path_SM,
path,
PLATFORM_MAX_PATH,
"extensions/%s." PLATFORM_LIB_EXT,
filename);
}
}
}
}
Initialize(filename, path, bRequired);
}
bool CRemoteExtension::Load(char *error, size_t maxlength)
@ -175,7 +171,7 @@ bool CLocalExtension::Load(char *error, size_t maxlength)
{
m_pLib->CloseLibrary();
m_pLib = NULL;
snprintf(error, maxlength, "Unable to find extension entry point");
ke::SafeStrcpy(error, maxlength, "Unable to find extension entry point");
return false;
}
@ -245,7 +241,7 @@ void CLocalExtension::Unload()
bool CRemoteExtension::Reload(char *error, size_t maxlength)
{
snprintf(error, maxlength, "Remote extensions do not support reloading");
ke::SafeStrcpy(error, maxlength, "Remote extensions do not support reloading");
return false;
}
@ -279,13 +275,13 @@ bool CExtension::PerformAPICheck(char *error, size_t maxlength)
{
if (!m_pAPI)
{
snprintf(error, maxlength, "No IExtensionInterface instance provided");
ke::SafeStrcpy(error, maxlength, "No IExtensionInterface instance provided");
return false;
}
if (m_pAPI->GetExtensionVersion() > SMINTERFACE_EXTENSIONAPI_VERSION)
{
snprintf(error, maxlength, "Extension version is too new to load (%d, max is %d)", m_pAPI->GetExtensionVersion(), SMINTERFACE_EXTENSIONAPI_VERSION);
ke::SafeSprintf(error, maxlength, "Extension version is too new to load (%d, max is %d)", m_pAPI->GetExtensionVersion(), SMINTERFACE_EXTENSIONAPI_VERSION);
return false;
}
@ -297,16 +293,15 @@ bool CExtension::Load(char *error, size_t maxlength)
CreateIdentity();
if (!m_pAPI->OnExtensionLoad(this, &g_ShareSys, error, maxlength, !bridge->IsMapLoading()))
{
g_ShareSys.RemoveInterfaces(this);
DestroyIdentity();
return false;
}
else
/* Check if we're past load time */
if (!bridge->IsMapLoading())
{
/* Check if we're past load time */
if (!bridge->IsMapLoading())
{
m_pAPI->OnExtensionsAllLoaded();
}
m_pAPI->OnExtensionsAllLoaded();
}
return true;
@ -493,7 +488,7 @@ bool CExtension::IsRunning(char *error, size_t maxlength)
{
if (error)
{
snprintf(error, maxlength, "%s", m_Error.c_str());
ke::SafeStrcpy(error, maxlength, m_Error.c_str());
}
return false;
}
@ -506,6 +501,11 @@ void CExtension::AddLibrary(const char *library)
m_Libraries.push_back(library);
}
bool CExtension::IsRequired()
{
return m_bRequired;
}
/*********************
* EXTENSION MANAGER *
*********************/
@ -570,7 +570,7 @@ void CExtensionManager::TryAutoload()
}
char file[PLATFORM_MAX_PATH];
len = ke::SafeSprintf(file, sizeof(file), "%s", lfile);
len = ke::SafeStrcpy(file, sizeof(file), lfile);
strcpy(&file[len - 9], ".ext");
LoadAutoExtension(file);
@ -586,7 +586,7 @@ IExtension *CExtensionManager::LoadAutoExtension(const char *path, bool bErrorOn
if (strcmp(ext, PLATFORM_LIB_EXT) == 0)
{
char path2[PLATFORM_MAX_PATH];
ke::SafeSprintf(path2, sizeof(path2), "%s", path);
ke::SafeStrcpy(path2, sizeof(path2), path);
path2[strlen(path) - strlen(PLATFORM_LIB_EXT) - 1] = '\0';
return LoadAutoExtension(path2, bErrorOnMissing);
}
@ -598,7 +598,7 @@ IExtension *CExtensionManager::LoadAutoExtension(const char *path, bool bErrorOn
}
char error[256];
CExtension *p = new CLocalExtension(path);
CExtension *p = new CLocalExtension(path, bErrorOnMissing);
/* We put us in the list beforehand so extensions that check for each other
* won't recursively load each other.
@ -678,7 +678,7 @@ IExtension *CExtensionManager::LoadExtension(const char *file, char *error, size
if (strcmp(ext, PLATFORM_LIB_EXT) == 0)
{
char path2[PLATFORM_MAX_PATH];
ke::SafeSprintf(path2, sizeof(path2), "%s", file);
ke::SafeStrcpy(path2, sizeof(path2), file);
path2[strlen(file) - strlen(PLATFORM_LIB_EXT) - 1] = '\0';
return LoadExtension(path2, error, maxlength);
}
@ -942,6 +942,7 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const ICommand
List<CExtension *>::iterator iter;
CExtension *pExt;
unsigned int num = 1;
switch (m_Libs.size())
{
case 1:
@ -960,7 +961,7 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const ICommand
break;
}
}
for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++,num++)
for (iter = m_Libs.begin(); iter != m_Libs.end(); iter++,num++)
{
pExt = (*iter);
if (pExt->IsLoaded())
@ -978,9 +979,15 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const ICommand
const char *descr = pAPI->GetExtensionDescription();
rootmenu->ConsolePrint("[%02d] %s (%s): %s", num, name, version, descr);
}
} else {
}
else if(pExt->IsRequired() || libsys->PathExists(pExt->GetPath()))
{
rootmenu->ConsolePrint("[%02d] <FAILED> file \"%s\": %s", num, pExt->GetFilename(), pExt->m_Error.c_str());
}
else
{
rootmenu->ConsolePrint("[%02d] <OPTIONAL> file \"%s\": %s", num, pExt->GetFilename(), pExt->m_Error.c_str());
}
}
return;
}
@ -1124,7 +1131,7 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const ICommand
if (pExt->unload_code == (unsigned)atoi(unload))
{
char filename[PLATFORM_MAX_PATH];
snprintf(filename, PLATFORM_MAX_PATH, "%s", pExt->GetFilename());
ke::SafeStrcpy(filename, PLATFORM_MAX_PATH, pExt->GetFilename());
UnloadExtension(pExt);
rootmenu->ConsolePrint("[SM] Extension %s is now unloaded.", filename);
}
@ -1139,7 +1146,7 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const ICommand
|| (!pExt->m_ChildDeps.size() && !pExt->m_Dependents.size()))
{
char filename[PLATFORM_MAX_PATH];
snprintf(filename, PLATFORM_MAX_PATH, "%s", pExt->GetFilename());
ke::SafeStrcpy(filename, PLATFORM_MAX_PATH, pExt->GetFilename());
UnloadExtension(pExt);
rootmenu->ConsolePrint("[SM] Extension %s is now unloaded.", filename);
return;
@ -1174,7 +1181,7 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const ICommand
/* Will our dependent care? */
if (!pExt->GetAPI()->QueryInterfaceDrop((*i_iter).iface))
{
rootmenu->ConsolePrint(" -> %s", pExt->GetFilename());
rootmenu->ConsolePrint(" -> %s", pOther->GetFilename());
/* Add to plugin unload list */
List<CPlugin *>::iterator p_iter;
for (p_iter=pOther->m_Dependents.begin();
@ -1240,7 +1247,7 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const ICommand
char filename[PLATFORM_MAX_PATH];
char error[255];
snprintf(filename, PLATFORM_MAX_PATH, "%s", pExt->GetFilename());
ke::SafeStrcpy(filename, PLATFORM_MAX_PATH, pExt->GetFilename());
if (pExt->Reload(error, sizeof(error)))
{

View File

@ -80,6 +80,7 @@ public:
void AddPlugin(CPlugin *pPlugin);
void MarkAllLoaded();
void AddLibrary(const char *library);
bool IsRequired();
public:
virtual bool Load(char *error, size_t maxlength);
virtual bool IsLoaded() =0;
@ -87,7 +88,7 @@ public:
virtual bool Reload(char *error, size_t maxlength) =0;
virtual bool IsSameFile(const char* file) =0;
protected:
void Initialize(const char *filename, const char *path);
void Initialize(const char *filename, const char *path, bool bRequired = true);
bool PerformAPICheck(char *error, size_t maxlength);
void CreateIdentity();
void DestroyIdentity();
@ -104,12 +105,13 @@ protected:
List<String> m_Libraries;
unsigned int unload_code;
bool m_bFullyLoaded;
bool m_bRequired;
};
class CLocalExtension : public CExtension
{
public:
CLocalExtension(const char *filename);
CLocalExtension(const char *filename, bool bRequired = true);
public:
bool Load(char *error, size_t maxlength);
bool IsLoaded();

View File

@ -252,6 +252,9 @@ int CForward::Execute(cell_t *result, IForwardFilter *filter)
if (filter)
filter->Preprocess(func, temp_info);
if (func->GetParentRuntime()->IsPaused())
continue;
for (unsigned int i=0; i<num_params; i++)
{
int err = SP_ERROR_PARAM;
@ -266,21 +269,9 @@ int CForward::Execute(cell_t *result, IForwardFilter *filter)
if ((i >= m_numparams) || (type & SP_PARAMFLAG_BYREF))
{
/* If we're byref or we're vararg, we always push everything by ref.
* Even if they're byval, we must push them byref.
*/
if (type == Param_String)
{
err = func->PushStringEx((char *)param->byref.orig_addr, param->byref.cells, param->byref.sz_flags, param->byref.flags);
}
else if (type == Param_Float || type == Param_Cell)
{
err = func->PushCellByRef(&param->val);
}
else
{
err = func->PushArray(param->byref.orig_addr, param->byref.cells, param->byref.flags);
assert(type == Param_Array || type == Param_FloatByRef || type == Param_CellByRef);
}
* Even if they're byval, we must push them byref.
*/
err = _ExecutePushRef(func, type, param);
}
else
{
@ -379,6 +370,58 @@ done:
return SP_ERROR_NONE;
}
int CForward::_ExecutePushRef(IPluginFunction *func, ParamType type, FwdParamInfo *param)
{
/* If we're byref or we're vararg, we always push everything by ref.
* Even if they're byval, we must push them byref.
*/
int err;
IPluginRuntime *runtime = func->GetParentRuntime();
switch (type)
{
case Param_String:
// Normal string was pushed.
if (!param->isnull)
return func->PushStringEx((char *)param->byref.orig_addr, param->byref.cells, param->byref.sz_flags, param->byref.flags);
// If NULL_STRING was pushed, push the reference to the pubvar of the callee instead.
uint32_t null_string_idx;
err = runtime->FindPubvarByName("NULL_STRING", &null_string_idx);
if (err)
return err;
cell_t null_string;
err = runtime->GetPubvarAddrs(null_string_idx, &null_string, nullptr);
if (err)
return err;
return func->PushCell(null_string);
case Param_Float:
case Param_Cell:
return func->PushCellByRef(&param->val);
default:
assert(type == Param_Array || type == Param_FloatByRef || type == Param_CellByRef);
// No NULL_VECTOR was pushed.
if (type != Param_Array || !param->isnull)
return func->PushArray(param->byref.orig_addr, param->byref.cells, param->byref.flags);
// If NULL_VECTOR was pushed, push the reference to the pubvar of the callee instead.
uint32_t null_vector_idx;
err = runtime->FindPubvarByName("NULL_VECTOR", &null_vector_idx);
if (err)
return err;
cell_t null_vector;
err = runtime->GetPubvarAddrs(null_vector_idx, &null_vector, nullptr);
if (err)
return err;
return func->PushCell(null_vector);
}
}
int CForward::PushCell(cell_t cell)
{
if (m_curparam < m_numparams)
@ -397,6 +440,7 @@ int CForward::PushCell(cell_t cell)
m_params[m_curparam].pushedas = Param_Cell;
}
m_params[m_curparam].isnull = false;
m_params[m_curparam++].val = cell;
return SP_ERROR_NONE;
@ -420,6 +464,7 @@ int CForward::PushFloat(float number)
m_params[m_curparam].pushedas = Param_Float;
}
m_params[m_curparam].isnull = false;
m_params[m_curparam++].val = *(cell_t *)&number;
return SP_ERROR_NONE;
@ -478,14 +523,22 @@ void CForward::_Int_PushArray(cell_t *inarray, unsigned int cells, int flags)
m_params[m_curparam].byref.cells = cells;
m_params[m_curparam].byref.flags = flags;
m_params[m_curparam].byref.orig_addr = inarray;
m_params[m_curparam].isnull = false;
}
int CForward::PushArray(cell_t *inarray, unsigned int cells, int flags)
{
/* We don't allow this here */
/* Push a reference to the NULL_VECTOR pubvar if NULL was passed. */
if (!inarray)
{
return SetError(SP_ERROR_PARAM);
/* Make sure this was intentional. */
if (cells == 3)
{
return PushNullVector();
} else {
/* We don't allow this here */
return SetError(SP_ERROR_PARAM);
}
}
if (m_curparam < m_numparams)
@ -517,10 +570,17 @@ void CForward::_Int_PushString(cell_t *inarray, unsigned int cells, int sz_flags
m_params[m_curparam].byref.flags = cp_flags;
m_params[m_curparam].byref.orig_addr = inarray;
m_params[m_curparam].byref.sz_flags = sz_flags;
m_params[m_curparam].isnull = false;
}
int CForward::PushString(const char *string)
{
/* Push a reference to the NULL_STRING pubvar if NULL was passed. */
if (!string)
{
return PushNullString();
}
if (m_curparam < m_numparams)
{
if (m_types[m_curparam] == Param_Any)
@ -567,6 +627,52 @@ int CForward::PushStringEx(char *buffer, size_t length, int sz_flags, int cp_fla
return SP_ERROR_NONE;
}
int CForward::PushNullString()
{
if (m_curparam < m_numparams)
{
if (m_types[m_curparam] == Param_Any)
{
m_params[m_curparam].pushedas = Param_String;
} else if (m_types[m_curparam] != Param_String) {
return SetError(SP_ERROR_PARAM);
}
} else {
if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
{
return SetError(SP_ERROR_PARAMS_MAX);
}
m_params[m_curparam].pushedas = Param_String;
}
m_params[m_curparam++].isnull = true;
return SP_ERROR_NONE;
}
int CForward::PushNullVector()
{
if (m_curparam < m_numparams)
{
if (m_types[m_curparam] == Param_Any)
{
m_params[m_curparam].pushedas = Param_Array;
} else if (m_types[m_curparam] != Param_Array) {
return SetError(SP_ERROR_PARAM);
}
} else {
if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
{
return SetError(SP_ERROR_PARAMS_MAX);
}
m_params[m_curparam].pushedas = Param_Array;
}
m_params[m_curparam++].isnull = true;
return SP_ERROR_NONE;
}
void CForward::Cancel()
{
if (!m_curparam)

View File

@ -72,6 +72,9 @@ private:
CForward(ExecType et, const char *name,
const ParamType *types, unsigned num_params);
int PushNullString();
int PushNullVector();
int _ExecutePushRef(IPluginFunction *func, ParamType type, FwdParamInfo *param);
void _Int_PushArray(cell_t *inarray, unsigned int cells, int flags);
void _Int_PushString(cell_t *inarray, unsigned int cells, int sz_flags, int cp_flags);
inline int SetError(int err)

View File

@ -0,0 +1,96 @@
/**
* vim: set ts=4 sw=4 tw=99 noet :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2017 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 "FrameIterator.h"
SafeFrameIterator::SafeFrameIterator(IFrameIterator *it)
{
while (!it->Done())
{
FrameInfo info = FrameInfo(it);
frames.append(info);
it->Next();
}
it->Reset();
current = 0;
}
bool SafeFrameIterator::Done() const
{
return current == frames.length();
}
bool SafeFrameIterator::Next()
{
if (!this->Done())
{
current++;
return true;
}
return false;
}
void SafeFrameIterator::Reset()
{
current = 0;
}
int SafeFrameIterator::LineNumber() const
{
if (this->Done())
{
return -1;
}
return (int)frames[current].LineNumber;
}
const char *SafeFrameIterator::FunctionName() const
{
if (this->Done())
{
return NULL;
}
return frames[current].FunctionName.chars();
}
const char *SafeFrameIterator::FilePath() const
{
if (this->Done())
{
return NULL;
}
return frames[current].FilePath.chars();
}

View File

@ -0,0 +1,77 @@
/**
* vim: set ts=4 sw=4 tw=99 noet :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2017 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 "sp_vm_api.h"
#include <am-vector.h>
#include <am-string.h>
using namespace SourcePawn;
/**
* Frame iterator cache which is safe for plugins to hold handles to,
* unlike what you'd recieve from IPluginContext::CreateFrameIterator.
*/
class SafeFrameIterator
{
public:
/**
* Struct which holds all of the cached values for each individual frame.
*/
struct FrameInfo
{
ke::AString FunctionName;
ke::AString FilePath;
unsigned LineNumber;
FrameInfo(IFrameIterator *it)
{
LineNumber = it->LineNumber();
FunctionName = it->FunctionName();
FilePath = it->FilePath();
}
};
SafeFrameIterator(IFrameIterator *);
bool Done() const;
bool Next();
void Reset();
int LineNumber() const;
const char *FunctionName() const;
const char *FilePath() const;
private:
size_t current;
ke::Vector<FrameInfo> frames;
};

View File

@ -39,6 +39,7 @@
#include <IHandleSys.h>
#include <IMemoryUtils.h>
#include <ISourceMod.h>
#include <IRootConsoleMenu.h>
#include "common_logic.h"
#include "sm_crc32.h"
#include "MemoryUtils.h"
@ -65,26 +66,33 @@ static const char *g_pParseEngine = NULL;
#define PSTATE_GAMEDEFS_OFFSETS 3
#define PSTATE_GAMEDEFS_OFFSETS_OFFSET 4
#define PSTATE_GAMEDEFS_KEYS 5
#define PSTATE_GAMEDEFS_SUPPORTED 6
#define PSTATE_GAMEDEFS_SIGNATURES 7
#define PSTATE_GAMEDEFS_SIGNATURES_SIG 8
#define PSTATE_GAMEDEFS_CRC 9
#define PSTATE_GAMEDEFS_CRC_BINARY 10
#define PSTATE_GAMEDEFS_CUSTOM 11
#define PSTATE_GAMEDEFS_ADDRESSES 12
#define PSTATE_GAMEDEFS_ADDRESSES_ADDRESS 13
#define PSTATE_GAMEDEFS_ADDRESSES_ADDRESS_READ 14
#define PSTATE_GAMEDEFS_KEYS_PLATFORM 6
#define PSTATE_GAMEDEFS_SUPPORTED 7
#define PSTATE_GAMEDEFS_SIGNATURES 8
#define PSTATE_GAMEDEFS_SIGNATURES_SIG 9
#define PSTATE_GAMEDEFS_CRC 10
#define PSTATE_GAMEDEFS_CRC_BINARY 11
#define PSTATE_GAMEDEFS_CUSTOM 12
#define PSTATE_GAMEDEFS_ADDRESSES 13
#define PSTATE_GAMEDEFS_ADDRESSES_ADDRESS 14
#define PSTATE_GAMEDEFS_ADDRESSES_ADDRESS_READ 15
#if defined PLATFORM_X86
#define PLATFORM_ARCH_SUFFIX ""
#elif defined PLATFORM_X64
#define PLATFORM_ARCH_SUFFIX "64"
#endif
#if defined PLATFORM_WINDOWS
#define PLATFORM_NAME "windows"
#define PLATFORM_NAME "windows" PLATFORM_ARCH_SUFFIX
#define PLATFORM_SERVER_BINARY "server.dll"
#elif defined PLATFORM_LINUX
#define PLATFORM_NAME "linux"
#define PLATFORM_COMPAT_ALT "mac" /* Alternate platform name if game data is missing for primary one */
#define PLATFORM_NAME "linux" PLATFORM_ARCH_SUFFIX
#define PLATFORM_COMPAT_ALT "mac" PLATFORM_ARCH_SUFFIX /* Alternate platform name if game data is missing for primary one */
#define PLATFORM_SERVER_BINARY "server_i486.so"
#elif defined PLATFORM_APPLE
#define PLATFORM_NAME "mac"
#define PLATFORM_COMPAT_ALT "linux"
#define PLATFORM_NAME "mac" PLATFORM_ARCH_SUFFIX
#define PLATFORM_COMPAT_ALT "linux" PLATFORM_ARCH_SUFFIX
#define PLATFORM_SERVER_BINARY "server.dylib"
#endif
@ -251,6 +259,13 @@ SMCResult CGameConfig::ReadSMC_NewSection(const SMCStates *states, const char *n
}
break;
}
case PSTATE_GAMEDEFS_KEYS:
{
strncopy(m_Key, name, sizeof(m_Key));
m_ParseState = PSTATE_GAMEDEFS_KEYS_PLATFORM;
matched_platform = false;
break;
}
case PSTATE_GAMEDEFS_OFFSETS:
{
m_Prop[0] = '\0';
@ -322,6 +337,7 @@ SMCResult CGameConfig::ReadSMC_NewSection(const SMCStates *states, const char *n
m_Address[0] = '\0';
m_AddressSignature[0] = '\0';
m_AddressReadCount = 0;
m_AddressLastIsOffset = false;
strncopy(m_Address, name, sizeof(m_Address));
m_ParseState = PSTATE_GAMEDEFS_ADDRESSES_ADDRESS;
@ -336,7 +352,8 @@ SMCResult CGameConfig::ReadSMC_NewSection(const SMCStates *states, const char *n
}
else
{
if (strcmp(name, "linux") != 0 && strcmp(name, "windows") != 0 && strcmp(name, "mac") != 0)
if (strcmp(name, "linux") != 0 && strcmp(name, "windows") != 0 && strcmp(name, "mac") != 0 &&
strcmp(name, "linux64") != 0 && strcmp(name, "windows64") != 0 && strcmp(name, "mac64") != 0)
{
logger->LogError("[SM] Error while parsing Address section for \"%s\" (%s):", m_Address, m_CurFile);
logger->LogError("[SM] Unrecognized platform \"%s\"", name);
@ -347,7 +364,7 @@ SMCResult CGameConfig::ReadSMC_NewSection(const SMCStates *states, const char *n
}
/* No sub-sections allowed:
case PSTATE_GAMEDEFS_OFFSETS_OFFSET:
case PSTATE_GAMEDEFS_KEYS:
case PSTATE_GAMEDEFS_KEYS_PLATFORM:
case PSTATE_GAMEDEFS_SUPPORTED:
case PSTATE_GAMEDEFS_SIGNATURES_SIG:
case PSTATE_GAMEDEFS_CRC_BINARY:
@ -384,6 +401,13 @@ SMCResult CGameConfig::ReadSMC_KeyValue(const SMCStates *states, const char *key
} else if (m_ParseState == PSTATE_GAMEDEFS_KEYS) {
ke::AString vstr(value);
m_Keys.replace(key, ke::Move(vstr));
}
else if (m_ParseState == PSTATE_GAMEDEFS_KEYS_PLATFORM) {
if (IsPlatformCompatible(key, &matched_platform))
{
ke::AString vstr(value);
m_Keys.replace(m_Key, ke::Move(vstr));
}
} else if (m_ParseState == PSTATE_GAMEDEFS_SUPPORTED) {
if (strcmp(key, "game") == 0)
{
@ -429,10 +453,18 @@ SMCResult CGameConfig::ReadSMC_KeyValue(const SMCStates *states, const char *key
}
}
} else if (m_ParseState == PSTATE_GAMEDEFS_ADDRESSES_ADDRESS || m_ParseState == PSTATE_GAMEDEFS_ADDRESSES_ADDRESS_READ) {
if (strcmp(key, "read") == 0) {
if (strcmp(key, "read") == 0 || strcmp(key, "offset") == 0) {
int limit = sizeof(m_AddressRead)/sizeof(m_AddressRead[0]);
if (m_AddressReadCount < limit)
if (m_AddressLastIsOffset)
{
logger->LogError("[SM] Error parsing Address \"%s\", 'offset' entry must be the last entry (gameconf \"%s\")", m_Address, m_CurFile);
}
else if (m_AddressReadCount < limit)
{
if (strcmp(key, "offset") == 0)
{
m_AddressLastIsOffset = true;
}
m_AddressRead[m_AddressReadCount] = atoi(value);
m_AddressReadCount++;
}
@ -489,6 +521,11 @@ SMCResult CGameConfig::ReadSMC_LeavingSection(const SMCStates *states)
m_ParseState = PSTATE_GAMEDEFS;
break;
}
case PSTATE_GAMEDEFS_KEYS_PLATFORM:
{
m_ParseState = PSTATE_GAMEDEFS_KEYS;
break;
}
case PSTATE_GAMEDEFS_OFFSETS_OFFSET:
{
/* Parse the offset... */
@ -636,7 +673,7 @@ SMCResult CGameConfig::ReadSMC_LeavingSection(const SMCStates *states)
if (m_Address[0] != '\0' && m_AddressSignature[0] != '\0')
{
AddressConf addrConf(m_AddressSignature, sizeof(m_AddressSignature), m_AddressReadCount, m_AddressRead);
AddressConf addrConf(m_AddressSignature, sizeof(m_AddressSignature), m_AddressReadCount, m_AddressRead, m_AddressLastIsOffset);
m_Addresses.replace(m_Address, addrConf);
}
@ -805,7 +842,12 @@ bool CGameConfig::Reparse(char *error, size_t maxlength)
if (libsys->PathExists(path))
{
ke::SafeSprintf(path, sizeof(path), "custom/%s.txt", m_File);
return EnterFile(path, error, maxlength);
bool success = EnterFile(path, error, maxlength);
if (success)
{
rootmenu->ConsolePrint("[SM] Parsed custom gamedata override file: %s", path);
}
return success;
}
return true;
}
@ -885,6 +927,8 @@ bool CGameConfig::Reparse(char *error, size_t maxlength)
return false;
}
rootmenu->ConsolePrint("[SM] Parsed custom gamedata override file: %s", path);
customDir->NextEntry();
}
@ -989,12 +1033,17 @@ bool CGameConfig::GetAddress(const char *key, void **retaddr)
int offset = addrConf.read[i];
//NULLs in the middle of an indirection chain are bad, end NULL is ok
if (addr == NULL || reinterpret_cast<uintptr_t>(addr) < VALID_MINIMUM_MEMORY_ADDRESS)
if (addr == NULL || reinterpret_cast<uintptr_t>(addr) < VALID_MINIMUM_MEMORY_ADDRESS)
{
*retaddr = NULL;
return false;
}
addr = *(reinterpret_cast<void**>(reinterpret_cast<uint8_t*>(addr) + offset));
//If lastIsOffset is set and this is the last iteration of the loop, don't deref
if (addrConf.lastIsOffset && i == addrConf.readCount-1) {
addr = reinterpret_cast<void*>(reinterpret_cast<uint8_t*>(addr) + offset);
} else {
addr = *(reinterpret_cast<void**>(reinterpret_cast<uint8_t*>(addr) + offset));
}
}
*retaddr = addr;
@ -1006,13 +1055,17 @@ static inline unsigned minOf(unsigned a, unsigned b)
return a <= b ? a : b;
}
CGameConfig::AddressConf::AddressConf(char *sigName, unsigned sigLength, unsigned readCount, int *read)
CGameConfig::AddressConf::AddressConf(char *sigName, unsigned sigLength, unsigned readCount, int *read, bool lastIsOffset)
{
unsigned readLimit = minOf(readCount, sizeof(this->read) / sizeof(this->read[0]));
strncopy(signatureName, sigName, sizeof(signatureName) / sizeof(signatureName[0]));
this->readCount = readLimit;
memcpy(&this->read[0], read, sizeof(this->read[0])*readLimit);
//For safety: if the readLimit isn't the same as the readCount, then the
//last read value was definitely discarded, so lastIsOffset should be ignored
this->lastIsOffset = readLimit < readCount ? false : lastIsOffset;
}
SendProp *CGameConfig::GetSendProp(const char *key)

View File

@ -72,6 +72,10 @@ public: //NameHashSet
{
return strcmp(key, value->m_File) == 0;
}
static inline uint32_t hash(const detail::CharsAndLength &key)
{
return key.hash();
}
private:
char m_File[PLATFORM_MAX_PATH];
char m_CurFile[PLATFORM_MAX_PATH];
@ -86,6 +90,7 @@ private:
char m_Prop[64];
char m_offset[64];
char m_Game[256];
char m_Key[64];
bool bShouldBeReadingDefault;
bool had_game;
bool matched_game;
@ -103,8 +108,9 @@ private:
char signatureName[64];
int readCount;
int read[8];
bool lastIsOffset;
AddressConf(char *sigName, unsigned sigLength, unsigned readCount, int *read);
AddressConf(char *sigName, unsigned sigLength, unsigned readCount, int *read, bool lastIsOffset);
AddressConf() {}
};
@ -113,6 +119,7 @@ private:
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;

View File

@ -35,6 +35,7 @@
#include <IHandleSys.h>
#include <stdio.h>
#include <sm_namehashset.h>
#include <amtl/am-autoptr.h>
#include <amtl/am-string.h>
#include <amtl/am-function.h>
#include "common_logic.h"
@ -110,6 +111,10 @@ struct QHandleType
{
return type->name && type->name->compare(key) == 0;
}
static inline uint32_t hash(const detail::CharsAndLength &key)
{
return key.hash();
}
};
typedef ke::Lambda<void(const char *)> HandleReporter;

View File

@ -41,7 +41,7 @@
LibrarySystem g_LibSys;
CLibrary::CLibrary(ke::Ref<ke::SharedLib> lib)
CLibrary::CLibrary(ke::RefPtr<ke::SharedLib> lib)
: lib_(lib)
{
}
@ -66,7 +66,7 @@ CDirectory::CDirectory(const char *path)
{
#if defined PLATFORM_WINDOWS
char newpath[PLATFORM_MAX_PATH];
snprintf(newpath, sizeof(newpath), "%s\\*.*", path);
ke::SafeSprintf(newpath, sizeof(newpath), "%s\\*.*", path);
m_dir = FindFirstFileA(newpath, &m_fd);
if (!IsValid())
{
@ -78,7 +78,7 @@ CDirectory::CDirectory(const char *path)
{
/* :TODO: we need to read past "." and ".."! */
ep = readdir(m_dir);
snprintf(m_origpath, PLATFORM_MAX_PATH, "%s", path);
ke::SafeStrcpy(m_origpath, PLATFORM_MAX_PATH, path);
} else {
ep = NULL;
}
@ -125,7 +125,9 @@ bool CDirectory::IsEntryDirectory()
return ((m_fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY);
#elif defined PLATFORM_POSIX
char temppath[PLATFORM_MAX_PATH];
snprintf(temppath, sizeof(temppath), "%s/%s", m_origpath, GetEntryName());
int ret = ke::SafeSprintf(temppath, sizeof(temppath), "%s/%s", m_origpath, GetEntryName());
if (static_cast<size_t>(ret) >= sizeof(temppath))
return false;
return ke::file::IsDirectory(temppath);
#endif
}
@ -136,7 +138,9 @@ bool CDirectory::IsEntryFile()
return !(m_fd.dwFileAttributes & (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_DEVICE));
#elif defined PLATFORM_POSIX
char temppath[PLATFORM_MAX_PATH];
snprintf(temppath, sizeof(temppath), "%s/%s", m_origpath, GetEntryName());
int ret = ke::SafeSprintf(temppath, sizeof(temppath), "%s/%s", m_origpath, GetEntryName());
if (static_cast<size_t>(ret) >= sizeof(temppath))
return false;
return ke::file::IsFile(temppath);
#endif
}
@ -226,7 +230,7 @@ void LibrarySystem::GetPlatformErrorEx(int code, char *error, size_t maxlength)
const char *ae = strerror_r(code, error, maxlength);
if (ae != error)
{
ke::SafeSprintf(error, maxlength, "%s", ae);
ke::SafeStrcpy(error, maxlength, ae);
}
#elif defined PLATFORM_POSIX
strerror_r(code, error, maxlength);
@ -241,7 +245,7 @@ void LibrarySystem::CloseDirectory(IDirectory *dir)
ILibrary *LibrarySystem::OpenLibrary(const char *path, char *error, size_t maxlength)
{
ke::Ref<ke::SharedLib> lib = ke::SharedLib::Open(path, error, maxlength);
ke::RefPtr<ke::SharedLib> lib = ke::SharedLib::Open(path, error, maxlength);
if (!lib)
return nullptr;
return new CLibrary(lib);
@ -305,12 +309,12 @@ size_t LibrarySystem::GetFileFromPath(char *buffer, size_t maxlength, const char
#endif
)
{
return ke::SafeSprintf(buffer, maxlength, "%s", &path[i+1]);
return ke::SafeStrcpy(buffer, maxlength, &path[i+1]);
}
}
/* We scanned and found no path separator */
return ke::SafeSprintf(buffer, maxlength, "%s", path);
return ke::SafeStrcpy(buffer, maxlength, path);
}
bool LibrarySystem::FileTime(const char *path, FileTimeType type, time_t *pTime)

View File

@ -66,12 +66,12 @@ private:
class CLibrary : public ILibrary
{
public:
CLibrary(ke::Ref<ke::SharedLib> lib);
CLibrary(ke::RefPtr<ke::SharedLib> lib);
public:
void CloseLibrary() override;
void *GetSymbolAddress(const char *symname) override;
private:
ke::Ref<ke::SharedLib> lib_;
ke::RefPtr<ke::SharedLib> lib_;
};
class LibrarySystem : public ILibrarySys

View File

@ -40,10 +40,6 @@
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,
@ -60,7 +56,7 @@ ConfigResult Logger::OnSourceModConfigChanged(const char *key,
} else if (strcasecmp(value, "off") == 0) {
state = false;
} else {
ke::SafeSprintf(error, maxlength, "Invalid value: must be \"on\" or \"off\"");
ke::SafeStrcpy(error, maxlength, "Invalid value: must be \"on\" or \"off\"");
return ConfigResult_Reject;
}
@ -68,7 +64,7 @@ ConfigResult Logger::OnSourceModConfigChanged(const char *key,
{
state ? EnableLogging() : DisableLogging();
} else {
m_InitialState = state;
m_Active = state;
}
return ConfigResult_Accept;
@ -81,7 +77,7 @@ ConfigResult Logger::OnSourceModConfigChanged(const char *key,
} else if (strcasecmp(value, "game") == 0) {
m_Mode = LoggingMode_Game;
} else {
ke::SafeSprintf(error, maxlength, "Invalid value: must be [daily|map|game]");
ke::SafeStrcpy(error, maxlength, "Invalid value: must be [daily|map|game]");
return ConfigResult_Reject;
}
@ -93,7 +89,12 @@ ConfigResult Logger::OnSourceModConfigChanged(const char *key,
void Logger::OnSourceModStartup(bool late)
{
InitLogger(m_Mode);
char buff[PLATFORM_MAX_PATH];
g_pSM->BuildPath(Path_SM, buff, sizeof(buff), "logs");
if (!libsys->IsPathDirectory(buff))
{
libsys->CreateFolder(buff);
}
}
void Logger::OnSourceModAllShutdown()
@ -103,127 +104,7 @@ void Logger::OnSourceModAllShutdown()
void Logger::OnSourceModLevelChange(const char *mapName)
{
MapChange(mapName);
}
void Logger::_NewMapFile()
{
if (!m_Active)
{
return;
}
/* Append "Log file closed" to previous log file */
_CloseFile();
char _filename[256];
int i = 0;
time_t t = g_pSM->GetAdjustedTime();
tm *curtime = localtime(&t);
while (true)
{
g_pSM->BuildPath(Path_SM, _filename, sizeof(_filename), "logs/L%02d%02d%03d.log", curtime->tm_mon + 1, curtime->tm_mday, i);
FILE *fp = fopen(_filename, "r");
if (!fp)
{
break;
}
fclose(fp);
i++;
}
m_NrmFileName.assign(_filename);
FILE *fp = fopen(m_NrmFileName.c_str(), "w");
if (!fp)
{
char error[255];
libsys->GetPlatformError(error, sizeof(error));
LogFatal("[SM] Unexpected fatal logging error (file \"%s\")", m_NrmFileName.c_str());
LogFatal("[SM] Platform returned error: \"%s\"", error);
LogFatal("[SM] Logging has been disabled.");
m_Active = false;
return;
} else {
char date[32];
strftime(date, sizeof(date), "%m/%d/%Y - %H:%M:%S", curtime);
fprintf(fp, "L %s: SourceMod log file started (file \"L%02d%02d%03d.log\") (Version \"%s\")\n", date, curtime->tm_mon + 1, curtime->tm_mday, i, SOURCEMOD_VERSION);
fclose(fp);
}
}
void Logger::_CloseFile()
{
if (!m_Active)
{
return;
}
FILE *fp = NULL;
if (!m_NrmFileName.empty())
{
fp = fopen(m_NrmFileName.c_str(), "r+");
if (fp)
{
fseek(fp, 0, SEEK_END);
LogMessage("Log file closed.");
fclose(fp);
}
m_NrmFileName.clear();
}
if (!m_ErrMapStart)
{
return;
}
fp = fopen(m_ErrFileName.c_str(), "r+");
if (fp)
{
fseek(fp, 0, SEEK_END);
LogError("Error log file session closed.");
fclose(fp);
}
m_ErrFileName.clear();
}
void Logger::InitLogger(LoggingMode mode)
{
m_Mode = mode;
m_Active = m_InitialState;
time_t t = g_pSM->GetAdjustedTime();
tm *curtime = localtime(&t);
m_NrmCurDay = curtime->tm_mday;
m_ErrCurDay = curtime->tm_mday;
char _filename[256];
g_pSM->BuildPath(Path_SM, _filename, sizeof(_filename), "logs/errors_%04d%02d%02d.log", curtime->tm_year + 1900, curtime->tm_mon + 1, curtime->tm_mday);
m_ErrFileName.assign(_filename);
switch (m_Mode)
{
case LoggingMode_PerMap:
{
if (!m_Active)
{
m_DelayedStart = true;
}
break;
}
case LoggingMode_Daily:
{
g_pSM->BuildPath(Path_SM, _filename, sizeof(_filename), "logs/L%04d%02d%02d.log", curtime->tm_year + 1900, curtime->tm_mon + 1, curtime->tm_mday);
m_NrmFileName.assign(_filename);
m_DailyPrintHdr = true;
break;
}
default:
{
/* do nothing... */
break;
}
}
_MapChange(mapName);
}
void Logger::CloseLogger()
@ -231,6 +112,13 @@ void Logger::CloseLogger()
_CloseFile();
}
void Logger::_CloseFile()
{
_CloseNormal();
_CloseError();
_CloseFatal();
}
void Logger::LogToOpenFile(FILE *fp, const char *msg, ...)
{
if (!m_Active)
@ -259,11 +147,6 @@ void Logger::LogToFileOnly(FILE *fp, const char *msg, ...)
void Logger::LogToOpenFileEx(FILE *fp, const char *msg, va_list ap)
{
if (!m_Active)
{
return;
}
static ConVar *sv_logecho = bridge->FindConVar("sv_logecho");
char buffer[3072];
@ -282,15 +165,12 @@ void Logger::LogToOpenFileEx(FILE *fp, const char *msg, va_list ap)
ke::SafeSprintf(conBuffer, sizeof(conBuffer), "L %s: %s\n", date, buffer);
bridge->ConPrint(conBuffer);
}
fflush(fp);
}
void Logger::LogToFileOnlyEx(FILE *fp, const char *msg, va_list ap)
{
if (!m_Active)
{
return;
}
char buffer[3072];
ke::SafeVsprintf(buffer, sizeof(buffer), msg, ap);
@ -298,8 +178,8 @@ void Logger::LogToFileOnlyEx(FILE *fp, const char *msg, va_list ap)
time_t t = g_pSM->GetAdjustedTime();
tm *curtime = localtime(&t);
strftime(date, sizeof(date), "%m/%d/%Y - %H:%M:%S", curtime);
fprintf(fp, "L %s: %s\n", date, buffer);
fflush(fp);
}
@ -324,63 +204,14 @@ void Logger::LogMessageEx(const char *vafmt, va_list ap)
return;
}
if (m_DelayedStart)
FILE *pFile = _OpenNormal();
if (!pFile)
{
m_DelayedStart = false;
_NewMapFile();
return;
}
time_t t = g_pSM->GetAdjustedTime();
tm *curtime = localtime(&t);
FILE *fp = NULL;
if (m_Mode == LoggingMode_PerMap)
{
fp = fopen(m_NrmFileName.c_str(), "a+");
if (!fp)
{
_NewMapFile();
fp = fopen(m_NrmFileName.c_str(), "a+");
if (!fp)
{
goto print_error;
}
}
} else {
if (m_NrmCurDay != curtime->tm_mday)
{
char _filename[256];
g_pSM->BuildPath(Path_SM, _filename, sizeof(_filename), "logs/L%04d%02d%02d.log", curtime->tm_year + 1900, curtime->tm_mon + 1, curtime->tm_mday);
m_NrmFileName.assign(_filename);
m_NrmCurDay = curtime->tm_mday;
m_DailyPrintHdr = true;
}
fp = fopen(m_NrmFileName.c_str(), "a+");
}
if (fp)
{
if (m_DailyPrintHdr)
{
char date[32];
m_DailyPrintHdr = false;
strftime(date, sizeof(date), "%m/%d/%Y - %H:%M:%S", curtime);
fprintf(fp, "L %s: SourceMod log file session started (file \"L%04d%02d%02d.log\") (Version \"%s\")\n", date, curtime->tm_year + 1900, curtime->tm_mon + 1, curtime->tm_mday, SOURCEMOD_VERSION);
}
LogToOpenFileEx(fp, vafmt, ap);
fclose(fp);
} else {
goto print_error;
}
return;
print_error:
char error[255];
libsys->GetPlatformError(error, sizeof(error));
LogFatal("[SM] Unexpected fatal logging error (file \"%s\")", m_NrmFileName.c_str());
LogFatal("[SM] Platform returned error: \"%s\"", error);
LogFatal("[SM] Logging has been disabled.");
m_Active = false;
LogToOpenFileEx(pFile, vafmt, ap);
fclose(pFile);
}
void Logger::LogError(const char *vafmt, ...)
@ -398,72 +229,20 @@ void Logger::LogErrorEx(const char *vafmt, va_list ap)
return;
}
time_t t = g_pSM->GetAdjustedTime();
tm *curtime = localtime(&t);
if (curtime->tm_mday != m_ErrCurDay)
FILE *pFile = _OpenError();
if (!pFile)
{
char _filename[256];
g_pSM->BuildPath(Path_SM, _filename, sizeof(_filename), "logs/errors_%04d%02d%02d.log", curtime->tm_year + 1900, curtime->tm_mon + 1, curtime->tm_mday);
m_ErrFileName.assign(_filename);
m_ErrCurDay = curtime->tm_mday;
m_ErrMapStart = false;
}
FILE *fp = fopen(m_ErrFileName.c_str(), "a+");
if (fp)
{
if (!m_ErrMapStart)
{
char date[32];
strftime(date, sizeof(date), "%m/%d/%Y - %H:%M:%S", curtime);
fprintf(fp, "L %s: SourceMod error session started\n", date);
fprintf(fp, "L %s: Info (map \"%s\") (file \"errors_%04d%02d%02d.log\")\n", date, m_CurMapName.c_str(), curtime->tm_year + 1900, curtime->tm_mon + 1, curtime->tm_mday);
m_ErrMapStart = true;
}
LogToOpenFileEx(fp, vafmt, ap);
fclose(fp);
}
else
{
char error[255];
libsys->GetPlatformError(error, sizeof(error));
LogFatal("[SM] Unexpected fatal logging error (file \"%s\")", m_NrmFileName.c_str());
LogFatal("[SM] Platform returned error: \"%s\"", error);
LogFatal("[SM] Logging has been disabled.");
m_Active = false;
return;
}
LogToOpenFileEx(pFile, vafmt, ap);
fclose(pFile);
}
void Logger::MapChange(const char *mapname)
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;
m_CurrentMapName = mapname;
_UpdateFiles(true);
}
void Logger::_PrintToGameLog(const char *fmt, va_list ap)
@ -480,30 +259,6 @@ void Logger::_PrintToGameLog(const char *fmt, va_list ap)
bridge->LogToGame(msg);
}
const char *Logger::GetLogFileName(LogType type) const
{
switch (type)
{
case LogType_Normal:
{
return m_NrmFileName.c_str();
}
case LogType_Error:
{
return m_ErrFileName.c_str();
}
default:
{
return "";
}
}
}
LoggingMode Logger::GetLoggingMode() const
{
return m_Mode;
}
void Logger::EnableLogging()
{
if (m_Active)
@ -539,16 +294,161 @@ void Logger::LogFatalEx(const char *msg, va_list ap)
* It's already implemented twice which is bad.
*/
char path[PLATFORM_MAX_PATH];
g_pSM->BuildPath(Path_Game, path, sizeof(path), "sourcemod_fatal.log");
FILE *fp = fopen(path, "at");
if (fp)
FILE *pFile = _OpenFatal();
if (!pFile)
{
m_Active = true;
LogToOpenFileEx(fp, msg, ap);
m_Active = false;
fclose(fp);
return;
}
LogToOpenFileEx(pFile, msg, ap);
fclose(pFile);
}
void Logger::_UpdateFiles(bool bLevelChange)
{
time_t t = g_pSM->GetAdjustedTime();
tm *curtime = localtime(&t);
if (!bLevelChange && curtime->tm_mday == m_Day)
{
return;
}
m_Day = curtime->tm_mday;
char buff[PLATFORM_MAX_PATH];
ke::SafeSprintf(buff, sizeof(buff), "%04d%02d%02d", curtime->tm_year + 1900, curtime->tm_mon + 1, curtime->tm_mday);
ke::AString currentDate(buff);
if (m_Mode == LoggingMode_PerMap)
{
if (bLevelChange)
{
for (size_t iter = 0; iter < static_cast<size_t>(-1); ++iter)
{
g_pSM->BuildPath(Path_SM, buff, sizeof(buff), "logs/L%s%u.log", currentDate.chars(), iter);
if (!libsys->IsPathFile(buff))
{
break;
}
}
}
else
{
ke::SafeStrcpy(buff, sizeof(buff), m_NormalFileName.chars());
}
}
else
{
g_pSM->BuildPath(Path_SM, buff, sizeof(buff), "logs/L%s.log", currentDate.chars());
}
if (m_NormalFileName.compare(buff))
{
_CloseNormal();
m_NormalFileName = buff;
}
else
{
if (bLevelChange)
{
LogMessage("-------- Mapchange to %s --------", m_CurrentMapName.chars());
}
}
g_pSM->BuildPath(Path_SM, buff, sizeof(buff), "logs/errors_%s.log", currentDate.chars());
if (bLevelChange || m_ErrorFileName.compare(buff))
{
_CloseError();
m_ErrorFileName = buff;
}
}
FILE *Logger::_OpenNormal()
{
_UpdateFiles();
FILE *pFile = fopen(m_NormalFileName.chars(), "a+");
if (pFile == NULL)
{
_LogFatalOpen(m_NormalFileName);
return pFile;
}
if (!m_DamagedNormalFile)
{
time_t t = g_pSM->GetAdjustedTime();
tm *curtime = localtime(&t);
char date[32];
strftime(date, sizeof(date), "%m/%d/%Y - %H:%M:%S", curtime);
fprintf(pFile, "L %s: SourceMod log file session started (file \"%s\") (Version \"%s\")\n", date, m_NormalFileName.chars(), SOURCEMOD_VERSION);
m_DamagedNormalFile = true;
}
return pFile;
}
FILE *Logger::_OpenError()
{
_UpdateFiles();
FILE *pFile = fopen(m_ErrorFileName.chars(), "a+");
if (pFile == NULL)
{
_LogFatalOpen(m_ErrorFileName);
return pFile;
}
if (!m_DamagedErrorFile)
{
time_t t = g_pSM->GetAdjustedTime();
tm *curtime = localtime(&t);
char date[32];
strftime(date, sizeof(date), "%m/%d/%Y - %H:%M:%S", curtime);
fprintf(pFile, "L %s: SourceMod error session started\n", date);
fprintf(pFile, "L %s: Info (map \"%s\") (file \"%s\")\n", date, m_CurrentMapName.chars(), m_ErrorFileName.chars());
m_DamagedErrorFile = true;
}
return pFile;
}
FILE *Logger::_OpenFatal()
{
char path[PLATFORM_MAX_PATH];
g_pSM->BuildPath(Path_Game, path, sizeof(path), "sourcemod_fatal.log");
return fopen(path, "at");
}
void Logger::_LogFatalOpen(ke::AString &str)
{
char error[255];
libsys->GetPlatformError(error, sizeof(error));
LogFatal("[SM] Unexpected fatal logging error (file \"%s\")", str.chars());
LogFatal("[SM] Platform returned error: \"%s\"", error);
}
void Logger::_CloseNormal()
{
if (m_DamagedNormalFile)
{
LogMessage("Log file closed.");
m_DamagedNormalFile = false;
}
}
void Logger::_CloseError()
{
if (m_DamagedErrorFile)
{
LogError("Error log file session closed.");
m_DamagedErrorFile = false;
}
}
void Logger::_CloseFatal()
{
}

View File

@ -34,11 +34,9 @@
#include "common_logic.h"
#include <stdio.h>
#include <sh_string.h>
#include <amtl/am-string.h>
#include <bridge/include/ILogger.h>
using namespace SourceHook;
enum LogType
{
LogType_Normal,
@ -55,9 +53,7 @@ enum LoggingMode
class Logger : public SMGlobalClass, public ILogger
{
public:
Logger() : m_Mode(LoggingMode_Daily), m_ErrMapStart(false),
m_Active(false), m_DelayedStart(false), m_DailyPrintHdr(false),
m_InitialState(true)
Logger() : m_Day(-1), m_Mode(LoggingMode_Daily), m_Active(true), m_DamagedNormalFile(false), m_DamagedErrorFile(false)
{
}
public: //SMGlobalClass
@ -70,7 +66,6 @@ public: //SMGlobalClass
void OnSourceModAllShutdown();
void OnSourceModLevelChange(const char *mapName);
public:
void InitLogger(LoggingMode mode);
void CloseLogger();
void EnableLogging();
void DisableLogging();
@ -85,25 +80,32 @@ public:
/* This version does not print to console, and is thus thread-safe */
void LogToFileOnly(FILE *fp, const char *msg, ...);
void LogToFileOnlyEx(FILE *fp, const char *msg, va_list ap);
void MapChange(const char *mapname);
const char *GetLogFileName(LogType type) const;
LoggingMode GetLoggingMode() const;
private:
void _MapChange(const char *mapname);
void _CloseFile();
void _NewMapFile();
void _CloseNormal();
void _CloseError();
void _CloseFatal();
FILE *_OpenNormal();
FILE *_OpenError();
FILE *_OpenFatal();
void _LogFatalOpen(ke::AString &str);
void _PrintToGameLog(const char *fmt, va_list ap);
void _UpdateFiles(bool bLevelChange = false);
private:
String m_NrmFileName;
String m_ErrFileName;
String m_CurMapName;
ke::AString m_NormalFileName;
ke::AString m_ErrorFileName;
ke::AString m_CurrentMapName;
int m_Day;
LoggingMode m_Mode;
int m_NrmCurDay;
int m_ErrCurDay;
bool m_ErrMapStart;
bool m_Active;
bool m_DelayedStart;
bool m_DailyPrintHdr;
bool m_InitialState;
bool m_DamagedNormalFile;
bool m_DamagedErrorFile;
};
extern Logger g_Logger;

View File

@ -43,18 +43,6 @@
#include <mach-o/dyld_images.h>
#include <mach-o/loader.h>
#include <mach-o/nlist.h>
/* Define things from 10.6 SDK for older SDKs */
#ifndef MAC_OS_X_VERSION_10_6
struct task_dyld_info
{
mach_vm_address_t all_image_info_addr;
mach_vm_size_t all_image_info_size;
};
typedef struct task_dyld_info task_dyld_info_data_t;
#define TASK_DYLD_INFO 17
#define TASK_DYLD_INFO_COUNT (sizeof(task_dyld_info_data_t) / sizeof(natural_t))
#endif // MAC_OS_X_VERSION_10_6
#endif // PLATFORM_APPLE
MemoryUtils g_MemUtils;
@ -63,25 +51,10 @@ MemoryUtils::MemoryUtils()
{
#ifdef PLATFORM_APPLE
Gestalt(gestaltSystemVersionMajor, &m_OSXMajor);
Gestalt(gestaltSystemVersionMinor, &m_OSXMinor);
/* Get pointer to struct that describes all loaded mach-o images in process */
if ((m_OSXMajor == 10 && m_OSXMinor >= 6) || m_OSXMajor > 10)
{
task_dyld_info_data_t dyld_info;
mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
task_info(mach_task_self(), TASK_DYLD_INFO, (task_info_t)&dyld_info, &count);
m_ImageList = (struct dyld_all_image_infos *)dyld_info.all_image_info_addr;
}
else
{
struct nlist list[2];
memset(list, 0, sizeof(list));
list[0].n_un.n_name = (char *)"_dyld_all_image_infos";
nlist("/usr/lib/dyld", list);
m_ImageList = (struct dyld_all_image_infos *)list[0].n_value;
}
task_dyld_info_data_t dyld_info;
mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
task_info(mach_task_self(), TASK_DYLD_INFO, (task_info_t)&dyld_info, &count);
m_ImageList = (struct dyld_all_image_infos *)dyld_info.all_image_info_addr;
#endif
}
@ -147,13 +120,25 @@ void *MemoryUtils::ResolveSymbol(void *handle, const char *symbol)
#elif defined PLATFORM_LINUX
#ifdef PLATFORM_X86
typedef Elf32_Ehdr ElfHeader;
typedef Elf32_Shdr ElfSHeader;
typedef Elf32_Sym ElfSymbol;
#define ELF_SYM_TYPE ELF32_ST_TYPE
#else
typedef Elf64_Ehdr ElfHeader;
typedef Elf64_Shdr ElfSHeader;
typedef Elf64_Sym ElfSymbol;
#define ELF_SYM_TYPE ELF64_ST_TYPE
#endif
struct link_map *dlmap;
struct stat dlstat;
int dlfile;
uintptr_t map_base;
Elf32_Ehdr *file_hdr;
Elf32_Shdr *sections, *shstrtab_hdr, *symtab_hdr, *strtab_hdr;
Elf32_Sym *symtab;
ElfHeader *file_hdr;
ElfSHeader *sections, *shstrtab_hdr, *symtab_hdr, *strtab_hdr;
ElfSymbol *symtab;
const char *shstrtab, *strtab;
uint16_t section_count;
uint32_t symbol_count;
@ -204,7 +189,7 @@ void *MemoryUtils::ResolveSymbol(void *handle, const char *symbol)
}
/* Map library file into memory */
file_hdr = (Elf32_Ehdr *)mmap(NULL, dlstat.st_size, PROT_READ, MAP_PRIVATE, dlfile, 0);
file_hdr = (ElfHeader *)mmap(NULL, dlstat.st_size, PROT_READ, MAP_PRIVATE, dlfile, 0);
map_base = (uintptr_t)file_hdr;
if (file_hdr == MAP_FAILED)
{
@ -219,7 +204,7 @@ void *MemoryUtils::ResolveSymbol(void *handle, const char *symbol)
return NULL;
}
sections = (Elf32_Shdr *)(map_base + file_hdr->e_shoff);
sections = (ElfSHeader *)(map_base + file_hdr->e_shoff);
section_count = file_hdr->e_shnum;
/* Get ELF section header string table */
shstrtab_hdr = &sections[file_hdr->e_shstrndx];
@ -228,7 +213,7 @@ void *MemoryUtils::ResolveSymbol(void *handle, const char *symbol)
/* Iterate sections while looking for ELF symbol table and string table */
for (uint16_t i = 0; i < section_count; i++)
{
Elf32_Shdr &hdr = sections[i];
ElfSHeader &hdr = sections[i];
const char *section_name = shstrtab + hdr.sh_name;
if (strcmp(section_name, ".symtab") == 0)
@ -248,15 +233,15 @@ void *MemoryUtils::ResolveSymbol(void *handle, const char *symbol)
return NULL;
}
symtab = (Elf32_Sym *)(map_base + symtab_hdr->sh_offset);
symtab = (ElfSymbol *)(map_base + symtab_hdr->sh_offset);
strtab = (const char *)(map_base + strtab_hdr->sh_offset);
symbol_count = symtab_hdr->sh_size / symtab_hdr->sh_entsize;
/* Iterate symbol table starting from the position we were at last time */
for (uint32_t i = libtable->last_pos; i < symbol_count; i++)
{
Elf32_Sym &sym = symtab[i];
unsigned char sym_type = ELF32_ST_TYPE(sym.st_info);
ElfSymbol &sym = symtab[i];
unsigned char sym_type = ELF_SYM_TYPE(sym.st_info);
const char *sym_name = strtab + sym.st_name;
Symbol *cur_sym;
@ -280,14 +265,29 @@ void *MemoryUtils::ResolveSymbol(void *handle, const char *symbol)
return symbol_entry ? symbol_entry->address : NULL;
#elif defined PLATFORM_APPLE
#ifdef PLATFORM_X86
typedef struct mach_header MachHeader;
typedef struct segment_command MachSegment;
typedef struct nlist MachSymbol;
const uint32_t MACH_LOADCMD_SEGMENT = LC_SEGMENT;
#else
typedef struct mach_header_64 MachHeader;
typedef struct segment_command_64 MachSegment;
typedef struct nlist_64 MachSymbol;
const uint32_t MACH_LOADCMD_SEGMENT = LC_SEGMENT_64;
#endif
typedef struct load_command MachLoadCmd;
typedef struct symtab_command MachSymHeader;
uintptr_t dlbase, linkedit_addr;
uint32_t image_count;
struct mach_header *file_hdr;
struct load_command *loadcmds;
struct segment_command *linkedit_hdr;
struct symtab_command *symtab_hdr;
struct nlist *symtab;
MachHeader *file_hdr;
MachLoadCmd *loadcmds;
MachSegment *linkedit_hdr;
MachSymHeader *symtab_hdr;
MachSymbol *symtab;
const char *strtab;
uint32_t loadcmd_count;
uint32_t symbol_count;
@ -357,16 +357,16 @@ void *MemoryUtils::ResolveSymbol(void *handle, const char *symbol)
/* If symbol isn't in our table, then we have to locate it in memory */
file_hdr = (struct mach_header *)dlbase;
loadcmds = (struct load_command *)(dlbase + sizeof(struct mach_header));
file_hdr = (MachHeader *)dlbase;
loadcmds = (MachLoadCmd *)(dlbase + sizeof(MachHeader));
loadcmd_count = file_hdr->ncmds;
/* Loop through load commands until we find the ones for the symbol table */
for (uint32_t i = 0; i < loadcmd_count; i++)
{
if (loadcmds->cmd == LC_SEGMENT && !linkedit_hdr)
if (loadcmds->cmd == MACH_LOADCMD_SEGMENT && !linkedit_hdr)
{
struct segment_command *seg = (struct segment_command *)loadcmds;
MachSegment *seg = (MachSegment *)loadcmds;
if (strcmp(seg->segname, "__LINKEDIT") == 0)
{
linkedit_hdr = seg;
@ -378,7 +378,7 @@ void *MemoryUtils::ResolveSymbol(void *handle, const char *symbol)
}
else if (loadcmds->cmd == LC_SYMTAB)
{
symtab_hdr = (struct symtab_command *)loadcmds;
symtab_hdr = (MachSymHeader *)loadcmds;
if (linkedit_hdr)
{
break;
@ -386,7 +386,7 @@ void *MemoryUtils::ResolveSymbol(void *handle, const char *symbol)
}
/* Load commands are not of a fixed size which is why we add the size */
loadcmds = (struct load_command *)((uintptr_t)loadcmds + loadcmds->cmdsize);
loadcmds = (MachLoadCmd *)((uintptr_t)loadcmds + loadcmds->cmdsize);
}
if (!linkedit_hdr || !symtab_hdr || !symtab_hdr->symoff || !symtab_hdr->stroff)
@ -396,14 +396,14 @@ void *MemoryUtils::ResolveSymbol(void *handle, const char *symbol)
}
linkedit_addr = dlbase + linkedit_hdr->vmaddr;
symtab = (struct nlist *)(linkedit_addr + symtab_hdr->symoff - linkedit_hdr->fileoff);
symtab = (MachSymbol *)(linkedit_addr + symtab_hdr->symoff - linkedit_hdr->fileoff);
strtab = (const char *)(linkedit_addr + symtab_hdr->stroff - linkedit_hdr->fileoff);
symbol_count = symtab_hdr->nsyms;
/* Iterate symbol table starting from the position we were at last time */
for (uint32_t i = libtable->last_pos; i < symbol_count; i++)
{
struct nlist &sym = symtab[i];
MachSymbol &sym = symtab[i];
/* Ignore the prepended underscore on all symbols, so +1 here */
const char *sym_name = strtab + sym.n_un.n_strx + 1;
Symbol *cur_sym;
@ -440,6 +440,12 @@ bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
#ifdef PLATFORM_WINDOWS
#ifdef PLATFORM_X86
const WORD PE_FILE_MACHINE = IMAGE_FILE_MACHINE_I386;
#else
const WORD PE_FILE_MACHINE = IMAGE_FILE_MACHINE_AMD64;
#endif
MEMORY_BASIC_INFORMATION info;
IMAGE_DOS_HEADER *dos;
IMAGE_NT_HEADERS *pe;
@ -465,10 +471,8 @@ bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
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)
/* Check architecture */
if (file->Machine != PE_FILE_MACHINE)
{
return false;
}
@ -484,9 +488,21 @@ bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
#elif defined PLATFORM_LINUX
#ifdef PLATFORM_X86
typedef Elf32_Ehdr ElfHeader;
typedef Elf32_Phdr ElfPHeader;
const unsigned char ELF_CLASS = ELFCLASS32;
const uint16_t ELF_MACHINE = EM_386;
#else
typedef Elf64_Ehdr ElfHeader;
typedef Elf64_Phdr ElfPHeader;
const unsigned char ELF_CLASS = ELFCLASS64;
const uint16_t ELF_MACHINE = EM_X86_64;
#endif
Dl_info info;
Elf32_Ehdr *file;
Elf32_Phdr *phdr;
ElfHeader *file;
ElfPHeader *phdr;
uint16_t phdrCount;
if (!dladdr(libPtr, &info))
@ -501,7 +517,7 @@ bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
/* This is for our insane sanity checks :o */
baseAddr = reinterpret_cast<uintptr_t>(info.dli_fbase);
file = reinterpret_cast<Elf32_Ehdr *>(baseAddr);
file = reinterpret_cast<ElfHeader *>(baseAddr);
/* Check ELF magic */
if (memcmp(ELFMAG, file->e_ident, SELFMAG) != 0)
@ -514,11 +530,15 @@ bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
{
return false;
}
/* Check ELF endianness */
if (file->e_ident[EI_DATA] != ELFDATA2LSB)
{
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)
/* Check ELF architecture */
if (file->e_ident[EI_CLASS] != ELF_CLASS || file->e_machine != ELF_MACHINE)
{
return false;
}
@ -530,11 +550,11 @@ bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
}
phdrCount = file->e_phnum;
phdr = reinterpret_cast<Elf32_Phdr *>(baseAddr + file->e_phoff);
phdr = reinterpret_cast<ElfPHeader *>(baseAddr + file->e_phoff);
for (uint16_t i = 0; i < phdrCount; i++)
{
Elf32_Phdr &hdr = phdr[i];
ElfPHeader &hdr = phdr[i];
/* We only really care about the segment with executable code */
if (hdr.p_type == PT_LOAD && hdr.p_flags == (PF_X|PF_R))
@ -553,9 +573,25 @@ bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
#elif defined PLATFORM_APPLE
#ifdef PLATFORM_X86
typedef struct mach_header MachHeader;
typedef struct segment_command MachSegment;
const uint32_t MACH_MAGIC = MH_MAGIC;
const uint32_t MACH_LOADCMD_SEGMENT = LC_SEGMENT;
const cpu_type_t MACH_CPU_TYPE = CPU_TYPE_I386;
const cpu_subtype_t MACH_CPU_SUBTYPE = CPU_SUBTYPE_I386_ALL;
#else
typedef struct mach_header_64 MachHeader;
typedef struct segment_command_64 MachSegment;
const uint32_t MACH_MAGIC = MH_MAGIC_64;
const uint32_t MACH_LOADCMD_SEGMENT = LC_SEGMENT_64;
const cpu_type_t MACH_CPU_TYPE = CPU_TYPE_X86_64;
const cpu_subtype_t MACH_CPU_SUBTYPE = CPU_SUBTYPE_X86_64_ALL;
#endif
Dl_info info;
struct mach_header *file;
struct segment_command *seg;
MachHeader *file;
MachSegment *seg;
uint32_t cmd_count;
if (!dladdr(libPtr, &info))
@ -570,16 +606,16 @@ bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
/* This is for our insane sanity checks :o */
baseAddr = (uintptr_t)info.dli_fbase;
file = (struct mach_header *)baseAddr;
file = (MachHeader *)baseAddr;
/* Check Mach-O magic */
if (file->magic != MH_MAGIC)
if (file->magic != MACH_MAGIC)
{
return false;
}
/* Check architecture (32-bit/x86) */
if (file->cputype != CPU_TYPE_I386 || file->cpusubtype != CPU_SUBTYPE_I386_ALL)
/* Check architecture */
if (file->cputype != MACH_CPU_TYPE || file->cpusubtype != MACH_CPU_SUBTYPE)
{
return false;
}
@ -591,17 +627,17 @@ bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
}
cmd_count = file->ncmds;
seg = (struct segment_command *)(baseAddr + sizeof(struct mach_header));
seg = (MachSegment *)(baseAddr + sizeof(MachHeader));
/* Add up memory sizes of mapped segments */
for (uint32_t i = 0; i < cmd_count; i++)
{
if (seg->cmd == LC_SEGMENT)
if (seg->cmd == MACH_LOADCMD_SEGMENT)
{
lib.memorySize += seg->vmsize;
}
seg = (struct segment_command *)((uintptr_t)seg + seg->cmdsize);
seg = (MachSegment *)((uintptr_t)seg + seg->cmdsize);
}
#endif

View File

@ -33,9 +33,11 @@
#include <IShareSys.h>
#include <IHandleSys.h>
#include <am-autoptr.h>
#include <am-string.h>
#include <am-utility.h>
#include <am-refcounting.h>
#include <sm_stringhashmap.h>
#include "common_logic.h"
class CNativeOwner;
@ -89,10 +91,14 @@ struct Native : public ke::Refcounted<Native>
return fake->name.chars();
}
static inline bool matches(const char *name, const ke::Ref<Native> &entry)
static inline bool matches(const char *name, const ke::RefPtr<Native> &entry)
{
return strcmp(name, entry->name()) == 0;
}
static inline uint32_t hash(const detail::CharsAndLength &key)
{
return key.hash();
}
};

View File

@ -73,7 +73,7 @@ void CNativeOwner::UnbindWeakRef(const WeakNative &ref)
pContext->GetRuntime()->UpdateNativeBinding(
ref.idx,
nullptr,
0,
SP_NTVFLAG_OPTIONAL,
nullptr);
}

View File

@ -81,7 +81,7 @@ protected:
unsigned int m_nMarkSerial;
List<WeakNative> m_WeakRefs;
ke::Vector<const sp_nativeinfo_t *> m_natives;
ke::Vector<ke::Ref<Native> > m_fakes;
ke::Vector<ke::RefPtr<Native> > m_fakes;
};
extern CNativeOwner g_CoreNatives;

View File

@ -89,6 +89,19 @@ IPhraseFile *CPhraseCollection::GetFile(unsigned int file)
return m_Files[file];
}
bool CPhraseCollection::TranslationPhraseExists(const char *key)
{
for (size_t i = 0; i < m_Files.size(); i++)
{
if (m_Files[i]->TranslationPhraseExists(key))
{
return true;
}
}
return false;
}
TransError CPhraseCollection::FindTranslation(const char *key, unsigned int langid, Translation *pTrans)
{
size_t i;

View File

@ -49,6 +49,7 @@ public:
unsigned int GetFileCount();
IPhraseFile *GetFile(unsigned int file);
void Destroy();
bool TranslationPhraseExists(const char *key);
TransError FindTranslation(const char *key, unsigned int langid, Translation *pTrans);
bool FormatString(
char *buffer,

View File

@ -75,7 +75,7 @@ CPlugin::CPlugin(const char *file)
m_serial = ++MySerial;
m_errormsg[0] = '\0';
m_DateTime[0] = '\0';
ke::SafeSprintf(m_filename, sizeof(m_filename), "%s", file);
ke::SafeStrcpy(m_filename, sizeof(m_filename), file);
memset(&m_info, 0, sizeof(m_info));
@ -251,7 +251,7 @@ void CPlugin::EvictWithError(PluginStatus status, const char *error_fmt, ...)
ke::SafeVsprintf(m_errormsg, sizeof(m_errormsg), error_fmt, ap);
va_end(ap);
if (m_pRuntime != NULL)
if (m_pRuntime)
{
m_pRuntime->SetPauseState(true);
}
@ -499,7 +499,7 @@ bool CPlugin::TryCompile()
IPluginContext *CPlugin::GetBaseContext()
{
if (m_pRuntime == NULL)
if (!m_pRuntime)
{
return NULL;
}
@ -558,7 +558,7 @@ bool CPlugin::IsSilentlyFailed()
bool CPlugin::IsDebugging()
{
if (m_pRuntime == NULL)
if (!m_pRuntime)
{
return false;
}
@ -676,7 +676,7 @@ void CPlugin::DependencyDropped(CPlugin *pOwner)
unsigned int unbound = 0;
for (size_t i = 0; i < pOwner->m_fakes.length(); i++)
{
ke::Ref<Native> entry(pOwner->m_fakes[i]);
ke::RefPtr<Native> entry(pOwner->m_fakes[i]);
uint32_t idx;
if (m_pRuntime->FindNativeByName(entry->name(), &idx) != SP_ERROR_NONE)
@ -769,7 +769,7 @@ void CPlugin::DropEverything()
bool CPlugin::AddFakeNative(IPluginFunction *pFunc, const char *name, SPVM_FAKENATIVE_FUNC func)
{
ke::Ref<Native> entry = g_ShareSys.AddFakeNative(pFunc, name, func);
ke::RefPtr<Native> entry = g_ShareSys.AddFakeNative(pFunc, name, func);
if (!entry)
return false;
@ -905,7 +905,7 @@ void CPluginManager::LoadPluginsFromDir(const char *basedir, const char *localpa
if (localpath == NULL)
{
/* If no path yet, don't add a former slash */
ke::SafeSprintf(new_local, sizeof(new_local), "%s", dir->GetEntryName());
ke::SafeStrcpy(new_local, sizeof(new_local), dir->GetEntryName());
} else {
libsys->PathFormat(new_local, sizeof(new_local), "%s/%s", localpath, dir->GetEntryName());
}
@ -920,7 +920,7 @@ void CPluginManager::LoadPluginsFromDir(const char *basedir, const char *localpa
char plugin[PLATFORM_MAX_PATH];
if (localpath == NULL)
{
ke::SafeSprintf(plugin, sizeof(plugin), "%s", name);
ke::SafeStrcpy(plugin, sizeof(plugin), name);
} else {
libsys->PathFormat(plugin, sizeof(plugin), "%s/%s", localpath, name);
}
@ -994,9 +994,9 @@ IPlugin *CPluginManager::LoadPlugin(const char *path, bool debug, PluginType typ
if (res == LoadRes_NeverLoad) {
if (m_LoadingLocked)
ke::SafeSprintf(error, maxlength, "There is a global plugin loading lock in effect");
ke::SafeStrcpy(error, maxlength, "There is a global plugin loading lock in effect");
else
ke::SafeSprintf(error, maxlength, "This plugin is blocked from loading (see plugin_settings.cfg)");
ke::SafeStrcpy(error, maxlength, "This plugin is blocked from loading (see plugin_settings.cfg)");
return NULL;
}
@ -1108,7 +1108,7 @@ bool CPluginManager::FindOrRequirePluginDeps(CPlugin *pPlugin)
/* Check that we aren't registering the same library twice */
pPlugin->AddRequiredLib(name);
CPlugin *found;
CPlugin *found = nullptr;
for (PluginIter iter(m_plugins); !iter.done(); iter.next()) {
CPlugin *pl = (*iter);
if (pl->HasLibrary(name)) {
@ -1192,10 +1192,11 @@ void CPlugin::SetRegistered()
m_state = PluginState::Registered;
}
void CPlugin::SetWaitingToUnload()
void CPlugin::SetWaitingToUnload(bool andReload)
{
assert(m_state == PluginState::Registered);
m_state = PluginState::WaitingToUnload;
assert(m_state == PluginState::Registered ||
(m_state == PluginState::WaitingToUnload && andReload));
m_state = andReload ? PluginState::WaitingToUnloadAndReload : PluginState::WaitingToUnload;
}
void CPluginManager::LoadExtensions(CPlugin *pPlugin)
@ -1276,7 +1277,7 @@ bool CPluginManager::MalwareCheckPass(CPlugin *pPlugin)
unsigned char *pCodeHash = pPlugin->GetRuntime()->GetCodeHash();
char codeHashBuf[40];
ke::SafeSprintf(codeHashBuf, 40, "plugin_");
ke::SafeStrcpy(codeHashBuf, sizeof(codeHashBuf), "plugin_");
for (int i = 0; i < 16; i++)
ke::SafeSprintf(codeHashBuf + 7 + (i * 2), 3, "%02x", pCodeHash[i]);
@ -1435,17 +1436,16 @@ void CPluginManager::TryRefreshDependencies(CPlugin *pPlugin)
bool CPluginManager::UnloadPlugin(IPlugin *plugin)
{
CPlugin *pPlugin = (CPlugin *)plugin;
return ScheduleUnload(pPlugin);
}
bool CPluginManager::ScheduleUnload(CPlugin *pPlugin)
{
// Should not be recursively removing.
assert(m_plugins.contains(pPlugin));
// If we're already in the unload queue, just wait.
if (pPlugin->State() == PluginState::WaitingToUnload)
if (pPlugin->State() == PluginState::WaitingToUnload ||
pPlugin->State() == PluginState::WaitingToUnloadAndReload)
{
return false;
}
// It is not safe to unload any plugin while another is on the callstack.
bool any_active = false;
@ -1460,8 +1460,8 @@ bool CPluginManager::ScheduleUnload(CPlugin *pPlugin)
if (any_active) {
pPlugin->SetWaitingToUnload();
ScheduleTaskForNextFrame([this, pPlugin] () -> void {
ScheduleUnload(pPlugin);
ScheduleTaskForNextFrame([this, pPlugin]() -> void {
UnloadPluginImpl(pPlugin);
});
return false;
}
@ -1607,7 +1607,7 @@ ConfigResult CPluginManager::OnSourceModConfigChanged(const char *key,
} else if (strcasecmp(value, "no") == 0) {
m_bBlockBadPlugins = false;
} else {
ke::SafeSprintf(error, maxlength, "Invalid value: must be \"yes\" or \"no\"");
ke::SafeStrcpy(error, maxlength, "Invalid value: must be \"yes\" or \"no\"");
return ConfigResult_Reject;
}
return ConfigResult_Accept;
@ -1733,7 +1733,7 @@ void CPluginManager::OnRootConsoleCommand(const char *cmdname, const ICommandArg
if (pl->GetStatus() < Plugin_Created || pl->GetStatus() == Plugin_Evicted)
{
if (pl->IsSilentlyFailed())
len += ke::SafeSprintf(&buffer[len], sizeof(buffer)-len, " Disabled:");
len += ke::SafeStrcpy(&buffer[len], sizeof(buffer)-len, " Disabled:");
len += ke::SafeSprintf(&buffer[len], sizeof(buffer)-len, " \"%s\"", (IS_STR_FILLED(info->name)) ? info->name : pl->GetFilename());
if (IS_STR_FILLED(info->version))
{
@ -1842,11 +1842,11 @@ void CPluginManager::OnRootConsoleCommand(const char *cmdname, const ICommandArg
if (pl->GetStatus() < Plugin_Created)
{
const sm_plugininfo_t *info = pl->GetPublicInfo();
ke::SafeSprintf(name, sizeof(name), (IS_STR_FILLED(info->name)) ? info->name : pl->GetFilename());
ke::SafeStrcpy(name, sizeof(name), (IS_STR_FILLED(info->name)) ? info->name : pl->GetFilename());
}
else
{
ke::SafeSprintf(name, sizeof(name), "%s", pl->GetFilename());
ke::SafeStrcpy(name, sizeof(name), pl->GetFilename());
}
if (UnloadPlugin(pl))
@ -1855,7 +1855,7 @@ void CPluginManager::OnRootConsoleCommand(const char *cmdname, const ICommandArg
}
else
{
rootmenu->ConsolePrint("[SM] Failed to unload plugin %s.", name);
rootmenu->ConsolePrint("[SM] Plugin %s will be unloaded on the next frame.", name);
}
return;
@ -2019,13 +2019,22 @@ void CPluginManager::OnRootConsoleCommand(const char *cmdname, const ICommandArg
else
strcpy(name, pl->GetFilename());
if (ReloadPlugin(pl))
if (ReloadPlugin(pl, true))
{
rootmenu->ConsolePrint("[SM] Plugin %s reloaded successfully.", name);
}
else
{
rootmenu->ConsolePrint("[SM] Failed to reload plugin %s.", name);
switch (pl->State())
{
//the unload/reload attempt next frame will print a message
case PluginState::WaitingToUnload:
case PluginState::WaitingToUnloadAndReload:
return;
default:
rootmenu->ConsolePrint("[SM] Failed to reload plugin %s.", name);
}
}
return;
@ -2045,15 +2054,14 @@ void CPluginManager::OnRootConsoleCommand(const char *cmdname, const ICommandArg
rootmenu->DrawGenericOption("unload_all", "Unloads all plugins");
}
bool CPluginManager::ReloadPlugin(CPlugin *pl)
bool CPluginManager::ReloadPlugin(CPlugin *pl, bool print)
{
char filename[PLATFORM_MAX_PATH];
bool wasloaded;
PluginType ptype;
IPlugin *newpl;
PluginState state = pl->State();
if (state == PluginState::WaitingToUnloadAndReload)
return false;
strcpy(filename, pl->GetFilename());
ptype = pl->GetType();
ke::AString filename(pl->GetFilename());
PluginType ptype = pl->GetType();
int id = 1;
for (PluginIter iter(m_plugins); !iter.done(); iter.next(), id++) {
@ -2063,13 +2071,34 @@ bool CPluginManager::ReloadPlugin(CPlugin *pl)
if (!UnloadPlugin(pl))
{
if (pl->State() == PluginState::WaitingToUnload)
{
pl->SetWaitingToUnload(true);
ScheduleTaskForNextFrame([this, id, filename, ptype, print]() -> void {
ReloadPluginImpl(id, filename.chars(), ptype, print);
});
}
return false;
}
if (!(newpl=LoadPlugin(filename, true, ptype, NULL, 0, &wasloaded)))
ReloadPluginImpl(id, filename.chars(), ptype, false);
return true;
}
void CPluginManager::ReloadPluginImpl(int id, const char filename[], PluginType ptype, bool print)
{
char error[128];
bool wasloaded;
IPlugin *newpl = LoadPlugin(filename, true, ptype, error, sizeof(error), &wasloaded);
if (!newpl)
{
return false;
rootmenu->ConsolePrint("[SM] Plugin %s failed to reload: %s.", filename, error);
return;
}
if (print)
rootmenu->ConsolePrint("[SM] Plugin %s reloaded successfully.", filename);
m_plugins.remove(static_cast<CPlugin *>(newpl));
PluginIter iter(m_plugins);
@ -2077,8 +2106,6 @@ bool CPluginManager::ReloadPlugin(CPlugin *pl)
// Empty loop.
}
m_plugins.insertBefore(iter, static_cast<CPlugin *>(newpl));
return true;
}
void CPluginManager::RefreshAll()
@ -2319,7 +2346,7 @@ public:
void AddPluginsListener_V1(IPluginsListener_V1 *listener) override
{
ke::Ref<PluginsListenerV1Wrapper> wrapper = new PluginsListenerV1Wrapper(listener);
ke::RefPtr<PluginsListenerV1Wrapper> wrapper = new PluginsListenerV1Wrapper(listener);
v1_wrappers_.append(wrapper);
g_PluginSys.AddPluginsListener(wrapper);
@ -2327,7 +2354,7 @@ public:
void RemovePluginsListener_V1(IPluginsListener_V1 *listener) override
{
ke::Ref<PluginsListenerV1Wrapper> wrapper;
ke::RefPtr<PluginsListenerV1Wrapper> wrapper;
// Find which wrapper has this listener.
for (decltype(v1_wrappers_)::iterator iter(v1_wrappers_); !iter.done(); iter.next()) {
@ -2356,7 +2383,7 @@ public:
}
private:
ReentrantList<ke::Ref<PluginsListenerV1Wrapper>> v1_wrappers_;
ReentrantList<ke::RefPtr<PluginsListenerV1Wrapper>> v1_wrappers_;
};
static OldPluginAPI sOldPluginAPI;
@ -2364,4 +2391,4 @@ static OldPluginAPI sOldPluginAPI;
IPluginManager *CPluginManager::GetOldAPI()
{
return &sOldPluginAPI;
}
}

View File

@ -88,7 +88,8 @@ enum class PluginState
Evicted,
// The plugin is waiting to be unloaded.
WaitingToUnload
WaitingToUnload,
WaitingToUnloadAndReload,
};
class CPlugin :
@ -142,11 +143,6 @@ public:
*/
static CPlugin *Create(const char *file);
static inline bool matches(const char *file, const CPlugin *plugin)
{
return strcmp(plugin->m_filename, file) == 0;
}
public:
// Evicts the plugin from memory and sets an error state.
void EvictWithError(PluginStatus status, const char *error_fmt, ...);
@ -176,7 +172,7 @@ public:
return m_state;
}
void SetRegistered();
void SetWaitingToUnload();
void SetWaitingToUnload(bool andReload=false);
PluginStatus GetDisplayStatus() const {
return m_status;
@ -426,7 +422,7 @@ public:
bool LibraryExists(const char *lib);
bool ReloadPlugin(CPlugin *pl);
bool ReloadPlugin(CPlugin *pl, bool print=false);
void UnloadAll();
@ -462,8 +458,8 @@ private:
bool RequireExtensions(CPlugin *pPlugin);
bool FindOrRequirePluginDeps(CPlugin *pPlugin);
bool ScheduleUnload(CPlugin *plugin);
void UnloadPluginImpl(CPlugin *plugin);
void ReloadPluginImpl(int id, const char filename[], PluginType ptype, bool print);
void Purge(CPlugin *plugin);
public:
@ -482,7 +478,36 @@ private:
typedef decltype(m_listeners)::iterator ListenerIter;
typedef decltype(m_plugins)::iterator PluginIter;
NameHashSet<CPlugin *> m_LoadLookup;
struct CPluginPolicy
{
static inline uint32_t hash(const detail::CharsAndLength &key)
{
/* For windows & mac, we convert the path to lower-case in order to avoid duplicate plugin loading */
#if defined PLATFORM_WINDOWS || defined PLATFORM_APPLE
ke::AString original(key.chars());
ke::AString lower = original.lowercase();
return detail::CharsAndLength(lower.chars()).hash();
#else
return key.hash();
#endif
}
static inline bool matches(const char *file, const CPlugin *plugin)
{
const char *pluginFileChars = const_cast<CPlugin*>(plugin)->GetFilename();
#if defined PLATFORM_WINDOWS || defined PLATFORM_APPLE
ke::AString pluginFile = ke::AString(pluginFileChars).lowercase();
ke::AString input = ke::AString(file).lowercase();
return pluginFile == input;
#else
return strcmp(pluginFileChars, file) == 0;
#endif
}
};
NameHashSet<CPlugin *, CPluginPolicy> m_LoadLookup;
bool m_AllPluginsLoaded;
IdentityToken_t *m_MyIdent;

View File

@ -0,0 +1,169 @@
/**
* vim: set ts=4 :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2017 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 "PseudoAddrManager.h"
#ifdef PLATFORM_APPLE
#include <mach/mach.h>
#include <mach/vm_region.h>
#endif
#ifdef PLATFORM_LINUX
#include <inttypes.h>
#endif
PseudoAddressManager::PseudoAddressManager() : m_NumEntries(0)
{
}
// A pseudo address consists of a table index in the upper 6 bits and an offset in the
// lower 26 bits. The table consists of memory allocation base addresses.
void *PseudoAddressManager::FromPseudoAddress(uint32_t paddr)
{
#ifdef PLATFORM_X64
uint8_t index = paddr >> PSEUDO_OFFSET_BITS;
uint32_t offset = paddr & ((1 << PSEUDO_OFFSET_BITS) - 1);
if (index >= m_NumEntries)
return nullptr;
return reinterpret_cast<void *>(uintptr_t(m_AllocBases[index]) + offset);
#else
return nullptr;
#endif
}
uint32_t PseudoAddressManager::ToPseudoAddress(void *addr)
{
#ifdef PLATFORM_X64
uint8_t index = 0;
uint32_t offset = 0;
bool hasEntry = false;
void *base = GetAllocationBase(addr);
if (base) {
for (int i = 0; i < m_NumEntries; i++) {
if (m_AllocBases[i] == base) {
index = i;
hasEntry = true;
break;
}
}
} else {
return 0;
}
if (!hasEntry) {
index = m_NumEntries;
if (m_NumEntries < SM_ARRAYSIZE(m_AllocBases))
m_AllocBases[m_NumEntries++] = base;
else
return 0; // Table is full
}
ptrdiff_t diff = uintptr_t(addr) - uintptr_t(base);
// Ensure difference fits in 26 bits
if (diff > (UINT32_MAX >> PSEUDO_INDEX_BITS))
return 0;
return (index << PSEUDO_OFFSET_BITS) | diff;
#else
return 0;
#endif
}
void *PseudoAddressManager::GetAllocationBase(void *ptr)
{
#if defined PLATFORM_WINDOWS
MEMORY_BASIC_INFORMATION info;
if (!VirtualQuery(ptr, &info, sizeof(MEMORY_BASIC_INFORMATION)))
return nullptr;
return info.AllocationBase;
#elif defined PLATFORM_APPLE
#ifdef PLATFORM_X86
typedef vm_region_info_t mach_vm_region_info_t;
typedef vm_region_basic_info_data_t mach_vm_region_basic_info_data_t;
const vm_region_flavor_t MACH_VM_REGION_BASIC_INFO = VM_REGION_BASIC_INFO;
const mach_msg_type_number_t MACH_VM_REGION_BASIC_INFO_COUNT = VM_REGION_BASIC_INFO_COUNT;
#define mach_vm_region vm_region
#elif defined PLATFORM_X64
typedef vm_region_info_64_t mach_vm_region_info_t ;
typedef vm_region_basic_info_data_64_t mach_vm_region_basic_info_data_t;
const vm_region_flavor_t MACH_VM_REGION_BASIC_INFO = VM_REGION_BASIC_INFO_64;
const mach_msg_type_number_t MACH_VM_REGION_BASIC_INFO_COUNT = VM_REGION_BASIC_INFO_COUNT_64;
#define mach_vm_region vm_region_64
#endif
vm_size_t size;
vm_address_t vmaddr = reinterpret_cast<vm_address_t>(ptr);
mach_vm_region_basic_info_data_t info;
memory_object_name_t obj;
vm_region_flavor_t flavor = MACH_VM_REGION_BASIC_INFO;
mach_msg_type_number_t count = MACH_VM_REGION_BASIC_INFO_COUNT;
kern_return_t kr = mach_vm_region(mach_task_self(), &vmaddr, &size, flavor,
reinterpret_cast<mach_vm_region_info_t>(&info),
&count, &obj);
if (kr != KERN_SUCCESS)
return nullptr;
return reinterpret_cast<void *>(vmaddr);
#elif defined PLATFORM_LINUX
uintptr_t addr = reinterpret_cast<uintptr_t>(ptr);
// Format:
// lower upper prot stuff path
// 08048000-0804c000 r-xp 00000000 03:03 1010107 /bin/cat
FILE *fp = fopen("/proc/self/maps", "r");
if (fp) {
uintptr_t lower, upper;
while (fscanf(fp, "%" PRIxPTR "-%" PRIxPTR, &lower, &upper) != EOF) {
if (addr >= lower && addr <= upper) {
fclose(fp);
return reinterpret_cast<void *>(lower);
}
// Read to end of line
int c;
while ((c = fgetc(fp)) != '\n') {
if (c == EOF)
break;
}
if (c == EOF)
break;
}
fclose(fp);
}
return nullptr;
#endif
}

View File

@ -0,0 +1,51 @@
/**
* vim: set ts=4 :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2017 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_PSEUDOADDRESSMANAGER_H_
#define _INCLUDE_SOURCEMOD_PSEUDOADDRESSMANAGER_H_
#include "common_logic.h"
class PseudoAddressManager
{
public:
PseudoAddressManager();
public:
void *FromPseudoAddress(uint32_t paddr);
uint32_t ToPseudoAddress(void *addr);
private:
void *GetAllocationBase(void *ptr);
private:
static constexpr uint8_t PSEUDO_OFFSET_BITS = 26;
static constexpr uint8_t PSEUDO_INDEX_BITS = sizeof(uint32_t) * 8 - PSEUDO_OFFSET_BITS;
void *m_AllocBases[1 << PSEUDO_INDEX_BITS];
uint8_t m_NumEntries;
};
#endif // _INCLUDE_SOURCEMOD_PSEUDOADDRESSMANAGER_H_

View File

@ -166,7 +166,7 @@ void RootConsoleMenu::DrawGenericOption(const char *cmd, const char *text)
{
buffer[len++] = ' ';
}
len += snprintf(&buffer[len], sizeof(buffer) - len, " - %s", text);
len += ke::SafeSprintf(&buffer[len], sizeof(buffer) - len, " - %s", text);
ConsolePrint("%s", buffer);
}
}
@ -256,7 +256,7 @@ static bool sm_dump_handles(int client, const ICommandArgs *args)
auto write_handles_to_game = [] (const char *str) -> void
{
char buffer[1024];
size_t len = ke::SafeSprintf(buffer, sizeof(buffer)-2, "%s", str);
size_t len = ke::SafeStrcpy(buffer, sizeof(buffer)-2, str);
buffer[len] = '\n';
buffer[len+1] = '\0';

View File

@ -46,6 +46,10 @@ struct ConsoleEntry
{
return strcmp(name, entry->command.c_str()) == 0;
}
static inline uint32_t hash(const detail::CharsAndLength &key)
{
return key.hash();
}
};
class RootConsoleMenu :

View File

@ -261,11 +261,11 @@ void ShareSystem::OverrideNatives(IExtension *myself, const sp_nativeinfo_t *nat
assert(false);
}
PassRef<Native> ShareSystem::FindNative(const char *name)
RefPtr<Native> ShareSystem::FindNative(const char *name)
{
NativeCache::Result r = m_NtvCache.find(name);
if (!r.found())
return NULL;
return nullptr;
return *r;
}
@ -292,7 +292,7 @@ void ShareSystem::BindNativesToPlugin(CPlugin *pPlugin, bool bCoreOnly)
continue;
/* Otherwise, the native must be in our cache. */
Ref<Native> pEntry = FindNative(native->name);
RefPtr<Native> pEntry = FindNative(native->name);
if (!pEntry)
continue;
@ -303,7 +303,7 @@ void ShareSystem::BindNativesToPlugin(CPlugin *pPlugin, bool bCoreOnly)
}
}
void ShareSystem::BindNativeToPlugin(CPlugin *pPlugin, const Ref<Native> &entry)
void ShareSystem::BindNativeToPlugin(CPlugin *pPlugin, const RefPtr<Native> &entry)
{
if (!entry->owner)
return;
@ -325,7 +325,7 @@ void ShareSystem::BindNativeToPlugin(CPlugin *pPlugin, const Ref<Native> &entry)
}
void ShareSystem::BindNativeToPlugin(CPlugin *pPlugin, const sp_native_t *native, uint32_t index,
const Ref<Native> &pEntry)
const RefPtr<Native> &pEntry)
{
uint32_t flags = 0;
if (pEntry->fake)
@ -341,6 +341,8 @@ void ShareSystem::BindNativeToPlugin(CPlugin *pPlugin, const sp_native_t *native
/* The native is optional, this is a special case */
if ((native->flags & SP_NTVFLAG_OPTIONAL) == SP_NTVFLAG_OPTIONAL)
{
flags |= SP_NTVFLAG_OPTIONAL;
/* Only add if there is a valid owner. */
if (!pEntry->owner)
return;
@ -368,15 +370,15 @@ void ShareSystem::BindNativeToPlugin(CPlugin *pPlugin, const sp_native_t *native
nullptr);
}
PassRef<Native> ShareSystem::AddNativeToCache(CNativeOwner *pOwner, const sp_nativeinfo_t *ntv)
AlreadyRefed<Native> ShareSystem::AddNativeToCache(CNativeOwner *pOwner, const sp_nativeinfo_t *ntv)
{
NativeCache::Insert i = m_NtvCache.findForAdd(ntv->name);
if (i.found())
return NULL;
return nullptr;
Ref<Native> entry = new Native(pOwner, ntv);
RefPtr<Native> entry = new Native(pOwner, ntv);
m_NtvCache.insert(ntv->name, entry);
return entry;
return entry.forget();
}
FakeNative::~FakeNative()
@ -390,7 +392,7 @@ void ShareSystem::ClearNativeFromCache(CNativeOwner *pOwner, const char *name)
if (!r.found())
return;
Ref<Native> entry(*r);
RefPtr<Native> entry(*r);
if (entry->owner != pOwner)
return;
@ -400,24 +402,24 @@ void ShareSystem::ClearNativeFromCache(CNativeOwner *pOwner, const char *name)
m_NtvCache.remove(r);
}
PassRef<Native> ShareSystem::AddFakeNative(IPluginFunction *pFunc, const char *name, SPVM_FAKENATIVE_FUNC func)
AlreadyRefed<Native> ShareSystem::AddFakeNative(IPluginFunction *pFunc, const char *name, SPVM_FAKENATIVE_FUNC func)
{
Ref<Native> entry(FindNative(name));
RefPtr<Native> entry(FindNative(name));
if (entry)
return NULL;
return nullptr;
AutoPtr<FakeNative> fake(new FakeNative(name, pFunc));
fake->gate = g_pSourcePawn2->CreateFakeNative(func, fake);
if (!fake->gate)
return NULL;
return nullptr;
CNativeOwner *owner = g_PluginSys.GetPluginByCtx(fake->ctx->GetContext());
entry = new Native(owner, fake.take());
m_NtvCache.insert(name, entry);
return entry;
return entry.forget();
}
void ShareSystem::AddCapabilityProvider(IExtension *myself, IFeatureProvider *provider,
@ -475,7 +477,7 @@ FeatureStatus ShareSystem::TestNative(IPluginRuntime *pRuntime, const char *name
}
}
Ref<Native> entry = FindNative(name);
RefPtr<Native> entry = FindNative(name);
if (!entry)
return FeatureStatus_Unknown;

View File

@ -121,15 +121,15 @@ public:
public:
void BeginBindingFor(CPlugin *pPlugin);
void BindNativesToPlugin(CPlugin *pPlugin, bool bCoreOnly);
void BindNativeToPlugin(CPlugin *pPlugin, const ke::Ref<Native> &pEntry);
ke::PassRef<Native> AddFakeNative(IPluginFunction *pFunc, const char *name, SPVM_FAKENATIVE_FUNC func);
ke::PassRef<Native> FindNative(const char *name);
void BindNativeToPlugin(CPlugin *pPlugin, const ke::RefPtr<Native> &pEntry);
ke::AlreadyRefed<Native> AddFakeNative(IPluginFunction *pFunc, const char *name, SPVM_FAKENATIVE_FUNC func);
ke::RefPtr<Native> FindNative(const char *name);
private:
ke::PassRef<Native> AddNativeToCache(CNativeOwner *pOwner, const sp_nativeinfo_t *ntv);
ke::AlreadyRefed<Native> AddNativeToCache(CNativeOwner *pOwner, const sp_nativeinfo_t *ntv);
void ClearNativeFromCache(CNativeOwner *pOwner, const char *name);
void BindNativeToPlugin(CPlugin *pPlugin, const sp_native_t *ntv, uint32_t index, const ke::Ref<Native> &pEntry);
void BindNativeToPlugin(CPlugin *pPlugin, const sp_native_t *ntv, uint32_t index, const ke::RefPtr<Native> &pEntry);
private:
typedef NameHashSet<ke::Ref<Native>, Native> NativeCache;
typedef NameHashSet<ke::RefPtr<Native>, Native> NativeCache;
List<IfaceInfo> m_Interfaces;
HandleType_t m_TypeRoot;

View File

@ -144,7 +144,7 @@ SMCError TextParsers::ParseSMCFile(const char *file,
fclose(fp);
errstr = GetSMCErrorString(result);
ke::SafeSprintf(buffer, maxsize, "%s", errstr != NULL ? errstr : "Unknown error");
ke::SafeStrcpy(buffer, maxsize, errstr != NULL ? errstr : "Unknown error");
return result;
}
@ -195,7 +195,7 @@ SMCError TextParsers::ParseSMCStream(const char *stream,
result = ParseStream_SMC(&rs, RawStreamReader, smc_listener, states);
const char *errstr = GetSMCErrorString(result);
ke::SafeSprintf(buffer, maxsize, "%s", errstr != NULL ? errstr : "Unknown error");
ke::SafeStrcpy(buffer, maxsize, errstr != NULL ? errstr : "Unknown error");
return result;
}

View File

@ -672,6 +672,12 @@ TransError CPhraseFile::GetTranslation(const char *szPhrase, unsigned int lang_i
return Trans_Okay;
}
bool CPhraseFile::TranslationPhraseExists(const char *phrase)
{
int address;
return m_PhraseLookup.retrieve(phrase, &address);
}
const char *CPhraseFile::GetFilename()
{
return m_File.c_str();
@ -934,7 +940,7 @@ bool Translator::AddLanguage(const char *langcode, const char *description)
Language *pLanguage = new Language;
idx = m_Languages.size();
ke::SafeSprintf(pLanguage->m_code2, sizeof(pLanguage->m_code2), "%s", langcode);
ke::SafeStrcpy(pLanguage->m_code2, sizeof(pLanguage->m_code2), langcode);
pLanguage->m_CanonicalName = m_pStringTab->AddString(lower);
m_LCodeLookup.insert(langcode, idx);

View File

@ -71,6 +71,7 @@ public:
void ReparseFile();
const char *GetFilename();
TransError GetTranslation(const char *szPhrase, unsigned int lang_id, Translation *pTrans);
bool TranslationPhraseExists(const char *phrase);
public: //ITextListener_SMC
void ReadSMC_ParseStart();
SMCResult ReadSMC_NewSection(const SMCStates *states, const char *name);

View File

@ -55,7 +55,7 @@
#include "sprintf.h"
#include "LibrarySys.h"
#include "RootConsoleMenu.h"
#include "CDataPack.h"
#include "CellArray.h"
#include <bridge/include/BridgeAPI.h>
#include <bridge/include/IProviderCallbacks.h>
@ -85,6 +85,9 @@ IScriptManager *scripts = &g_PluginSys;
IExtensionSys *extsys = &g_Extensions;
ILogger *logger = &g_Logger;
CNativeOwner g_CoreNatives;
#ifdef PLATFORM_X64
PseudoAddressManager pseudoAddr;
#endif
static void AddCorePhraseFile(const char *filename)
{
@ -114,6 +117,24 @@ static void RegisterProfiler(IProfilingTool *tool)
g_ProfileToolManager.RegisterTool(tool);
}
static void *FromPseudoAddress(uint32_t paddr)
{
#ifdef PLATFORM_X64
return pseudoAddr.FromPseudoAddress(paddr);
#else
return nullptr;
#endif
}
static uint32_t ToPseudoAddress(void *addr)
{
#ifdef PLATFORM_X64
return pseudoAddr.ToPseudoAddress(addr);
#else
return 0;
#endif
}
// Defined in smn_filesystem.cpp.
extern bool OnLogPrint(const char *msg);
@ -145,8 +166,10 @@ static sm_logic_t logic =
GenerateError,
AddNatives,
RegisterProfiler,
CDataPack::New,
CDataPack::Free,
CellArray::New,
CellArray::Free,
FromPseudoAddress,
ToPseudoAddress,
&g_PluginSys,
&g_ShareSys,
&g_Extensions,

View File

@ -33,6 +33,9 @@
#define _INCLUDE_SOURCEMOD_COMMON_LOGIC_H_
#include "../sm_globals.h"
#ifdef PLATFORM_X64
#include "PseudoAddrManager.h"
#endif
namespace SourceMod {
class CoreProvider;
@ -57,6 +60,7 @@ class IVEngineServerBridge;
#endif
} // namespace SourceMod
struct ServerGlobals;
class PseudoAddressManager;
extern SourceMod::CoreProvider *bridge;
extern SourceMod::IHandleSys *handlesys;
@ -76,6 +80,7 @@ extern SourceMod::IScriptManager *scripts;
extern SourceMod::IExtensionSys *extsys;
extern SourceMod::ILogger *logger;
extern SourceMod::IMenuManager *menus;
extern PseudoAddressManager pseudoAddr;
#if defined SM_LOGIC
extern SourceMod::IVEngineServerBridge *engine;

View File

@ -502,7 +502,11 @@ static cell_t CloneArray(IPluginContext *pContext, const cell_t *params)
return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
}
CellArray *array = oldArray->clone();
ICellArray *array = oldArray->clone();
if (!array)
{
return pContext->ThrowNativeError("Failed to clone array. Out of memory.");
}
Handle_t hndl = handlesys->CreateHandle(htCellArray, array, pContext->GetIdentity(), g_pCoreIdent, NULL);
if (!hndl)
@ -576,6 +580,21 @@ static cell_t FindValueInArray(IPluginContext *pContext, const cell_t *params)
return -1;
}
static cell_t GetArrayBlockSize(IPluginContext *pContext, const cell_t *params)
{
CellArray *array;
HandleError err;
HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
if ((err = handlesys->ReadHandle(params[1], htCellArray, &sec, (void **)&array))
!= HandleError_None)
{
return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
}
return array->blocksize();
}
REGISTER_NATIVES(cellArrayNatives)
{
{"ClearArray", ClearArray},
@ -597,6 +616,7 @@ REGISTER_NATIVES(cellArrayNatives)
{"CloneArray", CloneArray},
{"FindStringInArray", FindStringInArray},
{"FindValueInArray", FindValueInArray},
{"GetArrayBlockSize", GetArrayBlockSize},
// Transitional syntax support.
{"ArrayList.ArrayList", CreateArray},
@ -618,6 +638,7 @@ REGISTER_NATIVES(cellArrayNatives)
{"ArrayList.Clone", CloneArray},
{"ArrayList.FindString", FindStringInArray},
{"ArrayList.FindValue", FindValueInArray},
{"ArrayList.BlockSize.get", GetArrayBlockSize},
{NULL, NULL},
};

View File

@ -369,6 +369,21 @@ static cell_t ArrayStack_PopArray(IPluginContext *pContext, const cell_t *params
return 0;
}
static cell_t GetStackBlockSize(IPluginContext *pContext, const cell_t *params)
{
HandleError err;
CellArray *array;
HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
if ((err = handlesys->ReadHandle(params[1], htCellStack, &sec, (void **)&array))
!= HandleError_None)
{
return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
}
return array->blocksize();
}
REGISTER_NATIVES(cellStackNatives)
{
{"CreateStack", CreateStack},
@ -379,6 +394,7 @@ REGISTER_NATIVES(cellStackNatives)
{"PushStackArray", PushStackArray},
{"PushStackCell", PushStackCell},
{"PushStackString", PushStackString},
{"GetStackBlockSize", GetStackBlockSize},
// Transitional syntax support.
{"ArrayStack.ArrayStack", CreateStack},
@ -389,6 +405,7 @@ REGISTER_NATIVES(cellStackNatives)
{"ArrayStack.PushString", PushStackString},
{"ArrayStack.PushArray", PushStackArray},
{"ArrayStack.Empty.get", IsStackEmpty},
{"ArrayStack.BlockSize.get", GetStackBlockSize},
{NULL, NULL},
};

View File

@ -31,6 +31,7 @@
#include <stdlib.h>
#include "common_logic.h"
#include <am-autoptr.h>
#include <am-moveable.h>
#include <am-refcounting.h>
#include <sm_stringhashmap.h>
@ -181,7 +182,7 @@ struct TrieSnapshot
}
size_t length;
ke::AutoArray<int> keys;
ke::AutoPtr<int[]> keys;
BaseStringTable strings;
};
@ -556,7 +557,7 @@ static cell_t CreateTrieSnapshot(IPluginContext *pContext, const cell_t *params)
TrieSnapshot *snapshot = new TrieSnapshot;
snapshot->length = pTrie->map.elements();
snapshot->keys = new int[snapshot->length];
snapshot->keys = ke::MakeUnique<int[]>(snapshot->length);
size_t i = 0;
for (StringHashMap<Entry>::iterator iter = pTrie->map.iter(); !iter.empty(); iter.next(), i++)
snapshot->keys[i] = snapshot->strings.AddString(iter->key.chars(), iter->key.length());

View File

@ -2,7 +2,7 @@
* vim: set ts=4 sw=4 tw=99 noet :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
* Copyright (C) 2004-2017 AlliedModders LLC. All rights reserved.
* =============================================================================
*
* This program is free software; you can redistribute it and/or modify it under
@ -37,6 +37,8 @@
#include <ISourceMod.h>
#include <ITranslator.h>
#include <DebugReporter.h>
#include <FrameIterator.h>
#include <sourcehook.h>
#include <sh_memory.h>
@ -59,6 +61,7 @@ using namespace SourcePawn;
HandleType_t g_PlIter;
HandleType_t g_FrameIter;
IForward *g_OnLogAction = NULL;
@ -76,6 +79,7 @@ public:
hacc.access[HandleAccess_Clone] = HANDLE_RESTRICT_IDENTITY|HANDLE_RESTRICT_OWNER;
g_PlIter = handlesys->CreateType("PluginIterator", this, 0, NULL, NULL, g_pCoreIdent, NULL);
g_FrameIter = handlesys->CreateType("FrameIterator", this, 0, NULL, NULL, g_pCoreIdent, NULL);
g_OnLogAction = forwardsys->CreateForward("OnLogAction",
ET_Hook,
@ -91,13 +95,21 @@ public:
}
void OnHandleDestroy(HandleType_t type, void *object)
{
IPluginIterator *iter = (IPluginIterator *)object;
iter->Release();
if (type == g_FrameIter)
{
delete (SafeFrameIterator *) object;
}
else if (type == g_PlIter)
{
IPluginIterator *iter = (IPluginIterator *)object;
iter->Release();
}
}
void OnSourceModShutdown()
{
forwardsys->ReleaseForward(g_OnLogAction);
handlesys->RemoveType(g_PlIter, g_pCoreIdent);
handlesys->RemoveType(g_FrameIter, g_pCoreIdent);
}
} g_CoreNativeHelpers;
@ -696,7 +708,11 @@ enum NumberType
static cell_t LoadFromAddress(IPluginContext *pContext, const cell_t *params)
{
#ifdef PLATFORM_X86
void *addr = reinterpret_cast<void*>(params[1]);
#else
void *addr = pseudoAddr.FromPseudoAddress(params[1]);
#endif
if (addr == NULL)
{
@ -724,7 +740,11 @@ static cell_t LoadFromAddress(IPluginContext *pContext, const cell_t *params)
static cell_t StoreToAddress(IPluginContext *pContext, const cell_t *params)
{
#ifdef PLATFORM_X86
void *addr = reinterpret_cast<void*>(params[1]);
#else
void *addr = pseudoAddr.FromPseudoAddress(params[1]);
#endif
if (addr == NULL)
{
@ -759,6 +779,184 @@ static cell_t StoreToAddress(IPluginContext *pContext, const cell_t *params)
return 0;
}
static cell_t IsNullVector(IPluginContext *pContext, const cell_t *params)
{
cell_t *pNullVec = pContext->GetNullRef(SP_NULL_VECTOR);
if (!pNullVec)
return 0;
cell_t *addr;
pContext->LocalToPhysAddr(params[1], &addr);
return addr == pNullVec;
}
static cell_t IsNullString(IPluginContext *pContext, const cell_t *params)
{
char *str;
if (pContext->LocalToStringNULL(params[1], &str) != SP_ERROR_NONE)
return 0;
return str == nullptr;
}
static cell_t FrameIterator_Create(IPluginContext *pContext, const cell_t *params)
{
IFrameIterator *it = pContext->CreateFrameIterator();
SafeFrameIterator *iterator = new SafeFrameIterator(it);
pContext->DestroyFrameIterator(it);
Handle_t handle = handlesys->CreateHandle(g_FrameIter, iterator, pContext->GetIdentity(), g_pCoreIdent, NULL);
if (handle == BAD_HANDLE)
{
delete iterator;
return BAD_HANDLE;
}
return handle;
}
static cell_t FrameIterator_Next(IPluginContext *pContext, const cell_t *params)
{
Handle_t hndl = (Handle_t)params[1];
HandleError err;
SafeFrameIterator *iterator;
HandleSecurity sec;
sec.pIdentity = g_pCoreIdent;
sec.pOwner = pContext->GetIdentity();
if ((err=handlesys->ReadHandle(hndl, g_FrameIter, &sec, (void **)&iterator)) != HandleError_None)
{
return pContext->ThrowNativeError("Could not read Handle %x (error %d)", hndl, err);
}
return iterator->Next();
}
static cell_t FrameIterator_Reset(IPluginContext *pContext, const cell_t *params)
{
Handle_t hndl = (Handle_t)params[1];
HandleError err;
SafeFrameIterator *iterator;
HandleSecurity sec;
sec.pIdentity = g_pCoreIdent;
sec.pOwner = pContext->GetIdentity();
if ((err=handlesys->ReadHandle(hndl, g_FrameIter, &sec, (void **)&iterator)) != HandleError_None)
{
return pContext->ThrowNativeError("Could not read Handle %x (error %d)", hndl, err);
}
iterator->Reset();
return 0;
}
static cell_t FrameIterator_LineNumber(IPluginContext *pContext, const cell_t *params)
{
Handle_t hndl = (Handle_t)params[1];
HandleError err;
SafeFrameIterator *iterator;
HandleSecurity sec;
sec.pIdentity = g_pCoreIdent;
sec.pOwner = pContext->GetIdentity();
if ((err=handlesys->ReadHandle(hndl, g_FrameIter, &sec, (void **)&iterator)) != HandleError_None)
{
return pContext->ThrowNativeError("Could not read Handle %x (error %d)", hndl, err);
}
int lineNum = iterator->LineNumber();
if (lineNum < 0)
{
return pContext->ThrowNativeError("Iterator out of bounds. Check return value of FrameIterator.Next");
}
return lineNum;
}
static cell_t FrameIterator_GetFunctionName(IPluginContext *pContext, const cell_t *params)
{
Handle_t hndl = (Handle_t)params[1];
HandleError err;
SafeFrameIterator *iterator;
HandleSecurity sec;
sec.pIdentity = g_pCoreIdent;
sec.pOwner = pContext->GetIdentity();
if ((err=handlesys->ReadHandle(hndl, g_FrameIter, &sec, (void **)&iterator)) != HandleError_None)
{
return pContext->ThrowNativeError("Could not read Handle %x (error %d)", hndl, err);
}
const char* functionName = iterator->FunctionName();
if (!functionName)
{
return pContext->ThrowNativeError("Iterator out of bounds. Check return value of FrameIterator.Next");
}
char* buffer;
pContext->LocalToString(params[2], &buffer);
size_t size = static_cast<size_t>(params[3]);
ke::SafeStrcpy(buffer, size, functionName);
return 0;
}
static cell_t FrameIterator_GetFilePath(IPluginContext *pContext, const cell_t *params)
{
Handle_t hndl = (Handle_t)params[1];
HandleError err;
SafeFrameIterator *iterator;
HandleSecurity sec;
sec.pIdentity = g_pCoreIdent;
sec.pOwner = pContext->GetIdentity();
if ((err=handlesys->ReadHandle(hndl, g_FrameIter, &sec, (void **)&iterator)) != HandleError_None)
{
return pContext->ThrowNativeError("Could not read Handle %x (error %d)", hndl, err);
}
const char* filePath = iterator->FilePath();
if (!filePath)
{
return pContext->ThrowNativeError("Iterator out of bounds. Check return value of FrameIterator.Next");
}
char* buffer;
pContext->LocalToString(params[2], &buffer);
size_t size = static_cast<size_t>(params[3]);
ke::SafeStrcpy(buffer, size, filePath);
return 0;
}
static cell_t LogStackTrace(IPluginContext *pContext, const cell_t *params)
{
char buffer[512];
g_pSM->FormatString(buffer, sizeof(buffer), pContext, params, 1);
IFrameIterator *it = pContext->CreateFrameIterator();
ke::Vector<ke::AString> arr = g_DbgReporter.GetStackTrace(it);
pContext->DestroyFrameIterator(it);
IPlugin *pPlugin = scripts->FindPluginByContext(pContext->GetContext());
g_Logger.LogError("[SM] Stack trace requested: %s", buffer);
g_Logger.LogError("[SM] Called from: %s", pPlugin->GetFilename());
for (size_t i = 0; i < arr.length(); ++i)
{
g_Logger.LogError("%s", arr[i].chars());
}
return 0;
}
REGISTER_NATIVES(coreNatives)
{
{"ThrowError", ThrowError},
@ -787,5 +985,15 @@ REGISTER_NATIVES(coreNatives)
{"RequireFeature", RequireFeature},
{"LoadFromAddress", LoadFromAddress},
{"StoreToAddress", StoreToAddress},
{"IsNullVector", IsNullVector},
{"IsNullString", IsNullString},
{"LogStackTrace", LogStackTrace},
{"FrameIterator.FrameIterator", FrameIterator_Create},
{"FrameIterator.Next", FrameIterator_Next},
{"FrameIterator.Reset", FrameIterator_Reset},
{"FrameIterator.LineNumber.get", FrameIterator_LineNumber},
{"FrameIterator.GetFunctionName", FrameIterator_GetFunctionName},
{"FrameIterator.GetFilePath", FrameIterator_GetFilePath},
{NULL, NULL},
};

View File

@ -32,6 +32,7 @@
#include "common_logic.h"
#include "Database.h"
#include "ExtensionSys.h"
#include "sprintf.h"
#include "stringutil.h"
#include "ISourceMod.h"
#include "AutoHandleRooter.h"
@ -236,6 +237,9 @@ public:
}
void CancelThinkPart()
{
if (!m_pFunction->IsRunnable())
return;
m_pFunction->PushCell(BAD_HANDLE);
m_pFunction->PushCell(BAD_HANDLE);
m_pFunction->PushString("Driver is unloading");
@ -246,9 +250,6 @@ public:
{
/* Create a Handle for our query */
HandleSecurity sec(me->GetIdentity(), g_pCoreIdent);
HandleAccess access;
handlesys->InitAccessDefaults(NULL, &access);
access.access[HandleAccess_Delete] = HANDLE_RESTRICT_IDENTITY|HANDLE_RESTRICT_OWNER;
Handle_t qh = BAD_HANDLE;
@ -256,7 +257,7 @@ public:
{
CombinedQuery *c = new CombinedQuery(m_pQuery, m_pDatabase);
qh = handlesys->CreateHandle(hCombinedQueryType, c, me->GetIdentity(), g_pCoreIdent, NULL);
qh = CreateLocalHandle(hCombinedQueryType, c, &sec);
if (qh != BAD_HANDLE)
{
m_pQuery = NULL;
@ -266,11 +267,14 @@ public:
}
}
m_pFunction->PushCell(m_MyHandle);
m_pFunction->PushCell(qh);
m_pFunction->PushString(qh == BAD_HANDLE ? error : "");
m_pFunction->PushCell(m_Data);
m_pFunction->Execute(NULL);
if (m_pFunction->IsRunnable())
{
m_pFunction->PushCell(m_MyHandle);
m_pFunction->PushCell(qh);
m_pFunction->PushString(qh == BAD_HANDLE ? error : "");
m_pFunction->PushCell(m_Data);
m_pFunction->Execute(NULL);
}
if (qh != BAD_HANDLE)
{
@ -310,6 +314,12 @@ public:
error[0] = '\0';
strncopy(dbname, _dbname, sizeof(dbname));
me = scripts->FindPluginByContext(m_pFunction->GetParentContext()->GetContext());
m_pInfo = g_DBMan.GetDatabaseConf(dbname);
if (!m_pInfo)
{
g_pSM->Format(error, sizeof(error), "Could not find database config \"%s\"", dbname);
}
}
IdentityToken_t *GetOwner()
{
@ -321,22 +331,19 @@ public:
}
void RunThreadPart()
{
g_DBMan.LockConfig();
const DatabaseInfo *pInfo = g_DBMan.FindDatabaseConf(dbname);
if (!pInfo)
if (m_pInfo)
{
g_pSM->Format(error, sizeof(error), "Could not find database config \"%s\"", dbname);
} else {
m_pDatabase = m_pDriver->Connect(pInfo, false, error, sizeof(error));
m_pDatabase = m_pDriver->Connect(&m_pInfo->info, false, error, sizeof(error));
}
g_DBMan.UnlockConfig();
}
void CancelThinkPart()
{
if (m_pDatabase)
{
m_pDatabase->Close();
}
if (!m_pFunction->IsRunnable())
return;
if (m_ACM == ACM_Old)
m_pFunction->PushCell(BAD_HANDLE);
m_pFunction->PushCell(BAD_HANDLE);
@ -348,6 +355,13 @@ public:
{
Handle_t hndl = BAD_HANDLE;
if (!m_pFunction->IsRunnable())
{
if (m_pDatabase)
m_pDatabase->Close();
return;
}
if (m_pDatabase)
{
if ((hndl = g_DBMan.CreateHandle(DBHandle_Database, m_pDatabase, me->GetIdentity()))
@ -370,6 +384,7 @@ public:
delete this;
}
private:
ke::RefPtr<ConfDbInfo> m_pInfo;
IPlugin *me;
IPluginFunction *m_pFunction;
IDBDriver *m_pDriver;
@ -440,7 +455,7 @@ static cell_t ConnectToDbAsync(IPluginContext *pContext, const cell_t *params, A
g_pSM->Format(error,
sizeof(error),
"Could not find driver \"%s\"",
pInfo->driver[0] == '\0' ? g_DBMan.GetDefaultDriverName() : pInfo->driver);
pInfo->driver[0] == '\0' ? g_DBMan.GetDefaultDriverName().chars() : pInfo->driver);
} else if (!driver->IsThreadSafe()) {
g_pSM->Format(error,
sizeof(error),
@ -732,6 +747,24 @@ static cell_t SQL_QuoteString(IPluginContext *pContext, const cell_t *params)
return s ? 1 : 0;
}
static cell_t SQL_FormatQuery(IPluginContext *pContext, const cell_t *params)
{
IDatabase *db = NULL;
HandleError err;
if ((err = g_DBMan.ReadHandle(params[1], DBHandle_Database, (void **)&db))
!= HandleError_None)
{
return pContext->ThrowNativeError("Invalid database Handle %x (error: %d)", params[1], err);
}
g_FormatEscapeDatabase = db;
cell_t result = InternalFormat(pContext, params, 1);
g_FormatEscapeDatabase = NULL;
return result;
}
static cell_t SQL_FastQuery(IPluginContext *pContext, const cell_t *params)
{
IDatabase *db = NULL;
@ -1634,8 +1667,8 @@ private:
assert(results_.length() == txn_->entries.length());
ke::AutoArray<cell_t> data(new cell_t[results_.length()]);
ke::AutoArray<cell_t> handles(new cell_t[results_.length()]);
ke::AutoPtr<cell_t[]> data = ke::MakeUnique<cell_t[]>(results_.length());
ke::AutoPtr<cell_t[]> handles = ke::MakeUnique<cell_t[]>(results_.length());
for (size_t i = 0; i < results_.length(); i++)
{
CombinedQuery *obj = new CombinedQuery(results_[i], db_);
@ -1659,12 +1692,15 @@ private:
data[i] = txn_->entries[i].data;
}
success_->PushCell(dbh);
success_->PushCell(data_);
success_->PushCell(txn_->entries.length());
success_->PushArray(handles, results_.length());
success_->PushArray(data, results_.length());
success_->Execute(NULL);
if (success_->IsRunnable())
{
success_->PushCell(dbh);
success_->PushCell(data_);
success_->PushCell(txn_->entries.length());
success_->PushArray(handles.get(), results_.length());
success_->PushArray(data.get(), results_.length());
success_->Execute(NULL);
}
// Cleanup. Note we clear results_, since freeing their handles will
// call Destroy(), and we don't want to double-free in ~TTransactOp.
@ -1692,7 +1728,7 @@ public:
{
HandleSecurity sec(ident_, g_pCoreIdent);
ke::AutoArray<cell_t> data(new cell_t[results_.length()]);
ke::AutoPtr<cell_t[]> data = ke::MakeUnique<cell_t[]>(txn_->entries.length());
for (size_t i = 0; i < txn_->entries.length(); i++)
data[i] = txn_->entries[i].data;
@ -1703,20 +1739,23 @@ public:
db_->AddRef();
}
failure_->PushCell(dbh);
failure_->PushCell(data_);
failure_->PushCell(txn_->entries.length());
failure_->PushString(error_.chars());
failure_->PushCell(failIndex_);
failure_->PushArray(data, txn_->entries.length());
failure_->Execute(NULL);
if (failure_->IsRunnable())
{
failure_->PushCell(dbh);
failure_->PushCell(data_);
failure_->PushCell(txn_->entries.length());
failure_->PushString(error_.chars());
failure_->PushCell(failIndex_);
failure_->PushArray(data.get(), txn_->entries.length());
failure_->Execute(NULL);
}
handlesys->FreeHandle(dbh, &sec);
}
}
private:
ke::Ref<IDatabase> db_;
ke::RefPtr<IDatabase> db_;
Transaction *txn_;
IdentityToken_t *ident_;
IPluginFunction *success_;
@ -1814,6 +1853,7 @@ REGISTER_NATIVES(dbNatives)
{"Database.Driver.get", Database_Driver_get},
{"Database.SetCharset", SQL_SetCharset},
{"Database.Escape", SQL_QuoteString},
{"Database.Format", SQL_FormatQuery},
{"Database.IsSameConnection", SQL_IsSameConnection},
{"Database.Execute", SQL_ExecuteTransaction},
@ -1827,6 +1867,7 @@ REGISTER_NATIVES(dbNatives)
{"SQL_Connect", SQL_Connect},
{"SQL_ConnectEx", SQL_ConnectEx},
{"SQL_EscapeString", SQL_QuoteString},
{"SQL_FormatQuery", SQL_FormatQuery},
{"SQL_Execute", SQL_Execute},
{"SQL_FastQuery", SQL_FastQuery},
{"SQL_FetchFloat", SQL_FetchFloat},

View File

@ -61,7 +61,7 @@ public:
}
void OnHandleDestroy(HandleType_t type, void *object)
{
CDataPack::Free(reinterpret_cast<IDataPack *>(object));
CDataPack::Free(reinterpret_cast<CDataPack *>(object));
}
bool GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize)
{
@ -73,7 +73,7 @@ public:
static cell_t smn_CreateDataPack(IPluginContext *pContext, const cell_t *params)
{
IDataPack *pDataPack = CDataPack::New();
CDataPack *pDataPack = CDataPack::New();
if (!pDataPack)
{
@ -88,7 +88,7 @@ static cell_t smn_WritePackCell(IPluginContext *pContext, const cell_t *params)
Handle_t hndl = static_cast<Handle_t>(params[1]);
HandleError herr;
HandleSecurity sec;
IDataPack *pDataPack;
CDataPack *pDataPack;
sec.pOwner = pContext->GetIdentity();
sec.pIdentity = g_pCoreIdent;
@ -96,7 +96,13 @@ static cell_t smn_WritePackCell(IPluginContext *pContext, const cell_t *params)
if ((herr=handlesys->ReadHandle(hndl, g_DataPackType, &sec, (void **)&pDataPack))
!= HandleError_None)
{
return pContext->ThrowNativeError("Invalid data pack handle %x (error %d)", hndl, herr);
return pContext->ThrowNativeError("Invalid data pack handle %x (error %d).", hndl, herr);
}
bool insert = (params[0] >= 3) ? params[3] : false;
if (!insert)
{
pDataPack->RemoveItem();
}
pDataPack->PackCell(params[2]);
@ -109,7 +115,7 @@ static cell_t smn_WritePackFloat(IPluginContext *pContext, const cell_t *params)
Handle_t hndl = static_cast<Handle_t>(params[1]);
HandleError herr;
HandleSecurity sec;
IDataPack *pDataPack;
CDataPack *pDataPack;
sec.pOwner = pContext->GetIdentity();
sec.pIdentity = g_pCoreIdent;
@ -117,7 +123,13 @@ static cell_t smn_WritePackFloat(IPluginContext *pContext, const cell_t *params)
if ((herr=handlesys->ReadHandle(hndl, g_DataPackType, &sec, (void **)&pDataPack))
!= HandleError_None)
{
return pContext->ThrowNativeError("Invalid data pack handle %x (error %d)", hndl, herr);
return pContext->ThrowNativeError("Invalid data pack handle %x (error %d).", hndl, herr);
}
bool insert = (params[0] >= 3) ? params[3] : false;
if (!insert)
{
pDataPack->RemoveItem();
}
pDataPack->PackFloat(sp_ctof(params[2]));
@ -130,7 +142,7 @@ static cell_t smn_WritePackString(IPluginContext *pContext, const cell_t *params
Handle_t hndl = static_cast<Handle_t>(params[1]);
HandleError herr;
HandleSecurity sec;
IDataPack *pDataPack;
CDataPack *pDataPack;
sec.pOwner = pContext->GetIdentity();
sec.pIdentity = g_pCoreIdent;
@ -138,7 +150,13 @@ static cell_t smn_WritePackString(IPluginContext *pContext, const cell_t *params
if ((herr=handlesys->ReadHandle(hndl, g_DataPackType, &sec, (void **)&pDataPack))
!= HandleError_None)
{
return pContext->ThrowNativeError("Invalid data pack handle %x (error %d)", hndl, herr);
return pContext->ThrowNativeError("Invalid data pack handle %x (error %d).", hndl, herr);
}
bool insert = (params[0] >= 3) ? params[3] : false;
if (!insert)
{
pDataPack->RemoveItem();
}
char *str;
@ -153,7 +171,7 @@ static cell_t smn_WritePackFunction(IPluginContext *pContext, const cell_t *para
Handle_t hndl = static_cast<Handle_t>(params[1]);
HandleError herr;
HandleSecurity sec;
IDataPack *pDataPack;
CDataPack *pDataPack;
sec.pOwner = pContext->GetIdentity();
sec.pIdentity = g_pCoreIdent;
@ -161,7 +179,13 @@ static cell_t smn_WritePackFunction(IPluginContext *pContext, const cell_t *para
if ((herr = handlesys->ReadHandle(hndl, g_DataPackType, &sec, (void **)&pDataPack))
!= HandleError_None)
{
return pContext->ThrowNativeError("Invalid data pack handle %x (error %d)", hndl, herr);
return pContext->ThrowNativeError("Invalid data pack handle %x (error %d).", hndl, herr);
}
bool insert = (params[0] >= 3) ? params[3] : false;
if (!insert)
{
pDataPack->RemoveItem();
}
pDataPack->PackFunction(params[2]);
@ -174,7 +198,7 @@ static cell_t smn_ReadPackCell(IPluginContext *pContext, const cell_t *params)
Handle_t hndl = static_cast<Handle_t>(params[1]);
HandleError herr;
HandleSecurity sec;
IDataPack *pDataPack;
CDataPack *pDataPack;
sec.pOwner = pContext->GetIdentity();
sec.pIdentity = g_pCoreIdent;
@ -182,12 +206,17 @@ static cell_t smn_ReadPackCell(IPluginContext *pContext, const cell_t *params)
if ((herr=handlesys->ReadHandle(hndl, g_DataPackType, &sec, (void **)&pDataPack))
!= HandleError_None)
{
return pContext->ThrowNativeError("Invalid data pack handle %x (error %d)", hndl, herr);
return pContext->ThrowNativeError("Invalid data pack handle %x (error %d).", hndl, herr);
}
if (!pDataPack->IsReadable(sizeof(char) + sizeof(size_t) + sizeof(cell_t)))
if (!pDataPack->IsReadable())
{
return pContext->ThrowNativeError("DataPack operation is out of bounds.");
return pContext->ThrowNativeError("Data pack operation is out of bounds.");
}
if (pDataPack->GetCurrentType() != CDataPackType::Cell)
{
return pContext->ThrowNativeError("Invalid data pack type (got %d / expected %d).", pDataPack->GetCurrentType(), CDataPackType::Cell);
}
return pDataPack->ReadCell();
@ -198,7 +227,7 @@ static cell_t smn_ReadPackFloat(IPluginContext *pContext, const cell_t *params)
Handle_t hndl = static_cast<Handle_t>(params[1]);
HandleError herr;
HandleSecurity sec;
IDataPack *pDataPack;
CDataPack *pDataPack;
sec.pOwner = pContext->GetIdentity();
sec.pIdentity = g_pCoreIdent;
@ -206,12 +235,17 @@ static cell_t smn_ReadPackFloat(IPluginContext *pContext, const cell_t *params)
if ((herr=handlesys->ReadHandle(hndl, g_DataPackType, &sec, (void **)&pDataPack))
!= HandleError_None)
{
return pContext->ThrowNativeError("Invalid data pack handle %x (error %d)", hndl, herr);
return pContext->ThrowNativeError("Invalid data pack handle %x (error %d).", hndl, herr);
}
if (!pDataPack->IsReadable(sizeof(char) + sizeof(size_t) + sizeof(float)))
if (!pDataPack->IsReadable())
{
return pContext->ThrowNativeError("DataPack operation is out of bounds.");
return pContext->ThrowNativeError("Data pack operation is out of bounds.");
}
if (pDataPack->GetCurrentType() != CDataPackType::Float)
{
return pContext->ThrowNativeError("Invalid data pack type (got %d / expected %d).", pDataPack->GetCurrentType(), CDataPackType::Float);
}
return sp_ftoc(pDataPack->ReadFloat());
@ -222,7 +256,7 @@ static cell_t smn_ReadPackString(IPluginContext *pContext, const cell_t *params)
Handle_t hndl = static_cast<Handle_t>(params[1]);
HandleError herr;
HandleSecurity sec;
IDataPack *pDataPack;
CDataPack *pDataPack;
sec.pOwner = pContext->GetIdentity();
sec.pIdentity = g_pCoreIdent;
@ -230,15 +264,20 @@ static cell_t smn_ReadPackString(IPluginContext *pContext, const cell_t *params)
if ((herr=handlesys->ReadHandle(hndl, g_DataPackType, &sec, (void **)&pDataPack))
!= HandleError_None)
{
return pContext->ThrowNativeError("Invalid data pack handle %x (error %d)", hndl, herr);
return pContext->ThrowNativeError("Invalid data pack handle %x (error %d).", hndl, herr);
}
const char *str;
if (!(str=pDataPack->ReadString(NULL)))
if (!pDataPack->IsReadable())
{
return pContext->ThrowNativeError("DataPack operation is out of bounds.");
return pContext->ThrowNativeError("Data pack operation is out of bounds.");
}
if (pDataPack->GetCurrentType() != CDataPackType::String)
{
return pContext->ThrowNativeError("Invalid data pack type (got %d / expected %d).", pDataPack->GetCurrentType(), CDataPackType::String);
}
const char *str = pDataPack->ReadString(NULL);
pContext->StringToLocal(params[2], params[3], str);
return 1;
@ -249,7 +288,7 @@ static cell_t smn_ReadPackFunction(IPluginContext *pContext, const cell_t *param
Handle_t hndl = static_cast<Handle_t>(params[1]);
HandleError herr;
HandleSecurity sec;
IDataPack *pDataPack;
CDataPack *pDataPack;
sec.pOwner = pContext->GetIdentity();
sec.pIdentity = g_pCoreIdent;
@ -257,12 +296,17 @@ static cell_t smn_ReadPackFunction(IPluginContext *pContext, const cell_t *param
if ((herr = handlesys->ReadHandle(hndl, g_DataPackType, &sec, (void **)&pDataPack))
!= HandleError_None)
{
return pContext->ThrowNativeError("Invalid data pack handle %x (error %d)", hndl, herr);
return pContext->ThrowNativeError("Invalid data pack handle %x (error %d).", hndl, herr);
}
if (!pDataPack->IsReadable(sizeof(char) + sizeof(size_t) + sizeof(cell_t)))
if (!pDataPack->IsReadable())
{
return pContext->ThrowNativeError("DataPack operation is out of bounds.");
return pContext->ThrowNativeError("Data pack operation is out of bounds.");
}
if (pDataPack->GetCurrentType() != CDataPackType::Function)
{
return pContext->ThrowNativeError("Invalid data pack type (got %d / expected %d).", pDataPack->GetCurrentType(), CDataPackType::Function);
}
return pDataPack->ReadFunction();
@ -273,7 +317,7 @@ static cell_t smn_ResetPack(IPluginContext *pContext, const cell_t *params)
Handle_t hndl = static_cast<Handle_t>(params[1]);
HandleError herr;
HandleSecurity sec;
IDataPack *pDataPack;
CDataPack *pDataPack;
sec.pOwner = pContext->GetIdentity();
sec.pIdentity = g_pCoreIdent;
@ -281,14 +325,17 @@ static cell_t smn_ResetPack(IPluginContext *pContext, const cell_t *params)
if ((herr=handlesys->ReadHandle(hndl, g_DataPackType, &sec, (void **)&pDataPack))
!= HandleError_None)
{
return pContext->ThrowNativeError("Invalid data pack handle %x (error %d)", hndl, herr);
return pContext->ThrowNativeError("Invalid data pack handle %x (error %d).", hndl, herr);
}
pDataPack->Reset();
if (params[2])
{
pDataPack->ResetSize();
}
else
{
pDataPack->Reset();
}
return 1;
}
@ -298,7 +345,7 @@ static cell_t smn_GetPackPosition(IPluginContext *pContext, const cell_t *params
Handle_t hndl = static_cast<Handle_t>(params[1]);
HandleError herr;
HandleSecurity sec;
IDataPack *pDataPack;
CDataPack *pDataPack;
sec.pOwner = pContext->GetIdentity();
sec.pIdentity = g_pCoreIdent;
@ -306,7 +353,7 @@ static cell_t smn_GetPackPosition(IPluginContext *pContext, const cell_t *params
if ((herr=handlesys->ReadHandle(hndl, g_DataPackType, &sec, (void **)&pDataPack))
!= HandleError_None)
{
return pContext->ThrowNativeError("Invalid data pack handle %x (error %d)", hndl, herr);
return pContext->ThrowNativeError("Invalid data pack handle %x (error %d).", hndl, herr);
}
return static_cast<cell_t>(pDataPack->GetPosition());
@ -317,7 +364,7 @@ static cell_t smn_SetPackPosition(IPluginContext *pContext, const cell_t *params
Handle_t hndl = static_cast<Handle_t>(params[1]);
HandleError herr;
HandleSecurity sec;
IDataPack *pDataPack;
CDataPack *pDataPack;
sec.pOwner = pContext->GetIdentity();
sec.pIdentity = g_pCoreIdent;
@ -325,12 +372,12 @@ static cell_t smn_SetPackPosition(IPluginContext *pContext, const cell_t *params
if ((herr=handlesys->ReadHandle(hndl, g_DataPackType, &sec, (void **)&pDataPack))
!= HandleError_None)
{
return pContext->ThrowNativeError("Invalid data pack handle %x (error %d)", hndl, herr);
return pContext->ThrowNativeError("Invalid data pack handle %x (error %d).", hndl, herr);
}
if (!pDataPack->SetPosition(params[2]))
{
return pContext->ThrowNativeError("Invalid DataPack position, %d is out of bounds", params[2]);
return pContext->ThrowNativeError("Invalid data pack position, %d is out of bounds (%d)", params[2], pDataPack->GetCapacity());
}
return 1;
@ -341,7 +388,7 @@ static cell_t smn_IsPackReadable(IPluginContext *pContext, const cell_t *params)
Handle_t hndl = static_cast<Handle_t>(params[1]);
HandleError herr;
HandleSecurity sec;
IDataPack *pDataPack;
CDataPack *pDataPack;
sec.pOwner = pContext->GetIdentity();
sec.pIdentity = g_pCoreIdent;
@ -349,7 +396,7 @@ static cell_t smn_IsPackReadable(IPluginContext *pContext, const cell_t *params)
if ((herr=handlesys->ReadHandle(hndl, g_DataPackType, &sec, (void **)&pDataPack))
!= HandleError_None)
{
return pContext->ThrowNativeError("Invalid data pack handle %x (error %d)", hndl, herr);
return pContext->ThrowNativeError("Invalid data pack handle %x (error %d).", hndl, herr);
}
return pDataPack->IsReadable(params[2]) ? 1 : 0;

View File

@ -424,6 +424,58 @@ static cell_t FormatNativeString(IPluginContext *pContext, const cell_t *params)
return SP_ERROR_NONE;
}
static cell_t IsNativeParamNullVector(IPluginContext *pContext, const cell_t *params)
{
if (!s_curnative || (s_curnative->ctx != pContext))
{
return pContext->ThrowNativeError("Not called from inside a native function");
}
cell_t param = params[1];
if (param < 1 || param > s_curparams[0])
{
return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
}
int err;
cell_t *addr;
if ((err = s_curcaller->LocalToPhysAddr(s_curparams[param], &addr)) != SP_ERROR_NONE)
{
return err;
}
cell_t *pNullVec = s_curcaller->GetNullRef(SP_NULL_VECTOR);
if (!pNullVec)
{
return 0;
}
return addr == pNullVec ? 1 : 0;
}
static cell_t IsNativeParamNullString(IPluginContext *pContext, const cell_t *params)
{
if (!s_curnative || (s_curnative->ctx != pContext))
{
return pContext->ThrowNativeError("Not called from inside a native function");
}
cell_t param = params[1];
if (param < 1 || param > s_curparams[0])
{
return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
}
int err;
char *str;
if ((err = s_curcaller->LocalToStringNULL(s_curparams[param], &str)) != SP_ERROR_NONE)
{
return err;
}
return str == nullptr ? 1 : 0;
}
//tee hee
REGISTER_NATIVES(nativeNatives)
{
@ -439,5 +491,7 @@ REGISTER_NATIVES(nativeNatives)
{"SetNativeArray", SetNativeArray},
{"SetNativeCellRef", SetNativeCellRef},
{"SetNativeString", SetNativeString},
{"IsNativeParamNullVector", IsNativeParamNullVector},
{"IsNativeParamNullString", IsNativeParamNullString},
{NULL, NULL},
};

View File

@ -321,7 +321,7 @@ static cell_t sm_OpenDirectory(IPluginContext *pContext, const cell_t *params)
{
size_t len = strlen(path);
char wildcardedPath[PLATFORM_MAX_PATH];
snprintf(wildcardedPath, sizeof(wildcardedPath), "%s%s*", path, (path[len-1] != '/' && path[len-1] != '\\') ? "/" : "");
ke::SafeSprintf(wildcardedPath, sizeof(wildcardedPath), "%s%s*", path, (path[len-1] != '/' && path[len-1] != '\\') ? "/" : "");
char *pathID;
if ((err=pContext->LocalToStringNULL(params[3], &pathID)) != SP_ERROR_NONE)

View File

@ -29,7 +29,7 @@
* Version: $Id$
*/
#include <math.h>
#include <cmath>
#include <string.h>
#include <stdlib.h>
#include "common_logic.h"
@ -190,9 +190,8 @@ static cell_t sm_SquareRoot(IPluginContext *pCtx, const cell_t *params)
static cell_t sm_RoundToNearest(IPluginContext *pCtx, const cell_t *params)
{
float val = sp_ctof(params[1]);
val = (float)floor(val + 0.5f);
return static_cast<int>(val);
return (int)val;
}
static cell_t sm_RoundToFloor(IPluginContext *pCtx, const cell_t *params)
@ -289,44 +288,6 @@ static cell_t sm_ArcTangent2(IPluginContext *pCtx, const cell_t *params)
return sp_ftoc(val1);
}
#if 0
static cell_t sm_FloatRound(IPluginContext *pCtx, const cell_t *params)
{
float val = sp_ctof(params[1]);
switch (params[2])
{
case 1:
{
val = floor(val);
break;
}
case 2:
{
val = ceil(val);
break;
}
case 3:
{
if (val >= 0.0f)
{
val = floor(val);
} else {
val = ceil(val);
}
break;
}
default:
{
val = (float)floor(val + 0.5f);
break;
}
}
return static_cast<int>(val);
}
#endif
class RandomHelpers :
public SMGlobalClass,
public IPluginsListener

View File

@ -34,7 +34,7 @@
#include <IHandleSys.h>
#include <IForwardSys.h>
#include <ISourceMod.h>
#include <am-utility.h>
#include <amtl/am-autoptr.h>
HandleType_t g_GlobalFwdType = 0;
HandleType_t g_PrivateFwdType = 0;
@ -552,6 +552,88 @@ static cell_t sm_CallPushStringEx(IPluginContext *pContext, const cell_t *params
return 1;
}
static cell_t sm_CallPushNullVector(IPluginContext *pContext, const cell_t *params)
{
int err = SP_ERROR_NOT_FOUND;
if (!s_CallStarted)
{
return pContext->ThrowNativeError("Cannot push parameters when there is no call in progress");
}
if (s_pFunction)
{
// Find the NULL_VECTOR pubvar in the target plugin and push the local address.
IPluginRuntime *runtime = s_pFunction->GetParentRuntime();
uint32_t null_vector_idx;
err = runtime->FindPubvarByName("NULL_VECTOR", &null_vector_idx);
if (err)
{
return pContext->ThrowNativeErrorEx(err, "Target plugin has no NULL_VECTOR.");
}
cell_t null_vector;
err = runtime->GetPubvarAddrs(null_vector_idx, &null_vector, nullptr);
if (!err)
err = s_pCallable->PushCell(null_vector);
}
else if (s_pForward)
{
err = s_pForward->PushArray(NULL, 3);
}
if (err)
{
s_pCallable->Cancel();
ResetCall();
return pContext->ThrowNativeErrorEx(err, NULL);
}
return 1;
}
static cell_t sm_CallPushNullString(IPluginContext *pContext, const cell_t *params)
{
int err = SP_ERROR_NOT_FOUND;
if (!s_CallStarted)
{
return pContext->ThrowNativeError("Cannot push parameters when there is no call in progress");
}
if (s_pFunction)
{
// Find the NULL_STRING pubvar in the target plugin and push the local address.
IPluginRuntime *runtime = s_pFunction->GetParentRuntime();
uint32_t null_string_idx;
err = runtime->FindPubvarByName("NULL_STRING", &null_string_idx);
if (err)
{
return pContext->ThrowNativeErrorEx(err, "Target plugin has no NULL_STRING.");
}
cell_t null_string;
err = runtime->GetPubvarAddrs(null_string_idx, &null_string, nullptr);
if (!err)
err = s_pCallable->PushCell(null_string);
}
else if (s_pForward)
{
err = s_pForward->PushString(NULL);
}
if (err)
{
s_pCallable->Cancel();
ResetCall();
return pContext->ThrowNativeErrorEx(err, NULL);
}
return 1;
}
static cell_t sm_CallFinish(IPluginContext *pContext, const cell_t *params)
{
int err = SP_ERROR_NOT_RUNNABLE;
@ -668,6 +750,8 @@ REGISTER_NATIVES(functionNatives)
{"Call_PushArrayEx", sm_CallPushArrayEx},
{"Call_PushString", sm_CallPushString},
{"Call_PushStringEx", sm_CallPushStringEx},
{"Call_PushNullVector", sm_CallPushNullVector},
{"Call_PushNullString", sm_CallPushNullString},
{"Call_Finish", sm_CallFinish},
{"Call_Cancel", sm_CallCancel},
{"RequestFrame", sm_AddFrameAction},

View File

@ -152,7 +152,11 @@ static cell_t smn_GameConfGetAddress(IPluginContext *pCtx, const cell_t *params)
if (!gc->GetAddress(key, &val))
return 0;
#ifdef PLATFORM_X86
return (cell_t)val;
#else
return pseudoAddr.ToPseudoAddress(val);
#endif
}
static GameConfigsNatives s_GameConfigsNatives;

View File

@ -0,0 +1,69 @@
/**
* vim: set ts=4 sw=4 tw=99 noet :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2016 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 "common_logic.h"
#include <IGameHelpers.h>
#include <am-string.h>
#include <inttypes.h>
static cell_t GetServerAuthId(IPluginContext *pContext, const cell_t *params)
{
cell_t *pOut;
pContext->LocalToPhysAddr(params[2], &pOut);
switch ((AuthIdType)params[1])
{
case AuthIdType::Steam3:
gamehelpers->GetServerSteam3Id((char *)pOut, params[3]);
break;
case AuthIdType::SteamId64:
ke::SafeSprintf((char *)pOut, params[3], "%" PRIu64, gamehelpers->GetServerSteamId64());
break;
default:
return pContext->ThrowNativeError("Unsupported AuthIdType (%d) for GetServerAuthId.", params[1]);
}
return 1;
}
static cell_t GetServerAccountId(IPluginContext *pContext, const cell_t *params)
{
return (cell_t)(gamehelpers->GetServerSteamId64() & 0xFFFFFFFF);
}
REGISTER_NATIVES(halflifeNatives)
{
{ "GetServerAuthId", GetServerAuthId },
{ "GetServerSteamAccountId", GetServerAccountId },
{ nullptr, nullptr }
};

View File

@ -36,6 +36,31 @@
#include <ISourceMod.h>
#include <am-string.h>
static cell_t sm_TranslationPhraseExists(IPluginContext *pCtx, const cell_t *params)
{
IPlugin *pl = pluginsys->FindPluginByContext(pCtx->GetContext());
IPhraseCollection *collection = pl->GetPhrases();
char *phrase;
pCtx->LocalToString(params[1], &phrase);
return collection->TranslationPhraseExists(phrase);
}
static cell_t sm_IsTranslatedForLanguage(IPluginContext *pCtx, const cell_t *params)
{
IPlugin *pl = pluginsys->FindPluginByContext(pCtx->GetContext());
IPhraseCollection *collection = pl->GetPhrases();
char *phrase;
pCtx->LocalToString(params[1], &phrase);
int langid = params[2];
Translation trans;
return (collection->FindTranslation(phrase, langid, &trans) == Trans_Okay);
}
static cell_t sm_LoadTranslations(IPluginContext *pCtx, const cell_t *params)
{
char *filename, *ext;
@ -43,7 +68,7 @@ static cell_t sm_LoadTranslations(IPluginContext *pCtx, const cell_t *params)
IPlugin *pl = pluginsys->FindPluginByContext(pCtx->GetContext());
pCtx->LocalToString(params[1], &filename);
ke::SafeSprintf(buffer, sizeof(buffer), "%s", filename);
ke::SafeStrcpy(buffer, sizeof(buffer), filename);
/* Make sure there is no extension */
if ((ext = strstr(buffer, ".txt")) != NULL
@ -147,6 +172,8 @@ static cell_t sm_GetLanguageByName(IPluginContext *pContext, const cell_t *param
REGISTER_NATIVES(langNatives)
{
{"IsTranslatedForLanguage", sm_IsTranslatedForLanguage},
{"TranslationPhraseExists", sm_TranslationPhraseExists},
{"LoadTranslations", sm_LoadTranslations},
{"SetGlobalTransTarget", sm_SetGlobalTransTarget},
{"GetClientLanguage", sm_GetClientLanguage},

View File

@ -58,6 +58,10 @@ struct maplist_info_t
{
return strcmp(value->name, key) == 0;
}
static inline uint32_t hash(const detail::CharsAndLength &key)
{
return key.hash();
}
};
#define MAPLIST_FLAG_MAPSFOLDER (1<<0) /**< On failure, use all maps in the maps folder. */
@ -321,7 +325,7 @@ public:
{
return strcmp((char *)str1, (char *)str2);
}
CellArray *UpdateMapList(CellArray *pUseArray, const char *name, int *pSerial, unsigned int flags)
ICellArray *UpdateMapList(ICellArray *pUseArray, const char *name, int *pSerial, unsigned int flags)
{
int change_serial;
CellArray *pNewArray = NULL;
@ -515,10 +519,11 @@ private:
continue;
}
if (strcmp(bridge->GetSourceEngineName(), "insurgency") == 0)
if (strcmp(bridge->GetSourceEngineName(), "insurgency") == 0
|| strcmp(bridge->GetSourceEngineName(), "doi") == 0)
{
// Insurgency (presumably?) doesn't allow spaces in map names
// and does use a space to delimit the map name from the map mode
// Insurgency and Day of Infamy (presumably?) doesn't allow spaces in map names
// and do use a space to delimit the map name from the map mode
int i = 0;
while (ptr[i] != 0)
{
@ -594,7 +599,7 @@ static cell_t LoadMapList(IPluginContext *pContext, const cell_t *params)
char *str;
Handle_t hndl;
cell_t *addr, flags;
CellArray *pArray, *pNewArray;
ICellArray *pArray, *pNewArray;
hndl = params[1];
pContext->LocalToPhysAddr(params[2], &addr);

View File

@ -1652,7 +1652,7 @@ REGISTER_NATIVES(menuNatives)
{"Panel.TextRemaining.get", GetPanelTextRemaining},
{"Panel.CurrentKey.get", GetPanelCurrentKey},
{"Panel.CurrentKey.set", SetPanelCurrentKey},
{"Panel.Style", GetPanelStyle},
{"Panel.Style.get", GetPanelStyle},
{"Panel.CanDrawFlags", CanPanelDrawFlags},
{"Panel.SetTitle", SetPanelTitle},
{"Panel.SetKeys", SetPanelKeys},

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