mirror of
https://github.com/alliedmodders/sourcemod.git
synced 2025-12-06 18:08:36 +00:00
Merge branch 'master' into override-fix
This commit is contained in:
commit
f471b6fcfb
74
.github/CONTRIBUTING.md
vendored
Normal file
74
.github/CONTRIBUTING.md
vendored
Normal 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
26
.github/ISSUE_TEMPLATE.md
vendored
Normal 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.
|
||||
129
.travis.yml
129
.travis.yml
@ -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
|
||||
|
||||
290
AMBuildScript
290
AMBuildScript
@ -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 })
|
||||
|
||||
12
README.md
12
README.md
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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"
|
||||
}
|
||||
|
||||
|
||||
32
configure.py
32
configure.py
@ -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()
|
||||
|
||||
113
core/AMBuilder
113
core/AMBuilder
@ -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)
|
||||
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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];
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -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();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
551
core/convar_sm.h
551
core/convar_sm.h
@ -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
@ -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
|
||||
@ -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
@ -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)]
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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_
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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;
|
||||
};
|
||||
|
||||
|
||||
184
core/logic/DatabaseConfBuilder.cpp
Normal file
184
core/logic/DatabaseConfBuilder.cpp
Normal 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;
|
||||
}
|
||||
129
core/logic/DatabaseConfBuilder.h
Normal file
129
core/logic/DatabaseConfBuilder.h
Normal 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_
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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);
|
||||
};
|
||||
|
||||
@ -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)))
|
||||
{
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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(¶m->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(¶m->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)
|
||||
|
||||
@ -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)
|
||||
|
||||
96
core/logic/FrameIterator.cpp
Normal file
96
core/logic/FrameIterator.cpp
Normal 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();
|
||||
}
|
||||
77
core/logic/FrameIterator.h
Normal file
77
core/logic/FrameIterator.h
Normal 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;
|
||||
};
|
||||
@ -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)
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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()
|
||||
{
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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 = §ions[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
|
||||
|
||||
@ -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();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
@ -73,7 +73,7 @@ void CNativeOwner::UnbindWeakRef(const WeakNative &ref)
|
||||
pContext->GetRuntime()->UpdateNativeBinding(
|
||||
ref.idx,
|
||||
nullptr,
|
||||
0,
|
||||
SP_NTVFLAG_OPTIONAL,
|
||||
nullptr);
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
|
||||
|
||||
169
core/logic/PseudoAddrManager.cpp
Normal file
169
core/logic/PseudoAddrManager.cpp
Normal 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
|
||||
}
|
||||
51
core/logic/PseudoAddrManager.h
Normal file
51
core/logic/PseudoAddrManager.h
Normal 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_
|
||||
@ -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';
|
||||
|
||||
@ -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 :
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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},
|
||||
};
|
||||
|
||||
@ -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},
|
||||
};
|
||||
|
||||
@ -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());
|
||||
|
||||
@ -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},
|
||||
};
|
||||
|
||||
@ -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},
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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},
|
||||
};
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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},
|
||||
|
||||
@ -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;
|
||||
|
||||
69
core/logic/smn_halflife.cpp
Normal file
69
core/logic/smn_halflife.cpp
Normal 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 }
|
||||
};
|
||||
@ -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},
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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
Loading…
Reference in New Issue
Block a user